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, а не на изображении, но я открыт всем, что вы можете придумать...