PyTorch自动求导计算报TypeError,求修复方案
修复PyTorch自动求导中的TypeError: 'NoneType' object is not subscriptable错误
问题场景
在使用PyTorch对Burgers方程的解执行自动求导计算时,触发如下错误:
TypeError: 'NoneType' object is not subscriptable
相关代码如下:
自动求导代码
import torch import numpy as np x2 = torch.tensor(x, requires_grad=True) t2 = torch.tensor(t, requires_grad=True) def mr(): for k in range(n): z01 = solve_burgers(torch.tensor([x2[k]]), 0.25, 0.01/np.pi)[0] z01.backward(retain_graph=True) u_xr = x2.grad[k] u_tr = t2.grad[k] return u_xr, u_tr, u_xxr
Burgers方程求解函数
from scipy.integrate import quad def solve_burgers(X, t, nu): def f(y): return np.exp(-np.cos(np.pi * y) / (2 * np.pi * nu)) def g(y): return np.exp(-(y**2) / (4 * nu * t)) def fun(eta): return torch.sin(torch.pi * (x - eta)) * f(x - eta) * g(eta) def fun1(eta): return f(x - eta) * g(eta) U = torch.zeros_like(X) for i in range(len(X)): x = X[[[i]]] uxt = -quad(fun, -torch.inf, torch.inf)[0] uxt2 = torch.tensor(uxt, requires_grad=True) uxt30 = quad(fun1, -np.inf, np.inf)[0] uxt3 = torch.tensor(uxt30, requires_grad=True) U[i] = uxt2 / uxt3 return U
错误根源与修复方案
错误核心原因
t2从未被传入solve_burgers函数参与计算,导致t2.grad始终为None,执行t2.grad[k]时触发下标访问错误。solve_burgers中大量混用numpy与PyTorch运算,且手动用torch.tensor包装积分结果,直接切断了计算图,导致x2.grad也可能为None。- SciPy的
quad函数不支持PyTorch张量的自动求导,无法生成有效的计算图链路。
具体修复步骤
1. 让t2参与计算图传递
- 修改
solve_burgers的g(y)函数,用PyTorch运算替代numpy:def g(y): return torch.exp(-(y**2) / (4 * nu * t)) # 替换np.exp为torch.exp,确保t是PyTorch张量 - 调用
solve_burgers时传入t2而非固定数值:z01 = solve_burgers(torch.tensor([x2[k]]), t2, 0.01/np.pi)[0]
2. 修复计算图断裂问题
- 将
solve_burgers中所有numpy函数替换为PyTorch对应函数,确保计算链路完全在PyTorch中:def f(y): return torch.exp(-torch.cos(torch.pi * y) / (2 * torch.pi * nu)) # 替换np.cos、np.exp - 移除手动创建
uxt2、uxt3的代码,直接使用积分结果(需替换SciPy的quad为PyTorch兼容的积分方式)。例如用数值采样+梯形积分替代:def solve_burgers(X, t, nu): def f(y): return torch.exp(-torch.cos(torch.pi * y) / (2 * torch.pi * nu)) def g(y): return torch.exp(-(y**2) / (4 * nu * t)) def fun(eta): return torch.sin(torch.pi * (x - eta)) * f(x - eta) * g(eta) def fun1(eta): return f(x - eta) * g(eta) U = torch.zeros_like(X) # 用数值采样近似积分,范围和点数可根据精度调整 eta_samples = torch.linspace(-10, 10, 10000, requires_grad=False) d_eta = eta_samples[1] - eta_samples[0] for i in range(len(X)): x = X[[[i]]] # 梯形法数值积分 uxt = -torch.trapz(fun(eta_samples), eta_samples) uxt30 = torch.trapz(fun1(eta_samples), eta_samples) U[i] = uxt / uxt30 return U
3. 正确管理梯度累积
每次调用backward前清空梯度,避免累积导致的错误:
def mr(): # 初始化梯度为0 x2.grad.zero_() t2.grad.zero_() u_xr_list = [] u_tr_list = [] for k in range(n): z01 = solve_burgers(torch.tensor([x2[k]]), t2, 0.01/np.pi)[0] z01.backward(retain_graph=True) u_xr_list.append(x2.grad[k].item()) u_tr_list.append(t2.grad[k].item()) # 循环后清空梯度,避免下一次计算时累积 x2.grad.zero_() t2.grad.zero_() # 若需要返回张量,可转换为torch.tensor return torch.tensor(u_xr_list), torch.tensor(u_tr_list), u_xxr # 需补充u_xxr的计算逻辑
4. 补充u_xxr的定义
原代码中mr函数返回u_xxr但未实现,需补充二阶导数的计算逻辑(例如对一阶导数再执行一次自动求导),否则会引发新的未定义错误。
内容的提问来源于stack exchange,提问作者Nsss123
相关产品推荐
相关产品推荐

