• Pytorch总结六之 欠拟合和过拟合的解决方法


    Pytorch总结六之 欠拟合和过拟合的解决方法

    • 接上文:Pytorch总结五之 模型选择、⽋拟合和过拟合
    • 过拟合现象,即模型的训练误差远⼩于它在测试集上的误差。虽然增⼤训练数据集可能会减轻过拟合,但是获取额外的训练数据往往代价⾼昂。
    • 对过拟合问题的常用方法: 权重衰减 (weight decay)

    1. 权重衰减

    1.1 方法

    在这里插入图片描述
    在这里插入图片描述

    1.2 高维线性回归实验

    在这里插入图片描述

    #1.高维线性回归实验
    import torch
    import torch.nn as nn
    import numpy as np
    import sys
    sys.path.append("..")
    import d2lzh_pytorch as d2l
    
    #设置训练及验证集数量大小
    n_train, n_test, num_inputs = 20, 100, 200
    true_w, true_b = torch.ones(num_inputs, 1) * 0.01, 0.05
    features = torch.randn((n_train + n_test, num_inputs))
    labels = torch.matmul(features, true_w) + true_b
    labels += torch.tensor(np.random.normal(0, 0.01,size=labels.size()), dtype=torch.float)
    train_features, test_features = features[:n_train, :],features[n_train:, :]
    train_labels, test_labels = labels[:n_train], labels[n_train:]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    下边介绍从零开始实现权重衰减:

    • 1.初始化模型参数,首先定义随机初始化模型参数的函数,该函数为每个参数都附上梯度
    def init_params():
         w = torch.randn((num_inputs, 1), requires_grad=True)
         b = torch.zeros(1, requires_grad=True)
         return [w, b]
    
    • 1
    • 2
    • 3
    • 4
    • 2.定义L2范数惩罚项
    def l2_penalty(w):
        return (w**2).sum()/2
    
    • 1
    • 2
    • 3.定义训练和测试
    batch_size, num_epochs, lr = 1, 100, 0.003
    net, loss = d2l.linreg, d2l.squared_loss
    dataset = torch.utils.data.TensorDataset(train_features,train_labels)
    train_iter = torch.utils.data.DataLoader(dataset, batch_size,shuffle=True)
    def fit_and_plot(lambd):
        w, b = init_params()
        train_ls, test_ls = [], []
        for _ in range(num_epochs):
            for X, y in train_iter:
                # 添加了L2范数惩罚项
                l = loss(net(X, w, b), y) + lambd * l2_penalty(w)
                l = l.sum()
    
            if w.grad is not None:
                w.grad.data.zero_()
                b.grad.data.zero_()
            l.backward()
            d2l.sgd([w, b], lr, batch_size)
            train_ls.append(loss(net(train_features, w, b),train_labels).mean().item())
            test_ls.append(loss(net(test_features, w, b),test_labels).mean().item())
        d2l.semilogy(range(1, num_epochs + 1), train_ls, 'epochs','loss',range(1, num_epochs + 1), 
            test_ls, ['train','test'])
        print('L2 norm of w:', w.norm().item())
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 4.观察过拟合
    #1.4 过拟合,设置lambd=0,不适用权重衰减
    fit_and_plot(lambd=0)
    
    • 1
    • 2

    在这里插入图片描述

    fit_and_plot(lambd=3)
    
    • 1

    在这里插入图片描述

    fit_and_plot(lambd=10)
    
    • 1

    在这里插入图片描述

    1.3 小结

    • 正则化通过为模型损失函数添加惩罚项使学出的模型参数值较⼩,是应对过拟合的常⽤⼿段。
    • 权重衰减等价于 范数正则化,通常会使学到的权重参数的元素较接近0。
    • 权重衰减可以通过优化器中的 weight_decay 超参数来指定。
    • 可以定义多个优化器实例对不同的模型参数使⽤不同的迭代⽅法。

    2. 丢弃法

    除权重衰减外,深度学习模型常常使用丢弃法(dropout)来应对过拟合问题,本节提到的丢弃法指倒置丢弃法 (inverted dropout)

    2.1 方法

    在这里插入图片描述
    在这里插入图片描述

    2.2 从零开始实现丢弃法

    根据丢弃法的定义,我们可以很容易地实现它。下⾯的 dropout 函数将以 drop_prob 的概率丢弃 X
    中的元素。

    • 1.丢弃法
    import torch
    import torch.nn as nn
    import numpy as np
    import sys
    
    sys.path.append("..")
    import d2lzh_pytorch as d2l
    
    def dropout(X, drop_prob):
        X = X.float()
        assert 0 <= drop_prob <= 1
        keep_prob = 1 - drop_prob
        # 这种情况下把全部元素都丢弃
        if keep_prob == 0:
            return torch.zeros_like(X)
        mask = (torch.randn(X.shape) < keep_prob).float()
    
        return mask * X / keep_prob
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    #测试丢弃函数
    X = torch.arange(16).view(2, 8)
    print(X)
    a=dropout(X, 0)
    print(a)
    b=dropout(X, 0.5)
    print(b)
    c=dropout(X, 1.0)
    print(c)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    输出如下:
    在这里插入图片描述

      1. 定义模型及参数

    1.依然使⽤softmax回归的从零开始实现中介绍的Fashion-MNIST数据集。我们将定义⼀个包含两个隐藏层的多层感知机,其中两个隐藏层的输出个数都是256。
    2.定义的模型将全连接层和激活函数ReLU串起来,并对每个激活函数的输出使⽤丢弃法。我们可以分别设置各个层的丢弃概率。通常的建议是把靠近输⼊层的丢弃概率设得⼩⼀点。在这个实验中,我们把第⼀个隐藏层的丢弃概率设为 0.2 ,把第⼆个隐藏层的丢弃概率设为 0.5 。我们可以通过参数 is_training 函数来判断运⾏模式为训练还是测试,并只需在训练模式下使⽤丢弃法。

    #定义参数
    num_inputs, num_outputs, num_hiddens1, num_hiddens2 = 784, 10, 256,256
    W1 = torch.tensor(np.random.normal(0, 0.01, size=(num_inputs,num_hiddens1)), 
        dtype=torch.float, requires_grad=True)
    b1 = torch.zeros(num_hiddens1, requires_grad=True)
    W2 = torch.tensor(np.random.normal(0, 0.01, size=(num_hiddens1,num_hiddens2)),
        dtype=torch.float,requires_grad=True)
    b2 = torch.zeros(num_hiddens2, requires_grad=True)
    W3 = torch.tensor(np.random.normal(0, 0.01, size=(num_hiddens2,num_outputs)), 
        dtype=torch.float, requires_grad=True)
    b3 = torch.zeros(num_outputs, requires_grad=True)
    params = [W1, b1, W2, b2, W3, b3]
    
    #定义模型,我们把第⼀个隐藏层的丢弃概率设为 0.2 ,把第⼆个隐藏层的丢弃概率设为 0.5 。
    drop_prob1, drop_prob2 = 0.2, 0.5
    def net(X, is_training=True):
        X = X.view(-1, num_inputs)
        H1 = (torch.matmul(X, W1) + b1).relu()
        if is_training: # 只在训练模型时使⽤丢弃法
            H1 = dropout(H1, drop_prob1) # 在第⼀层全连接后添加丢弃层
        H2 = (torch.matmul(H1, W2) + b2).relu()
        if is_training:
            H2 = dropout(H2, drop_prob2) # 在第⼆层全连接后添加丢弃层
        return torch.matmul(H2, W3) + b3
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    我们在对模型评估的时候不应该进⾏丢弃,所以我们修改⼀下 d2lzh_pytorch 中 的evaluate_accuracy 函数:

    # 本函数已保存在d2lzh_pytorch
    def evaluate_accuracy(data_iter, net):
        acc_sum, n = 0.0, 0
        for X, y in data_iter:
            if isinstance(net, torch.nn.Module):
                net.eval() # 评估模式, 这会关闭dropout
                acc_sum += (net(X).argmax(dim=1) == y).float().sum().item()
                net.train() # 改回训练模式
            else: # ⾃定义的模型
                if('is_training' in net.__code__.co_varnames): # 如果有is_training这个参数
                # 将is_training设置成False
                    acc_sum += (net(X, is_training=False).argmax(dim=1)== y).float().sum().item()
                else:
                    acc_sum += (net(X).argmax(dim=1) == y).float().sum().item()
            n += y.shape[0]
    return acc_sum / n
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
      1. 训练与测试模型
    #训练与测试模型:
    num_epochs, lr, batch_size = 5, 100.0, 256
    loss = torch.nn.CrossEntropyLoss()
    train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)
    d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs,batch_size, params, lr)
    
    • 1
    • 2
    • 3
    • 4
    • 5

    输出如下:
    在这里插入图片描述

    2.3 简洁实现

    在PyTorch中,我们只需要在全连接层后添加 Dropout 层并指定丢弃概率。在训练模型时, Dropout
    层将以指定的丢弃概率随机丢弃上⼀层的输出元素;在测试模型时(即 model.eval()后), Dropout 层并不发挥作⽤。

    #简洁实现
    net = nn.Sequential(
        d2l.FlattenLayer(),
        nn.Linear(num_inputs, num_hiddens1),
        nn.ReLU(),
        nn.Dropout(drop_prob1),
        nn.Linear(num_hiddens1, num_hiddens2),
        nn.ReLU(),
        nn.Dropout(drop_prob2),
        nn.Linear(num_hiddens2, 10))
    for param in net.parameters():
        nn.init.normal_(param, mean=0, std=0.01)
    
    #para-待优化参数 lr-学习率 
    optimizer = torch.optim.SGD(net.parameters(), lr=0.5)
    d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs,batch_size, None, None, optimizer)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    输出:
    在这里插入图片描述
    注:由于这⾥使⽤的是PyTorch的SGD⽽不是d2lzh_pytorch⾥⾯的sgd,所以就不存在3.9.6节那
    样学习率看起来很⼤的问题了。

    2.4 小结

    • 通过使⽤丢弃法应对过拟合。
    • 丢弃法只在训练模型时使⽤。
  • 相关阅读:
    AIGC如何助力产品研发的创新和性能提升
    Ficow 的 AI 平台快速上手指南(ChatGPT, NewBing, ChatGLM-6B, cursor.so)
    COM组件IDispatch操作
    python打开windows上的文本文件的注意事项
    【Python接口自动化】--深入了解HTTP接口基本组成和网页构建原理
    WavJourney:进入音频故事情节生成世界的旅程
    判断当日是否为当月第一个交易日——时间相关函数3
    sonobe:针对IVC的fold arithmetic电路实例
    全国大数据与计算智能挑战赛:面向低资源的命名实体识别基线方案,排名13/64,组织单位:(大数据与决策实验室)
    代码随想录阅读笔记-字符串【翻转字符串中单词】
  • 原文地址:https://blog.csdn.net/yohnyang/article/details/126864215