跳转至

第三章:自动求导

什么是自动求导

自动求导(Autograd)是 PyTorch 的核心功能,它能**自动计算导数(梯度)**,无需手动推导公式。

在深度学习中,反向传播算法需要计算损失函数对每个参数的梯度。手动计算非常复杂,自动求导让这个过程自动化。

基本用法

requires_grad

标记需要计算梯度的张量:

import torch

# 创建需要求导的张量
x = torch.tensor([2.0], requires_grad=True)
print(x.requires_grad)  # True

# 普通张量不需要求导
y = torch.tensor([3.0])
print(y.requires_grad)  # False

简单示例

import torch

# 创建张量,标记需要求导
x = torch.tensor([2.0], requires_grad=True)

# 前向计算:定义函数 y = x²
y = x ** 2

# 反向传播:自动计算 dy/dx
y.backward()

# 查看梯度结果
print(x.grad)  # tensor([4.])

数学原理

步骤 说明
函数 y = x²
导数公式 dy/dx = 2x
代入 x=2 dy/dx = 2 × 2 = 4

计算图

PyTorch 通过计算图记录运算过程:

前向传播(计算输出):
x → x² → y

反向传播(计算梯度):
∂y/∂x ← ∂y/∂y
x = torch.tensor([2.0], requires_grad=True)
y = x ** 2      # y = 4
z = 3 * y + 1   # z = 13

# 反向传播
z.backward()

print(x.grad)   # tensor([12.])

链式法则计算

z = 3y + 1 = 3x² + 1
dz/dx = dz/dy × dy/dx = 3 × 2x = 6x = 12

多元函数梯度

多个变量的梯度

# 创建包含多个值的张量
x = torch.tensor([2.0, 3.0], requires_grad=True)

# 定义函数 y = x[0]² + x[1]²
y = x[0]**2 + x[1]**2

# 反向传播
y.backward()

# 查看梯度
print(x.grad)  # tensor([4., 6.])

计算过程

函数: y = x[0]² + x[1]²

偏导数:
∂y/∂x[0] = 2 × x[0] = 2 × 2.0 = 4.0
∂y/∂x[1] = 2 × x[1] = 2 × 3.0 = 6.0

梯度向量: (4.0, 6.0)

梯度 vs 导数

概念 适用场景 含义
导数 一元函数(一个变量) 变化率
梯度 多元函数(多个变量) 各偏导数组成的向量

简单理解

  • 导数:一个变量的变化率
  • 梯度:多个变量的变化率组成的向量,指向函数增长最快的方向

backward() 的作用

x = torch.tensor([2.0], requires_grad=True)
y = x ** 2

# 此时 x.grad 是 None
print(x.grad)  # None

# 执行反向传播
y.backward()

# 现在 x.grad 有值了
print(x.grad)  # tensor([4.])

为什么这样设计

神经网络很复杂,每次前向计算都求导很浪费。PyTorch 采用"延迟计算":

  1. 前向传播:只记录计算过程,不求导
  2. 调用 backward():一次性计算所有梯度

类比

前向传播 = 考试答题(记录答案)
backward() = 批改试卷(计算得分)
x.grad = 最终成绩

梯度累加与清零

问题:梯度会累加

x = torch.tensor([2.0], requires_grad=True)

for i in range(3):
    y = x ** 2
    y.backward()
    print(f"第{i+1}次: x.grad = {x.grad}")

# 输出:
# 第1次: x.grad = tensor([4.])
# 第2次: x.grad = tensor([8.])  # 累加了!
# 第3次: x.grad = tensor([12.]) # 继续累加!

解决:手动清零

x = torch.tensor([2.0], requires_grad=True)

for i in range(3):
    y = x ** 2
    y.backward()
    print(f"第{i+1}次: x.grad = {x.grad}")
    x.grad.zero_()  # 清零梯度

# 输出:
# 第1次: x.grad = tensor([4.])
# 第2次: x.grad = tensor([4.])
# 第3次: x.grad = tensor([4.])

禁用梯度计算

with torch.no_grad()

临时禁用梯度追踪,节省内存:

x = torch.tensor([2.0], requires_grad=True)

with torch.no_grad():
    y = x ** 2
    print(y.requires_grad)  # False

# 退出后恢复正常
z = x ** 2
print(z.requires_grad)  # True

.detach()

分离张量,返回不需要梯度的新张量:

x = torch.tensor([2.0], requires_grad=True)
y = x ** 2

# 分离
z = y.detach()
print(z.requires_grad)  # False

# 原张量不变
print(y.requires_grad)  # True

.requires_grad_(False)

永久禁用:

x = torch.tensor([2.0], requires_grad=True)
print(x.requires_grad)  # True

x.requires_grad_(False)
print(x.requires_grad)  # False

应用场景

1. 神经网络训练(最主要应用)

# 权重参数
w = torch.tensor([0.5], requires_grad=True)
b = torch.tensor([0.1], requires_grad=True)

# 训练数据
x = torch.tensor([1.0, 2.0, 3.0])
y_true = torch.tensor([2.0, 4.0, 6.0])

# 训练循环
for epoch in range(100):
    # 前向传播
    y_pred = w * x + b

    # 计算损失
    loss = ((y_pred - y_true) ** 2).mean()

    # 反向传播
    loss.backward()

    # 梯度下降更新参数
    w.data -= 0.01 * w.grad
    b.data -= 0.01 * b.grad

    # 清零梯度
    w.grad.zero_()
    b.grad.zero_()

print(f"训练后: w={w.item():.2f}, b={b.item():.2f}")
# 训练后: w=2.00, b=0.00

2. 优化问题

求解函数最小值:

# 求解 f(x) = x² - 4x + 3 的最小值
x = torch.tensor([0.0], requires_grad=True)

for i in range(100):
    y = x**2 - 4*x + 3
    y.backward()
    x.data -= 0.1 * x.grad
    x.grad.zero_()

print(f"最小值点: x = {x.item():.2f}")  # x = 2.00

3. 敏感性分析

分析输入变化对输出的影响:

price = torch.tensor([100.0], requires_grad=True)
quantity = torch.tensor([50.0], requires_grad=True)

revenue = price * quantity
revenue.backward()

print(f"价格对收入的影响: {price.grad}")    # 50
print(f"数量对收入的影响: {quantity.grad}")  # 100

小结

本章学习了:

  • ✅ 自动求导的概念和作用
  • ✅ requires_grad 标记需要求导的张量
  • ✅ backward() 执行反向传播
  • ✅ 梯度 vs 导数的区别
  • ✅ 梯度累加与清零
  • ✅ 禁用梯度计算的方法
  • ✅ 实际应用场景

核心要点

步骤 作用
requires_grad=True 标记需要求导的变量
前向计算 y = x² 构建计算图,记录运算
y.backward() 执行反向传播,计算梯度
x.grad 获取计算结果
x.grad.zero_() 清零梯度,防止累加

下一章

第四章:神经网络基础 - 学习使用 nn.Module 构建神经网络。