过拟合和欠拟合
概念
训练误差,泛化误差,测试集和验证集,
k折交叉验证应对训练数据不足的情况,将数据集分割诚k个不重合的子数据集,做k次模型训练和验证。
过拟合原因
模型复杂度过高,比如多项式拟合,高阶多项式模型参数多,模型选择空间,对于高阶多项式函数拟合会因为模型复杂度会出现下图情况。
训练数据集太小,尤其在模型复杂度较高时,如多层深度学习模型,希望数据集大一些,学习到全面特征。
解决过拟合的两大方法和其简洁实现
一、权重衰减
概念
首先是一个概念:正则化(regularization),是通过为模型损失函数添加惩罚项使学习模型参数值较小。
权重衰减相当于是L2范数正则化。
L2范数正则化在模型原来损失函数上添加L2范数惩罚项,惩罚项是模型权重参数每个元素平方和和一个正常数的乘积。如图,L(w,b)是损失函数。其中超参数lammda越大,惩罚越大。
简洁实现
def train_concise(wd):#输入为超参数lammda值
net = nn.Sequential(nn.Linear(num_inputs, 1))
for param in net.parameters():
param.data.normal_()
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)
animator = d2l.Animator(xlabel='epochs', ylabel='loss', yscale='log',
xlim=[5, num_epochs], legend=['train', 'test'])
for epoch in range(num_epochs):
for X, y in train_iter:
trainer.zero_grad()
l = loss(net(X), y)
l.mean().backward()
trainer.step()
if (epoch + 1) % 5 == 0:
animator.add(epoch + 1,
(d2l.evaluate_loss(net, train_iter, loss),
d2l.evaluate_loss(net, test_iter, loss)))
print('w的L2范数:', net[0].weight.norm().item())
train_concise(0)
train_concise(3)
输出分别为14.7和0.35。
二、丢弃法(倒置丢弃法)
概念
对隐藏层使用丢弃发,以概率p进行丢弃隐藏层节点,使得输出层以均等的概率无法过度依赖隐藏层中某一个(应该是在传播过程中某个节点权重过分大,而其他节点权重小,使得输出层受某节点影响大。)
方法是对隐藏层每一个节点以p的概率(p是超参数)将随机变量对权重梯度的乘积为0,以p-1的概率为1。即以p的概率可以将某一节点权重的梯度清零,后续过程中相当于丢弃该节点。
如图所示
简洁实现
对于深度学习框架的高级API,只需在每个全连接层之后添加一个Dropout层, 将暂退概率作为唯一的参数传递给它的构造函数。 在训练时,Dropout层将根据指定的暂退概率随机丢弃上一层的输出(相当于下一层的输入)。 在测试时,Dropout层仅传递数据。
#设置dropout层概率丢弃参数
dropout1, dropout2, batch_size, lr, num_epochs = 0.2, 0.5,256,0.5,10
loss = nn.CrossEntropyLoss(reduction='none')
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)
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);
#下面开始训练模型
trainer = torch.optim.SGD(net.parameters(), lr=lr)
d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, trainer)
结果如下:
小结
权重衰减相当于L2正则化为损失函数添加L2正则化惩罚项。
丢弃法本质其实相当于是通过添加dropout隐藏层实现自动丢弃,只需要传入丢弃概率。
对于解决过拟合问题,添加dropout层比权重衰减方法从代码方面更容易简单。