将Numpy代码迁移为CuPy时添加嵌套元组到集合报错:TypeError: unhashable type: 'ndarray'
Numpy代码迁移为CuPy时添加嵌套元组到集合报错:TypeError: unhashable type: 'ndarray'
这个问题我之前转CuPy代码时也踩过坑!核心原因是CuPy和Numpy在数组转元组时的处理逻辑有差异,导致你生成的嵌套元组里藏着不可哈希的对象。
为什么Numpy能跑但CuPy不行?
当你用Numpy数组生成嵌套元组时,tuple(row)会自动把Numpy数组的元素转换成Python原生的数值类型(比如float、int),这些原生类型都是可哈希的,所以整个嵌套元组能正常加入集合。
但CuPy不一样:遍历CuPy数组的行时,每一行本身还是一个CuPy ndarray对象;直接tuple(row)得到的元组里,每个元素是CuPy的标量对象(比如cp.float64),而这些CuPy标量对象是不可哈希的——哪怕外层是元组,只要里面包含不可哈希的元素,整个元组就没法被集合接受,这就是你看到TypeError的原因。
两种快速修复方案
方案1:逐行转为Python原生数值类型
在生成元组前,用.get()方法把CuPy行数组转成CPU端的原生数值结构,这样生成的元组元素都是可哈希的原生类型:
import cupy as cp def sortBis(mat: cp.ndarray): colInds = cp.lexsort(mat[:, 1:]) mat[:, 1:] = mat[:, 1:][:, colInds] return mat newMat = cp.array([[ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1.], [ 0., 1., 0., 0., 0., 0., 0., 0., 0., 0., -1.]]) newMatSet = set() # 关键修改:对每一行调用.get(),将CuPy数组转为原生数值序列 newMatSet.add(tuple(tuple(row.get()) for row in sortBis(newMat)))
方案2:先转整个数组为Numpy数组
如果你的数据量不算特别大,也可以先把处理后的CuPy数组完整转到CPU(转成Numpy数组),再按你原来的逻辑生成元组:
processed_mat = sortBis(newMat).get() # 也可以用cp.asnumpy(sortBis(newMat)) newMatSet.add(tuple(tuple(row) for row in processed_mat))
性能小提示
如果你的数据量很大,频繁在GPU和CPU之间传输数据会影响加速效果。但如果只是做集合去重这类轻量操作,把数据临时拉到CPU转原生类型是最直接的解决办法;要是对性能要求极高,可能需要换一种GPU端的哈希存储方案,但这种场景下一般用不到这么复杂的处理。
内容来源于stack exchange
相关产品推荐
相关产品推荐

