EDIT Я сохранил более сложную проблему, с которой я столкнулся ниже, но мои проблемы с np.take можно резюмировать следующим образом. Скажем, у вас есть массив img формы (planes, rows) и еще один массив lut формы (planes, 256), и вы хотите использовать их для создания нового массива out формы (planes, rows), где out[p,j] = lut[p, img[p, j]], Это может быть достигнуто при фантастическом индексировании следующим образом:
In [4]: %timeit lut[np.arange(planes).reshape(-1, 1), img]
1000 loops, best of 3: 471 us per loop
Но если вместо фантазии индексирования вы используете take и цикл python над planes, события могут значительно ускоряться:
In [6]: %timeit for _ in (lut[j].take(img[j]) for j in xrange(planes)) : pass
10000 loops, best of 3: 59 us per loop
Может ли lut и img быть каким-то образом перестроенным, чтобы вся операция выполнялась без циклов python, но используя numpy.take (или альтернативный метод) вместо обычной причудливой индексации, чтобы сохранить преимущество скорости?
ОРИГИНАЛЬНЫЙ ВОПРОС
У меня есть набор поисковых таблиц (LUT), которые я хочу использовать на изображении. Массив, содержащий LUT, имеет форму (planes, 256, n), а изображение имеет форму (planes, rows, cols). Оба имеют dtype = 'uint8', соответствующие оси 256 LUT. Идея состоит в том, чтобы запустить p -й плоскость изображения через каждый из n LUTs из p -й плоскости LUT.
Если мои lut и img следующие:
planes, rows, cols, n = 3, 4000, 4000, 4
lut = np.random.randint(-2**31, 2**31 - 1,
size=(planes * 256 * n // 4,)).view('uint8')
lut = lut.reshape(planes, 256, n)
img = np.random.randint(-2**31, 2**31 - 1,
size=(planes * rows * cols // 4,)).view('uint8')
img = img.reshape(planes, rows, cols)
Я могу добиться того, что я получаю после использования причудливого индексирования, такого как
out = lut[np.arange(planes).reshape(-1, 1, 1), img]
который дает мне массив формы (planes, rows, cols, n), где out[i, :, :, j] содержит i -я плоскость img, проходящая через j -й LUT i -й плоскости LUT...
Все хорошо, кроме этого:
In [2]: %timeit lut[np.arange(planes).reshape(-1, 1, 1), img]
1 loops, best of 3: 5.65 s per loop
что совершенно неприемлемо, тем более, что у меня есть все следующие не очень приятные альтернативы, использующие np.take, чем работающие быстрее:
-
Один LUT на одной плоскости быстрее работает примерно на x70:
In [2]: %timeit np.take(lut[0, :, 0], img[0]) 10 loops, best of 3: 78.5 ms per loop -
Цикл питона, проходящий через все нужные комбинации, быстрее заканчивается x6:
In [2]: %timeit for _ in (np.take(lut[j, :, k], img[j]) for j in xrange(planes) for k in xrange(n)) : pass 1 loops, best of 3: 947 ms per loop -
Даже запуск всех комбинаций плоскостей в LUT и изображении и последующее отбрасывание нежелательных
planes**2 - planesбыстрее, чем фантастическое индексирование:In [2]: %timeit np.take(lut, img, axis=1)[np.arange(planes), np.arange(planes)] 1 loops, best of 3: 3.79 s per loop -
И самая быстрая комбинация, которую я смог придумать, имеет цикл python, итератирующий по плоскостям, и быстрее заканчивает x13:
In [2]: %timeit for _ in (np.take(lut[j], img[j], axis=0) for j in xrange(planes)) : pass 1 loops, best of 3: 434 ms per loop
Вопрос, конечно, в том, что нет никакого способа сделать это с помощью np.take без какой-либо петли питона? В идеале любое изменение формы или изменение размера должно происходить на LUT, а не на изображении, но я открыт всем, что вы можете придумать...