欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

pytorch学习(十)——过拟合相关问题及解决方案

程序员文章站 2022-07-13 10:34:16
...

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) 2N1i=1N(hθ(x(i))y(i))0or=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(θ)=2m1i=1m[((hθ(xi)y(i))2+λj=1nθ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:=θja[m1i=1m(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(θ)=2m1i=1m[((hθ(xi)y(i))2+λj=1nθj)]
对所有的参数的惩罚力度都是一样的,可以让一部分权重变为0,因此产生系数模型,可以去除某些特征(权重等于0等下于去除),图像:
pytorch学习(十)——过拟合相关问题及解决方案

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(θ)=2m1i=1m[((hθ(xi)y(i))2+λj=1nθj2)]
减少了权重的固定比例,使权重圆滑,L2正则化不会使权重变为0,图形:
pytorch学习(十)——过拟合相关问题及解决方案
正则化的公式简单来看:

L1正则化:可以达到模型参数稀疏化的效果
C = C 0 + λ n ∑ w ∣ w ∣ C = C_0+\frac{λ}{n}\sum_w{|w|} C=C0+nλww

L2正则化:可以使得模型的权值衰减,使得模型参数值都直接接近于0
C = C 0 + λ 2 n ∑ w w 2 C = C_0+\frac{λ}{2n}\sum_w{w^2} C=C0+2nλww2

五、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()

输出结果
pytorch学习(十)——过拟合相关问题及解决方案
结论

  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)

输出结果
pytorch学习(十)——过拟合相关问题及解决方案
结论

  1. 正则化的方法也不是在什么情况下都适用的,有的情况下训练结果可能比不加更差
  2. 正则化方法可以抵抗过拟合