You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PyTorch梯度下降参数更新两种赋值写法的差异问题

问题本质原因

两种写法的核心差异是对PyTorch张量的操作模式完全不同,直接导致变量指向的对象发生了变化:

  • w = w - learning_rate * w.grad 属于out-of-place(异地)操作
    普通的减法运算会返回一个全新开辟内存的张量,和你最开始初始化的、设置了requires_grad=True的原w张量没有绑定关系。加上这段代码运行在torch.no_grad()上下文内,所有运算不会构建计算图,新生成的张量默认requires_grad=False,本身不会自动存储梯度属性。
    当你把新张量赋值给变量w时,w就不再指向最初那个带梯度记录的叶子参数张量了,此时访问w.grad得到的就是None,调用zero_()方法自然会抛出属性不存在的错误。而原来的参数张量因为失去了变量引用,会被Python自动回收。
  • w -= learning_rate * w.grad 属于in-place(原地)操作
    自减写法不会创建新张量,而是直接在原w张量的内存地址上修改存储的数值,变量w始终指向最开始初始化的、绑定了梯度配置的参数对象。在l.backward()执行完成后,原张量的.grad属性已经存储了反向传播计算得到的梯度值,后续调用w.grad.zero_()是对原有张量的梯度做清零操作,完全合法不会报错。

你可以自行验证:在参数更新前后分别打印id(w),使用第一种写法时更新前后的内存地址会发生明显变化,使用-=写法时内存地址始终保持一致。
额外注意:不管是否在torch.no_grad()上下文内,手动更新参数时都不要使用w = w - lr * w.grad这类替换变量指向的写法,这会把原本的叶子参数节点替换成计算图中的中间节点,后续梯度计算、清零逻辑都会失效。除了原地运算外,你也可以通过w.data = w.data - learning_rate * w.grad的方式修改参数数值,或者直接调用PyTorch内置的优化器(比如SGD、Adam)自动完成参数更新,避免这类低级错误。

内容的提问来源于stack exchange,提问作者高造擎

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 13:48:14