1 系统环境
硬件环境(Ascend/GPU/CPU): GPU
MindSpore版本: mindspore=1.10.1
执行模式(PyNative/ Graph):Graph
Python版本: Python=3.9.16
操作系统平台: Linux Ubuntu 20.04
2 报错信息
2.1 问题描述
在使用ops.top_k算子进行计算时(详见下方用例),会出现计算结果错误。
预期结果
如果正确执行,输出应该类似于如下结果:
$ python3 run_topk.py
26756342
实际执行结果如下,返回的是一个全零的Tensor:
$ python3 run_topk.py
0
备注:经过一定数值范围的测试,发现在K值选取1~128范围之间的返回结果有可能是正确的,或者两个打印模块同时打印输出结果也是正确的,唯独单次打印K值大于128的情况,返回结果异常。
2.2 报错信息
计算结果不符合预期。
2.3 脚本代码(代码格式,可上传附件)
# run_topk.py
import os
os.environ['GLOG_v']='4'
import numpy as np
import mindspore as ms
from mindspore import Tensor, ops, nn
class TopKNet(nn.Cell):
def __init__(self):
super().__init__()
self.top_k = ops.top_k
def construct(self, x, num):
x, ids = self.top_k(x, num)
return ids
np.random.seed(1)
input_x = Tensor(np.random.random((1, 648, 648)), ms.float16)
print (TopKNet()(input_x, 128).sum())
# print (TopKNet()(input_x, 129).sum())
直接运行上述用例,得到一个大的整数结果,这是正确场景;
注释第一个打印输出,取消第二个打印输出的注释,也就是选取前129个最大的值;
再次执行案例,得到的结果是0,或者是一个异常值。
3 根因分析
这是因为在mindspore关于topk的cuda代码中,一个核函数在做数据交换的时候,发生了数据类型强转(float和int)。导致当index的数值较大时(7 * 2388 * 2388+289),会出现精度损失。
4 解决方案
第一个办法,可以将mindspore/ccsrc/plugin/device/gpu/kernel/cuda_impl/topk_lib.cuh
这个位置下的58行进行修改
修改前
T b_tmp = b[i_1];
修改后
S b_tmp = b[i_1];
第二个办法是使用2.0版本的,这个更方便可靠。