PyTorch:张量与自动微分(Tensors and autograd)

3 阅读3分钟

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

总结

  1. autograd 核心价值:无需手动推导梯度公式,只需定义前向传播,调用 loss.backward() 即可自动计算所有可导参数的梯度;
  2. 梯度管理关键:参数更新时需用 torch.no_grad() 禁用梯度跟踪,更新后必须手动清零梯度(否则梯度会累积);
  3. 设备适配:torch.accelerator 可自动适配各类加速设备,简化跨平台代码编写。