【Pytorch神经网络理论篇】 14 过拟合问题的优化技巧(一):基本概念+正则化+数据增大
1 過擬合問題的描述
1.1 過擬合問題概述
深度額學習訓練過程中,在訓練階段得到了較好的準確率,但在識別非數據集數據時存在精度下降的問題,這種現象稱為過擬合現象。
主要原因:由于模型的擬合度過高,導致模型不僅學習樣本的群體規律,也學習樣本的個體規律。
1.2 過擬合問題模型的設計
1.2.1 構建數據集---Over_fitting.py(第1部分)
import sklearn.datasets import torch import numpy as np import matplotlib.pyplot as plt from LogicNet_fun import LogicNet,moving_average,predict,plot_decision_boundary# 1 構建數據集 np.random.seed(0) # 設置隨機數種子 X , Y =sklearn.datasets.make_moons(40,noise=0.2) # 生成兩組半圓形數據 arg = np.squeeze(np.argwhere(Y==0),axis=1) # 獲取第1組數據索引 arg2 = np.squeeze(np.argwhere(Y==1),axis=1) # 獲取第2組數據索引 # 顯示數據 plt.title("train moons data") plt.scatter(X[arg,0],X[arg,1],s=100,c='b',marker='+',label = 'data1') plt.scatter(X[arg2,0],X[arg2,1],s=40,c='r',marker='o',label = 'data2') plt.legend() plt.show()1.2.2 搭建網絡模型---Over_fitting.py(第2部分)
# 2 搭建網絡模型 model = LogicNet(inputdim=2,hiddendim=500,outputdim=2) # 實例化模型,增加擬合能力將hiddendim賦值為500 optimizer = torch.optim.Adam(model.parameters(),lr=0.01) # 定義優化器:反向傳播過程中使用。1.2.3 訓練模型,并將訓練過程可視化---Over_fitting.py(第3部分)
# 3 訓練模型+訓練過程loss可視化 xt = torch.from_numpy(X).type(torch.FloatTensor) # 將numpy數據轉化為張量 yt = torch.from_numpy(Y).type(torch.LongTensor) # 將numpy數據轉化為張量 epochs = 1000 # 定義迭代次數 losses = [] # 損失值列表 for i in range(epochs):loss = model.getloss(xt,yt)losses.append(loss.item()) # 保存損失值中間狀態optimizer.zero_grad() # 清空梯度loss.backward() # 反向傳播損失值optimizer.step() # 更新參數 avgloss = moving_average(losses) # 獲得損失值的移動平均值 plt.figure(1) plt.subplot(211) plt.xlabel('step number') plt.ylabel('Training loss') plt.title('step number vs Training loss') plt.show()1.2.4 將模型結果可視化,觀察過擬合現象---Over_fitting.py(第4部分)
# 4 模型結果可視化,觀察過擬合現象 plot_decision_boundary(lambda x: predict(model,x),X,Y) from sklearn.metrics import accuracy_score print("訓練時的準確率",accuracy_score(model.predict(xt),yt)) # 重新生成兩組半圓數據 Xtest,Ytest = sklearn.datasets.make_moons(80,noise=0.2) plot_decision_boundary(lambda x: predict(model,x),Xtest,Ytest) Xtest_t = torch.from_numpy(Xtest).type(torch.FloatTensor) # 將numpy數據轉化為張量 Ytest_t = torch.from_numpy(Ytest).type(torch.LongTensor) print("測試時準確率",accuracy_score(model.predict(Xtest_t),Ytest_t))1.2.5 模型代碼總覽---Over_fitting.py(總結)
#####Over_fitting.pyimport sklearn.datasets import torch import numpy as np import matplotlib.pyplot as plt from LogicNet_fun import LogicNet,moving_average,predict,plot_decision_boundary# 1 構建數據集 np.random.seed(0) # 設置隨機數種子 X , Y =sklearn.datasets.make_moons(40,noise=0.2) # 生成兩組半圓形數據 arg = np.squeeze(np.argwhere(Y==0),axis=1) # 獲取第1組數據索引 arg2 = np.squeeze(np.argwhere(Y==1),axis=1) # 獲取第2組數據索引 # 顯示數據 plt.title("train moons data") plt.scatter(X[arg,0],X[arg,1],s=100,c='b',marker='+',label = 'data1') plt.scatter(X[arg2,0],X[arg2,1],s=40,c='r',marker='o',label = 'data2') plt.legend() plt.show()# 2 搭建網絡模型 model = LogicNet(inputdim=2,hiddendim=500,outputdim=2) # 實例化模型,增加擬合能力將hiddendim賦值為500 optimizer = torch.optim.Adam(model.parameters(),lr=0.01) # 定義優化器:反向傳播過程中使用。# 3 訓練模型+訓練過程loss可視化 xt = torch.from_numpy(X).type(torch.FloatTensor) # 將numpy數據轉化為張量 yt = torch.from_numpy(Y).type(torch.LongTensor) # 將numpy數據轉化為張量 epochs = 1000 # 定義迭代次數 losses = [] # 損失值列表 for i in range(epochs):loss = model.getloss(xt,yt)losses.append(loss.item()) # 保存損失值中間狀態optimizer.zero_grad() # 清空梯度loss.backward() # 反向傳播損失值optimizer.step() # 更新參數 avgloss = moving_average(losses) # 獲得損失值的移動平均值 plt.figure(1) plt.subplot(211) plt.xlabel('step number') plt.ylabel('Training loss') plt.title('step number vs Training loss') plt.show()# 4 模型結果可視化,觀察過擬合現象 plot_decision_boundary(lambda x: predict(model,x),X,Y) from sklearn.metrics import accuracy_score print("訓練時的準確率",accuracy_score(model.predict(xt),yt)) # 重新生成兩組半圓數據 Xtest,Ytest = sklearn.datasets.make_moons(80,noise=0.2) plot_decision_boundary(lambda x: predict(model,x),Xtest,Ytest) Xtest_t = torch.from_numpy(Xtest).type(torch.FloatTensor) # 將numpy數據轉化為張量 Ytest_t = torch.from_numpy(Ytest).type(torch.LongTensor) print("測試時準確率",accuracy_score(model.predict(Xtest_t),Ytest_t)) LogicNet_fun.py ### LogicNet_fun.pyimport torch.nn as nn #引入torch網絡模型庫 import torch import numpy as np import matplotlib.pyplot as plt# 1.2 定義網絡模型 class LogicNet(nn.Module): #繼承nn.Module類,構建網絡模型def __init__(self,inputdim,hiddendim,outputdim): #初始化網絡結構 ===》即初始化接口部分super(LogicNet,self).__init__()self.Linear1 = nn.Linear(inputdim,hiddendim) #定義全連接層self.Linear2 = nn.Linear(hiddendim,outputdim) #定義全連接層self.criterion = nn.CrossEntropyLoss() #定義交叉熵函數def forward(self,x):# 搭建用兩個全連接層組成的網絡模型 ===》 即正向接口部分:將網絡層模型結構按照正向傳播的順序搭建x = self.Linear1(x)# 將輸入傳入第一個全連接層x = torch.tanh(x)# 將第一個全連接層的結果進行非線性變化x = self.Linear2(x)# 將網絡數據傳入第二個全連接層return xdef predict(self,x):# 實現LogicNet類的預測窗口 ===》 即預測接口部分:利用搭建好的正向接口,得到模型預測結果#調用自身網絡模型,并對結果進行softmax()處理,分別的出預測數據屬于每一個類的概率pred = torch.softmax(self.forward(x),dim=1)# 將正向結果進行softmax(),分別的出預測結果屬于每一個類的概率return torch.argmax(pred,dim=1)# 返回每組預測概率中最大的索引def getloss(self,x,y):# 實現LogicNet類的損失值接口 ===》 即損失值計算接口部分:計算模型的預測結果與真實值之間的誤差,在反向傳播時使用y_pred = self.forward(x)loss = self.criterion(y_pred,y)# 計算損失值的交叉熵return loss# 1.5 訓練可視化 def moving_average(a,w=10): #計算移動平均損失值if len(a) < w:return a[:]return [val if idx < w else sum(a[(idx - w):idx]) / w for idx, val in enumerate(a)]def moving_average_to_simp(a,w=10): #if len(a) < w:return a[:]val_list = []for idx, val in enumerate(a):if idx < w:# 如果列表 a 的下標小于 w, 直接將元素添加進 xxx 列表val_list.append(val)else:# 向前取 10 個元素計算平均值, 添加到 xxx 列表val_list.append(sum(a[(idx - w):idx]) / w)def plot_losses(losses):avgloss = moving_average(losses)#獲得損失值的移動平均值plt.figure(1)plt.subplot(211)plt.plot(range(len(avgloss)),avgloss,'b--')plt.xlabel('step number')plt.ylabel('Training loss')plt.title('step number vs Training loss')plt.show()# 1.7 數據可視化模型 def predict(model,x): #封裝支持Numpy的預測接口x = torch.from_numpy(x).type(torch.FloatTensor)model = LogicNet(inputdim=2, hiddendim=3, outputdim=2)ans = model.predict(x)return ans.numpy()def plot_decision_boundary(pred_func,X,Y): #在直角模型中實現預測結果的可視化#計算范圍x_min ,x_max = X[:,0].min()-0.5 , X[:,0].max()+0.5y_min ,y_max = X[:,1].min()-0.5 , X[:,1].max()+0.5h=0.01xx, yy = np.meshgrid(np.arange(x_min, x_max, h), np.arange(y_min, y_max, h))#根據數據輸入進行預測Z = pred_func(np.c_[xx.ravel(),yy.ravel()])Z = Z.reshape(xx.shape)#將數據的預測結果進行可視化plt.contourf(xx,yy,Z,cmap=plt.cm.Spectral)plt.title("Linear predict")arg = np.squeeze(np.argwhere(Y==0),axis=1)arg2 = np.squeeze(np.argwhere(Y==1),axis=1)plt.scatter(X[arg,0],X[arg,1],s=100,c='b',marker='+')plt.scatter(X[arg2,0],X[arg2,1],s=40,c='r',marker='o')plt.show()2 改善過擬合現象的方法
2.1 過擬合現象產生的原因
因為神經網絡在訓練過程中,只看到有限的信息,在數據量不足的情況下,無法合理地區分哪些屬于個體特征,哪些屬于群體特征。而在真實場景下,所有的樣本特征都是多樣的,很難在訓練數據集中將所有的樣本情況全部包括。
2.2 有效改善過擬合現象的方法
2.2.1?early stopping
在發生過擬合之前提前結束訓l練。這個方法在理論上是可行的,但是這個結束的時間點不好把握。
2.2.2?數據集擴增(data augmentation)
讓模型見到更多的情況,可以最大化滿足全樣本,但實際應用中,對于未來事件的頸測卻顯得力不叢心。
2.2.3 正則化
通過范數的概念,增強模型的泛化能力,包括L1正則化、L2正則化(L2正則化也稱為weight decay).
2.2.4 dropout
每次訓練時舍去一些節點來增強泛化能力
3 正則化
在神經網絡計算損失值的過程中,在損失后面再加一項。這樣損失值所代表的輸出與標準結果間的誤差就會受到干擾,導致學習參數w和b無法按照目標方向來調整。實現模型無法與樣本完全擬合的結果,達到防止過擬合的效果。
3.1 正則化效果描述
?不加正則化訓練出來的模型:?
加了正則的模型表現?
可以看到訓練出來的模型太復雜,會影響使用,容易過擬合。?
3.2?正則化的分類與公式
3.2.1 干擾項的特性
當欠擬合(模型的擬合能力不足)時,希望它對模型誤差影響盡量小,讓模型快速來擬合實際。
當過擬合(模型的擬合能力過強)時,希望它對模型誤差影響盡量大,讓模型不要產生過擬合的情況。
3.2.2 范數
L1:所有學習參數w的絕對值的和
L2:所有學習參數w的平方和,然后求平方根
3.2.3 正則化的損失函數-L1
?3.2.4?正則化的損失函數-L2
?
3.3 L2正則化的實現
3.3.1 正則化實現
使用weight_decay參數指定權重衰減率,相當于L2正則化中的正則化系數,用來調整正則化對loss的影響。
weight_decay參數默認對模型中的所有參數進行L2正則化處理,包括權重w和偏置b。
3.3.2 優化器參數的方式實現正則化:字典的方式實現
optimizer =torch.optim.Adam([{'params':weight_p,'weight_decay':0.001},{'params':bias_p,'weight_decay':0}],lr=0.01)字典中的param以指的是模型中的權重。將具體的權重張量放入優化器再為參數weight_decay賦值,指定權重值哀減率,便可以實現為指定參數進行正則化處理。
如何獲得權重張量weight_p與bias_p?
# 主要通過實例化后的模型對象得到 weight_p , bias_p =[],[] for name , p in model.named_parameters():if 'bias' in name:bias_p += [p]else:weight_p += [p]3.4 使用L2正則化改善模型的過擬合狀況
3.4.1 修改Over_fitting.py 中的優化器部分
import sklearn.datasets import torch import numpy as np import matplotlib.pyplot as plt from LogicNet_fun import LogicNet,moving_average,predict,plot_decision_boundary# 1 構建數據集 np.random.seed(0) # 設置隨機數種子 X , Y =sklearn.datasets.make_moons(40,noise=0.2) # 生成兩組半圓形數據 arg = np.squeeze(np.argwhere(Y==0),axis=1) # 獲取第1組數據索引 arg2 = np.squeeze(np.argwhere(Y==1),axis=1) # 獲取第2組數據索引 # 顯示數據 plt.title("train moons data") plt.scatter(X[arg,0],X[arg,1],s=100,c='b',marker='+',label = 'data1') plt.scatter(X[arg2,0],X[arg2,1],s=40,c='r',marker='o',label = 'data2') plt.legend() plt.show()# 2 搭建網絡模型 model = LogicNet(inputdim=2,hiddendim=500,outputdim=2) # 實例化模型,增加擬合能力將hiddendim賦值為500 #optimizer = torch.optim.Adam(model.parameters(),lr=0.01) # 定義優化器:反向傳播過程中使用。 # 修改為: #添加正則化處理 weight_p , bias_p =[],[] for name , p in model.named_parameters(): # 獲取模型中的所有參數及參數名字if 'bias' in name:bias_p += [p] # 收集偏置參數else:weight_p += [p] # 收集權重 optimizer =torch.optim.Adam([{'params':weight_p,'weight_decay':0.001},{'params':bias_p,'weight_decay':0}],lr=0.01) # 帶有正則化處理的優化器3.4.2?regularization01.py 總覽
import sklearn.datasets import torch import numpy as np import matplotlib.pyplot as plt from LogicNet_fun import LogicNet,moving_average,predict,plot_decision_boundary# 1 構建數據集 np.random.seed(0) # 設置隨機數種子 X , Y =sklearn.datasets.make_moons(40,noise=0.2) # 生成兩組半圓形數據 arg = np.squeeze(np.argwhere(Y==0),axis=1) # 獲取第1組數據索引 arg2 = np.squeeze(np.argwhere(Y==1),axis=1) # 獲取第2組數據索引 # 顯示數據 plt.title("train moons data") plt.scatter(X[arg,0],X[arg,1],s=100,c='b',marker='+',label = 'data1') plt.scatter(X[arg2,0],X[arg2,1],s=40,c='r',marker='o',label = 'data2') plt.legend() plt.show()# 2 搭建網絡模型 model = LogicNet(inputdim=2,hiddendim=500,outputdim=2) # 實例化模型,增加擬合能力將hiddendim賦值為500 #optimizer = torch.optim.Adam(model.parameters(),lr=0.01) # 定義優化器:反向傳播過程中使用。 # 修改為: #添加正則化處理 weight_p , bias_p =[],[] for name , p in model.named_parameters(): # 獲取模型中的所有參數及參數名字if 'bias' in name:bias_p += [p] # 收集偏置參數else:weight_p += [p] # 收集權重 optimizer =torch.optim.Adam([{'params':weight_p,'weight_decay':0.001},{'params':bias_p,'weight_decay':0}],lr=0.01) # 帶有正則化處理的優化器# 3 訓練模型+訓練過程loss可視化 xt = torch.from_numpy(X).type(torch.FloatTensor) # 將numpy數據轉化為張量 yt = torch.from_numpy(Y).type(torch.LongTensor) # 將numpy數據轉化為張量 epochs = 1000 # 定義迭代次數 losses = [] # 損失值列表 for i in range(epochs):loss = model.getloss(xt,yt)losses.append(loss.item()) # 保存損失值中間狀態optimizer.zero_grad() # 清空梯度loss.backward() # 反向傳播損失值optimizer.step() # 更新參數 avgloss = moving_average(losses) # 獲得損失值的移動平均值 plt.figure(1) plt.subplot(211) plt.xlabel('step number') plt.ylabel('Training loss') plt.title('step number vs Training loss') plt.show()# 4 模型結果可視化,觀察過擬合現象 plot_decision_boundary(lambda x: predict(model,x),X,Y) from sklearn.metrics import accuracy_score print("訓練時的準確率",accuracy_score(model.predict(xt),yt)) # 重新生成兩組半圓數據 Xtest,Ytest = sklearn.datasets.make_moons(80,noise=0.2) plot_decision_boundary(lambda x: predict(model,x),Xtest,Ytest) Xtest_t = torch.from_numpy(Xtest).type(torch.FloatTensor) # 將numpy數據轉化為張量 Ytest_t = torch.from_numpy(Ytest).type(torch.LongTensor) print("測試時準確率",accuracy_score(model.predict(Xtest_t),Ytest_t))?4?數據集擴增(data augmentation)
4.1 數據集增廣
增加數據集
4.2 通過增大數據集的方式改善過擬合的狀況
4.2.1 修改Over_fitting.py 中的優化器部分
# 2 搭建網絡模型 model = LogicNet(inputdim=2,hiddendim=500,outputdim=2) # 實例化模型,增加擬合能力將hiddendim賦值為500 optimizer = torch.optim.Adam(model.parameters(),lr=0.01) # 定義優化器:反向傳播過程中使用。# 3 訓練模型+訓練過程loss可視化 # xt = torch.from_numpy(X).type(torch.FloatTensor) # 將numpy數據轉化為張量 # yt = torch.from_numpy(Y).type(torch.LongTensor) # 將numpy數據轉化為張量 # epochs = 1000 # 定義迭代次數 # losses = [] # 損失值列表 # for i in range(epochs): # loss = model.getloss(xt,yt) # losses.append(loss.item()) # 保存損失值中間狀態 # optimizer.zero_grad() # 清空梯度 # loss.backward() # 反向傳播損失值 # optimizer.step() # 更新參數 # avgloss = moving_average(losses) # 獲得損失值的移動平均值# 修改為 epochs = 1000 # 定義迭代次數 losses = [] # 損失值列表 for i in range(epochs):X ,Y = sklearn.datasets.make_moons(40,noise=0.2)xt = torch.from_numpy(X).type(torch.FloatTensor)yt = torch.from_numpy(Y).type(torch.LongTensor)loss = model.getloss(xt,yt)losses.append(loss.item())optimizer.zero_grad()loss.backward()optimizer.step()4.2.2?Data_increase.py
import sklearn.datasets import torch import numpy as np import matplotlib.pyplot as plt from LogicNet_fun import LogicNet,moving_average,predict,plot_decision_boundary# 1 構建數據集 np.random.seed(0) # 設置隨機數種子 X , Y =sklearn.datasets.make_moons(40,noise=0.2) # 生成兩組半圓形數據 arg = np.squeeze(np.argwhere(Y==0),axis=1) # 獲取第1組數據索引 arg2 = np.squeeze(np.argwhere(Y==1),axis=1) # 獲取第2組數據索引 # 顯示數據 plt.title("train moons data") plt.scatter(X[arg,0],X[arg,1],s=100,c='b',marker='+',label = 'data1') plt.scatter(X[arg2,0],X[arg2,1],s=40,c='r',marker='o',label = 'data2') plt.legend() plt.show()# 2 搭建網絡模型 model = LogicNet(inputdim=2,hiddendim=500,outputdim=2) # 實例化模型,增加擬合能力將hiddendim賦值為500 optimizer = torch.optim.Adam(model.parameters(),lr=0.01) # 定義優化器:反向傳播過程中使用。# 3 訓練模型+訓練過程loss可視化 # xt = torch.from_numpy(X).type(torch.FloatTensor) # 將numpy數據轉化為張量 # yt = torch.from_numpy(Y).type(torch.LongTensor) # 將numpy數據轉化為張量 # epochs = 1000 # 定義迭代次數 # losses = [] # 損失值列表 # for i in range(epochs): # loss = model.getloss(xt,yt) # losses.append(loss.item()) # 保存損失值中間狀態 # optimizer.zero_grad() # 清空梯度 # loss.backward() # 反向傳播損失值 # optimizer.step() # 更新參數 # avgloss = moving_average(losses) # 獲得損失值的移動平均值# 修改為 epochs = 1000 # 定義迭代次數 losses = [] # 損失值列表 for i in range(epochs):X ,Y = sklearn.datasets.make_moons(40,noise=0.2)xt = torch.from_numpy(X).type(torch.FloatTensor)yt = torch.from_numpy(Y).type(torch.LongTensor)loss = model.getloss(xt,yt)losses.append(loss.item())optimizer.zero_grad()loss.backward()optimizer.step()plt.figure(1) plt.subplot(211) plt.xlabel('step number') plt.ylabel('Training loss') plt.title('step number vs Training loss') plt.show()# 4 模型結果可視化,觀察過擬合現象 plot_decision_boundary(lambda x: predict(model,x),X,Y) from sklearn.metrics import accuracy_score print("訓練時的準確率",accuracy_score(model.predict(xt),yt)) # 重新生成兩組半圓數據 Xtest,Ytest = sklearn.datasets.make_moons(80,noise=0.2) plot_decision_boundary(lambda x: predict(model,x),Xtest,Ytest) Xtest_t = torch.from_numpy(Xtest).type(torch.FloatTensor) # 將numpy數據轉化為張量 Ytest_t = torch.from_numpy(Ytest).type(torch.LongTensor) print("測試時準確率",accuracy_score(model.predict(Xtest_t),Ytest_t))總結
以上是生活随笔為你收集整理的【Pytorch神经网络理论篇】 14 过拟合问题的优化技巧(一):基本概念+正则化+数据增大的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: php解析xml数据格式,PHP解析xm
- 下一篇: django ModuleNotFoun