导致过拟合的原因:训练网络的数据量太少;网络神经元太多;
解决过拟合:增加训练时的数据量;正规化;dropout(每次随机丢弃一定数量的neuron,防止对神经元的过分依赖)
1. 训练过程用两个不同的网络测试,动图如下:(自己截动图很麻烦,所以从网上拿来的)
2. 自己运行的结果图如下:可以看到没加dropout的网络几乎照顾到了每一个训练数据(过拟合),但是对测试数据来说效果就很差了;
注意:加了dropout的网络在进行测试时,要声明是测试模式(net.eval()),测试结束再有训练时,要声明是训练模式(net.train())。由于在训练过程中drop了一部分的neuron,所以神经网络在训练和测试时的参数是不同的。
import torch
import matplotlib.pyplot as plt
import torch.nn as nn
torch.manual_seed(1)
# 数据量过少,神经元比数据量多太多,容易引起过拟合
N_SAMPLES=20 # the number of data
N_HIDDENS=300 # the number of hidden units
# training data
x=torch.unsqueeze(torch.linspace(-1,1,N_SAMPLES),1)
y=x+0.3*torch.normal(torch.zeros(N_SAMPLES,1),torch.ones(N_SAMPLES,1))
# test data
test_x=torch.unsqueeze(torch.linspace(-1,1,N_SAMPLES),1)
test_y=test_x+0.3*torch.normal(torch.zeros(N_SAMPLES,1),torch.ones(N_SAMPLES,1))
# 搭建两个神经网络,在训练时进行对比:net with dropout, net without dropout(overfitting)
net_overfit=nn.Sequential(
torch.nn.Linear(1,N_HIDDENS),
torch.nn.ReLU(),
torch.nn.Linear(N_HIDDENS,N_HIDDENS),
torch.nn.ReLU(),
torch.nn.Linear(N_HIDDENS,1),
)
net_dropout=nn.Sequential(
torch.nn.Linear(1,N_HIDDENS),
torch.nn.ReLU(),
torch.nn.Dropout(0.5), # drop 50% of the neuron
torch.nn.Linear(N_HIDDENS,N_HIDDENS),
torch.nn.ReLU(),
torch.nn.Dropout(0.5),
torch.nn.Linear(N_HIDDENS,1)
)
# training
optimizer_overfit=torch.optim.Adam(net_overfit.parameters(),lr=0.01)
optimizer_dropout=torch.optim.Adam(net_dropout.parameters(),lr=0.01)
loss_func=torch.nn.MSELoss()
for epoch in range(500):
pred_overfit=net_overfit(x)
pred_dropout=net_dropout(x)
loss_overfit=loss_func(pred_overfit,y)
loss_dropout=loss_func(pred_dropout,y)
optimizer_overfit.zero_grad()
optimizer_dropout.zero_grad()
loss_overfit.backward()
loss_dropout.backward()
optimizer_overfit.step()
optimizer_dropout.step()
# 对两个网络的训练过程进行测试,可视化
if epoch % 10 == 0:
# net_overfit.eval() #对于 net_overfit,这一步可有可无
net_dropout.eval() # 改为测试模式,因为有dropout的网络在train和test时的参数不一样,所以要有这一句
# 可视化过程
plt.cla() #清除当前活动的轴,其他轴不受影响
test_pred_overgit=net_overfit(test_x)
test_pred_dropout=net_dropout(test_x)
plt.scatter(x.data.numpy(), y.data.numpy(), label='train_data')
plt.scatter(test_x.data.numpy(), test_y.data.numpy(), label='test_data')
plt.plot(test_x.data.numpy(),test_pred_overgit.data.numpy(),label='overfitting',color='black')
plt.plot(test_x.data.numpy(),test_pred_dropout.data.numpy(),label='dropout',color='red',linestyle='--')
plt.text(0,-1.2,'overfitting loss=%.4f'%loss_func(test_pred_overgit,test_y).data.numpy()) # 文本显示的位置;
plt.text(0,-1.5,'dropout loss=%.4f'%loss_func(test_pred_dropout,test_y).data.numpy(),color='red') # 文本显示的位置;
plt.xlim(-1.2,1.2)
plt.ylim(-2,2)
plt.legend(loc='upper left')
plt.pause(0.1)
# 测试完之后要把测试状态改为训练状态
# net_overfit.train()
net_dropout.train()
plt.show()