- 模型过拟合两种解决方法,也都是属于正则化方式:
(1)权重衰减
(2)Dropout丢弃法 - 模型过拟合出现的原因是模型太过复杂,从而时模型把数据的噪音都完美拟合了出来,也就是把训练数据训练的过于拟合了,而在测试数据集上面误差却比训练时相差太大,权重衰减和Dropout就是使模型变得简单,不那么复杂
- 权重衰减通过限制模型权重参数为一个小的范围,使模型函数趋于平滑;权重衰减是作用于loss函数上面,常见的有L1 norm,L2 norm等正则项
- Dropout通过对输出层以每一个元素以P概率丢掉,1-P的概率保留,同时保留的元素数值需要除以(1-P),从而保证输出层所有元素数值在使用dropout前后的期望值(均值)不变,每个层丢掉一些神经元(输出元素),且每一次batch_size数据迭代时drop的元素都不一样,从而当迭代几百万次时,每个输出层的输出元素都有可能丢掉多次,从而保证了模型的稳定性
- Dropout通常使用在全连接层上面,batch_norm作用于卷积层上面
- 在测试模型时,我们为了拿到更加确定性的结果,而不是一个随机的结果,一般对输出层不使用Dropout丢弃法,Dropout丢弃法只使用于训练模型时。因此在Pytorch中模型含有Dropout层时,当模型开始训练时需要在前面加入model.train()代码,表示模型处于训练状态,此时需要使用dropout层,当模型开始处于测试状态时,需要在前面加入model.evel()代码,此时模型不使用dropout层
- 当我们将丢弃法应用到隐藏层,以P的概率将隐藏单元置为零时, 结果可以看作是一个只包含原始神经元子集的网络。 比如在 下图中多层感知机Dropout前后的形状,删除了h2和h5, 因此输出的计算不再依赖于h2或h5,并且它们各自的梯度在执行反向传播时也会消失。 这样,输出层的计算不能过度依赖于的任何一个元素。

- 将丢弃法Dropout应用于每个隐藏层的输出(在激活函数之后), 并且可以为每一层分别设置暂退概率: 常见的技巧是在靠近输入层的地方设置较低的丢弃概率,远离输入层的地方设置较高的丢弃概率。 下面代码的模型将第一个和第二个隐藏层的Dropout概率分别设置为0.2和0.5, 并且Dropout只在训练期间有效。通常Dropout概率设置为0.1,0.2,0.5,0.8,0.9,1这几个数
- 下面是手动实现Dropout层和使用Pytorch框架实现的Dropout层
import torch
from d2l.torch import d2l
from torch import nn
from torch.nn import Linear
def dropout_layer(X,dropout):
assert 0<=dropout<=1
if dropout == 1:
return torch.zeros_like(X)
if dropout ==0:
return X
zero_one_X = torch.randn(X.shape)
mask = (zero_one_X > dropout).float()
return mask * X /(1-dropout)
X = torch.arange(16,dtype=torch.float32).reshape(2,8)
def test_dropout():
print("X: ", X)
print("dropout = 0", dropout_layer(X, dropout=0))
print("dropout = 0.2", dropout_layer(X, dropout=0.2))
print("dropout = 0.5", dropout_layer(X, dropout=0.5))
print("dropout = 1", dropout_layer(X, dropout=1))
test_dropout()
num_inputs = 784
num_outputs = 10
num_hiddens1 = 256
num_hiddens2 = 256
dropout_1 = 0.2
dropout_2 = 0.5
class model(nn.Module):
def __init__(self,num_inputs,num_outputs,num_hiddens1,num_hiddens2,is_training = True):
super(model, self).__init__()
self.num_inputs = num_inputs
self.num_outputs = num_outputs
self.is_training = is_training
self.linear1 = nn.Linear(num_inputs,num_hiddens1,bias=True)
self.linear2 = nn.Linear(num_hiddens1,num_hiddens2,bias=True)
self.linear3 = nn.Linear(num_hiddens2,num_outputs,bias=True)
self.relu = nn.ReLU()
def forward(self,X):
X = X.reshape(-1,self.num_inputs)
l1 = self.linear1(X)
H1 = self.relu(l1)
if self.is_training:
H1 = dropout_layer(H1,dropout=dropout_1)
l2 = self.linear2(H1)
H2 = self.relu(l2)
if self.is_training:
H2 = dropout_layer(H2,dropout=dropout_2)
out = self.linear3(H2)
return out
def network_train(net):
num_epoch = 10
lr = 0.5
batch_size = 256
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size=batch_size)
loss = nn.CrossEntropyLoss(reduction='none')
trainer = torch.optim.SGD(net.parameters(), lr=lr)
d2l.train_ch3(net, train_iter, test_iter, loss, num_epoch, trainer)
def dropout_scratch():
net = model(num_inputs, num_outputs, num_hiddens1, num_hiddens2, is_training=True)
print("net : ", net)
network_train(net)
def dropout_concise():
net = nn.Sequential(nn.Flatten(),
nn.Linear(num_inputs,num_hiddens1,bias=True),
nn.ReLU(),
nn.Dropout(dropout_1),
nn.Linear(num_hiddens1,num_hiddens2,bias=True),
nn.ReLU(),
nn.Dropout(dropout_2),
nn.Linear(num_hiddens2,num_outputs)
)
net.apply(init_weights)
network_train(net)
def init_weights(model):
if(type(model) == nn.Linear):
nn.init.normal_(model.weight,std = 0.01)
dropout_concise()
- 权重衰减和Dropout在同一个模型中可以同时使用解决模型过拟合的问题,一个控制模型权重参数大小,一个控制模型的维数(宽窄)