使用共享阵列在Python中进行快速FFT的内存对齐

时间:2012-03-27 18:53:56

标签: python numpy multiprocessing fft memory-alignment

我编写了一个需要做多件事的图像处理应用程序,它必须尽可能多地实时完成。 获取数据及其处理在不同的过程中运行(主要是出于性能原因)。数据本身非常大(2MPix 16位灰度图像)。

我可以在进程之间共享数组,如本文所述: How do I pass large numpy arrays between python subprocesses without saving to disk?(我使用numpy-shared包中的shmarray脚本)。 我可以毫无问题地对这些数据执行提供的Numpy FFT,但速度非常慢。

调用FFTW可能要快得多,但为了从中充分受益,我应该在内存对齐的数组上运行我的操作。

问题:有没有办法在进程之间创建和共享类似Numpy的数组,同时保证内存对齐?

3 个答案:

答案 0 :(得分:7)

获得正确对齐内存的最简单标准技巧是分配比需要更多的内容,如果对齐错误,则跳过前几个字节。如果我没记错的话,NumPy数组总是8字节对齐,而FFTW需要16字节对齐才能表现最佳。因此,您只需要分配超过需要的8个字节,并在必要时跳过前8个字节。

编辑:这很容易实现。指向数据的指针在NumPy数组的ctypes.data属性中以整数形式提供。使用移位块可以通过切片,查看作为不同的数据类型和重新整形来实现 - 所有这些都不会复制数据,而是重用相同的buf。

要分配一个16字节对齐的1000x1000 64位浮点数数组,我们可以使用以下代码:

m = n = 1000
dtype = numpy.dtype(numpy.float64)
nbytes = m * n * dtype.itemsize
buf = numpy.empty(nbytes + 16, dtype=numpy.uint8)
start_index = -buf.ctypes.data % 16
a = buf[start_index:start_index + nbytes].view(dtype).reshape(m, n)

现在,a是一个包含所需属性的数组,可以通过检查a.ctypes.data % 16确实是0来验证。

答案 1 :(得分:1)

概括了Sven的答案,这个函数将返回任何numpy数组的对齐副本(如果需要):

import numpy as np
def aligned(a, alignment=16):
    if (a.ctypes.data % alignment) == 0:
        return a

    extra = alignment / a.itemsize
    buf = np.empty(a.size + extra, dtype=a.dtype)
    ofs = (-buf.ctypes.data % alignment) / a.itemsize
    aa = buf[ofs:ofs+a.size].reshape(a.shape)
    np.copyto(aa, a)
    assert (aa.ctypes.data % alignment) == 0
    return aa

答案 2 :(得分:0)

我在 2021 年运行 payne's answer 并遇到类型错误(Python 3.7,Numpy 1.18.5),所以我调整了代码:

def aligned(a, alignment = 16):
    if (a.ctypes.data % alignment) == 0:
        return a
    assert alignment % a.itemsize == 0
    extra = alignment // a.itemsize
    buf = np.empty(a.size + extra, dtype = a.dtype)
    ofs = (-buf.ctypes.data % alignment) // a.itemsize
    aa = buf[ofs:ofs + a.size].reshape(a.shape)
    np.copyto(aa, a)
    assert aa.ctypes.data % alignment == 0
    return aa

我将其更改为使用整数除法来消除类型错误,并添加了额外的 assert 以进行完整性检查。