第三章:自动求导¶
什么是自动求导¶
自动求导(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 = 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.])
链式法则计算:
多元函数梯度¶
多个变量的梯度¶
# 创建包含多个值的张量
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 采用"延迟计算":
- 前向传播:只记录计算过程,不求导
- 调用 backward():一次性计算所有梯度
类比:
梯度累加与清零¶
问题:梯度会累加¶
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 构建神经网络。