D2L-四-多层感知机
DL动手学深度学习_四
多层感知机
4.4 模型选择,欠拟合和过拟合
训练误差:模型在训练数据集上计算得到的
泛化误差:模型在从原始样本的分布中抽取的无限多数据样本时的误差的期望
模型泛化的影响因素:
- 可调整参数数量
- 参数采用的值
- 训练样本的数量
K折交叉验证
原始训练数据被分成K个不重叠子集,然后执行K次模型训练和验证,每次在K-1个子集上进行训练并在剩余子集上进行验证。通过K此实验结果取平均估计训练和验证误差
def get_k_fold_data(k, i, X, y):
assert k > 1
fold_size = X.shape[0] // k
X_train, y_train = None, None
for j in range(k):
idx = slice(j * fold_size, (j + 1) * fold_size)
X_part, y_part = X[idx, :], y[idx]
if j == i:
X_valid, y_valid = X_part, y_part
elif X_train is None:
X_train, y_train = X_part, y_part
else:
X_train = torch.cat([X_train, X_part], 0)
y_train = torch.cat([y_train, y_part], 0)
return X_train, y_train, X_valid, y_valid
4.5 权重衰减(L2正则化)
技术通过函数与零的距离来衡量函数的复杂度
一般的损失函数:
$$
L(\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
$$
引入正则化常数后的损失函数:
$$
L(\mathbf{w}, b) + \frac{\lambda}{2} \left| \mathbf{w} \right|^2
$$
学习算法偏向于在大量特征上均匀分布权重的模型
L2正则化回归的小批量随机梯度下降更新后为:
$$
\mathbf{w} \leftarrow (1 - \eta\lambda)\mathbf{w}
- \frac{\eta}{|\mathcal{B}|} \sum_{i \in \mathcal{B}}
\mathbf{x}^{(i)} \left( \mathbf{w}^{\top} \mathbf{x}^{(i)} + b - y^{(i)} \right)
$$
根据估计值与观测值之间的差异来更新w
实现方法:在实例化优化器时直接通过weight_decay指定weight decay超参数。
net = nn.Sequential(nn.Linear(num_inputs, 1))
for param in net.parameters():
param.data.normal_()
#注意,nn.linear()本身自带初始化,调用Kaiming/Xavier
#此处,用标准正态初始化
loss = nn.MSELoss(reduction='none')
num_epochs, lr = 100, 0.003
# 偏置参数没有衰减
trainer = torch.optim.SGD([
{"params":net[0].weight,'weight_decay': wd},
{"params":net[0].bias}], lr=lr)
#parameter groups(参数组
#我把参数分成两组,不同组可以用不同设置
# 第一组
# {"params": net[0].weight,
# "weight_decay": wd}
# 第二组:
#{"params": net[0].bias}
# 但是没有指定 weight_decay,所以使用默认:
4.6 暂退法(dropout)
在标准暂退法正则化中,通过按保留(未丢弃)的节点的分数进行规范化来消除每一层的偏差。 换言之,每个中间活性值h以暂退概率p由随机变量h'替换,如下所示:
$$
h' =
\begin{cases}
0, & \text{概率为 } p \[6pt]
\dfrac{h}{1-p}, & \text{其他情况}
\end{cases}
$$
依据此模型,其期望值不变
一般将暂退法应用到隐藏层,以p概率将隐藏单元置于零时,结果可以看作一个只包含原始神经元子集的网络。
注意,暂退法仅仅在训练中使用,在测试过程中,给定一个训练好的模型和一个新的样本不会使用
concise implementation
dropout1, dropout2 = 0.2, 0.5
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)
#nn.linear一般会对w和b进行初始化,这里想把改成高斯分布
net.apply(init_weights);#遍历网络,对每一层执行初始化函数
4.8 数值稳定性
对于比较深层的神经网路,由于层之间的乘积作用,容易出现梯度消失和梯度爆炸。为了让训练更稳定
- 乘法变加法:ResNet,LSTM
- 归一化:梯度归一化,梯度裁剪
- 合理的权重初始化和激活函数
- 当然,优化期间适当正则化也可以提高稳定性
Xavier初始化:
$$
\frac{1}{2} (n_{\text{in}} + n_{\text{out}}) \sigma^2 = 1
\quad \text{或等价于} \quad
\sigma = \sqrt{\frac{2}{n_{\text{in}} + n_{\text{out}}}}
$$

浙公网安备 33010602011771号