李沐《动手学深度学习》预备知识 张量操作及数据处理
李沐《动手学深度学习》预备知识 线性代数及微积分
李沐《动手学深度学习》线性神经网络 线性回归
李沐《动手学深度学习》线性神经网络 softmax回归
李沐《动手学深度学习》多层感知机 模型概念和代码实现
教材:李沐《动手学深度学习》
问题是,我们永远不能准确地计算出泛化误差。 这是因为无限多的数据样本是一个虚构的对象。 在实际中,我们只能通过将模型应用于一个独立的测试集来估计泛化误差, 该测试集由随机选取的、未曾在训练集中出现的数据样本构成。
倾向于影响模型泛化的因素:
在机器学习中,我们通常在评估几个候选模型后选择最终的模型。 这个过程叫做模型选择。为了确定候选模型中的最佳模型,我们通常会使用验证集。
是否过拟合或欠拟合可能取决于模型复杂性和可用训练数据集的大小。
要保证权重向量比较小, 最常用方法是将其范数作为惩罚项加到最小化损失的问题中。 将原来的训练目标最小化训练标签上的预测损失, 调整为最小化预测损失和惩罚项之和:(其中
λ
\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∑??w?l(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∑??w?l(i)(w,b)=w?∣B∣η?i∈B∑?x(i)(wTx(i)+b?y(i))
权重衰减的从零开始代码实现:
def l2_penalty(w):
return torch.sum(w.pow(2)) / 2
# 广播机制使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)
暂退法:在前向传播过程中,计算每一内部层的同时注入噪声。
之所以被称为暂退法,是因为我们从表面上看是在训练过程中丢弃(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其他情况?
暂退法的从零开始代码实现:
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)
根据返回的结果可知,最终的矩阵乘积发生爆炸:
假设一个简单的多层感知机有一个隐藏层和两个隐藏单元。 在这种情况下,我们可以对第一层的权重
进行重排列, 并且同样对输出层的权重进行重排列,可以获得相同的函数。 第一个隐藏单元与第二个隐藏单元没有什么特别的区别。 换句话说,我们在每一层的隐藏单元之间具有排列对称性。
训练数据为:
测试数据为:
训练集由真实照片组成,而测试集只包含卡通图片。 假设在一个与测试集的特征有着本质不同的数据集上进行训练, 如果没有方法来适应新的领域,可能会有麻烦。
根据症状来预测患者的疾病时,疾病的相对流行率会随着时间的推移而变化
当我们部署机器学习系统时, 不仅仅是在优化一个预测模型, 而通常是在提供一个会被用来(部分或完全)进行自动化决策的工具。 这些技术系统可能会通过其进行的决定而影响到每个人的生活。从考虑预测到决策的飞跃不仅提出了新的技术问题, 而且还提出了一系列必须仔细考虑的伦理问题。