PyTorch 学习笔记 (1): 自动求导 (Autograd)
2025-09-07·8 min read
#PyTorch#Deep Learning
自动求导是 PyTorch 最重要的特性之一!
核心概念
- 神经网络训练需要计算梯度(导数)
- 手动计算梯度非常繁琐且容易出错
- PyTorch 可以自动计算梯度
原理:
- 每个 Tensor 都有
.grad属性存储梯度 - 设置
requires_grad=True来追踪计算历史 - 调用
.backward()自动计算梯度
基本自动求导
创建一个需要追踪梯度的张量:
python
import torch
# 创建一个需要追踪梯度的张量
x = torch.tensor([2.0], requires_grad=True)
print(f"x = {x}")
print(f"x.requires_grad = {x.requires_grad}")
# 定义一个函数 y = x^2
y = x ** 2
print(f"y = x^2 = {y}")
# 计算梯度(dy/dx = 2x)
y.backward() # 反向传播
print(f"在 x=2 处,dy/dx = 2x = {x.grad}") # 应该是 4
更复杂的计算图
这就是神经网络的基本操作:
python
# 重置梯度
x = torch.tensor([2.0], requires_grad=True)
w = torch.tensor([3.0], requires_grad=True)
b = torch.tensor([1.0], requires_grad=True)
# 构建 y = w * x + b (神经网络的基本操作!)
y = w * x + b
print(f"x = {x}, w = {w}, b = {b}")
print(f"y = w * x + b = {y}")
# 定义损失函数 loss = y^2
loss = y ** 2
print(f"loss = y^2 = {loss}")
# 反向传播
loss.backward()
print(f"梯度:")
print(f"d(loss)/d(x) = {x.grad}") # 2y * w = 2*7*3 = 42
print(f"d(loss)/d(w) = {w.grad}") # 2y * x = 2*7*2 = 28
print(f"d(loss)/d(b) = {b.grad}") # 2y * 1 = 2*7 = 14
多变量函数
损失函数通常涉及多个样本:
python
# 损失函数通常涉及多个样本
x = torch.tensor([1.0, 2.0, 3.0], requires_grad=True)
print(f"x = {x}")
# y = x^2 的和
y = (x ** 2).sum()
print(f"y = sum(x^2) = {y}")
y.backward()
print(f"dy/dx = {x.grad}") # 应该是 [2, 4, 6],即 2x
梯度累加问题
重要:梯度会累加,每次迭代前需要清空!
python
x = torch.tensor([2.0], requires_grad=True)
# 第一次计算
y1 = x ** 2
y1.backward()
print(f"第一次 backward 后 x.grad = {x.grad}") # 4
# 第二次计算(梯度会累加!)
y2 = x ** 3
y2.backward()
print(f"第二次 backward 后 x.grad = {x.grad}") # 4 + 12 = 16(累加了!)
# 正确做法:每次迭代前清空梯度
x.grad.zero_() # 清空梯度
print(f"清空后 x.grad = {x.grad}")
控制梯度追踪
有时候不需要计算梯度(如推理阶段),可以临时禁用:
python
x = torch.tensor([2.0], requires_grad=True)
# 方法1:with torch.no_grad() 临时禁用梯度追踪
with torch.no_grad():
y = x ** 2
print(f"在 no_grad() 内,y.requires_grad = {y.requires_grad}") # False
# 方法2:.detach() 创建一个不需要梯度的副本
y_detach = x.detach()
print(f"detach 后,y_detach.requires_grad = {y_detach.requires_grad}") # False
# 方法3:requires_grad_(False) 永久禁用
x.requires_grad_(False)
print(f"设置 False 后,x.requires_grad = {x.requires_grad}") # False
理解计算图
python
a = torch.tensor([2.0], requires_grad=True)
b = torch.tensor([3.0], requires_grad=True)
# 构建计算图:
# c = a * b
# d = a + b
# e = c * d
c = a * b
d = a + b
e = c * d
print("计算图结构:")
print(f" a = {a.item()}, b = {b.item()}")
print(f" c = a * b = {c.item()}")
print(f" d = a + b = {d.item()}")
print(f" e = c * d = {e.item()}")
e.backward()
print(f"梯度:")
print(f" de/da = {a.grad}") # 21
print(f" de/db = {b.grad}") # 16
验证:
text
e = c * d = (a*b) * (a+b)
de/da = b*(a+b) + (a*b)*1 = 3*5 + 6*1 = 21
de/db = a*(a+b) + (a*b)*1 = 2*5 + 6*1 = 16
总结:神经网络的梯度计算流程
训练神经网络的标准流程:
text
1. 初始化参数(requires_grad=True)
2. 前向传播:计算预测值
3. 计算损失
4. 反向传播:loss.backward() 自动计算所有梯度
5. 更新参数:optimizer.step()
6. 清空梯度:optimizer.zero_grad()(准备下一次迭代)
这个流程会在后续的线性回归和神经网络示例中反复使用!