PyTorch需梯度Tensor调用numpy()报错的解决方法问询
问题排查与修复方案
报错根因
- 核心问题是计算逻辑混用了NumPy算子和带梯度的PyTorch张量:
- 你定义的
function_parabola中全部使用np.log、np.prod等NumPy原生算子,输入的参数variable是开启了requires_grad=True的PyTorch张量,NumPy无法直接处理带梯度的张量,会自动切断计算图甚至直接抛出类型错误,这是两次报错的共同根源。 - 原代码中NumPy处理后返回的是NumPy数组,你后续试图对该数组调用
.data、.cpu()等只有PyTorch张量才有的方法,也会触发报错。
- 你定义的
修复方案
第一步:修改损失函数兼容两种输入类型
因为后续show_contours函数会传入NumPy数组计算等高线,所以需要让损失函数自动判断输入类型,选择对应的算子:
def function_parabola(variable): # 输入为NumPy数组时使用NumPy算子 if isinstance(variable, np.ndarray): return np.prod(np.log(np.log(variable + 7))) # 输入为PyTorch张量时使用PyTorch算子,保留计算图 elif isinstance(variable, torch.Tensor): return torch.prod(torch.log(torch.log(variable + 7)))
第二步:调整历史值记录逻辑
使用规范的detach方法剥离梯度后再转NumPy数组,替换过时的.data用法:
# 原var_history记录代码调整为 var_history.append(x.detach().numpy().copy()) # 原fn_history记录代码调整为 fn_history.append(function_parabola(x).detach().cpu().numpy().copy())
完整可运行代码
import torch import numpy as np import matplotlib.pyplot as plt x = torch.tensor([[5., 10.], [1., 2.]], requires_grad=True) var_history = [] fn_history = [] alpha = 0.001 optimizer = torch.optim.SGD([x], lr=alpha) def function_parabola(variable): if isinstance(variable, np.ndarray): return np.prod(np.log(np.log(variable + 7))) elif isinstance(variable, torch.Tensor): return torch.prod(torch.log(torch.log(variable + 7))) def make_gradient_step(function, variable): function_result = function(variable) function_result.backward() optimizer.step() optimizer.zero_grad() for i in range(500): var_history.append(x.detach().numpy().copy()) fn_history.append(function_parabola(x).detach().cpu().numpy().copy()) make_gradient_step(function_parabola, x) print(x) def show_contours(objective, x_lims=[-10.0, 10.0], y_lims=[-10.0, 10.0], x_ticks=100, y_ticks=100): x_step = (x_lims[1] - x_lims[0]) / x_ticks y_step = (y_lims[1] - y_lims[0]) / y_ticks X, Y = np.mgrid[x_lims[0]:x_lims[1]:x_step, y_lims[0]:y_lims[1]:y_step] res = [] for x_index in range(X.shape[0]): res.append([]) for y_index in range(X.shape[1]): x_val = X[x_index, y_index] y_val = Y[x_index, y_index] res[-1].append(objective(np.array([[x_val, y_val]]).T)) res = np.array(res) plt.figure(figsize=(7,7)) plt.contour(X, Y, res, 100) plt.xlabel('$x_1$') plt.ylabel('$x_2$') show_contours(function_parabola) plt.scatter(np.array(var_history)[:,0], np.array(var_history)[:,1], s=10, c='r'); plt.show()
内容的提问来源于stack exchange,提问作者user13524649
相关产品推荐
相关产品推荐

