Умножение 3D-матрицы без петель в Python - PullRequest
10 голосов
/ 17 марта 2011

Я хочу сделать следующую операцию в Python (Numpy).

Matrix A is M x N x R
Matrix B is N x 1 x R

Матрица умножается на AB = C, где C - матрица M x 1 x R.По сути, каждый слой M x N матрицы A (R из них) умножается независимо на каждый вектор N x 1 в B. Я уверен, что это однострочный.Я пытался использовать tenordot (), но я, кажется, дает мне ответы, которые я не ожидаю.

Я программирую в Igor Pro уже почти 10 лет, и сейчас я пытаюсь преобразовать их страницы в python.

Ответы [ 2 ]

14 голосов
/ 28 января 2014

Извините за некромантию, но этот ответ можно существенно улучшить, используя бесценный np.einsum.

import numpy as np

D,M,N,R = 1,2,3,4
A = np.random.rand(M,N,R)
B = np.random.rand(N,D,R)

print np.einsum('mnr,ndr->mdr', A, B).shape

Обратите внимание, что у него есть несколько преимуществ: прежде всего, это быстрый.np.einsum в целом хорошо оптимизирован, но, кроме того, np.einsum достаточно умен, чтобы избежать создания временного массива MxNxR, но выполняет сжатие непосредственно над N.

Но, что еще важнее, он очень читабелен,Нет сомнений в том, что этот код правильный;и вы могли бы сделать все намного сложнее без каких-либо проблем.

Обратите внимание, что фиктивная ось 'D' может быть просто удалена из B и оператора einsum, если вы хотите.

8 голосов
/ 17 марта 2011

numpy.tensordot () - правильный способ сделать это:

a = numpy.arange(24).reshape(2, 3, 4)
b = numpy.arange(12).reshape(3, 1, 4)
c = numpy.tensordot(a, b, axes=[1, 0]).diagonal(axis1=1, axis2=3)

Редактировать : Первая версия была неисправной, и эта версия вычисляет больше, чем нужно, и выбрасывает большую часть. Возможно, цикл Python над последней осью - лучший способ сделать это.

Другое правление : я пришел к выводу, что numpy.tensordot() является , а не лучшим решением здесь.

c = (a[:,:,None] * b).sum(axis=1)

будет более эффективным (хотя еще труднее понять).

...