除了上一篇文章介绍的权重衰减法,深度学习常用的缓解过拟合问题的方法还有丢弃法。本文介绍倒置丢弃法及其实现。
丢弃法主要应用在含有隐藏层的模型中,所以我们以多层感知机为例,来说明丢弃法的实现方法。
当对这个多层感知机的隐藏层使用丢弃法时,该层的隐藏单元将有概率被丢弃(归零),有的概率会以做拉伸。丢弃概率是丢弃法的超参数。
由于对神经单元的丢弃是随机的,因此都有可能被清零,输出层的计算无法过度依赖中的任何一个。在训练过程中,丢弃法起到了正则化的作用,并可以用来缓解过拟合的问题。
但在测试过程中,一般不使用丢弃法。
对于一个单隐藏层,输入个数为4,隐藏层神经单元个数为5,激活函数为的多层感知机它的隐藏单元的计算表达式为
我们现在对这个隐藏层使用丢弃概率为的丢弃法。设随机变量为0和1的概率分别为和。得到新的隐藏单元计算表达式为
由于随机变量的期望,因此丢弃法对隐藏单元的输出期望没有影响。
def dropout(X,p):
X = X.float()
#断言判断输入的p是否满足大于0小于1
assert 0<=p<=1
kp = 1-p
#p=1,丢弃所有元素
if kp == 0:
return torch.zeros(X.shape)
#xi返回0或1。rand生成大于0小于1的随机数
xi = (torch.rand(X.shape)<kp).float()
return xi*X/kp
下面创建一个tensor测试一下dropout函数
X = torch.tensor([1,2,3,4])
dropout(X,0) #丢弃概率为0
dropout(X,0.5) #丢弃概率为0.5
dropout(X,0.9) #丢弃概率为0.9
测试得到的结果如下,证明我们的丢弃法函数实现了需要的效果
tensor([1., 2., 3., 4.])
tensor([2., 4., 0., 0.])
dropout(X,0.9)
应用丢弃法仅仅需要在搭建神经网络时,在应用丢弃法的层后面,调用Dropout层并指定丢弃概率即可。
下面以一个含有两个隐藏层的多层感知机为例,实现在神经网络中使用丢弃法。
这里使用torch.nn模块中的Dropout函数,这个函数可以在训练时发挥作用,测试模型时,不发挥作用。
导入需要的库
import torch
from torch import nn
设置参数
num_inputs = 784
num_hiddens1 = 256
num_hiddens2 = 256
num_outputs = 10
p1,p2 = 0.5,0.5
#超参数,调节变量p1,p2可以看到丢弃法的效果
搭建神经网络
class FlattenLayer(nn.Moudle):
def __init__(self):
super(FlattenLayer,self).__init__()
def forward(self,x):
return x.view(x.shape[0],-1)
net = nn.Sequential(
FlattemLayer(),
nn.Linear(num_inputs,num_hiddens1),
nn.ReLU(),
nn.Dropout(p1),
nn.Linear(num_hiddens1,num_hiddens2),
nn.ReLU(),
nn.Dropout(p2),
nn.Linear(num_hiddens2,num_outputs)
)
初始化模型参数
for param in net.parameters():
nn.init.normal_(param,mean=0,std = 0.01)
看一下神经网络的结构
print(net)
由于使用的本质还是softmax回归模型,因此使用softmax运算和交叉熵损失函数,这里直接使用PyTorch中的函数
loss = torch.nn.CrossEntropyLoss()
这里我们还是使用小批量随机梯度下降算法作为优化算法。
optimizer = torch.optoim.SGD(net.parameters(),lr = 0.5)
在开始训练模型之前,首先需要读取数据集(因为读取的还是Fashion-MNIST数据集,所以代码与之前的一样)。
batch_size = 256
mnist_train = torchvision.datasets.FashionMNIST(root='~/Datasets/FashionMNIST',train=True,download=True,transform=transforms.ToTensor())
#获取训练集
mnist_test = torchvision.datasets.FashionMNIST(root='~/Datasets/FashionMNIST',train=False,download=True,transform=transforms.ToTensor())
#获取测试集
#生成迭代器
train_iter = torch.utils.data.DataLoader(mnist_train,batch_size=batch_size,shuffle = True,num_workers = 0)
test_iter = torch.utils.data.DataLoader(mnist_test,batch_size = batch_size,shuffle=False,num_workers=0)
为了看出效果,需要计算出分类的准确率,在之前的推文写过了,这里不再赘述(详见softmax回归部分文章)。
def net_accurary(data_iter,net):
right_sum,n = 0.0,0
for X,y in data_iter:
#从迭代器data_iter中获取X和y
right_sum += (net(X).argmax(dim=1)==y).float().sum().item()
#计算准确判断的数量
n +=y.shape[0]
#通过shape[0]获取y的零维度(列)的元素数量
return right_sum/n
def train(net,loss,optimizer,net_accuary,train_iter,test_iter,batch_size,num_epochs):
for epoch in range(num_epochs+1):
for X,y in train_iter:
l = loss(net(X),y).sum()
optimizer.zero_grad()
l.backward()
optimizer.step()
train_right = net_accuary(train_iter,net) #训练集准确率
test_right = net_accurary(test_iter, net) #测试集的准确率
print('第%d学习周期, 训练准确率%.3f, 测试准确率%.3f' % (epoch + 1, train_right, test_right))
由于Fashion-MNIST数据集较大,不容易产生过拟合现象,因此效果不是很明显。