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

PyTorch中s[:]与s在AdaDelta优化器中的差异疑问

AdaDelta优化器中s[:]与直接赋值s的差异疑问

我在学习《Dive Into Deep Learning》中的AdaDelta优化器时,发现示例代码里用了s[:]和delta[:]做赋值操作。一开始我觉得直接用s和delta就行,就把代码第1、2行的左侧赋值改成了s和delta,但多次设置manual_seed测试后,结果差异特别大——直接用s和delta时的结果曲线波动剧烈得多。我注意到两种赋值方式后s的形状是一致的,而且用s.data和delta.data替换s[:]、delta[:]并做对应修改后,效果和原代码一致,想问问这两种写法的本质差异是什么。

原代码:

def adadelta(params, states, hyperparams):
    rho, eps = hyperparams['rho'], 1e-5
    for p, (s, delta) in zip(params, states):
        s[:] = rho * s + (1 - rho) * (p.grad.data**2)# 1
        g =  p.grad.data * torch.sqrt((delta + eps) / (s + eps))
        p.data -= g
        delta[:] = rho * delta + (1 - rho) * g * g# 2

本质差异解析

1. 对象引用 vs 原地修改

直接写s = rho * s + ...时,你是创建了一个全新的Tensor对象,并让循环里的变量s指向这个新对象。但states列表中保存的还是原来那个旧Tensor的引用,下一次迭代时,取到的依然是旧对象的初始值(或未正确更新的值)——这等于完全破坏了AdaDelta核心的滑动平均累积逻辑,因为每次迭代都没有真正更新状态变量,导致优化器无法正确跟踪梯度的二阶矩,最终训练曲线波动剧烈。

而s[:] = rho * s + ...是原地修改原Tensor的内容:变量s指向的还是states里的那个原始Tensor对象,只是把它内部的数据更新了。这样每次迭代后,states中的状态值都会被正确累积,AdaDelta的滑动平均计算才能正常工作。

2. 关于.data的等价性

用s.data = ...或s.data.copy_(...)替换s[:]效果一致,是因为.data访问的是Tensor的底层数据存储,修改它同样是在原对象上操作,没有改变states中的引用关系。不过要注意,PyTorch新版本中.data已被标记为过时,更推荐用torch.no_grad()上下文管理器包裹赋值操作,或者直接使用原地切片赋值(s[:] = ...)的方式,避免意外的计算图追踪问题。

内容的提问来源于stack exchange,提问作者XUHAO77

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 19:27:23