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

PyTorch反向传播原地操作报错RuntimeError:原因及解决方法

PyTorch梯度计算原地操作报错问题解决

问题代码

tracejacob函数

def tracejacob(jacob):
    a11,a22=jacob[0,0,:,:],jacob[1,1,:,:]
    return a11+a22

fwd_inf_2d函数

def fwd_inf_2d(m,K,phi,phiinv,timesteps): #m0 initial momenta, K is the kernel, deltat is the time step, timesteps is the number of time steps
    n,h,w=m.shape
    deltat=1/timesteps
    idty=get_idty_2d(h,w)

    for t in range(timesteps):
        v=K(m)
        phi = phi + compose_function_2d(v,phi)*deltat
        phiinv = compose_function_2d(phiinv,idty-v*deltat)
        jacob_v=get_jacobian_matrix_2d(v)
        jacob_m=get_jacobian_matrix_2d(m)
        DvTm = jacobxvectorfield(jacob_v,m,transpose_jacob=True)
        Dmv= jacobxvectorfield(jacob_m,v,transpose_jacob=False)
        divvm = tracejacob(jacob_v)*m
        
        m = m - DvTm - Dmv - divvm
    return(phi,phiinv)

报错信息

执行loss.backward()计算梯度时触发:

RuntimeError: one of the variables needed for gradient computation has been modified by an inplace operation: [torch.FloatTensor [2, 50, 50]] is at version 1; expected version 0 instead

错误关联到divvm = tracejacob(jacob_v)*m行。


问题原因

这行代码本身并非原地操作,但报错根源在于两个关键点:

  1. 视图引用导致版本冲突:tracejacob中对jacob的切片操作返回原张量的视图而非副本,若jacob_v依赖于m,视图会让PyTorch自动微分追踪逻辑误以为原张量被修改,引发版本不匹配。
  2. 循环中张量复用的计算图冲突:每次迭代中m既作为输入参与计算,又被重新赋值为新张量,PyTorch追踪循环内计算图时会关联历次m的版本,若中间存在隐式视图引用或间接修改,就会触发版本错误。

修复方案

1. 修改tracejacob函数,返回独立副本

将切片后的张量转为副本,切断与原张量的视图关联:

def tracejacob(jacob):
    # 使用.clone()创建独立副本,避免视图引用
    a11 = jacob[0,0,:,:].clone()
    a22 = jacob[1,1,:,:].clone()
    return a11 + a22

2. 循环中显式隔离m的引用

计算divvm时使用m的副本,更新m时显式创建新张量,确保计算图追踪独立的张量实例:

for t in range(timesteps):
    v=K(m)
    phi = phi + compose_function_2d(v,phi)*deltat
    phiinv = compose_function_2d(phiinv,idty-v*deltat)
    jacob_v=get_jacobian_matrix_2d(v)
    jacob_m=get_jacobian_matrix_2d(m)
    DvTm = jacobxvectorfield(jacob_v,m,transpose_jacob=True)
    Dmv= jacobxvectorfield(jacob_m,v,transpose_jacob=False)
    # 使用m.clone()避免直接引用原张量
    divvm = tracejacob(jacob_v) * m.clone()
    
    # 显式创建新张量赋值,而非依赖原张量运算
    m = m - DvTm - Dmv - divvm

3. 检查辅助函数的原地操作

确认get_jacobian_matrix_2d、jacobxvectorfield、compose_function_2d等函数内部是否使用了后缀带下划线的原地方法(如+=、*=、resize_),若有需改为非原地操作,返回新张量。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 16:05:39