我正在尝试计算二进制向量和二进制向量矩阵之间的汉明距离。我能找到的最快的方法是使用Numpy:的无符号8位整数
import numpy as np
np.count_nonzero(data[0] != data, axis=1)
然而,这种方法的问题在于,它首先找到所有不同的比特,然后求和差的数量。这不是有点浪费吗?我尝试在C++中实现一个基本版本,在那里我还记录了不同的位数,这样最后就不需要求和了,但这要慢得多。可能是因为Numpy使用SIMD指令。
所以我的问题是,有没有一种方法可以在Numpy/Python/Cyton中使用SIMD指令直接计算汉明距离?
理想情况下,您实际希望CPU执行的是具有尽可能大的块的sum += popcount( a[i] ^ b[i])
。例如,在x86上,使用AVX2一次对32个字节与一条指令进行异或,然后再执行几条指令(包括vpshufb和vpaddq(,将计数累积为每个元素计数的SIMD矢量(在末尾水平求和(。
对于特定的ISA(如x86-64(,使用C++内部函数很容易做到这一点。
您可以使用std::bitset<64>
将64位块XOR在一起,并将.count()
作为高效popcount的可移植API来实现可移植代码。Clang可以将标量popcount自动矢量化为AVX2,但GCC不能。
为了在不违反严格别名的情况下安全地构造它,您可能需要将另一类型的任意数据memcpy
转换为unsigned long long
。
我不知道Numpy是否在中编译了一个循环,否则你可能需要在一次过程中进行XOR,然后在另一次中进行popcount,这会影响计算强度,所以你肯定想在返回重新读取之前,将块缓存到L1d缓存中保持热状态的小块中。