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

PyTorch 中.backward() 详解使用

1️、背景:自动求导机制(Autograd)

  • PyTorch 使用 动态图机制 (Dynamic Computation Graph)

    • 每一次 forward 操作都会在后台构建一张计算图(autograd graph)。
    • 计算图的节点:Tensor
    • 边:运算(Function
  • 调用 .backward() 时,PyTorch 会从 标量(loss)开始,沿着计算图反向传播,自动计算各个参数的梯度,并存储在 tensor.grad 中。


2️、基本用法

import torch# 定义张量,开启梯度跟踪
x = torch.tensor(2.0, requires_grad=True)
y = x**2 + 3*x + 1  # y = x^2 + 3x + 1# 反向传播
y.backward()print(x.grad)  # dy/dx = 2x + 3 = 7

3️、.backward() 的常见参数

(1) gradient=None

  • 适用于 标量张量(只含一个值)。
  • 如果 tensor 不是标量(多元素张量),必须传入 gradient 参数(同 shape 的权重),告诉 PyTorch 怎么把向量 → 标量。

例子:

x = torch.tensor([1.0, 2.0, 3.0], requires_grad=True)
y = x**2
# y = [1,4,9],不是标量
# 如果直接 y.backward() 会报错# 传入 gradient 向量,等价于对 sum(y) 求导
y.backward(torch.tensor([1.0, 1.0, 1.0]))
print(x.grad)  # [2,4,6]

(2) retain_graph=False

  • 默认情况下,backward() 执行后会 释放计算图(节省内存)。
  • 如果你需要对 同一个图多次反向传播,必须设 retain_graph=True
x = torch.tensor(2.0, requires_grad=True)
y = x**3y.backward(retain_graph=True)
print(x.grad)  # 12 (dy/dx=3x^2=12)y.backward()   # 第二次 backward,如果没有 retain_graph 会报错
print(x.grad)  # 24 (累积梯度)

(3) create_graph=False

  • 是否在反向传播时 构建计算图(用于高阶导数)。
  • 默认 False(只算一次梯度)。
  • 如果要继续对梯度求导,就需要 create_graph=True
x = torch.tensor(2.0, requires_grad=True)
y = x**3dy_dx = torch.autograd.grad(y, x, create_graph=True)[0]
# dy/dx = 12d2y_dx2 = torch.autograd.grad(dy_dx, x)[0]
print(d2y_dx2)  # 12

4️、梯度累积机制

PyTorch 中 .grad累积的,不会自动清零。

x = torch.tensor(2.0, requires_grad=True)y1 = x**2
y1.backward()
print(x.grad)  # 4y2 = 3*x
y2.backward()
print(x.grad)  # 4 + 3 = 7# 解决方法:每次反向传播前清零
x.grad.zero_()

在训练循环中,通常这样写:

optimizer.zero_grad()  # 清空旧梯度
loss.backward()        # 计算新梯度
optimizer.step()       # 更新参数

5️、.backward()torch.autograd.grad

  • .backward():会把梯度 存储到 tensor.grad
  • torch.autograd.grad()返回梯度值,不会自动累积到 .grad

例子:

x = torch.tensor(2.0, requires_grad=True)
y = x**3# 用 backward
y.backward()
print(x.grad)  # 12# 用 autograd.grad
dy_dx = torch.autograd.grad(y, x)[0]
print(dy_dx)  # 12
print(x.grad) # 12 (还是累积的)

6️、.backward() 的典型使用场景

  1. 训练神经网络

    for data, target in dataloader:optimizer.zero_grad()output = model(data)loss = criterion(output, target)loss.backward()optimizer.step()
    
  2. 自定义梯度计算(比如物理约束 loss)

    x = torch.randn(3, requires_grad=True)
    y = (x**2).sum()
    y.backward()
    print(x.grad)  # 2x
    
  3. 高阶导数

    x = torch.tensor(1.0, requires_grad=True)
    y = x**3
    dy_dx = torch.autograd.grad(y, x, create_graph=True)[0]
    d2y_dx2 = torch.autograd.grad(dy_dx, x)[0]
    print(d2y_dx2)  # 6
    

7️、常见坑

  1. loss 不是标量 → 必须传 gradient 参数。
  2. 忘记清零梯度 → 梯度会累积,导致训练异常。
  3. 重复 backward → 必须 retain_graph=True
  4. requires_grad=False 的 tensor → 不会求导。
  5. in-place 操作(如 x += 1)可能破坏计算图,导致错误。

8、综合示例

示例 1:简单函数 + backward 验证

函数:

y=(x1⋅x2+x3)2 y = (x_1 \cdot x_2 + x_3)^2 y=(x1x2+x3)2

import torch# 定义输入
x1 = torch.tensor(2.0, requires_grad=True)
x2 = torch.tensor(3.0, requires_grad=True)
x3 = torch.tensor(1.0, requires_grad=True)# 前向计算
y = (x1 * x2 + x3) ** 2
print("y =", y.item())# 反向传播
y.backward()# 查看梯度
print("dy/dx1 =", x1.grad.item())  # 2 * (x1*x2 + x3) * x2
print("dy/dx2 =", x2.grad.item())  # 2 * (x1*x2 + x3) * x1
print("dy/dx3 =", x3.grad.item())  # 2 * (x1*x2 + x3)

结果

y = 49
dy/dx1 = 42
dy/dx2 = 28
dy/dx3 = 14

对应梯度推导:

  • dy/dx1=2(x1x2+x3)⋅x2=2(2∗3+1)∗3=42dy/dx_1 = 2(x_1x_2 + x_3) \cdot x_2 = 2(2*3+1)*3 = 42dy/dx1=2(x1x2+x3)x2=2(23+1)3=42
  • dy/dx2=2(x1x2+x3)⋅x1=2(6+1)∗2=28dy/dx_2 = 2(x_1x_2 + x_3) \cdot x_1 = 2(6+1)*2 = 28dy/dx2=2(x1x2+x3)x1=2(6+1)2=28
  • dy/dx3=2(x1x2+x3)=14dy/dx_3 = 2(x_1x_2 + x_3) = 14dy/dx3=2(x1x2+x3)=14

.backward() 自动完成了这些链式法则计算。


示例 2:神经网络训练一个回归任务

任务:用一个 简单的全连接网络 拟合函数 y=2x+3y = 2x + 3y=2x+3

import torch
import torch.nn as nn
import torch.optim as optim# 构造数据
x = torch.linspace(-5, 5, 100).unsqueeze(1)  # shape [100,1]
y = 2 * x + 3 + 0.1 * torch.randn_like(x)    # 加点噪声**定义网络**
model = nn.Sequential(nn.Linear(1, 10),nn.ReLU(),nn.Linear(10, 1)
)**损失函数 + 优化器**
criterion = nn.MSELoss()
optimizer = optim.SGD(model.parameters(), lr=0.01)**训练**
for epoch in range(200):optimizer.zero_grad()          # 清空梯度y_pred = model(x)              # 前向loss = criterion(y_pred, y)    # 计算lossloss.backward()                # 🔹 反向传播,计算梯度optimizer.step()                # 更新参数if epoch % 50 == 0:print(f"Epoch {epoch}, Loss = {loss.item():.4f}")

训练过程中:

  • .backward() 会自动计算网络所有参数的梯度(通过计算图 + 链式法则)。
  • optimizer.step() 利用梯度更新参数。

最终模型能学到近似 y=2x+3y = 2x + 3y=2x+3


对比两例

  • 示例 1:展示了 .backward()简单函数 中的梯度传播过程。
  • 示例 2:展示了 .backward()实际深度学习训练 中的应用,自动处理整个网络的梯度。

总结

.backward() 是 PyTorch 自动求导的核心函数:

  • 默认从 标量 loss 反向传播,计算所有叶子节点的梯度,存到 .grad

  • 关键参数:

    • gradient:非标量情况需要指定权重。
    • retain_graph:是否保留计算图,支持多次 backward。
    • create_graph:是否构建高阶导数的计算图。
  • 梯度会 累积,必须在训练循环里手动清零。

  • .backward()torch.autograd.grad 可以互补使用。


http://www.xdnf.cn/news/1464877.html

相关文章:

  • 前后端国密加密传输用户密码流程
  • Unity 解决天空盒中间出现一条线
  • flink 伪代码
  • 高效管理网络段和端口集合的工具之ipset
  • Bug排查日记:高效记录与解决之道
  • 高通AR1平台Recovery架构分析与自动恢复出厂设置实现
  • 从 elecworks 到云端协同:SOLIDWORKS Electrical 发展历史 + 核心功能 + 采购指南
  • Linux 磁盘扩容及分区相关操作实践
  • 从Java全栈到云原生:一场技术深度对话
  • Golang语言设计理念
  • 【GEOS-Chem伴随模型第一期】GEOS-Chem Adjoint 模型详解
  • 常见Bash脚本漏洞分析与防御
  • 【Flutter】RefreshIndicator 无法下拉刷新问题
  • 【存储选型终极指南】RustFS vs MinIO:5大维度深度对决,95%技术团队的选择秘密!
  • LeetCode 131 分割回文串
  • 【LeetCode热题100道笔记】删除链表的倒数第 N 个结点
  • Kafka核心原理与常见面试问题解析
  • 《AI 问答系统:从开发到落地,关键技术与实践案例全解析》
  • 【技术教程】如何将文档编辑器集成至基于Java的Web应用程序
  • c++工程如何提供http服务接口
  • 基于 GEE 批量下载 Landsat8 地表温度(LST)数据
  • 【计算机科学与应用】砚文化虚拟博物馆的Unity3D设计
  • 理解损失函数:机器学习的指南针与裁判
  • 踩坑实录:Django继承AbstractUser时遇到的related_name冲突及解决方案
  • 【Flask】测试平台中,记一次在vue2中集成编辑器组件tinymce
  • XR数字融合工作站打造智能制造专业学习新范式
  • windows通过xrdp远程连接Ubuntu黑屏问题解决
  • FDTD_3 d mie_仿真
  • 计算机毕设选题:基于Python数据挖掘的高考志愿推荐系统
  • AI+消费,阿里的新故事很性感