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

本文介绍了在 PyTorch 中如何使用权重衰减和丢弃法来解决过拟合问题。权重衰减通过L2范数惩罚项使模型参数更小,防止过拟合。丢弃法则在训练过程中随机丢弃一部分神经元,增加模型的泛化能力。在实验中,通过调整权重衰减系数和丢弃概率,展示了它们对模型性能的影响。
摘要由CSDN通过智能技术生成

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.初始化模型参数,首先定义随机初始化模型参数的函数,该函数为每个参数都附上梯度
def init_params():
     w = torch.randn((num_inputs, 1), requires_grad=True)
     b = torch.zeros(1, requires_grad=True)
     return [w, b]
  • 2.定义L2范数惩罚项
def l2_penalty(w):
    return (w**2).sum()/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())
  • 4.观察过拟合
#1.4 过拟合,设置lambd=0,不适用权重衰减
fit_and_plot(lambd=0)

在这里插入图片描述

fit_and_plot(lambd=3)

在这里插入图片描述

fit_and_plot(lambd=10)

在这里插入图片描述

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
#测试丢弃函数
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. 定义模型及参数

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

我们在对模型评估的时候不应该进⾏丢弃,所以我们修改⼀下 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. 训练与测试模型
#训练与测试模型:
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)

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

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)

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

2.4 小结

  • 通过使⽤丢弃法应对过拟合。
  • 丢弃法只在训练模型时使⽤。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

明月醉窗台

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值