在Python/Cython/Numpy中计算2个二进制矢量之间的Hamming距离的最快方法



我正在尝试计算二进制向量和二进制向量矩阵之间的汉明距离。我能找到的最快的方法是使用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缓存中保持热状态的小块中。

最新更新