线性回归
主要内容包括:
- 线性回归的基本要素
- 线性回归模型从零开始的实现
- 线性回归模型使用pytorch的简洁实现
线性回归的基本要素
模型
为了简单起见,这里我们假设价格只取决于房屋状况的两个因素,即面积(平方米)和房龄(年)。接下来我们希望探索价格与这两个因素的具体关系。线性回归假设输出与各个输入之间是线性关系:
$$
\mathrm{price} = w_{\mathrm{area}} \cdot \mathrm{area} + w_{\mathrm{age}} \cdot \mathrm{age} + b
$$
模型学习的即为$ω$(权重)和$b$(偏差)。
数据集
我们通常收集一系列的真实数据,例如多栋房屋的真实售出价格和它们对应的面积和房龄。我们希望在这个数据上面寻找模型参数来使模型的预测价格与真实价格的误差最小。在机器学习术语里,该数据集被称为训练数据集(training data set)或训练集(training set),一栋房屋被称为一个样本(sample),其真实售出价格叫作标签(label),用来预测标签的两个因素叫作特征(feature)。特征用来表征样本的特点。
损失函数
在模型训练中,我们需要衡量价格预测值与真实值之间的误差。通常我们会选取一个非负数作为误差,且数值越小表示误差越小。一个常用的选择是平方函数,即我们通常说的最小均方误差。它在评估索引为 $i$ 的样本误差的表达式为
$$
l^{(i)}(\mathbf{w}, b) = \frac{1}{2} \left(\hat{y}^{(i)} - y^{(i)}\right)^2,
$$
$$
L(\mathbf{w}, b) =\frac{1}{n}\sum_{i=1}^n l^{(i)}(\mathbf{w}, b) =\frac{1}{n} \sum_{i=1}^n \frac{1}{2}\left(\mathbf{w}^\top \mathbf{x}^{(i)} + b - y^{(i)}\right)^2.
$$
优化函数 - 随机梯度下降
当模型和损失函数形式较为简单时,上面的误差最小化问题的解可以直接用公式表达出来。这类解叫作解析解(analytical solution)。本节使用的线性回归和平方误差刚好属于这个范畴。然而,大多数深度学习模型并没有解析解,只能通过优化算法有限次迭代模型参数来尽可能降低损失函数的值。这类解叫作数值解(numerical solution)。
在求数值解的优化算法中,小批量随机梯度下降(mini-batch stochastic gradient descent)在深度学习中被广泛使用。它的算法很简单:先选取一组模型参数的初始值,如随机选取;接下来对参数进行多次迭代,使每次迭代都可能降低损失函数的值。在每次迭代中,先随机均匀采样一个由固定数目训练数据样本所组成的小批量(mini-batch)$\mathcal{B}$,然后求小批量中数据样本的平均损失有关模型参数的导数(梯度),最后用此结果与预先设定的一个正数的乘积作为模型参数在本次迭代的减小量。
$$
(\mathbf{w},b) \leftarrow (\mathbf{w},b) - \frac{\eta}{|\mathcal{B}|} \sum_{i \in \mathcal{B}} \partial_{(\mathbf{w},b)} l^{(i)}(\mathbf{w},b)
$$
学习率: $\eta$代表在每次优化中,能够学习的步长的大小
批量大小: $\mathcal{B}$是小批量计算中的批量大小batch size
总结一下,优化函数的有以下两个步骤:
- (i)初始化模型参数,一般来说使用随机初始化;
- (ii)我们在数据上迭代多次,通过在负梯度方向移动参数来更新每个参数。
矢量计算
在模型训练或预测时,我们常常会同时处理多个数据样本并用到矢量计算。在介绍线性回归的矢量计算表达式之前,让我们先考虑对两个向量相加的两种方法。
- 向量相加的一种方法是,将这两个向量按元素逐一做标量加法。
- 向量相加的另一种方法是,将这两个向量直接做矢量加法。
note: 利用torch生成向量,参考文档: torch document, pytorch 中文文档,利用torch.Size( )查看torch向量的维度,参考文档: torch.Tensor.size
1 | import torch |
1 | torch.Size([1000]) torch.Size([1000]) |
定义一个计时类Timer测量程序运行时间。
1 | # define a timer class to record time |
现在我们可以来测试了。首先将两个向量使用for循环按元素逐一做标量加法。
1 | timer = Timer() # 将Timer实例化,实例化:定义了一个“某班学生类”,实例化:分析具体的某一个学生的特征,此时的timer也有两个属性:times & start |
1 | '0.01669 sec' |
另外是使用torch来将两个向量直接做矢量加法:
1 | timer.start() # 计时开始 |
1 | '0.00100 sec' |
结果很明显,后者比前者运算速度更快。因此,我们应该尽可能采用矢量计算,以提升计算效率。
线性回归模型从零开始的实现
1 | # import packages and modules |
1 | 1.3.1 |
生成数据集
使用线性模型来生成数据集,生成一个1000个样本的数据集,下面是用来生成数据的线性关系:
$$
\mathrm{price} = w_{\mathrm{area}} \cdot \mathrm{area} + w_{\mathrm{age}} \cdot \mathrm{age} + b
$$
1 | # 设置输入特征参数,两个特征 |
使用图像来展示生成的数据
1 | def use_svg_display(): |
![svg](E:/deeplearning_hand/post/线性回归 (2)/output_16_0.svg)
读取数据集
1 | def data_iter(batch_size, features, labels): |
yield 函数:
返回前先存在生成器g (generator),此时需要返回的没有值,需要调用next()函数才能显示,下一次循环才return之前的值。
参考: CSDN Blog
1 | batch_size = 10 |
1 | tensor([[ 0.1194, -0.7470], |
上面的cell注释break,页面 —> 匹诺曹的鼻子
初始化模型参数
1 | w = torch.tensor(np.random.normal(0, 0.01, (num_inputs, 1)), dtype=torch.float32) # 步长0.01 |
1 | tensor([0.], requires_grad=True) |
pytorch autograd 参考网页
定义模型
定义用来训练参数的训练模型:
$$
\mathrm{price} = w_{\mathrm{area}} \cdot \mathrm{area} + w_{\mathrm{age}} \cdot \mathrm{age} + b
$$
1 | def linreg(X, w, b): |
定义损失函数
我们使用的是均方误差损失函数:
$$
l^{(i)}(\mathbf{w}, b) = \frac{1}{2} \left(\hat{y}^{(i)} - y^{(i)}\right)^2,
$$
1 | def squared_loss(y_hat, y): |
定义优化函数
在这里优化函数使用的是小批量随机梯度下降:
$$
(\mathbf{w},b) \leftarrow (\mathbf{w},b) - \frac{\eta}{|\mathcal{B}|} \sum_{i \in \mathcal{B}} \partial_{(\mathbf{w},b)} l^{(i)}(\mathbf{w},b)
$$
1 | def sgd(params, lr, batch_size): |
训练
当数据集、模型、损失函数和优化函数定义完了之后就可来准备进行模型的训练了。
1 | # super parameters init |
1 | epoch 1, loss 0.044235 |
1 | w, true_w, b, true_b |
1 | (tensor([[ 2.0005], |
线性回归模型使用pytorch的简洁实现
1 | import torch |
1 | 1.3.1 |
生成数据集
在这里生成数据集跟从零开始的实现中是完全一样的。
1 | num_inputs = 2 |
读取数据集
1 | import torch.utils.data as Data |
1 | for X, y in data_iter: |
1 | tensor([[ 1.9411, -1.2459], |
定义模型
1 | class LinearNet(nn.Module): |
1 | LinearNet( |
1 | # 3 ways to init a multilayer network |
1 | Sequential( |
初始化模型参数
1 | from torch.nn import init |
1 | Parameter containing: |
1 | for param in net.parameters(): |
1 | Parameter containing: |
定义损失函数
1 | loss = nn.MSELoss() # nn built-in squared loss function |
定义优化函数
1 | import torch.optim as optim |
1 | SGD ( |
训练
1 | num_epochs = 3 |
1 | epoch 1, loss: 0.000307 |
1 | # result comparision |
1 | [2, -3.4] tensor([[ 2.0005, -3.3996]]) |
两种实现方式的比较
从零开始的实现(推荐用来学习)
能够更好的理解模型和神经网络底层的原理
使用pytorch的简洁实现
能够更加快速地完成模型的设计与实现