Linear Regression
概念
首先咱们先来了解一下 回归、线性等概念。
回归
回归(regression)是能为一个或多个自变量与因变量之间关系建模的一类方法。直白点,就是先一堆点里面找一根线,让线在尽可能在所有点的中间。
而回归的目的就是为了预测未来,通过找到的这根线来预测未来。
线性
而线性也比较简单,就是自变量、因变量可以用一条直线来表示。
此时应该已经明白线性回归的意思了吧。在一堆点里面寻找一条直线,尽可能让直线在所有点的中间。
原理
为了能够有预测某种东西的模型,我们需要收集一个真实的数据集,这个用机器学习的术语叫做 训练数据集 或 训练集。这些数据集里面包含了很多行数据,每一行数据就是一个样本/数据点/数据样本。而每一行数据里面的预测信息称为特征/协变量,需要预测的目标为 标签/目标。
比如,想预测一下房价。先去网上拿到一堆交易信息(包含面积、房龄、销售价钱),这个就是训练数据集;每一个交易信息就是一个样本;每一个样本里面的面积、房龄 被叫做特征;想要预测的房屋价钱就是标签/目的。
线性模型
在线性模型中,我们假设因变量可以通过自变量的线性组合来描述。
当有 d 个特征时,线性模型的一般形式可以表示为:
将所有特征放到向量
这两个是干什么的呢?下面只是说一下作用,后面会详细讲的。
第一个:模型质量的的度量方式可以帮助我们评估模型预测的准确程度。
第二个:为了提高模型预测质量,我们需要使用一种有效的方法来更新模型的参数.
损失函数
损失函数用来衡量模型预测结果与真实值之间的差异或误差程度。通常我们会选择非负数作为损失,且数值越小表示损失越小,完美预测时的损失为0。
损失函数
下面咱们用比较常用的平分损失函数(MSE)
为了方便计算梯度时的推导和计算,咱们采用1/2来表示。
当我们对损失函数进行优化时,使用梯度下降等方法来更新模型参数。在求解梯度时,平方的因子 2 可以抵消平方项的导数中产生的系数,简化了计算过程。
解析解
解析解是指直接通过数学公式来计算得到的闭式解,而不是通过迭代算法进行优化。对于线性回归问题,解析解可以使用最小二乘法来求解。
首先,需要把偏置
这样就变成了
随机梯度下降
但模型没有显示解(解析解)的时候,我们只能选择迭代优化算法来确定模型的参数。
我们选择的是 梯度下降(gradient descent)的方法, 这种方法几乎可以优化所有深度学习模型。 它通过不断地在损失函数递减的方向上更新参数来降低误差。
首先,我们需要确定初始化模型参数
在公式中
在每次迭代中,我们首先随机抽样一个小批量
表示每个小批量中的样本数,这也称为批量大小(batch size)。
梯度下降法
根据这个视频,我理解的是如何走,才使得损失函数走到最小值。
已知函数沿着梯度(一个向量)走将取得最大值、变化最快、变化率最大;那么反方向走就是下降最快,走到最小值点即可!!
从零实现
首先,需要导入后面用到的包
1 | !pip install d2l==0.14 #安装d2l包 |
生成数据集
我们将根据带有噪声的线性模型构造一个人造数据集。 我们的任务是使用这个有限样本的数据集来恢复这个模型的参数。
下面代码生成一个包含1000个样本的数据集, 每个样本包含从标准正态分布中采样的2个特征。合成的数据集是一个矩阵
我们使用线性模型参数
1 | def synthetic_data(w, b, num_examples): #@save |
1 | torch.normal(mean, std, size, *, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False) -> Tensor |
1 | torch.matmul(input, other, *, out=None) -> Tensor |
接下来咱们可以看一下散点图
1 | d2l.set_figsize() |
读取数据集
还记得咱们更新参数的时候,需要选取一小部分样本来代替这个数据集进行更新模型。所以我们最好封装一个函数,来进行随机获取小批量样本。
1 | def data_iter(batch_size, features, labels): # batch_size需要样本的长度 |
yield 是一个Python关键字,用于定义生成器函数。当在函数中使用yield语句时,函数将成为一个生成器函数。
它的作用是使函数能够暂停执行并返回一个值,然后在下一次迭代时从离开的地方继续执行。每次调用生成器函数时,它会返回一个生成器对象,该对象可以用于迭代获取生成器函数产生的值。
可以读取一组试试
1 | batch_size = 10 |
初始化模型参数
接下来我们利用 normal函数随机初始化 w,并把偏差设置为0
1 | w = torch.normal(0, 0.01, size=(2,1), requires_grad=True) |
定义模型
接下来就是定义一下模型,根据咱们上面的公式来用py写
1 | def linreg(X, w, b): |
定义损失函数
这里和咱们之前讲的一样,用平分损失函数。
注意:需要把两个张量形状转换为一样的。
1 | def squared_loss(y_hat, y): |
定义优化算法
这里咱们就不使用解析解了,直接用迭代优化算法来确定模型参数的值。这里采用随机梯度下降法。
1 | def sgd(params, lr, batch_size): #params是所有参数w、b的列表;lr为学习率、baatch_size为样本数量 |
训练
接下来设置超参数后,就可以进行训练了。
在每次迭代中,我们读取一小批量训练样本,并通过我们的模型来获得一组预测。 计算完损失后,我们开始反向传播,存储每个参数的梯度。 最后,我们调用优化算法sgd来更新模型参数。
在每个迭代周期(epoch)中,我们使用data_iter函数遍历整个数据集, 并将训练数据集中所有样本都使用一次(假设样本数能够被批量大小整除)。 这里的迭代周期个数num_epochs和学习率lr都是超参数,分别设为3和0.03。
1 | lr = 0.03 # 学习率 |
简洁实现
由于线性回归在深度学习里面比较常见,所有有框架可以使用,接下来用框架来实现,不用手写其中的一些东西。
生成数据集
还是和之前一样,手动生成。
1 | def synthetic_data(w, b, num_examples): |
读取数据集
可以调用API来随机读取小批量数据,不需要手动创建下标数组,打乱随机取。
1 | def load_array(data_arrays, batch_size, is_train=True): |
data.TensorDataset就是把特征和标签打包在一起,使之形成一一对应的关系。
*data_arrays是解包,把元祖里面的内容解出来。
data.DataLoader 就是随机返回 batch_size个样本。
关于更详细的,请看下面这篇文章。
TensorDataSet 和 DataLoader
接下来可以看看是否可以正确读取
1 | next(iter(data_iter)) #用于从数据迭代器 data_iter 中获取下一个批量的数据。 |
定义模型
在前面,我们是通过数学公式来编写代码定义模型的;但是当公式复杂的时候,这时候就需要简化这个过程了。
对于标准深度学习模型,我们可以使用框架的预定义好的层。这使我们只需关注使用哪些层来构造模型,而不必关注层的实现细节。
1 | # nn是神经网络的缩写 |
在这里,nn.Linear(2, 1) 创建了一个线性层(全连接层),输入特征的维度为 2,输出特征的维度为 1。这个线性层用于将输入特征的维度从 2 维降低到 1 维。
然后,通过 nn.Sequential 将这个线性层添加到神经网络模型中。nn.Sequential 接受一个或多个层作为参数,并按照传入的顺序将这些层组合起来形成一个序列化的神经网络模型。 最后,将创建的神经网络模型赋值给变量 net。
初始化模型参数
深度学习框架通常有预定义的方法来初始化参数。 在这里,我们指定每个权重参数应该从均值为0、标准差为0.01的正态分布中随机采样, 偏置参数将初始化为零。
1 | net[0].weight.data.normal_(0, 0.01) |
定义损失函数
计算均方误差使用的是MSELoss类,也称为平方
1 | loss = nn.MSELoss() |
定义优化算法
小批量随机梯度下降算法是一种优化神经网络的标准工具, PyTorch在optim模块中实现了该算法的许多变种。
只需要传入优化的参数、学习率即可
1 | trainer = torch.optim.SGD(net.parameters(), lr=0.03) |
训练
在每个迭代周期里,我们将完整遍历一次数据集(train_data), 不停地从中获取一个小批量的输入和相应的标签。 对于每一个小批量,我们会进行以下步骤:
* 通过调用net(X)生成预测并计算损失l(前向传播) * 通过进行反向传播来计算梯度 * 通过调用优化器来更新模型参数
1 | num_epochs = 3 |
最后可以与正确的参数值进行比较,看看差了多少
1 | w = net[0].weight.data |
- Title: Linear Regression
- Author: StarHui
- Created at : 2023-06-20 14:31:38
- Updated at : 2023-11-05 22:40:49
- Link: https://renyuhui0415.github.io/post/Linear_Regression.html
- License: This work is licensed under CC BY-NC-SA 4.0.