HBU_神经网络与深度学习 实验3 线性回归


写在前面的一些内容

  1. 本文为HBU_神经网络与深度学习实验(2022年秋)实验3的实验报告,此文的基本内容参照 [1]神经网络与深度学习:案例与实践 - 第2章(上):线性回归理论解读[2]NNDL 实验2(下),检索时请按对应题号进行检索。
  2. 本实验编程语言为Python 3.10,使用Pycharm进行编程。
  3. 本实验报告目录标题级别顺序:一、1. (1)
  4. 水平有限,难免有误,如有错漏之处敬请指正。

一、实现一个简单的线性回归模型

进行实验前,我们需要先导入torch包。

import torch

1. 数据集构建

首先,我们构造一个小的回归数据集。假设输入特征和输出标签的维度都为1,那么我们来定义一个被拟合的函数。

def linefunc(x, w=1.8, b=0.5):
    y = w * x + b
    return y

接下来的内容都将以   y = 1.8 x + 0.5 \ y=1.8x+0.5  y=1.8x+0.5 这个被拟合函数为基准进行操作。

# create_data.py
def create_data(func, interval, sample_num, noise, add_outlier=False, outlier_ratio=0.001):
    """
    根据给定的函数,生成样本
    输入:
       - func:函数
       - interval: x的取值范围
       - sample_num: 样本数目
       - noise: 噪声均方差
       - add_outlier:是否生成异常值
       - outlier_ratio:异常值占比
    输出:
       - X: 特征数据,shape=[n_samples,1]
       - y: 标签数据,shape=[n_samples,1]
    """
    # 均匀采样
    # 使用paddle.rand在生成sample_num个随机数
    X = torch.rand(sample_num) * (interval[1] - interval[0]) + interval[0]
    y = func(X)
    # 生成高斯分布的标签噪声
    # 使用paddle.normal生成概率分布为N~(0,noise^2)的数据
    epsilon = torch.normal(0, noise, y.shape)
    y = y + epsilon
    if add_outlier:  # 生成额外的异常点
        outlier_num = int(len(y) * outlier_ratio)
        if outlier_num != 0:
            # 使用paddle.randint生成服从均匀分布的、范围在[0, len(y))的随机张量
            outlier_idx = torch.randint(len(y), [outlier_num])
            y[outlier_idx] = y[outlier_idx] * 5
    return X, y

利用上面的生成样本函数,生成150个带噪音的样本,其中100个训练样本,50个测试样本,并打印出训练数据的可视化分布。

from matplotlib import pyplot as plt
from create_data import create_data

def data_processing(func, interval, train_num, test_num, step, noise):
    X_train, y_train = create_data(func=func, interval=interval, sample_num=train_num, noise=noise, add_outlier=False)
    X_test, y_test = create_data(func=func, interval=interval, sample_num=test_num, noise=noise, add_outlier=False)
    # paddle.linspace返回一个张量,张量的值为在区间start和stop上均匀间隔的num个值,输出张量的长度为num
    X_underlying = torch.linspace(interval[0], interval[1], step)
    y_underlying = func(X_underlying)
    return X_train, y_train, X_test, y_test, X_underlying, y_underlying

func = linefunc
interval = (-10, 10)  # x的取值范围
train_num, test_num = 100, 50  # 训练样本数目和测试样本数目
noise = 3  # 标准差
step = 100
X_train, y_train, X_test, y_test, X_underlying, y_underlying = data_processing(func, interval, train_num, test_num, step, noise)

# 绘制数据
plt.scatter(X_train, y_train, marker='*', facecolor="none", edgecolor='#9932CC', s=50, label="train data") # 训练数据标点颜色为暗紫色 (darkorchid)
plt.scatter(X_test, y_test, facecolor="none", edgecolor='#00BFFF', s=50, label="test data") # 测试数据标点颜色为深天蓝色 (deepskyblue)
plt.plot(X_underlying, y_underlying, c='#000000', label=r"underlying distribution")
plt.legend(fontsize='x-large')  # 给图像加图例
plt.savefig('ml-vis.pdf') # 保存图像到PDF文件中
plt.show()

代码执行结果如下图所示:
训练数据的可视化分布
这里的data_processing中的内容在本次实验后续内容还会再次使用,所以将其写成函数。


2. 模型构建

在线性回归中,自变量为样本的特征向量   x ∈ R D \ \boldsymbol{x} \in \mathbb{R}^D  xRD(每一维对应一个自变量),因变量是连续值的标签   y ∈ R \ y \in R  yR
线性模型定义为:
f ( x ; w , b ) = w T x + b \begin{align} f(\boldsymbol{x}; \boldsymbol{w},b)= \boldsymbol{w}^T \boldsymbol{x}+b \end{align} f(x;w,b)=wTx+b其中权重向量   w ∈ R D \ \boldsymbol{w} \in \mathbb{R}^D  wRD和偏置   b ∈ R \ b \in \mathbb{R}  bR都是可学习的参数。[1]

在实践中,为了提高预测样本的效率,我们通常会将   N \ N  N 样本归为一组进行成批地预测,这样可以更好地利用GPU设备的并行计算能力。
y = X w + b \begin{align} \boldsymbol{y} = \boldsymbol{X} \boldsymbol{w} + b \end{align} y=Xw+b其中   X ∈ R N × D \ \boldsymbol{X} \in \mathbb{R}^{N \times D}  XRN×D   N \ N  N 个样本的特征矩阵,   y ∈ R N \ \boldsymbol{y} \in \mathbb{R}^N  yRN   N \ N  N 个预测值组成的列向量。[1]

好了,接下来我们先定义一个算子(op.py):

# op.py
import torch
torch.manual_seed(10)  # 设置随机种子

class Op(object):
    def __init__(self):
        pass

    def __call__(self, inputs):
        return self.forward(inputs)

    def forward(self, inputs):
        raise NotImplementedError

    def backward(self, inputs):
        raise NotImplementedError

# 线性算子
class Linear(Op):
    def __init__(self, input_size):
        """
        输入:
           - input_size:模型要处理的数据特征向量长度
        """
        self.input_size = input_size
        # 模型参数
        self.params = {
   }
        self.params['w'] = torch.randn(self.input_size, 1)
        self.params['b'] = torch.zeros([1])

    def __call__(self, X):
        return self.forward(X)

    # 前向函数
    def forward(self, X):
        """
        输入:
           - X: tensor, shape=[N,D]
           注意这里的X矩阵是由N个x向量的转置拼接成的,与原教材行向量表示方式不一致
        输出:
           - y_pred: tensor, shape=[N]
        """
        N, D = X.shape
        if self.input_size == 0:
            return torch.full(size=[N, 1], fill_value=self.params['b'])
        assert D == self.input_size  # 输入数据维度合法性验证

        # 使用torch.matmul计算两个tensor的乘积
        y_pred = torch.matmul(X, self.params['w']) + self.params['b']
        return y_pred

然后我们来构建一个线性回归模型:

import op

# 注意这里我们为了和后面章节统一,这里的X矩阵是由N个x向量的转置拼接成的,与原教材行向量表示方式不一致
input_size = 3
N = 2
X = torch.randn(N, input_size)  # 生成2个维度为3的数据
model = op.Linear(input_size)
y_pred = model(X)
print("y_pred:", y_pred)  # 输出结果的个数也是2个

代码执行结果:

y_pred: tensor([[1.8529],
        [0.6011]])

3. 损失函数

回归任务是对连续值的预测,希望模型能根据数据的特征输出一个连续值作为预测值。因此回归任务中常用的评估指标是均方误差
  y ∈ R N \ \boldsymbol{y} \in \mathbb{R}^N  yRN   y ^ ∈ R N \ \hat{\boldsymbol{y}} \in \mathbb{R}^N  y^RN分别为   N \ N  N 个样本的真实标签和预测标签,均方误差的定义为:
L ( y , y ^ ) = 1 2 N

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值