導致過擬合的原因:訓練網絡的數據量太少;網絡神經元太多;
解決過擬合:增加訓練時的數據量;正規化;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()