2016-02-22 1 views
1

Я прочитал через einsum manual и ajcr-х basic introductionсуммируя внешнее произведение множества векторов в einsum

У меня есть нулевой опыт с Эйнштейном суммирования в некодирующей контексте, хотя я пытался исправить, что с некоторых интернет-исследований (будут предоставлять ссылки, но не имеют репутации более двух). Я также пробовал экспериментировать с python с einsum, чтобы узнать, могу ли я лучше разбираться в вещах.

И все же я до сих пор неясно, является ли на это возможно и эффективно сделать следующим образом:

на две массивы массивов (а и б) одинаковой длины (3) и высоты (п), строка за строкой производит внешний продукт (строка i: a on b) плюс внешний продукт (строка i: b на a), а затем суммирует все внешние матрицы продуктов для вывода одной конечной матрицы.

Я знаю, что 'i, j-> ij' производит внешнее произведение одного вектора на другом - это следующие шаги, которые потеряли меня. ('ijk, jik-> ij' определенно не так)

Моей другой доступной опцией является прохождение через массив и вызов основных функций (двойного внешнего продукта и добавления матрицы) из написанных мной функций в cython (использование numpy, встроенного в функцию external и sum, не является опцией, оно слишком медленное). Скорее всего, я тоже вернусь к цитону.

так:

  1. как можно выразить einsum-чески процедуру, описанную выше я?

  2. будет ли он предлагать реальные выгоды, чем делать все на cython? или есть другие альтернативы, о которых я не знаю? (включая возможность того, что я использовал numpy менее эффективно, чем я мог бы быть ...)

Спасибо.


редактировать с примером:

A=np.zeros((3,3)) 
arrays_1=np.array([[1,0,0],[1,2,3],[0,1,0],[3,2,1]]) 
arrays_2=np.array([[1,2,3],[0,1,0],[1,0,0],[3,2,1]]) 
for i in range(len(arrays_1)): 
    A=A+(np.outer(arrays_1[i], arrays_2[i])+np.outer(arrays_2[i],arrays_1[i])) 

(обратите внимание, однако, что на практике мы имеем дело с массивами гораздо большей длины (то есть еще длина 3 для каждого внутреннего элемента, но до нескольких тысячи таких членов), и этот раздел кода получает (неизбежно) называется много раз)

в случае это вообще полезно, вот Cython для суммирующих двух внешних продуктов:

def outer_product_sum(np.ndarray[DTYPE_t, ndim=1] a_in, np.ndarray[DTYPE_t, ndim=1] b_in): 
    cdef double *a = <double *>a_in.data 
    cdef double *b = <double *>b_in.data 
    return np.array([ 
[a[0]*b[0]+a[0]*b[0], a[0]*b[1]+a[1]*b[0], a[0] * b[2]+a[2] * b[0]], 
[a[1]*b[0]+a[0]*b[1], a[1]*b[1]+a[1]*b[1], a[1] * b[2]+a[2] * b[1]], 
[a[2]*b[0]+a[0]*b[2], a[2]*b[1]+a[1]*b[2], a[2] * b[2]+a[2] * b[2]]]) 

, который прямо сейчас я вызываю из цикла «i in range (len (array))», как показано выше.

+0

Не могли бы вы показать, как вы бы выполнить вашу сумму-продукта с использованием 'for' цикла (желательно с некоторыми представительными поддельными входы)? –

+0

@ali_m конечно, сделано – dWitty

ответ

0

Суммирование Эйнштейна может быть использовано только для мультипликативной части вопроса (т. Е. Внешнего произведения). К счастью, суммирование не обязательно должно выполняться по элементам, но вы можете сделать это на матрицах уменьшения. Использование массивов из вашего примера:

arrays_1 = np.array([[1,0,0],[1,2,3],[0,1,0],[3,2,1]]) 
arrays_2 = np.array([[1,2,3],[0,1,0],[1,0,0],[3,2,1]]) 
A = np.einsum('ki,kj->ij', arrays_1, arrays_2) + np.einsum('ki,kj->ij', arrays_2, arrays_1) 

входные массивы имеют форму (4,3), суммирование происходит по первому индексу (названный 'k'). Если суммирование должно происходить по второму индексу, измените строку индексов на 'ik,jk->ij'.

+0

спасибо! Мне все еще нужно запускать больше тестов по скорости, но это определенно превзошло цикл с вызовами на цитон, поэтому я думаю, что это также отвечает на мой вопрос о качестве. – dWitty

0

Независимо от того, что вы можете сделать с помощью np.einsum, вы можете обычно делать быстрее, используя np.dot. В этом случае A является суммой двух продуктов точечно:

arrays_1 = np.array([[1,0,0],[1,2,3],[0,1,0],[3,2,1]]) 
arrays_2 = np.array([[1,2,3],[0,1,0],[1,0,0],[3,2,1]]) 

A1 = (np.einsum('ki,kj->ij', arrays_1, arrays_2) + 
     np.einsum('ki,kj->ij', arrays_2, arrays_1)) 

A2 = arrays_1.T.dot(arrays_2) + arrays_2.T.dot(arrays_1) 

print(np.allclose(A1, A2)) 
# True 

%timeit (np.einsum('ki,kj->ij', arrays_1, arrays_2) + 
     np.einsum('ki,kj->ij', arrays_2, arrays_1)) 
# 100000 loops, best of 3: 7.51 µs per loop 

%timeit arrays_1.T.dot(arrays_2) + arrays_2.T.dot(arrays_1) 
# 100000 loops, best of 3: 4.51 µs per loop 
+0

в моем фактическом коде, вызывающий np.dot 347,766 раз стоит 1230 мс против 1982 мс einsum. [numpy documentation] (http://docs.scipy.org/doc/numpy-1.10.0/reference/generated/numpy.dot.html) указанная точка выполняет внутреннее произведение для двух векторов, но я полагаю, что я либо неправильно понимал или читал неправильную версию. спасибо! – dWitty

+0

.. Если точка массива массивов рассматривает их как 2D и применяет матрицы, есть ли способ сделать это вместо того, чтобы делать разборные внутренние продукты? (эквивалент einsum ('ij, ij', arrays1, arrays2) - на основе предположения, что большинство приложений einsum могут быть точками вместо – dWitty

+0

.dot на двух массивах 2d рассматривается как матричное умножение, которое является таким же, как и ik , kj -> ij 'в соглашении суммирования эйнштейнов. Перенесите первую матрицу, и вы увидите, что оба einsum и dot дают один и тот же ответ. – Rob

Смежные вопросы