有没有人思考过这么一个问题:


label = torch.Tensor([0, 2, 1]).long()


fc_out = torch.Tensor([
    [245, 13., 3.34],
    [45., 43., 37.],
    [1.22, 35.05, 1.23]
])

def cross_entropy_loss(out, label):
    # convert out to softmax probability
    out = out.numpy().tolist()
    out = np.array([np.exp(i)/np.sum(np.exp(i)) for i in out])
    print(out)

loss = torch.nn.CrossEntropyLoss()
# lv = loss(fc_out, label)
lv = cross_entropy_loss(fc_out, label)
print(lv)

我们尝试用np来编写一个CrossEntropy, 实现和pytorch一样的输出. 但是, 遇到一个问题.
其中那行代码:

    out = out.numpy().tolist()

如果改为:

    out = out.numpy()

则结果不一样. 结果差异如下:

[[1.00000000e+000 1.75258947e-101 1.11788072e-105]
 [8.80536902e-001 1.19167711e-001 2.95387223e-004]
 [2.03150559e-015 1.00000000e+000 2.05192254e-015]]


a.py:23: RuntimeWarning: overflow encountered in exp
  out = np.array([np.exp(i)/np.sum(np.exp(i)) for i in out])
a.py:23: RuntimeWarning: invalid value encountered in true_divide
  out = np.array([np.exp(i)/np.sum(np.exp(i)) for i in out])
[[          nan 0.0000000e+00 0.0000000e+00]
 [8.8053685e-01 1.1916771e-01 2.9538720e-04]
 [2.0315054e-15 1.0000000e+00 2.0519225e-15]]

这不是一个经常会遇到的问题, 但是在实际之中你确实应该思考差异的缘由.
to_list() 去掉之后, 结果会出现溢出. 这个十分的不对劲.
发生这个现象的根本原因是: list和np里面默认的精度是不一样的. numpy里面是float, list是动态的. float无法表征10-501这么小的数, 因此会溢出.