当前位置: 首页 > news >正文

5.自动求导 [跟着沐神-动手学深度学习]

自动求导 

  自动求导的作用

    1.自动计算梯度:深度学习模型的训练依赖于梯度下降法优化损失函数。只需要定义好模型和损失函数,调用 .backward(),框架就能算出每个参数的梯度。

    2.支持反向传播算法:自动求导是反向传播的基础,它构建计算图并应用链式法则来自动求出每一层的误差梯度,这正是神经网络能够端到端训练的关键。

    3.加速模型开发和调试:有了自动求导,研究者和工程师可以专注于设计模型结构,而不是浪费时间在复杂的数学推导上。能够更快速地迭代和调试模型。

    4.适应复杂模型结构:现代神经网络越来越复杂(如循环结构、分支、条件语句等)。 自动求导能在**动态图(如 PyTorch、MXNet Gluon)**中即时构建计算图,灵活地处理这些结构。

    5.提高代码可复用性和模块化:自动求导使得代码更清晰、模块化、复用性更强。可以轻松组合各种层、损失函数和优化器,而不必担心手动实现梯度。

 

    自动求导是深度学习模型训练过程中自动计算梯度的机制,使得模型训练变得高效、灵活且易于实现,是现代深度学习框架的基石。

  向量链式法则 

      向量:

      

      例子:

        X,W∈ Rn , y∈ R     z = (<x,w> - y)2 ,计算z对w求偏导

        等于 2(<x,w> - y)xT

  计算图

    将计算表示为一个无环图

    

    将代码分解成操作子

from mxnet import autograd, ndwith autograd.record():a = nd.ones((2,1))b = nd.ones((2,1))c = 2*a + b
#a 和 b 是两个 shape 为 (2,1) 的张量(2 行 1 列),值全为 1。
a = [[1.0],[1.0]]b = [[1.0],[1.0]]#执行计算     c = 2*a + b
#这是实际的计算操作,会被 autograd 记录。
#2*a 是张量 a 乘以标量 2,结果是 [[2.0], [2.0]]。
#再加上 b,得到 c = [[3.0], [3.0]]。

  自动求导的两种模式

    链式法则

      和线性代数一样

      

    正向累积

      

    反向累积(反向传递)

      

  复杂度

    计算复杂度:O(n),n是操作子的个数。

    表示在进行前向传播和反向传播时所需的计算量。 比如,一个神经网络的前向传播是 𝑂 ( 𝑛 ) O(n),反向传播可能也是 𝑂 ( 𝑛 ) O(n),因为每一步都需要用到链式法则传播梯度。 在一些研究中,也会研究 memory complexity(内存复杂度)。

   内存复杂度:O(n),因为需要存储正向的所有中间结果。在运行一个算法或模型时,占用的内存空间随输入规模的增长情况。

    在训练深度神经网络时,内存消耗主要来自以下几个方面:

      1. 模型参数 每一层的权重和偏置都会占用内存。 比如,一个全连接层有 𝑛 × 𝑚 n×m 个参数,如果用 float32 表示,每个参数占 4 字节。

      2. 中间激活值(forward activations) 为了反向传播,自动求导需要保留前向传播过程中每一层的输出(激活)。 这通常是内存消耗最大的部分。

      3. 梯度信息 每个参数和每个中间变量都需要保存梯度。 若使用反向传播,几乎所有中间变量都需要记录其梯度。

      4. 临时张量、缓存、优化器状态等 例如 Adam 优化器会为每个参数维护两个额外的状态变量(动量和方差),所以内存需求是参数的 3 倍。 一些框架也会有额外缓存机制。

      

   跟正向累积对比

    O(n)计算复杂度用来计算一个变量的梯度

    O(1)内存复杂度

    

 

自动求导的实现

  怎么存梯度?

  

  计算y

  

  pytorch中自动求微分(autograd),点积和矩阵乘法

import torchx = torch.tensor([1.0, 2.0], requires_grad=True)
y = torch.tensor([3.0, 4.0], requires_grad=True)z = torch.dot(x, y)  # 点积:1*3 + 2*4 = 11
print(z)  # tensor(11., grad_fn=<DotBackward0>)z.backward()  # 反向传播计算梯度
print(x.grad)  # tensor([3., 4.])  # ∂z/∂x = y
print(y.grad)  # tensor([1., 2.])  # ∂z/∂y = x

  梯度累积

  1.梯度累积的默认行为

    PyTorch 的 Autograd 引擎在默认情况下会累加(accumulate)梯度到 .grad 属性中,而不是替换原有值。意味着:

      ·每次调用backward(),计算出的梯度都会加到之前存的梯度上。

      ·如果不手动清零,梯度会随着训练步骤不断累积,导致错误更新。

      梯度存在哪里?

        叶子张量(Leaf Tensors):用户直接创建的张量(如模型参数 nn.Parameter),其梯度存储在 .grad 属性中。

        非叶子张量:默认不保留梯度(除非显式调用 retain_grad()),以节省内存。

  2.为什么需要梯度累积?

    ·小批量训练(Mini-Batch Training):

      当显存不足时,可以通过多次小前向传播累积梯度,模拟大批量的效果。

# 模拟大批量(batch_size=8)分为4个小步(batch_size=2)
for i in range(4):outputs = model(inputs[i*2 : (i+1)*2])loss = criterion(outputs, labels[i*2 : (i+1)*2])loss.backward()  # 梯度累积optimizer.step()     # 更新参数(使用累积的梯度)
optimizer.zero_grad()  # 清零梯度

    ·多任务学习:  同时计算多个损失的梯度并累加。    

  3.如何正确管理梯度?

    部分清零梯度 如果只想清零特定变量的梯度:x.grad.zero_()

 非标量变量的反向传播

   非标量:向量、矩阵、高维张量

    

    backward() 默认只能对标量(scalar)进行梯度计算,PyTorch 的 backward() 默认要求张量是标量(即 shape=()),因为梯度是标量对张量的导数。如果直接对非标量调用 backward(),PyTorch 无法确定如何将梯度传播回输入张量,非标量变量的反向传播显示传入梯度权重(gradient参数)

  

  分离计算

    将某些计算移动到记录的计算图之外

    

   

 

  Python控制流的梯度计算

    

  计算梯度

    

http://www.sczhlp.com/news/9609/

相关文章:

  • nebulagraph图计算总结
  • 光隔离探头的技术优势与应用局限解析
  • ceph常用rbd命令
  • Gitee:本土代码托管平台——效率跃升与安全护航的双重实践
  • 技术学习-分布式系统
  • mcp介绍与mcp server开发(with python)
  • WinForm + SQL Server 实现简单的增删改查
  • 2025 主流 BPM 厂商技术路线、生态布局与未来趋势分析
  • Windows 同时安装多个 MySQL
  • ZBUFF:C内存数据操作领域的“效率革命者”
  • 八月
  • (自适应手机端)红色大气的网络建站公司网站模板
  • (自适应手机端)网站优化SEO博客类网站模板
  • (自适应手机端)冷却塔网站模板 制冷设备网站源码
  • (自适应手机端)防爆控制箱网站模板 防爆设备网站源码
  • P12038 [USTCPC 2025] 送温暖
  • (PC+WAP)聚氨酯粉末涂料网站模板 粉末涂料网站源码下载
  • (自适应手机端)光伏测试仪网站模板 电站运维设备网站源码下载
  • 面经学习-如何优化HTTPS
  • (PC+WAP)智能机器人网站模板 传感器网站源码下载
  • mysql日志
  • 小模型如何击败大机构AI系统:Coral协议技术解析
  • 从 90KB 到 24KB:我如何把远程 React 组件做成可版本化、可缓存、可观测的主题系统
  • pygame小游戏飞机大战_5创建敌人
  • html精通——读懂网页设计
  • Ubuntu24.04家用服务站搭建指南
  • React与Vue构建TODO应用的深层逻辑!
  • 萝莉控都能看懂的sosdp
  • 2025.8.11校队分享:旅游路线
  • React与Vue构建TODO应用的深层逻辑