我有一个大小为(149797, 64)的 2D UINT8 numpy 数组。每个元素都是 0 或 1。我想将每一行中的这些二进制值打包成一个UINT64值,以便我得到一个形状为 149797 的 UINT64 数组。我使用 numpy bitpack 函数尝试了以下代码。
test = np.random.randint(0, 2, (149797, 64),dtype=np.uint8)
col_pack=np.packbits(test.reshape(-1, 8, 8)[:, ::-1]).view(np.uint64)
packbits 函数执行大约需要10 毫秒。这个数组本身的简单 整形似乎需要大约7 毫秒。我还尝试使用移位操作迭代 2d numpy 数组以达到相同的结果;但速度没有提高。
最后,我还想使用numba for CPU 编译它。
@njit
def shifting(bitlist):
x=np.zeros(149797,dtype=np.uint64) #54
rows,cols=bitlist.shape
for i in range(0,rows): #56
out=0
for bit in range(0,cols):
out = (out << 1) | bitlist[i][bit] # If i comment out bitlist, time=190 microsec
x[i]=np.uint64(out) # Reduces time to microseconds if line is commented in njit
return x
使用njit大约需要6 毫秒。
这是并行njit版本
@njit(parallel=True)
def shifting(bitlist):
rows,cols=149797,64
out=0
z=np.zeros(rows,dtype=np.uint64)
for i in prange(rows):
for bit in range(cols):
z[i] = (z[i] * 2) + bitlist[i,bit] # Time becomes 100 micro if i use 'out' instead of 'z[i] array'
return z
3.24ms的执行时间(google colab dual core 2.2Ghz)略好一些目前,带有swapbytes(Paul's)方法的 python 解决方案似乎是最好的,即1.74 ms。
我们怎样才能进一步加快这种转换?是否有使用任何矢量化(或并行化)、位数组等来实现加速的空间?
参考:numpy packbits 打包到 uint16 数组
在12 核机器上(Intel(R) Xeon(R) CPU E5-1650 v2 @ 3.50GHz),
Pauls 方法:1595.0微秒(我想它不使用多核)
Numba 代码:146.0微秒(前面提到的 parallel-numba)
即大约 10 倍的加速!