• 李沐深度学习记录4:12.权重衰减/L2正则化


    权重衰减从零开始实现

    #高维线性回归
    %matplotlib inline
    import torch
    from torch import nn
    from d2l import torch as d2l
    
    #整个流程是,1.生成标准数据集,包括训练数据和测试数据
    #          2.定义线性模型训练
    #           模型初始化(函数)、包含惩罚项的损失(函数)
    #           定义epochs进行训练,每训练5轮评估一次模型在训练集和测试集的损失,画图显示
    #           训练结束后分别查看并比较是否添加范数惩罚项损失对应的训练结果w的L2范数
    #生成数据集
    n_train, n_test, num_inputs, batch_size = 20, 100, 200, 5  #训练数据样本数20,测试样本数100,数据维度200,批量大小5
    true_w, true_b = torch.ones((num_inputs, 1)) * 0.01, 0.05  #生成w矩阵(200,1),w值0.01,偏置b为0.05
    train_data = d2l.synthetic_data(true_w, true_b, n_train) #生成训练数据集X(20,200),y(20,1),y=Xw+b+噪声,train_data接收返回的X,y
    train_iter = d2l.load_array(train_data, batch_size)  #传入数据集和批量大小,构造训练数据迭代器
    test_data = d2l.synthetic_data(true_w, true_b, n_test) #生成测试数据集
    test_iter = d2l.load_array(test_data, batch_size, is_train=False)  #构造测试数据迭代器
    
    #初始化模型参数
    def init_params():
        w = torch.normal(0, 1, size=(num_inputs, 1), requires_grad=True)
        b = torch.zeros(1, requires_grad=True)
        return [w, b]
    
    #定义L2范数惩罚项
    def l2_penalty(w):
        return torch.sum(w.pow(2)) / 2  #L2范数公式需要开平方根,但这里L2范数惩罚项是L2范数的平方,所以不需要开平方根了
    
    #训练代码
    def train(lambd):  #输入λ超参数
        w, b = init_params()  #初始化模型参数
        net, loss = lambda X: d2l.linreg(X, w, b), d2l.squared_loss  #net线性模型torch.matmul(X, w) + b;loss是均方误差
        num_epochs, lr = 100, 0.003
        animator = d2l.Animator(xlabel='epochs', ylabel='loss', yscale='log',
                                xlim=[5, num_epochs], legend=['train', 'test'])
        for epoch in range(num_epochs):  #进行多次迭代训练
            for X, y in train_iter:  #每个epoch,取训练数据
                # 增加了L2范数惩罚项,
                # 广播机制使l2_penalty(w)成为一个长度为batch_size的向量
                l = loss(net(X), y) + lambd * l2_penalty(w)  #loss计算加上了λ×范数惩罚项
                l.sum().backward()  #这里计算损失和,下面参数更新时会对梯度求平均再更新参数
                d2l.sgd([w, b], lr, batch_size)  #进行参数更新操作
            if (epoch + 1) % 5 == 0:  #每5次epoch训练,评估一次模型的训练损失和测试损失
                animator.add(epoch + 1, (d2l.evaluate_loss(net, train_iter, loss),
                                         d2l.evaluate_loss(net, test_iter, loss)))
        print('w的L2范数是:', torch.norm(w).item())  #训练结束后,计算w的L2范数(没有平方)
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    #λ为0,无正则化项,训练
    train(lambd=0)
    d2l.plt.show()
    
    • 1
    • 2
    • 3

    在这里插入图片描述

    #λ为10,有正则化项,训练
    train(lambd=5)
    d2l.plt.show()
    
    • 1
    • 2
    • 3

    在这里插入图片描述

    权重衰减的简洁实现

    #权重衰减的简洁实现
    def train_concise(wd):
        net = nn.Sequential(nn.Linear(num_inputs, 1))   #定义模型
        for param in net.parameters():   #初始化参数
            param.data.normal_()
        loss = nn.MSELoss(reduction='none')  #计算loss,这里不包含正则项
        num_epochs, lr = 100, 0.003
        # 偏置参数没有衰减
        #在参数优化部分,计算梯度时加入了权重衰减
        #所以是计算loss时没计算正则项,只是在计算梯度时加入了权重衰减吗?
        trainer = torch.optim.SGD([
            {"params":net[0].weight,'weight_decay': wd},
            {"params":net[0].bias}], lr=lr)
        animator = d2l.Animator(xlabel='epochs', ylabel='loss', yscale='log',
                                xlim=[5, num_epochs], legend=['train', 'test'])
        for epoch in range(num_epochs):   #训练100轮
            for X, y in train_iter:  #对于每轮,取数据训练
                trainer.zero_grad()   #梯度清零
                l = loss(net(X), y)  #计算loss
                l.mean().backward() #反向传播
                trainer.step()  #更新梯度
            if (epoch + 1) % 5 == 0:   #每5轮评估一次模型在测试集和训练集的损失
                animator.add(epoch + 1,
                             (d2l.evaluate_loss(net, train_iter, loss),
                              d2l.evaluate_loss(net, test_iter, loss)))
        print('w的L2范数:', net[0].weight.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
    • 24
    • 25
    • 26
    #没有进行权重衰减
    train_concise(0)
    
    • 1
    • 2

    在这里插入图片描述

    #进行权重衰减
    train_concise(5)
    
    • 1
    • 2

    在这里插入图片描述

  • 相关阅读:
    LabVIEW以编程方式启用IEPE激励
    【Maven基础概览】Maven是什么 | Maven的优势 | Maven的核心概念 | Maven的安装和使用;【分布式架构】特点介绍 | 使用Apache Kafka进行消息传递
    KKSwarm功能升级,低成本实现多车集群与避障
    冒泡排序详解
    632. 最小区间
    R语言“优雅地“进行医学统计分析
    Spring Cloud Netflix微服务组件-Eureka
    CodeTON Round 3 (Div. 1 + Div. 2, Rated, Prizes!) A. Indirect Sort 解题报告
    偏微分方程为什么要先先验估计再求解的存在性,先验估计有什么用?
    达梦数据库相关SQL及适配Mysql配置总结
  • 原文地址:https://blog.csdn.net/qq_46238275/article/details/133582315