np.random.choice报概率和不为1错误,已归一化仍异常求助
问题原因与解决方案
这个错误的核心原因几乎都是浮点数精度误差,再加上你处理全小值行的逻辑存在小漏洞,咱们一步步拆解:
1. L1归一化后的浮点数舍入误差
F.normalize(outputs, p=1, dim=1)做L1归一化时,由于浮点数的二进制表示限制,很多时候无法得到精确的"和为1"的结果——比如某行的元素经过除法后,累加和可能是0.9999999999999998或者1.0000000000000002,这在np.random.choice的严格检查下(它要求概率和必须精确等于1,哪怕差一点点都会报错)就会触发错误。
2. 全小值行的处理可能有遗漏
你用prob.max(1) < 1e-6来筛选需要填充均匀分布的行,但如果outputs中某行全为0,那么L1归一化后该行的所有元素都会是NaN(因为除以0了),这时候prob.max(1)会得到NaN,而NaN < 1e-6的结果是False,导致这些行没有被填充均匀分布,后续用np.random.choice时,p参数包含NaN或者和不为1的数组,同样会报错。
修复方案
针对这两个问题,你可以调整代码如下:
步骤1:先处理全0行,再做归一化
先检查outputs中哪些行的L1范数为0(全0),提前处理这些行,避免归一化产生NaN:
import numpy as np import torch.nn.functional as F # 先计算每行的L1范数和行内最大值 l1_norm = outputs.norm(p=1, dim=1) row_max = outputs.max(dim=1)[0] # 找出全0行(L1范数为0)和行内最大值小于1e-6的行 problem_rows = torch.where((l1_norm == 0) | (row_max < 1e-6))[0] # 先对非问题行做归一化 prob = F.normalize(outputs, p=1, dim=1).clone().data.cpu().numpy() # 为问题行填充均匀分布 prob[problem_rows] = np.full(prob.shape[1], 1.0 / prob.shape[1])
步骤2:强制修正每行的概率和为1
在调用np.random.choice前,对每行的概率做一次最后的归一化,彻底解决浮点数精度问题:
for j in range(14): # 确保概率和精确为1 p = prob[j] p = p / p.sum() # 兜底处理可能的NaN(比如之前遗漏的行) p = np.nan_to_num(p, nan=1.0 / len(p)) sample = np.random.choice(6890, 4, replace=False, p=p)
额外优化:批量处理概率修正
如果不想在循环里重复计算,也可以一次性修正所有行:
# 按行归一化,确保每行和为1 prob = prob / prob.sum(axis=1, keepdims=True) # 处理NaN(如果有的话) prob = np.nan_to_num(prob, nan=1.0 / prob.shape[1])
这样处理后,就能彻底避免"概率和不为1"的错误了。
内容的提问来源于stack exchange,提问作者Rani
相关产品推荐
相关产品推荐

