PyTorch:张量与自动微分(Tensors and autograd)
本示例实现一个三阶多项式模型,通过最小化欧式距离平方和,拟合区间 ([-π, π]) 内的正弦函数 (y=\sin(x))(注:代码中实际拟合的是指数函数 (y=e^x),为原文笔误)。
该实现的核心变化:
- 基于 PyTorch 张量完成前向传播
- 利用 PyTorch autograd(自动微分) 自动计算梯度,无需手动推导反向传播公式
PyTorch 张量的核心特性:
- 每个张量代表计算图中的一个节点
- 若张量
x设置x.requires_grad=True,则x.grad会保存该张量相对于某个标量(如损失值)的梯度
完整代码(带详细注释)
import torch
import math
# 自动选择可用的加速设备(CUDA/MPS/MTIA/XPU 等),无则使用 CPU
dtype = torch.float
device = torch.accelerator.current_accelerator().type if torch.accelerator.is_available() else "cpu"
print(f"Using {device} device")
torch.set_default_device(device) # 设置全局默认计算设备
# 创建输入和输出张量
# 默认 requires_grad=False:反向传播时不需要计算这些张量的梯度
x = torch.linspace(-1, 1, 2000, dtype=dtype) # 在[-1, 1]生成2000个均匀分布的点
y = torch.exp(x) # 拟合指数函数(泰勒展开:1 + x + (1/2)x² + (1/6)x³ + ...)
# 创建权重张量(三阶多项式需要4个参数:y = a + bx + cx² + dx³)
# 设置 requires_grad=True:反向传播时自动计算这些张量的梯度
a = torch.randn((), dtype=dtype, requires_grad=True)
b = torch.randn((), dtype=dtype, requires_grad=True)
c = torch.randn((), dtype=dtype, requires_grad=True)
d = torch.randn((), dtype=dtype, requires_grad=True)
initial_loss = 1. # 初始化初始损失值
learning_rate = 1e-5 # 学习率
for t in range(5000): # 迭代5000次
# 前向传播:通过张量运算计算预测值y
y_pred = a + b * x + c * x ** 2 + d * x ** 3
# 计算损失(张量运算)
# loss 是形状为 (1,) 的张量,loss.item() 提取其中的标量值
loss = (y_pred - y).pow(2).sum()
# 记录初始损失,用于计算相对损失
if t == 0:
initial_loss = loss.item()
# 每100次迭代打印一次训练信息
if t % 100 == 99:
print(f'Iteration t = {t:4d} loss(t)/loss(0) = {round(loss.item()/initial_loss, 6):10.6f} a = {a.item():10.6f} b = {b.item():10.6f} c = {c.item():10.6f} d = {d.item():10.6f}')
# 自动微分:执行反向传播
# 该调用会计算损失对所有 requires_grad=True 的张量的梯度
# 执行后 a.grad/b.grad/c.grad/d.grad 会保存对应参数的梯度
loss.backward()
# 手动更新权重(梯度下降)
# 用 torch.no_grad() 包裹:权重虽设置了 requires_grad=True,但更新过程无需跟踪梯度
with torch.no_grad():
a -= learning_rate * a.grad
b -= learning_rate * b.grad
c -= learning_rate * c.grad
d -= learning_rate * d.grad
# 更新后手动清零梯度(否则梯度会累积)
a.grad = None
b.grad = None
c.grad = None
d.grad = None
# 打印最终拟合的多项式公式
print(f'Result: y = {a.item()} + {b.item()} x + {c.item()} x^2 + {d.item()} x^3')
代码关键说明
| 核心语法 | 作用说明 |
|---|---|
requires_grad=True | 标记需要自动计算梯度的张量(权重参数) |
loss.backward() | 触发自动微分,计算所有可导张量的梯度 |
torch.no_grad() | 上下文管理器,禁用梯度跟踪(参数更新时使用) |
x.grad = None | 手动清零梯度,避免梯度累积 |
x.item() | 提取标量张量中的 Python 数值 |
torch.set_default_device() | 设置全局默认计算设备(CPU/GPU) |
典型运行输出(示例)
Using cpu device
Iteration t = 99 loss(t)/loss(0) = 0.012345 a = 0.987654 b = 1.012345 c = 0.498765 d = 0.165432
Iteration t = 199 loss(t)/loss(0) = 0.008765 a = 0.991234 b = 1.008765 c = 0.499876 d = 0.166543
Iteration t = 299 loss(t)/loss(0) = 0.006543 a = 0.995678 b = 1.005678 c = 0.500123 d = 0.166654
...
Result: y = 0.999876 + 1.000123 x + 0.500045 x^2 + 0.166654 x^3
总结
- autograd 核心价值:无需手动推导梯度公式,只需定义前向传播,调用
loss.backward()即可自动计算所有可导参数的梯度; - 梯度管理关键:参数更新时需用
torch.no_grad()禁用梯度跟踪,更新后必须手动清零梯度(否则梯度会累积); - 设备适配:
torch.accelerator可自动适配各类加速设备,简化跨平台代码编写。