系列文章
李沐《动手学深度学习》预备知识 张量操作及数据处理
李沐《动手学深度学习》预备知识 线性代数及微积分
李沐《动手学深度学习》线性神经网络 线性回归
李沐《动手学深度学习》线性神经网络 softmax回归
李沐《动手学深度学习》多层感知机 模型概念和代码实现
目录
- 系列文章
- 一、模型选择、欠拟合和过拟合
- (一)训练误差和泛化误差
- (二)模型选择:验证集
- (三)欠拟合与过拟合
- 二、过拟合的解决
- (一)权重衰减:正则化
- (二)暂退法dropout
- 三、前向传播和反向传播
- 四、数值稳定性和模型初始化
- (一)梯度消失和梯度爆炸
- (二)参数初始化
- 五、环境和分布偏移
- (一)分布偏移的类型
- (二)分布偏移纠正
- (三)学习问题的分类法
- (四)机器学习中的公平、责任和透明度
教材:李沐《动手学深度学习》
一、模型选择、欠拟合和过拟合
(一)训练误差和泛化误差
- 训练误差:模型在训练数据集上计算得到的误差;
- 泛化误差:模型应用在同样从原始样本的分布中抽取的无限多数据样本时,模型误差的期望。
问题是,我们永远不能准确地计算出泛化误差。 这是因为无限多的数据样本是一个虚构的对象。 在实际中,我们只能通过将模型应用于一个独立的测试集来估计泛化误差, 该测试集由随机选取的、未曾在训练集中出现的数据样本构成。
倾向于影响模型泛化的因素:
- 可调整参数的数量:当可调整参数的数量(有时称为自由度)很大时,模型往往更容易过拟合;
- 参数采用的值:当权重的取值范围较大时,模型可能更容易过拟合;
- 训练样本的数量:训练样本达到一定数量时,模型可能出现过拟合。
(二)模型选择:验证集
在机器学习中,我们通常在评估几个候选模型后选择最终的模型。 这个过程叫做模型选择。为了确定候选模型中的最佳模型,我们通常会使用验证集。
- 为了避免过拟合测试数据的风险,通常会将数据分成三份:训练数据集、测试数据集、验证数据集。(实际应用时验证数据和测试数据之间的边界十分模糊。)
- 训练数据稀缺时,可能无法提供足够的数据来构成一个合适的验证集,这时可以采用K折交叉验证法:
- 将原始训练数据分成K个不重叠的子集;
- 执行K次模型训练和验证,每次在K-1个子集上进行训练, 并在剩余的一个子集(在该轮中没有用于训练的子集)上进行验证;
- 对K次实验的结果取平均来估计训练和验证误差。
(三)欠拟合与过拟合
- 欠拟合:训练误差和验证误差都很严重, 但它们之间仅有一点差距;
- 过拟合:训练误差明显低于验证误差;
是否过拟合或欠拟合可能取决于模型复杂性和可用训练数据集的大小。
二、过拟合的解决
(一)权重衰减:正则化
要保证权重向量比较小, 最常用方法是将其范数作为惩罚项加到最小化损失的问题中。 将原来的训练目标最小化训练标签上的预测损失, 调整为最小化预测损失和惩罚项之和:(其中
λ
\lambda
λ为正则化常数)
L
(
w
,
b
)
+
λ
2
∣
∣
w
∣
∣
2
L(w,b)+\frac{\lambda}{2}||w||^2
L(w,b)+2λ∣∣w∣∣2
L2正则化回归的小批量随机梯度下降更新:
w
←
(
1
−
η
λ
)
w
−
η
∣
B
∣
∑
i
∈
B
∂
w
l
(
i
)
(
w
,
b
)
=
w
−
η
∣
B
∣
∑
i
∈
B
x
(
i
)
(
w
T
x
(
i
)
+
b
−
y
(
i
)
)
w\leftarrow (1-\eta\lambda)w-\frac{\eta}{|B|}\sum_{i\in B}\partial_{w}l^{(i)}(w,b)=w-\frac{\eta}{|B|}\sum_{i\in B}x^{(i)}(w^Tx^{(i)}+b-y^{(i)})
w←(1−ηλ)w−∣B∣ηi∈B∑∂wl(i)(w,b)=w−∣B∣ηi∈B∑x(i)(wTx(i)+b−y(i))
线性回归中w参数的随机梯度下降更新:
w ← w − η ∣ B ∣ ∑ i ∈ B ∂ w l ( i ) ( w , b ) = w − η ∣ B ∣ ∑ i ∈ B x ( i ) ( w T x ( i ) + b − y ( i ) ) w\leftarrow w-\frac{\eta}{|B|}\sum_{i\in B}\partial_{w}l^{(i)}(w,b)=w-\frac{\eta}{|B|}\sum_{i\in B}x^{(i)}(w^Tx^{(i)}+b-y^{(i)}) w←w−∣B∣ηi∈B∑∂wl(i)(w,b)=w−∣B∣ηi∈B∑x(i)(wTx(i)+b−y(i))
权重衰减的从零开始代码实现:
- 定义L2范数惩罚:实现这一惩罚最方便的方法是对所有项求平方后并将它们求和
def l2_penalty(w):
return torch.sum(w.pow(2)) / 2
- 将L2的平方惩罚添加到原始目标函数中
# 广播机制使l2_penalty(w)成为一个长度为batch_size的向量
l = loss(net(X), y) + lambd * l2_penalty(w)
权重衰减的简洁代码实现:
深度学习框架为了便于我们使用权重衰减, 将权重衰减集成到优化算法中,以便与任何损失函数结合使用。 在实例化优化器时可以直接通过weight_decay指定weight decay超参数。 默认情况下,PyTorch同时衰减权重和偏移。 这里只为权重设置了weight_decay,所以偏置参数b不会衰减。
# 偏置参数没有衰减
trainer = torch.optim.SGD([
{"params":net[0].weight,'weight_decay': wd},
{"params":net[0].bias}], lr=lr)
(二)暂退法dropout
暂退法:在前向传播过程中,计算每一内部层的同时注入噪声。
之所以被称为暂退法,是因为我们从表面上看是在训练过程中丢弃(drop out)一些神经元。 在整个训练过程的每一次迭代中,标准暂退法包括在计算下一层之前将当前层中的一些节点置零。
在标准暂退法正则化中,通过按保留(未丢弃)的节点的分数进行规范化来消除每一层的偏差。每个中间活性值
h
h
h 以暂退概率
p
p
p 由随机变量
h
′
h'
h′ 替换(满足
E
[
h
′
]
=
h
E[h']=h
E[h′]=h):
h
′
=
{
0
概率为p
h
1
−
p
其他情况
h' = \begin{cases} 0 & \text{概率为p} \\ \frac{h}{1-p} & \text{其他情况} \end{cases}
h′={01−ph概率为p其他情况
暂退法的从零开始代码实现:
- 定义dropout_layer 函数: 以dropout的概率丢弃张量输入X中的元素, 将剩余部分除以1.0-dropout。
def dropout_layer(X, dropout):
assert 0 <= dropout <= 1
# 在本情况中,所有元素都被丢弃
if dropout == 1:
return torch.zeros_like(X)
# 在本情况中,所有元素都被保留
if dropout == 0:
return X
mask = (torch.rand(X.shape) > dropout).float()
return mask * X / (1.0 - dropout)
- 将暂退法应用于每个隐藏层的输出(在激活函数之后), 并为每一层分别设置暂退概率: 常见的技巧是在靠近输入层的地方设置较低的暂退概率。暂退法只在训练期间有效。
dropout1, dropout2 = 0.2, 0.5#将第一个和第二个隐藏层的暂退概率分别设置为0.2和0.5
class Net(nn.Module):
def __init__(self, num_inputs, num_outputs, num_hiddens1, num_hiddens2,
is_training = True):
super(Net, self).__init__()
self.num_inputs = num_inputs
self.training = is_training
self.lin1 = nn.Linear(num_inputs, num_hiddens1)
self.lin2 = nn.Linear(num_hiddens1, num_hiddens2)
self.lin3 = nn.Linear(num_hiddens2, num_outputs)
self.relu = nn.ReLU()
def forward(self, X):
H1 = self.relu(self.lin1(X.reshape((-1, self.num_inputs))))
# 只有在训练模型时才使用dropout
if self.training == True:
# 在第一个全连接层之后添加一个dropout层
H1 = dropout_layer(H1, dropout1)
H2 = self.relu(self.lin2(H1))
if self.training == True:
# 在第二个全连接层之后添加一个dropout层
H2 = dropout_layer(H2, dropout2)
out = self.lin3(H2)
return out
net = Net(num_inputs, num_outputs, num_hiddens1, num_hiddens2)
暂退法的简洁代码实现:
对于深度学习框架的高级API,只需在每个全连接层之后添加一个Dropout层, 将暂退概率作为唯一的参数传递给它的构造函数。 在训练时,Dropout层将根据指定的暂退概率随机丢弃上一层的输出(相当于下一层的输入)。 在测试时,Dropout层仅传递数据。
net = nn.Sequential(nn.Flatten(),
nn.Linear(784, 256),
nn.ReLU(),
# 在第一个全连接层之后添加一个dropout层
nn.Dropout(dropout1),
nn.Linear(256, 256),
nn.ReLU(),
# 在第二个全连接层之后添加一个dropout层
nn.Dropout(dropout2),
nn.Linear(256, 10))
def init_weights(m):
if type(m) == nn.Linear:
nn.init.normal_(m.weight, std=0.01)
net.apply(init_weights);
三、前向传播和反向传播
- 前向传播:在神经网络定义的计算图中按顺序计算和存储中间变量,它的顺序是从输入层到输出;
- 反向传播:计算神经网络参数梯度的方法,根据微积分中的链式规则,按相反的顺序从输出层到输入层遍历网络。
在训练神经网络时,前向传播和反向传播相互依赖。 对于前向传播,我们沿着依赖的方向遍历计算图并计算其路径上的所有变量。 然后将这些用于反向传播,其中计算顺序与计算图的相反。
四、数值稳定性和模型初始化
(一)梯度消失和梯度爆炸
- 梯度爆炸问题: 参数更新过大,破坏了模型的稳定收敛;
- 梯度消失问题: 参数更新过小,在每次更新时几乎不会移动,导致模型无法学习。
sigmoid函数的梯度损失问题:
%matplotlib inline
import torch
from d2l import torch as d2l
x = torch.arange(-8.0, 8.0, 0.1, requires_grad=True)
y = torch.sigmoid(x)
y.backward(torch.ones_like(x))
d2l.plot(x.detach().numpy(), [y.detach().numpy(), x.grad.numpy()],
legend=['sigmoid', 'gradient'], figsize=(4.5, 2.5))
当sigmoid函数的输入很大或是很小时,它的梯度都会消失。当反向传播通过许多层时,一旦有一层的梯度接近于0,整个乘积的梯度可能会消失。
梯度爆炸问题:
生成100个高斯随机矩阵,并将它们与某个初始矩阵相乘:
M = torch.normal(0, 1, size=(4,4))
print('一个矩阵 \n',M)
for i in range(100):
M = torch.mm(M,torch.normal(0, 1, size=(4, 4)))
print('乘以100个矩阵后\n', M)
根据返回的结果可知,最终的矩阵乘积发生爆炸:
(二)参数初始化
- 随机初始化是保证在进行优化前打破对称性的关键;
假设一个简单的多层感知机有一个隐藏层和两个隐藏单元。 在这种情况下,我们可以对第一层的权重
进行重排列, 并且同样对输出层的权重进行重排列,可以获得相同的函数。 第一个隐藏单元与第二个隐藏单元没有什么特别的区别。 换句话说,我们在每一层的隐藏单元之间具有排列对称性。
- 默认初始化:不指定初始化方法, 框架将使用默认的随机初始化方法;
- Xavier初始化:通常从均值为0,方差 σ 2 = 2 n i n + n o u t \sigma^2=\frac{2}{n_{in}+n_{out}} σ2=nin+nout2的高斯分布中采样权重,也可以改为选择从均匀分布中抽取权重时的方差;
- Xavier初始化表明,对于每一层,输出的方差不受输入数量的影响,任何梯度的方差不受输出数量的影响。
五、环境和分布偏移
(一)分布偏移的类型
- 协变量偏移:输入分布发生变化了,但是标签函数(即条件分布 P ( y ∣ x ) P(y|x) P(y∣x)没有改变)
训练数据为:
测试数据为:
训练集由真实照片组成,而测试集只包含卡通图片。 假设在一个与测试集的特征有着本质不同的数据集上进行训练, 如果没有方法来适应新的领域,可能会有麻烦。
- 标签偏移:标签边缘概率 P ( y ) P(y) P(y)发生了改变,但是类别条件分布 P ( x ∣ y ) P(x|y) P(x∣y)在不同领域之间保持不变。
根据症状来预测患者的疾病时,疾病的相对流行率会随着时间的推移而变化
- 概念偏移:标签的定义发生了变化。
(二)分布偏移纠正
- 经验风险与实际风险
真实风险是从真实分布中抽取的所有数据的总体损失的预期。然而,这个数据总体通常是无法获得的。经验风险是训练数据的平均损失,用于近似真实风险。在实践中,我们进行经验风险最小化。 - 在相应的假设条件下,可以利用加权经验风险最小化在测试时检测并纠正协变量偏移和标签偏移。在测试时,不考虑这种偏移可能会成为问题。
- 概念偏移纠正
- 使用新数据更新现有的网络权重,而不是从头开始训练。
(三)学习问题的分类法
- 批量学习:访问一组训练特征和标签 , 使用这些特性和标签训练。 然后部署此模型来对来自同一分布的新数据进行评分。
- 在线学习:首先观测到x, 然后我们得出一个估计值f(x), 只有当我们做到这一点后,我们才观测到y。 然后根据我们的决定,我们会得到奖励或损失。 在这个循环中,给定新的观测结果,我们会不断地改进我们的模型。
- 老虎机:受到限制的在线学习,即给定新的观测结果后我们可以采取的行动是有限的。
- 控制:环境会记住我们所做的事, 不一定是以一种对抗的方式,但它会记住,而且它的反应将取决于之前发生的事情。
- 强化学习:强调如何基于环境而行动,以取得最大化的预期利益。
- 考虑到环境:上述不同情况之间的一个关键区别是: 在静止环境中可能一直有效的相同策略, 在环境能够改变的情况下可能不会始终有效。
(四)机器学习中的公平、责任和透明度
当我们部署机器学习系统时, 不仅仅是在优化一个预测模型, 而通常是在提供一个会被用来(部分或完全)进行自动化决策的工具。 这些技术系统可能会通过其进行的决定而影响到每个人的生活。从考虑预测到决策的飞跃不仅提出了新的技术问题, 而且还提出了一系列必须仔细考虑的伦理问题。