天天看點

動手學深度學習(十)——過拟合相關問題及解決方案

文章目錄

    • pytorch學習(十)——過拟合相關問題及解決方案
      • 一、過拟合定義
      • 二、過拟合出現的原因
      • 三、解決過拟合的方法
      • 四、正則化
      • 五、MNIST資料集使用dropout方法減小過拟合的可能性
      • 六、MNIST 資料集使用L1和L2正則化

pytorch學習(十)——過拟合相關問題及解決方案

說明:寫這篇博文參考了很多其他部落客的文章和知乎大佬的回答,因為比較雜沒有一一列出,如果大佬們看見了需要加上引用請直接聯系我^^

一、過拟合定義

overfitting:If we have too many features, the learned hypothesis may fit the training set vey well, but fail to generalize to new examples.

fit the training set very well數學語言:

1 2 N ∑ i = 1 N ( h θ ( x ( i ) ) − y ( i ) ) ≈ 0 ( o r = 0 ) \frac{1}{2N}\sum_{i=1}^{N}(h_{\theta}(x^{(i)})-y^{(i)}) ≈ 0(or = 0) 2N1​i=1∑N​(hθ​(x(i))−y(i))≈0(or=0)

二、過拟合出現的原因

  1. 訓練集的資料太少
  2. 訓練集和新資料的特征分布不一緻
  3. 訓練集中存在噪音。噪音大到模型過分記住了噪音的特征,反而忽略了真實的輸入輸出間的關系。
  4. 權值學習疊代次數足夠多,拟合了訓練資料中的噪音和訓練樣例中沒有代表性的特征。

三、解決過拟合的方法

  1. 擴大資料集
  2. early stopping
  3. Dropout(每次随機選取一部分神經元不參與計算)
  4. 正則化(L1和L2正則化)

四、正則化

  • 帶正則化的損失函數:

    J ( θ ) = 1 2 m ∑ i = 1 m [ ( ( h θ ( x i ) − y ( i ) ) 2 + λ ∑ j = 1 n θ j 2 ) ] J({\theta}) = \frac{1}{2m}\sum_{i=1}^{m}[((h_{\theta}(x^{i})-y^{(i)})^2+{\lambda}\sum_{j=1}^{n}{\theta}_j^2)] J(θ)=2m1​i=1∑m​[((hθ​(xi)−y(i))2+λj=1∑n​θj2​)]

  • 帶正則化項的更新函數:對上面公式求導

    θ j : = θ j − a [ 1 m ∑ i = 1 m ( h θ ( x i ) − y ( i ) ) x j ( i ) + λ m θ j ] {\theta}_{j}:= {\theta}_{j}-a[\frac{1}{m}\sum_{i=1}^{m}(h_{\theta}(x^{i})-y^{(i)})x_j^{(i)} + \frac{\lambda}{m}{\theta}_j] θj​:=θj​−a[m1​i=1∑m​(hθ​(xi)−y(i))xj(i)​+mλ​θj​]

L1正則化

J ( θ ) = 1 2 m ∑ i = 1 m [ ( ( h θ ( x i ) − y ( i ) ) 2 + λ ∑ j = 1 n ∣ θ j ∣ ) ] J({\theta}) = \frac{1}{2m}\sum_{i=1}^{m}[((h_{\theta}(x^{i})-y^{(i)})^2+{\lambda}\sum_{j=1}^{n}{|\theta}_j|)] J(θ)=2m1​i=1∑m​[((hθ​(xi)−y(i))2+λj=1∑n​∣θj​∣)]

對所有的參數的懲罰力度都是一樣的,可以讓一部分權重變為0,是以産生系數模型,可以去除某些特征(權重等于0等下于去除),圖像:

動手學深度學習(十)——過拟合相關問題及解決方案

L2正則化

J ( θ ) = 1 2 m ∑ i = 1 m [ ( ( h θ ( x i ) − y ( i ) ) 2 + λ ∑ j = 1 n θ j 2 ) ] J({\theta}) = \frac{1}{2m}\sum_{i=1}^{m}[((h_{\theta}(x^{i})-y^{(i)})^2+{\lambda}\sum_{j=1}^{n}{\theta}_j^2)] J(θ)=2m1​i=1∑m​[((hθ​(xi)−y(i))2+λj=1∑n​θj2​)]

減少了權重的固定比例,使權重圓滑,L2正則化不會使權重變為0,圖形:

動手學深度學習(十)——過拟合相關問題及解決方案

正則化的公式簡單來看:

L1正則化:可以達到模型參數稀疏化的效果

C = C 0 + λ n ∑ w ∣ w ∣ C = C_0+\frac{λ}{n}\sum_w{|w|} C=C0​+nλ​w∑​∣w∣

L2正則化:可以使得模型的權值衰減,使得模型參數值都直接接近于0

C = C 0 + λ 2 n ∑ w w 2 C = C_0+\frac{λ}{2n}\sum_w{w^2} C=C0​+2nλ​w∑​w2

五、MNIST資料集使用dropout方法減小過拟合的可能性

内部函數說明:

nn.Sequential:類似于keras中的序貫模型,當一個模型較簡單的時候,我們可以使用torch.nn.Sequential類來實作簡單的順序連接配接模型.

# 導入函數庫
import numpy as np
import torchvision
from torch import nn
from torch import optim
from torch.autograd import Variable
from torchvision import datasets,transforms
from torch.utils.data import DataLoader
import matplotlib.pyplot as plt
import torch

#載入資料
# 載入訓練集
train_dataset = datasets.MNIST(root='./data/06_MNIST/', # 這個位址需要自己指定
                               train=True, # 載入訓練集
                               transform=transforms.ToTensor(), # 轉變為tensor資料
                               download=True)       # 下載下傳資料
#載入測試集
test_dataset = datasets.MNIST(root='./data/06_MNIST/',
                               train=False, # 載入測試集
                               transform=transforms.ToTensor(), # 轉變為tensor資料
                               download=True)       # 下載下傳資料

#裝載資料
# 設定批次大小(每次傳入資料量)
batch_size = 64

# 裝載資料集
train_loader = DataLoader(dataset=train_dataset,
                          batch_size=batch_size, #每批資料的大小
                          shuffle=True) # shuffle表示打亂資料
test_loader = DataLoader(dataset=test_dataset,
                          batch_size=batch_size, #每批資料的大小
                          shuffle=True) # shuffle表示打亂資料

#定義網絡結構
class Net(nn.Module):
    def __init__(self):
        super(Net,self).__init__()
        # nn.Dropout(p=0.5)表示百分之50的神經元不工作
        self.layer1 = nn.Sequential(nn.Linear(784,500),nn.Dropout(p=0.5),nn.Tanh())
        self.layer2 = nn.Sequential(nn.Linear(500,300),nn.Dropout(p=0.5),nn.Tanh())
        self.layer3 = nn.Sequential(nn.Linear(300,10),nn.Softmax(dim=1))
        
    def forward(self,x):
        # 得到的資料格式torch.Size([64, 1, 28, 28])需要轉變為(64,784)
        x = x.view(x.size()[0],-1) # -1表示自動比對
        x = self.layer1(x)
        x = self.layer2(x)
        x = self.layer3(x)
        return x

    
# 定義模型
model = Net()
#定義代價函數
CrossEntropy_loss = nn.CrossEntropyLoss()
#定義優化器
LR=0.5 
optimizer = optim.SGD(model.parameters(),lr=LR)


# 訓練模型
def train_model():
    model.train() # 模型的訓練狀态,dropout起作用
    for i,data in enumerate(train_loader):
        inputs, labels = data
        out = model(inputs)
        loss = CrossEntropy_loss(out,labels)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
    # 求訓練集的準确率
    
    correct = 0   
    for i,data in enumerate(train_loader):
        inputs, labels = data
        out = model(inputs)
        _,predicted = torch.max(out,1)
        correct += (predicted==labels).sum()   
    print("Train acc:{0}".format(correct.item()/len(train_dataset)))
        
def test_model():
    model.eval() # 模型的測試狀态,dropout不起作用
    # 求測試集的準确率
    correct = 0
    for i,data in enumerate(test_loader):
        inputs, labels = data
        out = model(inputs)
        _,predicted = torch.max(out,1)
        correct += (predicted==labels).sum()   
    print("Test acc:{0}".format(correct.item()/len(test_dataset)))
    
if __name__=='__main__':
    for epoch in range(20):
        print('epoch:',epoch)
        train_model()
        test_model()
           

輸出結果:

動手學深度學習(十)——過拟合相關問題及解決方案

結論:

  1. dropout方法不是在什麼情況下都适用的,有的情況下不使用dropout訓練的結果可能更好
  2. dropout可以抵抗過拟合

六、MNIST 資料集使用L1和L2正則化

在優化器的位置上設定L2正則化(weight_decay=0.0001)

# 定義模型
model = Net()
#定義代價函數
CrossEntropy_loss = nn.CrossEntropyLoss()
#定義優化器,設定L2正則化(weight_decay=0.0001)
LR=0.5 
optimizer = optim.SGD(model.parameters(),lr=LR,weight_decay=0.001)
           

輸出結果:

動手學深度學習(十)——過拟合相關問題及解決方案

結論:

  1. 正則化的方法也不是在什麼情況下都适用的,有的情況下訓練結果可能比不加更差
  2. 正則化方法可以抵抗過拟合

繼續閱讀