Как использовать вещание с моими массивами numpy (3000,3) и (3,2,3000)

В настоящее время у меня есть 2 массива с формами v1=(3000,3) и v2=(3,2,3000). 3000 — это измерение времени, поэтому v1 имеет 3000 (1,3) отсчетов, а v2 — 3000 (3,2) отсчетов. Я хочу сделать матричное умножение и транслировать по измерению 3000, чтобы взамен получить 3000 (1,2) векторов.

Я попытался изменить форму так, чтобы v1 = (1,3,3000) и v2 = (3,2,300), что дает ошибку, говорящую о том, что формы не выровнены.

код:

v1 = np.ones((1,3,3000)) +1
v2 = np.ones((3,2,3000)) - 0.5
np.dot(v1,v2)

person seanysull    schedule 18.02.2019    source источник


Ответы (2)


С v1 формы (3000,3) и v2 как (3,2,3000) мы можем использовать np.einsum -

np.einsum('ij,jki->ik',v1,v2)

Это дает нам результат формы (3000,2).

Мы могли бы поиграть с аргументом optimize в np.einsum. С optimize = True он использует BLAS внутренне, а с optimize = False прибегает к простым C-циклам. Этот BLAS способ также требует некоторой работы по настройке. Таким образом, при приличной длине осей, которые подвергаются уменьшению суммы, мы можем захотеть установить этот флаг как True, а в противном случае - False. В этом случае кажется, что эти оси действительно короткие, поэтому нам, вероятно, лучше использовать ввод по умолчанию: optimize = False.

person Divakar    schedule 18.02.2019
comment
эквивалентно ли это умножению матриц? Я пытался читать документы на einsum, но они меня озадачили. - person seanysull; 19.02.2019
comment
@seanysull Он выполняет умножение матриц на тензорах (более 2 размеров) под капотом, используя BLAS с этим флагом оптимизации, установленным как True, так же, как np.dot. - person Divakar; 19.02.2019
comment
@Divakar Знаете ли вы, почему использование optimize=True занимает больше времени, чем когда его не используют? (см. тайминги в моем коде ниже). Возможно ли, что он тратит много времени на оптимизацию кода? - person kmario23; 19.02.2019
comment
@ kmario23 Какая у вас версия NumPy? - person Divakar; 19.02.2019
comment
@Divakar, конечно, я использую '1.16.1' - person kmario23; 19.02.2019
comment
@Ты прав. Отредактированный вопрос с комментариями к тому же. Спасибо, что указали на это. - person Divakar; 19.02.2019

Я бы посоветовал вам не использовать флаг optimize=True, потому что по какой-то странной причине он неэффективен. Кроме того, я бы рекомендовал вам явно преобразовать 2D-массив в 3D, выполнить пакетное умножение матриц, а затем сжать одноэлементное измерение результирующего массива, если вы в end нужен 2D-массив в качестве конечного результата. Пожалуйста, найдите код ниже:

# sample arrays
In [25]: v1 = np.random.random_sample((3000, 3))
In [26]: v2 = np.random.random_sample((3, 2, 3000))

# Divakar's approach
In [27]: %timeit np.einsum('ij,jki->ik',v1,v2, optimize=True)
80.7 µs ± 792 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

# needed for future use
In [28]: res_optimized = np.einsum('ij,jki->ik',v1,v2, optimize=True)

# promoting to 3D array and swapping axes
In [29]: v1 = v1[:, np.newaxis, :]
In [30]: v2 = np.moveaxis(v2, 2, 0)

# perform batch matrix multiplication
In [31]: %timeit np.einsum("bij, bjk -> bik", v1, v2)
47.9 µs ± 496 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

# for sanity checking
In [32]: res = np.einsum("bij, bjk -> bik", v1, v2)

In [33]: res.shape, res_optimized.shape
Out[33]: ((3000, 1, 2), (3000, 2))

# squeeze the singleton dimension and perform sanity check with Divakar's approach
In [34]: np.allclose(res.squeeze(), res_optimized)
Out[34]: True

Итак, как мы видим из приведенных выше таймингов, мы выигрываем ок. 2-кратное ускорение без использования флага optimize=True. Кроме того, явное преобразование массивов в 3D дает немного больше понимания того, что происходит, когда мы используем numpy.einsum().

Примечание. Тайминги выполнялись с использованием последней версии NumPy '1.16.1'.


P.S. Узнайте больше о понимании einsum() NumPy.

person kmario23    schedule 19.02.2019