Выравнивание памяти для быстрого FFT в Python с использованием разделяемых массивов - PullRequest
5 голосов
/ 27 марта 2012

Я пишу приложение для обработки изображений, которое должно выполнять несколько задач и выполнять их в режиме реального времени, насколько это возможно.Сбор данных и их обработка выполняется в отдельных процессах (в основном по соображениям производительности).Сами данные довольно велики (2-мегапиксельные 16-битные изображения в градациях серого).

Я могу совместно использовать массивы между процессами, как описано в этом посте: Как передать большие массивы с нулевыми значениями между подпроцессами python без сохраненияна диск? (я использую скрипт shmarray из пакета numpy-shared).Я могу выполнить поставляемое Numpy FFT для этих данных без проблем, но это довольно медленно.

Вызов FFTW, вероятно, будет намного быстрее, но для того, чтобы в полной мере воспользоваться этим, я должен выполнять свои операции намассивы, которые выровнены по памяти.

Вопрос: существует ли способ создания и совместного использования Numpy-подобных массивов между процессами, которые в то же время гарантированно выровнены по памяти?

Ответы [ 2 ]

7 голосов
/ 27 марта 2012

Самый простой стандартный прием для получения правильно выровненной памяти - выделить немного больше, чем нужно, и пропустить первые несколько байтов, если выравнивание неверно.Если я правильно помню, массивы NumPy всегда будут выровнены по 8 байтов, а FFTW требует 16-байтового выравнивания для лучшей работы.Таким образом, вы просто выделите на 8 байтов больше, чем нужно, и пропустите первые 8 байтов, если необходимо.

Редактировать : Это довольно просто реализовать.Указатель на данные доступен в виде целого числа в атрибуте ctypes.data массива NumPy.Использование сдвинутого блока может быть достигнуто путем нарезки, просмотра в качестве другого типа данных и изменения формы - все это не будет копировать данные, а скорее будет использовать один и тот же буфер.

Для выделения 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 голос
/ 30 ноября 2013

Обобщая ответ Свена, эта функция будет возвращать выровненную копию (если необходимо) любого массива:

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
...