【动手学深度学习】权重衰减(含Pytorch从零开始实现的源代码)

news2024/11/17 17:39:56

目录:权重衰减

  • 一、理论知识
  • 二、高维线性回归的实现步骤
  • 三、简单实现
  • 四、源代码

一、理论知识

前面我们已经介绍学习了过拟合的问题,这次我们来讲讲一个正则化模型的技术。

我们总是可以通过去收集更多的训练数据来缓解过拟合,但这可能成本很高,耗时颇多,或者完全超出我们的控制,因而在短期内不可能做到。

假设我们已经拥有了尽可能多的高质量的数据,我们便可以把重心放在正则化技术上。

在多项式回归的例子中,我们可以通过调整拟合多项式的阶数来限制模型的容量。

实际上,限制特征的数量是缓解过拟合的一种常用技术。然而,简单的丢弃特征对于这项工作来说可能过于生硬。我们继续思考多项式回归的例子,考虑高维输入可能发生的情况。 多项式对多变量数据的自然扩展称为单项式(monomials), 也可以说是变量幂的乘积。 单项式的阶数是幂的和。例如, x 1 2 x 2 x_1^2x_2 x12x2 x 3 x 5 2 x_3x_5^2 x3x52都是三次多项式。

注意,随着结束 d d d的增长,带有结束 d d d的项数迅速增加。给定 k k k个变量,阶数为 d d d的项的个数为 ( k − 1 + d k − 1 ) \binom{k-1+d}{k-1} (k1k1+d),即 C k − 1 + d k − 1 = ( k − 1 + d ) ! d ! ( k − 1 ) ! {C_{k-1+d}^{k-1}} =\frac{(k-1+d)!}{d!(k-1)!} Ck1+dk1=d!(k1)!(k1+d)!。因此,即便是阶数上的微小变化,比如从2到3,也会显著增加我们模型的复杂性。

在之前的学习中,我们已经接触了 L 2 L_2 L2范数和 L 1 L_1 L1范数,它们是更为一般的 L p L_p Lp范数的特殊情况。

在训练参数化机器学习模型时, 权重衰减(weight decay)是最广泛使用的正则化的技术之一, 它通常也被称为 L 2 L_2 L2正则化。 这项技术通过函数与零的距离来衡量函数的复杂度, 因为在所有函数 f f f中,函数 f = 0 f=0 f=0(所有输入都得到值0)在某种意义上是最简单的。 但是我们应该如何精确地测量一个函数和零之间的距离呢? 没有一个正确的答案。 事实上,函数分析和巴拿赫空间理论的研究,都在致力于回答这个问题。

一种简单的方法是通过线性函数 f ( X ) = w T X f(\textbf{X})=\textbf{w}^T\textbf{X} f(X)=wTX中的权重向量的某个范数来度量其复杂性, 例如 ∣ ∣ w ∣ ∣ 2 ||\textbf{w}||^2 w2。 要保证权重向量比较小, 最常用方法是将其范数作为惩罚项加到最小化损失的问题中。 将原来的训练目标最小化训练标签上的预测损失, 调整为最小化预测损失和惩罚项之和。 现在,如果我们的权重向量增长的太大, 我们的学习算法可能会更集中于最小化权重范数 ∣ ∣ w ∣ ∣ 2 ||\textbf{w}||^2 w2。这正是我们想要的。我们的损失由下式给出:
L ( w , b ) = 1 n ∑ i = 1 n 1 2 ( w T x ( i ) + b − y ( i ) ) L(\textbf{w},b)=\frac{1}{n}\sum_{i=1}^{n}\frac{1}{2}(\textbf{w}^T\textbf{x}^{(i)}+b-y^{(i)} ) L(w,b)=n1i=1n21(wTx(i)+by(i))
回想一下, x ( i ) \textbf{x}^{(i)} x(i)是样本 i i i的特征, y ( i ) y^{(i)} y(i)是样本 i i i的标签, ( w , b ) (\textbf{w},b) (w,b)是权重和偏置参数。 为了惩罚权重向量的大小, 我们必须以某种方式在损失函数中添加 ∣ ∣ w ∣ ∣ 2 ||\textbf{w}||^2 w2, 但是模型应该如何平衡这个新的额外惩罚的损失? 实际上,我们通过正则化常数 λ \lambda λ来描述这种权衡, 这是一个非负超参数,我们使用验证数据拟合:
L ( w , b ) + λ 2 ∣ ∣ w ∣ ∣ 2 L(\textbf{w},b)+\frac{\lambda }{2}||\textbf{w}||^2 L(w,b)+2λw2
对于 λ = 0 \lambda=0 λ=0,我们恢复了原来的损失函数。

对于 λ > 0 \lambda>0 λ>0,我们限制 ∣ ∣ w ∣ ∣ ||\textbf{w}|| w的大小。

这里我们仍然除以2,当我们取一个二次函数的导数时,2和1/2会抵消掉。以确保更新表达式看起来既漂亮又简单。 你可能会想知道为什么我们使用平方范数而不是标准范数(即欧几里得距离)? 我们这样做是为了便于计算。 通过平方 L 2 L_2 L2范数,我们去掉平方根,留下权重向量每个分量的平方和。 这使得惩罚的导数很容易计算:导数的和等于和的导数。

L 2 L_2 L2正则化回归的小批量随机梯度下降更新如下式:
w ← ( 1 − η λ ) w − η ∣ β ∣ ∑ i ∈ β x ( i ) ( w T x ( i ) + b − y ( i ) ) \textbf{w}\leftarrow (1-\eta \lambda )\textbf{w}-\frac{\eta }{|\beta|}\sum_{i\in \beta}\textbf{x}^{(i)}(\textbf{w}^T\textbf{x}^{(i)}+b-y^{(i)}) w(1ηλ)wβηiβx(i)(wTx(i)+by(i))
根据之前章节所讲的,我们根据估计值与观测值之间的差异来更新 w \textbf{w} w。 然而,我们同时也在试图将 w \textbf{w} w的大小缩小到零。 这就是为什么这种方法有时被称为权重衰减。 我们仅考虑惩罚项,优化算法在训练的每一步衰减权重。 与特征选择相比,权重衰减为我们提供了一种连续的机制来调整函数的复杂度。 较小的 λ \lambda λ值对应较少约束的 w \textbf{w} w, 而较大的 λ \lambda λ值对 w \textbf{w} w的约束更大。

是否对相应的偏置 b b b进行惩罚在不同的实践中会有所不同, 在神经网络的不同层中也会有所不同。 通常,网络输出层的偏置项不会被正则化。

二、高维线性回归的实现步骤

我们通过一个简单的例子来演示权重衰减。

2.1 准备数据

import torch
from torch import nn
from d2l import torch as d2l

首先,我们像以前一样生成一些数据,生成公式如下:
y = 0.05 + ∑ i = 1 d 0.01 x i + ϵ w h e r e ϵ ∈ N ( 0 , 0.0 1 2 ) y=0.05+\sum_{i=1}^{d}0.01x_i+\epsilon \quad where\quad \epsilon \in N(0,0.01^2) y=0.05+i=1d0.01xi+ϵwhereϵN(0,0.012)
我们选择标签是关于输入的线性函数。 标签同时被均值为0,标准差为0.01高斯噪声破坏。 为了使过拟合的效果更加明显,我们可以将问题的维数增加到 d = 200 d=200 d=200, 并使用一个只包含20个样本的小训练集。

n_train, n_test, num_inputs, batch_size = 20, 100, 200, 5
true_w, true_b = torch.ones((num_inputs, 1)) * 0.01, 0.05
train_data = d2l.synthetic_data(true_w, true_b, n_train)
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) # 这里的is_train是表示是否打乱

2.2 初始化模型参数

首先,我们将定义一个函数来随机初始化模型参数。

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]

2.3 定义 L 2 L_2 L2范数惩罚

实现这一惩罚最方便的方法是对所有项求平方后并将它们求和。

def l2_penalty(w):
    return torch.sum(w.pow(2) / 2)

2.4 定义训练代码实现

下面的代码将模型拟合训练数据集,并在测试数据集上进行评估。 线性网络和平方损失没有变化, 所以我们通过d2l.linreg和d2l.squared_loss导入它们。 唯一的变化是损失现在包括了惩罚项。

def train(lambd):
    w, b = init_params()
    net, loss = lambda X : d2l.linreg(X, w, b), d2l.squared_loss
    num_epochs, lr = 100, 0.01
    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:
            l = loss(net(X), y) + lambd * 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('w的L2范数是:', torch.norm(w))
    d2l.plt.show()

2.5 是否加入正则化

2.5.1 忽略正则化

train(0)

输出结果为:
在这里插入图片描述
此时:

w的L2范数是: tensor(13.1169, grad_fn=<CopyBackwards>)

2.5.2 加入正则化

选择 λ = 1 \lambda = 1 λ=1

train(1)

在这里插入图片描述
此时:

w的L2范数是: tensor(0.2394, grad_fn=<CopyBackwards>)

三、简单实现

由于权重衰减在神经网络优化中很常用, 深度学习框架为了便于我们使用权重衰减, 将权重衰减集成到优化算法中,以便与任何损失函数结合使用。 此外,这种集成还有计算上的好处, 允许在不增加任何额外的计算开销的情况下向算法中添加权重衰减。 由于更新的权重衰减部分仅依赖于每个参数的当前值, 因此优化器必须至少接触每个参数一次。

在下面的代码中,我们在实例化优化器时直接通过weight_decay指定weight decay超参数。 默认情况下,PyTorch同时衰减权重和偏移。 这里我们只为权重设置了weight_decay,所以偏置参数 b b b不会衰减。

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')
    num_epochs, lr = 100, 0.01
    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):
        for X, y in train_iter:
            trainer.zero_grad()
            l = loss(net(X), y)
            l.mean().backward()
            trainer.step()
        if (epoch + 1) % 10 == 0:
            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())
    d2l.plt.show()

无正则化的时候:

train_concise(0)

在这里插入图片描述

w的L2范数: tensor(13.3643, grad_fn=<CopyBackwards>)

加上正则化的时候:

train_concise(3)

在这里插入图片描述

w的L2范数: tensor(0.1036, grad_fn=<CopyBackwards>)

四、源代码

# 通过一个例子来演示权重衰减
import torch
from torch import nn
from d2l import torch as d2l


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]


def l2_penalty(w):
    return torch.sum(w.pow(2) / 2)


def train(lambd):
    w, b = init_params()
    net, loss = lambda X : d2l.linreg(X, w, b), d2l.squared_loss
    num_epochs, lr = 100, 0.01
    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:
            l = loss(net(X), y) + lambd * 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('w的L2范数是:', torch.norm(w))
    d2l.plt.show()


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')
    num_epochs, lr = 100, 0.01
    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):
        for X, y in train_iter:
            trainer.zero_grad()
            l = loss(net(X), y)
            l.mean().backward()
            trainer.step()
        if (epoch + 1) % 10 == 0:
            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())
    d2l.plt.show()


if __name__ == '__main__':
    n_train, n_test, num_inputs, batch_size = 20, 100, 200, 5
    true_w, true_b = torch.ones((num_inputs, 1)) * 0.01, 0.05
    train_data = d2l.synthetic_data(true_w, true_b, n_train)
    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) # 这里的is_train是表示是否打乱
    train_concise(3)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/30125.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

从发现问题到创造价值 数据智能如何助力商家双11高质量增长?

近年来&#xff0c;随着消费者的购买行为趋于多样化&#xff0c;很多品牌商家开始布局多平台及多渠道的经营&#xff0c;但随之也带来跨平台多渠道经营的数据不互通、生意数字难以追踪的难题。许多商家也借助双11等大促节点&#xff0c;围绕线下和线上开展全域营销&#xff0c;…

[附源码]java毕业设计宿舍管理系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

Bio-Helix丨Bio-Helix艾美捷100bp DNA ladder说明书

Bio-Helix艾美捷100bp DNA ladder (11条条带&#xff0c;100-1,500pb)背景&#xff1a; PCR产物和许多专有质粒的独特组合&#xff0c;用适当的限制性酶消化&#xff0c;产生11个片段&#xff0c;适合用作琼脂糖凝胶电泳的分子量标准。DNA包括100-1500个碱基对的片段。500和15…

【Java开发】 Spring 05 :Project Reactor 响应式流框架(以Reactive方式访问Redis为例)

响应式编程基于 Project Reactor&#xff08;Reactor 是一个运行在 Java8 之上的响应式框架&#xff09;的思想&#xff0c;当你做一个带有一定延迟的才能够返回的 IO 操作时&#xff0c;不会阻塞&#xff0c;而是立刻返回一个流&#xff0c;并且订阅这个流&#xff0c;当这个流…

【论文阅读】社交网络传播最大化问题-03

Leader-aware community detection in complex networksLeader-aware community detection algorithm - 领导感知社区检测算法创新点相关工作概念定义基础概念创新概念1. &#xff08;领导力&#xff09;2. &#xff08;边缘紧性&#xff09;3.&#xff08;引力&#xff09;模型…

【javaEE】网络原理(传输层Part1)

努力经营当下&#xff0c;直至未来明朗&#xff01; 文章目录前言传输层1. 介绍UDP协议2.【TCP】&#xff08;重难考点&#xff09;TCP可靠传输的机制1. 确认应答2. 超时重传3. 连接管理&#xff08;三次握手、四次挥手&#xff09;【面试题&#xff01;&#xff01;】THINK前言…

项目记录:使用SpringBoot + MyBatisPlus 在MySQL字段设置外键后ID自增失效导致添加失败问题(ID生成策略)

目录 说明 外键列设置后自增失效特性演示 ID不设置自增策略&#xff0c;报错问题和解决 设置自增策略冲突问题和解决。 说明 记录在使用SpringBoot MyBatisPlus操作数据库以及和前端页面交互时遇到的问题和解决方式。 1.表主键字段设置外键之后&#xff0c;自增功能失效…

Spring Security使用JSON格式登录

本文内容来自王松老师的《深入浅出Spring Security》&#xff0c;自己在学习的时候为了加深理解顺手抄录的&#xff0c;有时候还会写一些自己的想法。 Spring Security中默认的登录参数传递的格式是key/value形式&#xff0c;也是表单登录格式。在实际项目中我们可能会通过Json…

小米蓝牙耳机怎么选?适合小米手机的蓝牙耳机推荐

小米可以说是数码界的一股清流&#xff0c;在手机价格上做出了巨大的贡献&#xff0c;它的产品已经覆盖了我们的生活&#xff0c;包括智能家居、穿戴设备、通讯等等&#xff0c;蓝牙耳机作为出行必备的蓝牙耳机单品&#xff0c;耳机品牌众多&#xff0c;意味着我们有更多的选择…

带你深入了解什么是 Java 线程池技术

我们在程序开发中为了“压榨”计算机的 CPU 资源&#xff0c;会去使用多线程来提高程序的性能&#xff0c;在高并发的场景下&#xff0c;多线程编程显得尤为重要。而在线上&#xff0c;我们使用多线程大部分都是通过线程池来管理。线程池是一种基于池化思想的线程管理工具&…

服务器优化

文章目录服务器负载分析CPU 使用率内存使用率磁盘 I/O平均负载网络使用情况服务器内核参数调优单个进程最大打开文件数TCP 相关设置服务器负载分析 在性能调优时&#xff0c;需要先对服务器负载进行分析&#xff0c;通常而言&#xff0c;我们主要分析 CPU 使用率、内存使用率、…

android——自定义加载按钮LoadingButton

方式一 效果图&#xff1a; simpleButton类代码&#xff1a; package com.oneway.demo.navcontroller.view;import android.animation.ObjectAnimator; import android.animation.ValueAnimator; import android.annotation.SuppressLint; import android.content.Context; i…

基于TCP的DNS传输:操作要求

本文档更新了RFC 1123和RFC 1536。本文档要求将允许DNS消息在Internet上通过TCP传输的操作实践作为当前最佳实践。此操作要求与RFC 7766中的实施要求一致。TCP的使用包括基于未加密TCP的DNS以及加密的TLS会话。该文件还考虑了这种形式的DNS通信的后果&#xff0c;以及在不支持当…

腾讯T3整理分享的LeetCode算法小抄完整文档

前言 本文⽬前可以⼿把⼿带你解决 110 道 LeetCode 算法问题&#xff0c;⽽且在不断更新&#xff0c;全部基于 LeetCode 的题⽬&#xff0c;涵盖了所有题型和技巧。 目录 主要内容 ⽬前已包含的 114 道题⽬教程如下&#xff1a; 1.两数之和 10.正则表达式匹配 100.相同的树 …

vue中的transition学习

transition 会在一个元素或组件进入和离开 DOM 时应用动画。他可以将进入和离开的动画应用通过默认插槽传递给它的元素或者组件上 transitionGroup 会在一个 v-for 列表中的元素或组件被插入&#xff0c;移动&#xff0c;或移除时应用动画 <Transition> 组件 进入或者…

[附源码]java毕业设计研究生管理系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

GoLand 文件增加头部注释

一 背景 为了统一规范,决定在项目中要增加注释,包括文件的头部注释以及函数方法的注释。函数方法的注释好说,文件头部注释这个搞了半天(搞完后才发现真的很容易),记录下自己搞得过程,方便其他人。 二 设置头部注释的步骤 我的系统环境是Macos,这篇文章针对的Mac电…

mitmproxy

我们经常了解到的抓包工具有wireshark、fiddler、charles等&#xff0c;mitmproxy也是一个代理工具&#xff0c;突出的优点是可以命令行方式或脚本的方式进行代理&#xff0c;可以对请求数据进行二次开发&#xff08;二次定制&#xff09; 官网&#xff1a;https://mitmproxy.o…

10 张图解 K8S CNI Calico 网络模型原理与功能实战

一、概述 Calico 是一个联网和网络策略供应商。Calico 支持一套灵活的网络选项&#xff0c;因此你可以根据自己的情况选择最有效的选项&#xff0c;包括非覆盖和覆盖网络&#xff0c;带或不带 BGP。Calico 使用相同的引擎为主机、Pod 和&#xff08;如果使用 Istio 和 Envoy&am…

Nginx:配置

文章目录1、Nginx 工作原理2、Nginx 安装启动2.1、安装2.2、启动3、配置文件3.1、块配置3.2、代理 & 负载均衡3.2.1、代理正向代理反向代理3.2.2、负载均衡3.3、Nginx 缓存3.4、Nginx 限流4、http 配置使用4.1、配置结构4.2、配置命令4.2.1、设置配置命令4.2.2、设置回调方…