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

如何不使用detach()将PyTorch Tensor转换为NumPy数组?

问题描述

实现算法时遇到以下代码块报错:

def get_action(self, state):
        state = torch.from_numpy(state).float().unsqueeze(0)
        probs = self.policy_network.forward(Variable(state))
        highest_prob_action = np.random.choice(self.num_actions, p=np.squeeze(probs.numpy())) //This line
        log_prob = torch.log(probs.squeeze(0)[highest_prob_action])
        return highest_prob_action, log_prob

为了给np.random.choice传入概率分布,代码中使用了probs tensor。已知使用detach函数可以解决该问题,但代码需要提交到自动评分器,调用detach()会返回错误,因此无法使用该函数。
需求:有没有不使用detach函数的实现方式?
当前probs tensor的结构如下:

tensor([[0.2522, 0.2533, 0.2385, 0.2560]], grad_fn=<SoftmaxBackward>)

需要的最终输出类型示例如下(数值无实际意义):

array([0., 1., 2., 3.], dtype=float32)

错误复现代码

import torch

tensor1 = torch.tensor([1.0,2.0],requires_grad=True)

print(tensor1)
print(type(tensor1))

tensor1 = tensor1.numpy()

print(tensor1)
print(type(tensor1))

已尝试的方案

按照建议使用torch.multinomial,代码如下:

states.append(state)
            probs = self.policy.forward(Variable(torch.from_numpy(state).float().unsqueeze(0)))
            highest_prob_action = np.random.choice(torch.multinomial(probs, self.num_actions).squeeze(0))
#             highest_prob_action = np.random.choice(self.num_actions, p=np.squeeze(probs.numpy()))
            log_prob = torch.log(probs.squeeze(0)[highest_prob_action])

但运行若干轮后会返回如下报错:

130             states.append(state)
    131             probs = self.policy.forward(Variable(torch.from_numpy(state).float().unsqueeze(0)))
--> 132             highest_prob_action = np.random.choice(torch.multinomial(probs, self.num_actions).squeeze(0))
    133 #             highest_prob_action = np.random.choice(self.num_actions, p=np.squeeze(probs.numpy()))
    134             log_prob = torch.log(probs.squeeze(0)[highest_prob_action])

RuntimeError: probability tensor contains either `inf`, `nan` or element < 0
解决方案

方案1:适配原numpy实现逻辑,完全不调用detach

将报错行替换为以下代码即可:

highest_prob_action = np.random.choice(self.num_actions, p=np.squeeze(np.array(probs.tolist())))

原理:tolist()会直接将带梯度的tensor中的数值导出为Python原生浮点数列表,整个过程不需要调用detach,也不会修改原probs tensor的梯度关联属性,后续计算log_prob的梯度传递完全不受影响。导出的列表转为numpy数组后就可以直接传入np.random.choice的p参数。

方案2:纯PyTorch实现,避免调用numpy,修复multinomial报错

之前使用multinomial报错是两个原因导致:一是采样数设置错误,不需要采样num_actions个结果,仅需采样1个动作;二是softmax输出可能出现数值不稳定的极小值,触发边界校验报错。修改后代码如下:

states.append(state)
probs = self.policy.forward(Variable(torch.from_numpy(state).float().unsqueeze(0)))
# 裁剪概率值避免出现0/负数,解决数值不稳定问题
probs = torch.clamp(probs, min=1e-10, max=1.0)
# 仅采样1个动作,直接取出索引值
highest_prob_action = torch.multinomial(probs, num_samples=1).item()
log_prob = torch.log(probs.squeeze(0)[highest_prob_action])

该方案完全不需要调用numpy相关操作,也不涉及detach调用,计算效率更高,梯度传递更稳定。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.22 02:12:13