PyTorch手动实现简单梯度下降优化器迭代时报错该如何解决?
报错原因分析
你的代码存在两个核心问题导致第二次迭代反向传播报错:
- 梯度更新时使用
q = q - eta * grads的赋值方式,会直接创建一个全新的张量,新张量默认不开启梯度追踪,第二次迭代计算出的loss和无梯度属性的q关联,反向传播时就会抛出找不到梯度函数的错误 with torch.no_grad()后缺少冒号,属于语法错误,即使修复第一个问题也会直接运行失败q.requires_grad = True的设置位置错误,不需要每次循环中重复设置,初始化阶段开启即可
手动梯度下降修复后的代码
# 初始化阶段就给q开启梯度追踪 q.requires_grad_(True) eta = 0.01 for i in range(10): # 每次迭代前先清空上一轮的梯度,避免梯度累加 if q.grad is not None: q.grad.zero_() print('i =', i, ' q =', q) v_trans = forward(v, q) loss = error(v_trans, v_target) loss.backward() # 用inplace操作更新q,不创建新张量,保留梯度属性 with torch.no_grad(): q -= eta * q.grad print('Final q = ', q)
非神经网络项目使用PyTorch内置优化器的方法
PyTorch的内置优化器并非只能用于神经网络场景,任何需要梯度优化的张量都可以直接调用,无需手动实现梯度更新逻辑,使用示例如下:
import torch.optim as optim # 初始化待优化张量,开启梯度追踪 q.requires_grad_(True) eta = 0.01 # 实例化优化器,把需要优化的张量传入即可,支持SGD、Adam等所有内置优化器 optimizer = optim.SGD([q], lr=eta) # 对学习率调整不熟悉的场景可以直接用Adam,收敛更稳定 # optimizer = optim.Adam([q], lr=eta) for i in range(10): # 固定步骤:清空上一轮梯度 optimizer.zero_grad() print('i =', i, ' q =', q) v_trans = forward(v, q) loss = error(v_trans, v_target) # 反向传播计算梯度 loss.backward() # 优化器自动完成参数更新 optimizer.step() print('Final q = ', q)
额外注意事项
- 所有参与loss计算、需要被优化的张量,都要在计算图构建前开启
requires_grad=True,不要在计算过程中中途开启或者用赋值操作替换原张量 - 固定取值的张量(比如示例中的v、v_target)不需要开启梯度,能节省显存和计算开销
- 不管是手动更新参数还是用内置优化器,每次迭代前必须清空上一轮梯度,否则PyTorch会默认累加梯度,导致更新逻辑错误
内容的提问来源于stack exchange,提问作者Notin_sensus
相关产品推荐
相关产品推荐

