PyTorch实现权重衰退:从零实现与简洁实现

一、权重衰退原理

权重衰退(L2正则化)通过向损失函数添加权重的L2范数惩罚项,防止模型过拟合。其损失函数形式为:


二、从零开始实现

1.1 导入库与数据生成

python 复制代码
%matplotlib inline
import torch
from torch import nn
from d2l import torch as d2l

# 超参数设置
train_samples, test_samples, inputs, batch_size = 20, 100, 200, 5
true_w, true_b = torch.ones((inputs, 1)) * 0.01, 0.05

# 生成合成数据
train_data = d2l.synthetic_data(true_w, true_b, train_samples)
train_iter = d2l.load_array(train_data, batch_size)
test_data = d2l.synthetic_data(true_w, true_b, test_samples)
test_iter = d2l.load_array(test_data, batch_size)

1.2 模型参数初始化

python 复制代码
def init_params():
    w = torch.normal(0, 1, size=(inputs, 1), requires_grad=True)
    b = torch.zeros(1, requires_grad=True)
    return [w, b]

1.3 定义L2正则化

python 复制代码
def l2_penalty(w):
    return torch.sum(w**2) / 2

1.4 训练函数

python 复制代码
def train(l):
    w, b = init_params()
    net = lambda x: d2l.linreg(x, w, b)
    loss = d2l.squared_loss
    epochs, lr = 100, 0.03
    
    animator = d2l.Animator(
        xlabel='epoch', ylabel='loss', yscale='log',
        xlim=[5, epochs], legend=['train', 'test']
    )
    
    for epoch in range(epochs):
        for X, y in train_iter:
            l_ = loss(net(X), y) + l * l2_penalty(w)
            l_.sum().backward()
            d2l.sgd([w, b], lr, batch_size)
            
        if (epoch + 1) % 5 == 0:
            animator.add(epoch + 1, (
                d2l.evaluate_loss(net, train_iter, loss),
                d2l.evaluate_loss(net, test_iter, loss)
            ))
    print(f"w的L2范数: {torch.norm(w).item():.5f}")

1.5 训练结果

不使用权重衰退(λ=0)
python 复制代码
train(l=0)

输出结果

bash 复制代码
w的L2范数: 13.72006
使用权重衰退(λ=3)
python 复制代码
train(lambd=3)

输出结果

bash 复制代码
w的L2范数: 0.0426

2. PyTorch简洁实现

2.1 定义模型与训练

python 复制代码
def train_concise(lambd):
    net = nn.Sequential(nn.Linear(inputs, 1))
    for param in net.parameters():
        param.data.normal_()
    
    loss = nn.MSELoss()
    optimizer = torch.optim.SGD([
        {"params": net[0].weight, "weight_decay": lambd},
        {"params": net[0].bias}], lr=0.03)
    
    animator = d2l.Animator(xlabel='epoch', ylabel='loss', yscale='log',
                            xlim=[5, 100], legend=['train', 'test'])
    
    for epoch in range(100):
        for X, y in train_iter:
            optimizer.zero_grad()
            l = loss(net(X), y)
            l.backward()
            optimizer.step()
        
        if (epoch + 1) % 5 == 0:
            animator.add(epoch + 1, (
                d2l.evaluate_loss(net, train_iter, loss),
                d2l.evaluate_loss(net, test_iter, loss)))
    
    print(f"w的L2范数: {torch.norm(net[0].weight).item():.4f}")

2.2 训练结果

不使用权重衰退(λ=0)
python 复制代码
train_concise(0)

输出结果

bash 复制代码
w的L2范数: 14.3265
使用权重衰退(λ=3)
python 复制代码
train_concise(3)

输出结果

bash 复制代码
w的L2范数: 0.0528

关键点解析

  1. L2正则化 :通过向损失函数添加权重的平方和项(λ * ||w||^2),限制权重的大小,防止过拟合。

  2. 参数对比

    • 无正则化时,权重范数较大(13.72),模型可能过拟合。

    • 加入正则化后,权重范数显著降低(0.04),模型更稳定。

  3. 损失曲线:正则化后测试损失与训练损失更接近,表明泛化能力提升。


常见错误解决

在简洁实现中,若出现 TypeError: 'function' object is not iterable,请检查:

  1. evaluate_loss 的参数是否正确传递数据迭代器(如 train_iter 而非 train)。

  2. 确保数据加载器已正确定义。


通过本文,读者可以掌握权重衰退的核心思想,并学会在PyTorch中实现正则化方法。完整代码已通过测试,可直接运行。

相关推荐
threelab18 分钟前
07.three官方示例+编辑器+AI快速学习webgl_buffergeometry_attributes_integer
人工智能·学习·编辑器
背太阳的牧羊人43 分钟前
tokenizer.encode_plus,BERT类模型 和 Sentence-BERT 他们之间的区别与联系
人工智能·深度学习·bert
学算法的程霖1 小时前
TGRS | FSVLM: 用于遥感农田分割的视觉语言模型
人工智能·深度学习·目标检测·机器学习·计算机视觉·自然语言处理·遥感图像分类
博睿谷IT99_1 小时前
华为HCIP-AI认证考试版本更新通知
人工智能·华为
小彭律师1 小时前
数字化工厂中央控制室驾驶舱系统架构文档
python
一点.点2 小时前
SafeDrive:大语言模型实现自动驾驶汽车知识驱动和数据驱动的风险-敏感决策——论文阅读
人工智能·语言模型·自动驾驶
concisedistinct2 小时前
如何评价大语言模型架构 TTT ?模型应不应该永远“固定”在推理阶段?模型是否应当在使用时继续学习?
人工智能·语言模型·大模型
找了一圈尾巴2 小时前
AI Agent-基础认知与架构解析
人工智能·ai agent
jzwei0233 小时前
Transformer Decoder-Only 参数量计算
人工智能·深度学习·transformer
小言Ai工具箱3 小时前
PuLID:高效的图像变脸,可以通过文本提示编辑图像,通过指令修改人物属性,个性化文本到图像生成模型,支持AI变脸!艺术创作、虚拟形象定制以及影视制作
图像处理·人工智能·计算机视觉