持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第18天,点击查看活动详情
1.环境配置及要求
- pytorch1.12.1
- numpy 1.23.3
- python 3.8
- pandas 1.2.4
- matplotlib 3.5.1
- jupyter note运行
2.要解决的问题
丢弃法的出现还是为了解决过拟合的问题,过拟合是指:模型的训练误差远小于它在测试数据集上的误差,我们称该现象为过拟合。
3.丢弃法原理及方法
原理即是当对隐藏层使用丢弃法时,该层的隐藏单元将有一定概率被丢弃掉,即通过概率筛选的方式对数据进行处理。丢弃概率是丢弃法的超参数,且丢弃法不改变其输入的期望值。
由于在训练中隐藏层神经元的丢弃是随机的,即h1,....h5都有可能被清零,输出层的计算无法过度依赖h1,。。。h5中的任意一个,从而在训练模型时起到正则化的作用,并可以用来应对过拟合。当然我们在测试的时候,为了结果的确定性,一般不适用丢弃法,仅是在测试的时候!
4.丢弃法的实现
根据丢弃法的定义,我们可以进一步实现它,其中dropout函数将以drop_prob的概率丢弃x中的元素。
4.1 导入环境
import matplotlib_inline
import torch
import torch.nn as nn
import numpy as np
import sys
sys.path.append(r"E:\anaconda\envs\pytorch\Lib\d2lzh_pytorch")
import d2lzh_pytorch as d2l
这里还是使用之前的库包版本,一般情况下更高的版本可以向下兼容。注意导入d2l包,路径的放置前如果报错了要注意在路径前添加r。
4.2设置丢弃函数即dropout函数
def dropout(X,drop_prob):
X=X.float()
assert 0<=drop_prob<=1
keep_prob=1-drop_prob
#这种情况下把全部元素都丢弃
if keep_prob==0:
return torch.zeros_like(X)#输出以Xshape相同的形状
mask=(torch.randn(X.shape)<keep_prob).float()
return mask*X/keep_prob
这里我们将丢弃函数设置好后可以对其进行测试:
X=torch.arange(16).view(2,8)
dropout(X,0)#丢弃率为0
dropout(X,0.5)#丢弃率为0.5
dropout(X,1)#丢弃率为1
可以很明显的看出,当概率设置为0时,X中的元素全部保留,当概率设置为0.5时,X中的元素有一半设置为0,当概率为1时,X中的元素全部为0。综上,丢弃函数的功能已经达到我们的预期要求。
4.3定义模型参数
参数,即我们的模型需要使用的数据,这里我们使用Fashion-MNIST数据集,定义一个包含两个隐藏层的多层感知机,其中两个隐藏层的输出个数都是256.
num_inputs,num_outputs,num_hiddens1,num_hiddens2=784,10,256,256
W1=torch.tensor(np.random.normal(0,0.01,size=(num_inputs,num_hiddens1)),dtype=torch.float,requires_grad=True)
b1=torch.zeros(num_hiddens1,requires_grad=True)
W2=torch.tensor(np.random.normal(0,0.01,size=(num_hiddens1,num_hiddens2)),dtype=torch.float,requires_grad=True)
b2=torch.zeros(num_hiddens2,requires_grad=True)
W3=torch.tensor(np.random.normal(0,0.01,size=(num_hiddens2,num_outputs)),dtype=torch.float,requires_grad=True)
b3=torch.zeros(num_outputs,requires_grad=True)
params=[W1,b1,W2,b2,W3,b3]
这里跟之前的区别不会很大,唯一的区别在于这是个两层隐藏层的方式,即第一层传来的数字进入第二层的时候,第二层再进行计算的一个过程。
4.4 定义模型
这里就用到我们之前了解到的一个激活函数,ReLU激活函数,并对每个激活函数的输出使用丢弃法。我们分别设置各个层的丢弃概率,我们通常会将输入层的丢弃概率设的小一点,在这里我们把第一个隐藏层的丢弃概率设为0.2,把第二个隐藏层的丢弃概率设为0.5.
drop_prob1,drop_prob2=0.2,0.5
def net(X,is_training=True):
X=X.view(-1,num_inputs)
H1=(torch.matmul(X,W1)+b1).relu()
if is_training: #只在训练模型时使用丢弃法
H1=dropout(H1,drop_prob1) #在第一层全连接后添加丢弃层
H2=(torch.matmul(H1,W2)+b2).relu()
if is_training:
H2=dropout(H2,drop_prob2)#在第二层全连接后添加丢弃层
return torch.matmul(H2,W3)+b3
这里我们应该注意一点,对模型评估的时候不应该进行丢弃。
def evaluate_accuracy(data_iter,net):
acc_sum,n=0.0,0
for X,y in data_iter:
if isinstance(net,torch.nn.Module):
net.eval()#评估模式,这会关闭dropout
acc_sum+=(net(X).argmax(dim=1)==y).float().sum().item()
net.train()#改回训练模式
else:
if('is_training' in net.__code__.co_varnames):#如果有is_training这个参数
acc_sum+=(net(X,is_training=False).argmax(dim=1)==y).float().sum().item()
else:
acc_sum+=(net(X).argmax(dim=1)==y).float().sum().item()
n+=y.shape[0]
return acc_sum/n
4.5 训练和测试模型
这一部分与之前多层感知机的训练和测试类似。
num_epochs,lr,batch_size=5,100.0,256
loss=torch.nn.CrossEntropyLoss()
train_iter,test_iter=d2l.load_data_fashion_mnist(batch_size)
d2l.train_ch3(net,train_iter,test_iter,loss,num_epochs,batch_size,params,lr)