动手学深度学习PyTorch版学习笔记1

线性回归
主要内容包括:

线性回归的基本要素
线性回归模型从零开始的实现
线性回归模型使用pytorch的简洁实现
线性回归的基本要素
模型
为了简单起见,这里我们假设价格只取决于房屋状况的两个因素,即面积(平方米)和房龄(年)。接下来我们希望探索价格与这两个因素的具体关系。线性回归假设输出与各个输入之间是线性关系:

price=warea⋅area+wage⋅age+b

数据集
我们通常收集一系列的真实数据,例如多栋房屋的真实售出价格和它们对应的面积和房龄。我们希望在这个数据上面寻找模型参数来使模型的预测价格与真实价格的误差最小。在机器学习术语里,该数据集被称为训练数据集(training data set)或训练集(training set),一栋房屋被称为一个样本(sample),其真实售出价格叫作标签(label),用来预测标签的两个因素叫作特征(feature)。特征用来表征样本的特点。

损失函数
在模型训练中,我们需要衡量价格预测值与真实值之间的误差。通常我们会选取一个非负数作为误差,且数值越小表示误差越小。一个常用的选择是平方函数。 它在评估索引为 i 的样本误差的表达式为

l(i)(w,b)=12(y^(i)−y(i))2,

L(w,b)=1n∑i=1nl(i)(w,b)=1n∑i=1n12(w⊤x(i)+b−y(i))2.

优化函数 - 随机梯度下降
当模型和损失函数形式较为简单时,上面的误差最小化问题的解可以直接用公式表达出来。这类解叫作解析解(analytical solution)。本节使用的线性回归和平方误差刚好属于这个范畴。然而,大多数深度学习模型并没有解析解,只能通过优化算法有限次迭代模型参数来尽可能降低损失函数的值。这类解叫作数值解(numerical solution)。

在求数值解的优化算法中,小批量随机梯度下降(mini-batch stochastic gradient descent)在深度学习中被广泛使用。它的算法很简单:先选取一组模型参数的初始值,如随机选取;接下来对参数进行多次迭代,使每次迭代都可能降低损失函数的值。在每次迭代中,先随机均匀采样一个由固定数目训练数据样本所组成的小批量(mini-batch) B ,然后求小批量中数据样本的平均损失有关模型参数的导数(梯度),最后用此结果与预先设定的一个正数的乘积作为模型参数在本次迭代的减小量。

(w,b)←(w,b)−η|B|∑i∈B∂(w,b)l(i)(w,b)

学习率: η 代表在每次优化中,能够学习的步长的大小
批量大小: B 是小批量计算中的批量大小batch size

总结一下,优化函数的有以下两个步骤:

(i)初始化模型参数,一般来说使用随机初始化;
(ii)我们在数据上迭代多次,通过在负梯度方向移动参数来更新每个参数。

softmax和分类模型
内容包含:

softmax回归的基本概念
如何获取Fashion-MNIST数据集和读取数据
softmax回归模型的从零开始实现,实现一个对Fashion-MNIST训练集中的图像数据进行分类的模型
使用pytorch重新实现softmax回归模型
softmax的基本概念
分类问题
一个简单的图像分类问题,输入图像的高和宽均为2像素,色彩为灰度。
图像中的4像素分别记为 x1,x2,x3,x4 。
假设真实标签为狗、猫或者鸡,这些标签对应的离散值为 y1,y2,y3 。
我们通常使用离散的数值来表示类别,例如 y1=1,y2=2,y3=3 。

权重矢量
o1=x1w11+x2w21+x3w31+x4w41+b1

o2=x1w12+x2w22+x3w32+x4w42+b2

o3=x1w13+x2w23+x3w33+x4w43+b3

神经网络图
下图用神经网络图描绘了上面的计算。softmax回归同线性回归一样,也是一个单层神经网络。由于每个输出 o1,o2,o3 的计算都要依赖于所有的输入 x1,x2,x3,x4 ,softmax回归的输出层也是一个全连接层。
Image Name

softmax回归是一个单层神经网络

既然分类问题需要得到离散的预测输出,一个简单的办法是将输出值 oi 当作预测类别是 i 的置信度,并将值最大的输出所对应的类作为预测输出,即输出 argmaxioi 。例如,如果 o1,o2,o3 分别为 0.1,10,0.1 ,由于 o2 最大,那么预测类别为2,其代表猫。

输出问题
直接使用输出层的输出有两个问题:
一方面,由于输出层的输出值的范围不确定,我们难以直观上判断这些值的意义。例如,刚才举的例子中的输出值10表示“很置信”图像类别为猫,因为该输出值是其他两类的输出值的100倍。但如果 o1=o3=103 ,那么输出值10却又表示图像类别为猫的概率很低。
另一方面,由于真实标签是离散值,这些离散值与不确定范围的输出值之间的误差难以衡量。
softmax运算符(softmax operator)解决了以上两个问题。它通过下式将输出值变换成值为正且和为1的概率分布:

y1,y2,y^3=softmax(o1,o2,o3)

其中

y1=exp(o1)∑3i=1exp(oi),y2=exp(o2)∑3i=1exp(oi),y^3=exp(o3)∑3i=1exp(oi).

容易看出 y1+y2+y^3=1 且 0≤y1,y2,y^3≤1 ,因此 y1,y2,y^3 是一个合法的概率分布。这时候,如果 y^2=0.8 ,不管 y^1 和 y^3 的值是多少,我们都知道图像类别为猫的概率是80%。此外,我们注意到

argmaxioi=argmaxiy^i

因此softmax运算不改变预测类别输出。

计算效率
单样本矢量计算表达式
为了提高计算效率,我们可以将单样本分类通过矢量计算来表达。在上面的图像分类问题中,假设softmax回归的权重和偏差参数分别为
W=⎡⎣⎢⎢⎢w11w21w31w41w12w22w32w42w13w23w33w43⎤⎦⎥⎥⎥,b=[b1b2b3],

设高和宽分别为2个像素的图像样本 i 的特征为

x(i)=[x(i)1x(i)2x(i)3x(i)4],

输出层的输出为

o(i)=[o(i)1o(i)2o(i)3],

预测为狗、猫或鸡的概率分布为

y(i)=[y(i)1y(i)2y(i)3].

softmax回归对样本 i 分类的矢量计算表达式为

o(i)y^(i)=x(i)W+b,=softmax(o(i)).

小批量矢量计算表达式
为了进一步提升计算效率,我们通常对小批量数据做矢量计算。广义上讲,给定一个小批量样本,其批量大小为 n ,输入个数(特征数)为 d ,输出个数(类别数)为 q 。设批量特征为 X∈Rn×d 。假设softmax回归的权重和偏差参数分别为 W∈Rd×q 和 b∈R1×q 。softmax回归的矢量计算表达式为
OY^=XW+b,=softmax(O),

其中的加法运算使用了广播机制, O,Y^∈Rn×q 且这两个矩阵的第 i 行分别为样本 i 的输出 o(i) 和概率分布 y^(i) 。

交叉熵损失函数
对于样本 i ,我们构造向量 y(i)∈Rq ,使其第 y(i) (样本 i 类别的离散数值)个元素为1,其余为0。这样我们的训练目标可以设为使预测概率分布 y^(i) 尽可能接近真实的标签概率分布 y(i) 。

平方损失估计
Loss=|y^(i)−y(i)|2/2

然而,想要预测分类结果正确,我们其实并不需要预测概率完全等于标签概率。例如,在图像分类的例子里,如果 y(i)=3 ,那么我们只需要 y^(i)3 比其他两个预测值 y^(i)1 和 y^(i)2 大就行了。即使 y^(i)3 值为0.6,不管其他两个预测值为多少,类别预测均正确。而平方损失则过于严格,例如 y(i)1=y(i)2=0.2 比 y(i)1=0,y(i)2=0.4 的损失要小很多,虽然两者都有同样正确的分类预测结果。

改善上述问题的一个方法是使用更适合衡量两个概率分布差异的测量函数。其中,交叉熵(cross entropy)是一个常用的衡量方法:

H(y(i),y(i))=−∑j=1qy(i)jlogy(i)j,

其中带下标的 y(i)j 是向量 y(i) 中非0即1的元素,需要注意将它与样本 i 类别的离散数值,即不带下标的 y(i) 区分。在上式中,我们知道向量 y(i) 中只有第 y(i) 个元素 y(i)y(i) 为1,其余全为0,于是 H(y(i),y(i))=−logyy(i)(i) 。也就是说,交叉熵只关心对正确类别的预测概率,因为只要其值足够大,就可以确保分类结果正确。当然,遇到一个样本有多个标签时,例如图像里含有不止一个物体时,我们并不能做这一步简化。但即便对于这种情况,交叉熵同样只关心对图像中出现的物体类别的预测概率。

假设训练数据集的样本数为 n ,交叉熵损失函数定义为
ℓ(Θ)=1n∑i=1nH(y(i),y^(i)),

其中 Θ 代表模型参数。同样地,如果每个样本只有一个标签,那么交叉熵损失可以简写成 ℓ(Θ)=−(1/n)∑ni=1logy^(i)y(i) 。从另一个角度来看,我们知道最小化 ℓ(Θ) 等价于最大化 exp(−nℓ(Θ))=∏ni=1y^(i)y(i) ,即最小化交叉熵损失函数等价于最大化训练数据集所有标签类别的联合预测概率。

多层感知机
多层感知机的基本知识
使用多层感知机图像分类的从零开始的实现
使用pytorch的简洁实现
多层感知机的基本知识
深度学习主要关注多层模型。在这里,我们将以多层感知机(multilayer perceptron,MLP)为例,介绍多层神经网络的概念。

隐藏层
表达公式
具体来说,给定一个小批量样本 X∈Rn×d ,其批量大小为 n ,输入个数为 d 。假设多层感知机只有一个隐藏层,其中隐藏单元个数为 h 。记隐藏层的输出(也称为隐藏层变量或隐藏变量)为 H ,有 H∈Rn×h 。因为隐藏层和输出层均是全连接层,可以设隐藏层的权重参数和偏差参数分别为 Wh∈Rd×h 和 bh∈R1×h ,输出层的权重和偏差参数分别为 Wo∈Rh×q 和 bo∈R1×q 。

我们先来看一种含单隐藏层的多层感知机的设计。其输出 O∈Rn×q 的计算为

HO=XWh+bh,=HWo+bo,

也就是将隐藏层的输出直接作为输出层的输入。如果将以上两个式子联立起来,可以得到

O=(XWh+bh)Wo+bo=XWhWo+bhWo+bo.

从联立后的式子可以看出,虽然神经网络引入了隐藏层,却依然等价于一个单层神经网络:其中输出层权重参数为 WhWo ,偏差参数为 bhWo+bo 。不难发现,即便再添加更多的隐藏层,以上设计依然只能与仅含输出层的单层神经网络等价。

激活函数
上述问题的根源在于全连接层只是对数据做仿射变换(affine transformation),而多个仿射变换的叠加仍然是一个仿射变换。解决问题的一个方法是引入非线性变换,例如对隐藏变量使用按元素运算的非线性函数进行变换,然后再作为下一个全连接层的输入。这个非线性函数被称为激活函数(activation function)。

下面我们介绍几个常用的激活函数:

ReLU函数
ReLU(rectified linear unit)函数提供了一个很简单的非线性变换。给定元素 x ,该函数定义为

ReLU(x)=max(x,0).

可以看出,ReLU函数只保留正数元素,并将负数元素清零。

Sigmoid函数
sigmoid函数可以将元素的值变换到0和1之间:

sigmoid(x)=11+exp(−x).

tanh函数
tanh(双曲正切)函数可以将元素的值变换到-1和1之间:

tanh(x)=1−exp(−2x)1+exp(−2x).

我们接着绘制tanh函数。当输入接近0时,tanh函数接近线性变换。虽然该函数的形状和sigmoid函数的形状很像,但tanh函数在坐标系的原点上对称。

关于激活函数的选择
ReLu函数是一个通用的激活函数,目前在大多数情况下使用。但是,ReLU函数只能在隐藏层中使用。

用于分类器时,sigmoid函数及其组合通常效果更好。由于梯度消失问题,有时要避免使用sigmoid和tanh函数。

在神经网络层数较多的时候,最好使用ReLu函数,ReLu函数比较简单计算量少,而sigmoid和tanh函数计算量大很多。

在选择激活函数的时候可以先选用ReLu函数如果效果不理想可以尝试其他激活函数。

多层感知机
多层感知机就是含有至少一个隐藏层的由全连接层组成的神经网络,且每个隐藏层的输出通过激活函数进行变换。多层感知机的层数和各隐藏层中隐藏单元个数都是超参数。以单隐藏层为例并沿用本节之前定义的符号,多层感知机按以下方式计算输出:

HO=ϕ(XWh+bh),=HWo+bo,

其中 ϕ 表示激活函数。

过拟合、欠拟合及其解决方案
过拟合、欠拟合的概念
权重衰减
丢弃法
模型选择、过拟合和欠拟合
训练误差和泛化误差
在解释上述现象之前,我们需要区分训练误差(training error)和泛化误差(generalization error)。通俗来讲,前者指模型在训练数据集上表现出的误差,后者指模型在任意一个测试数据样本上表现出的误差的期望,并常常通过测试数据集上的误差来近似。计算训练误差和泛化误差可以使用之前介绍过的损失函数,例如线性回归用到的平方损失函数和softmax回归用到的交叉熵损失函数。

机器学习模型应关注降低泛化误差。

模型选择
验证数据集
从严格意义上讲,测试集只能在所有超参数和模型参数选定后使用一次。不可以使用测试数据选择模型,如调参。由于无法从训练误差估计泛化误差,因此也不应只依赖训练数据选择模型。鉴于此,我们可以预留一部分在训练数据集和测试数据集以外的数据来进行模型选择。这部分数据被称为验证数据集,简称验证集(validation set)。例如,我们可以从给定的训练集中随机选取一小部分作为验证集,而将剩余部分作为真正的训练集。

K折交叉验证
由于验证数据集不参与模型训练,当训练数据不够用时,预留大量的验证数据显得太奢侈。一种改善的方法是K折交叉验证(K-fold cross-validation)。在K折交叉验证中,我们把原始训练数据集分割成K个不重合的子数据集,然后我们做K次模型训练和验证。每一次,我们使用一个子数据集验证模型,并使用其他K-1个子数据集来训练模型。在这K次训练和验证中,每次用来验证模型的子数据集都不同。最后,我们对这K次训练误差和验证误差分别求平均。

过拟合和欠拟合
接下来,我们将探究模型训练中经常出现的两类典型问题:

一类是模型无法得到较低的训练误差,我们将这一现象称作欠拟合(underfitting);
另一类是模型的训练误差远小于它在测试数据集上的误差,我们称该现象为过拟合(overfitting)。 在实践中,我们要尽可能同时应对欠拟合和过拟合。虽然有很多因素可能导致这两种拟合问题,在这里我们重点讨论两个因素:模型复杂度和训练数据集大小。
模型复杂度
为了解释模型复杂度,我们以多项式函数拟合为例。给定一个由标量数据特征和对应的标量标签组成的训练数据集,多项式函数拟合的目标是找一个阶多项式函数

来近似 。在上式中,是模型的权重参数,是偏差参数。与线性回归相同,多项式函数拟合也使用平方损失函数。特别地,一阶多项式函数拟合又叫线性函数拟合。

给定训练数据集,模型复杂度和误差之间的关系:

Image Name

训练数据集大小
影响欠拟合和过拟合的另一个重要因素是训练数据集的大小。一般来说,如果训练数据集中样本数过少,特别是比模型参数数量(按元素计)更少时,过拟合更容易发生。此外,泛化误差不会随训练数据集里样本数量增加而增大。因此,在计算资源允许的范围之内,我们通常希望训练数据集大一些,特别是在模型复杂度较高时,例如层数较多的深度学习模型。

权重衰减
方法
权重衰减等价于 范数正则化(regularization)。正则化通过为模型损失函数添加惩罚项使学出的模型参数值较小,是应对过拟合的常用手段。

L2 范数正则化(regularization)
范数正则化在模型原损失函数基础上添加范数惩罚项,从而得到训练所需要最小化的函数。范数惩罚项指的是模型权重参数每个元素的平方和与一个正的常数的乘积。以线性回归中的线性回归损失函数为例

其中是权重参数,是偏差参数,样本的输入为,标签为,样本数为。将权重参数用向量表示,带有范数惩罚项的新损失函数为

其中超参数。当权重参数均为0时,惩罚项最小。当较大时,惩罚项在损失函数中的比重较大,这通常会使学到的权重参数的元素较接近0。当设为0时,惩罚项完全不起作用。上式中范数平方展开后得到。 有了范数惩罚项后,在小批量随机梯度下降中,我们将线性回归一节中权重和的迭代方式更改为

可见,范数正则化令权重和先自乘小于1的数,再减去不含惩罚项的梯度。因此,范数正则化又叫权重衰减。权重衰减通过惩罚绝对值较大的模型参数为需要学习的模型增加了限制,这可能对过拟合有效。

高维线性回归实验从零开始的实现
下面,我们以高维线性回归为例来引入一个过拟合问题,并使用权重衰减来应对过拟合。设数据样本特征的维度为。对于训练数据集和测试数据集中特征为的任一样本,我们使用如下的线性函数来生成该样本的标签:

其中噪声项服从均值为0、标准差为0.01的正态分布。为了较容易地观察过拟合,我们考虑高维线性回归问题,如设维度;同时,我们特意把训练数据集的样本数设低,如20。

丢弃法
多层感知机中神经网络图描述了一个单隐藏层的多层感知机。其中输入个数为4,隐藏单元个数为5,且隐藏单元()的计算表达式为

这里是激活函数,是输入,隐藏单元的权重参数为,偏差参数为。当对该隐藏层使用丢弃法时,该层的隐藏单元将有一定概率被丢弃掉。设丢弃概率为,那么有的概率会被清零,有的概率会除以做拉伸。丢弃概率是丢弃法的超参数。具体来说,设随机变量为0和1的概率分别为和。使用丢弃法时我们计算新的隐藏单元
由于,因此

即丢弃法不改变其输入的期望值。让我们对之前多层感知机的神经网络中的隐藏层使用丢弃法,一种可能的结果如图所示,其中和被清零。这时输出值的计算不再依赖和,在反向传播时,与这两个隐藏单元相关的权重的梯度均为0。由于在训练中隐藏层神经元的丢弃是随机的,即都有可能被清零,输出层的计算无法过度依赖中的任一个,从而在训练模型时起到正则化的作用,并可以用来应对过拟合。在测试模型时,我们为了拿到更加确定性的结果,一般不使用丢弃法

总结
欠拟合现象:模型无法达到一个较低的误差

过拟合现象:训练误差较低但是泛化误差依然较高,二者相差较大

梯度消失和梯度爆炸
深度模型有关数值稳定性的典型问题是消失(vanishing)和爆炸(explosion)。

当神经网络的层数较多时,模型的数值稳定性容易变差。

假设一个层数为的多层感知机的第层的权重参数为,输出层的权重参数为。为了便于讨论,不考虑偏差参数,且设所有隐藏层的激活函数为恒等映射(identity mapping)。给定输入,多层感知机的第层的输出。此时,如果层数较大,的计算可能会出现衰减或爆炸。举个例子,假设输入和所有层的权重参数都是标量,如权重参数为0.2和5,多层感知机的第30层输出为输入分别与(消失)和(爆炸)的乘积。当层数较多时,梯度的计算也容易出现消失或爆炸。

随机初始化模型参数
在神经网络中,通常需要随机初始化模型参数。下面我们来解释这样做的原因。

回顾多层感知机一节描述的多层感知机。为了方便解释,假设输出层只保留一个输出单元(删去和以及指向它们的箭头),且隐藏层使用相同的激活函数。如果将每个隐藏单元的参数都初始化为相等的值,那么在正向传播时每个隐藏单元将根据相同的输入计算出相同的值,并传递至输出层。在反向传播中,每个隐藏单元的参数梯度值相等。因此,这些参数在使用基于梯度的优化算法迭代后值依然相等。之后的迭代也是如此。在这种情况下,无论隐藏单元有多少,隐藏层本质上只有1个隐藏单元在发挥作用。因此,正如在前面的实验中所做的那样,我们通常将神经网络的模型参数,特别是权重参数,进行随机初始化。

PyTorch的默认随机初始化
随机初始化模型参数的方法有很多。在线性回归的简洁实现中,我们使用torch.nn.init.normal_()使模型net的权重参数采用正态分布的随机初始化方式。不过,PyTorch中nn.Module的模块参数都采取了较为合理的初始化策略(不同类型的layer具体采样的哪一种初始化方法的可参考源代码),因此一般不用我们考虑。

Xavier随机初始化
还有一种比较常用的随机初始化方法叫作Xavier随机初始化。 假设某全连接层的输入个数为,输出个数为,Xavier随机初始化将使该层中权重参数的每个元素都随机采样于均匀分布

它的设计主要考虑到,模型参数初始化后,每层输出的方差不该受该层输入个数影响,且每层梯度的方差也不该受该层输出个数影响。

考虑环境因素
协变量偏移
这里我们假设,虽然输入的分布可能随时间而改变,但是标记函数,即条件分布P(y∣x)不会改变。虽然这个问题容易理解,但在实践中也容易忽视。

想想区分猫和狗的一个例子。我们的训练数据使用的是猫和狗的真实的照片,但是在测试时,我们被要求对猫和狗的卡通图片进行分类。

cat cat dog dog
Image Name Image Name Image Name Image Name
测试数据:

cat cat dog dog
Image Name Image Name Image Name Image Name
显然,这不太可能奏效。训练集由照片组成,而测试集只包含卡通。在一个看起来与测试集有着本质不同的数据集上进行训练,而不考虑如何适应新的情况,这是不是一个好主意。不幸的是,这是一个非常常见的陷阱。

统计学家称这种协变量变化是因为问题的根源在于特征分布的变化(即协变量的变化)。数学上,我们可以说P(x)改变了,但P(y∣x)保持不变。尽管它的有用性并不局限于此,当我们认为x导致y时,协变量移位通常是正确的假设。

标签偏移
当我们认为导致偏移的是标签P(y)上的边缘分布的变化,但类条件分布是不变的P(x∣y)时,就会出现相反的问题。当我们认为y导致x时,标签偏移是一个合理的假设。例如,通常我们希望根据其表现来预测诊断结果。在这种情况下,我们认为诊断引起的表现,即疾病引起的症状。有时标签偏移和协变量移位假设可以同时成立。例如,当真正的标签函数是确定的和不变的,那么协变量偏移将始终保持,包括如果标签偏移也保持。有趣的是,当我们期望标签偏移和协变量偏移保持时,使用来自标签偏移假设的方法通常是有利的。这是因为这些方法倾向于操作看起来像标签的对象,这(在深度学习中)与处理看起来像输入的对象(在深度学习中)相比相对容易一些。

病因(要预测的诊断结果)导致 症状(观察到的结果)。

训练数据集,数据很少只包含流感p(y)的样本。

而测试数据集有流感p(y)和流感q(y),其中不变的是流感症状p(x|y)。

概念偏移
另一个相关的问题出现在概念转换中,即标签本身的定义发生变化的情况。这听起来很奇怪,毕竟猫就是猫。的确,猫的定义可能不会改变,但我们能不能对软饮料也这么说呢?事实证明,如果我们周游美国,按地理位置转移数据来源,我们会发现,即使是如图所示的这个简单术语的定义也会发生相当大的概念转变。

如果我们要建立一个机器翻译系统,分布P(y∣x)可能因我们的位置而异。这个问题很难发现。另一个可取之处是P(y∣x)通常只是逐渐变化。

[摘自伯禹学习平台《ElitesAI·动手学深度学习PyTorch版》]

你可能感兴趣的:(机器学习)