3D точечный продукт numpy

У меня есть две матрицы 3dim numpy, и я хочу сделать точечный продукт по одной оси без использования цикла:

a=[ [[ 0, 0, 1, 1, 0,  0,  0,  0,  0,  0,  1,  0,  0,  1,  0],
  [ 1,  0,  0,  1,  0,  0,  0,  0,  0,  0,  0,  1,  0,  1,  0],
  [ 0,  1,  0,  0,  0,  1,  0,  0,  0,  0,  0,  0,  0,  0,  1],
  [ 0,  1,  0,  0,  0,  0,  1,  0,  0,  0,  1,  0,  1,  0,  0]],
    [[ 0,  0,  1,  1,  0,  0,  0,  0,  0,  0,  1,  0,  0,  1,  0],
  [ 1,  0,  0,  1,  0,  0,  0,  0,  0,  0,  0,  1,  0,  1,  0],
  [ 0,  1,  0,  0,  0,  1,  0,  0,  0,  0,  0,  0,  0,  0,  1],
  [ 0,  1,  0,  0,  0,  0,  1,  0,  0,  0,  1,  0,  1,  0,  0]],
 [ [ 0,  0,  1,  1,  0,  0,  0,  0,  0,  0,  1,  0,  0,  1,  0],
  [ 1,  0,  0,  1,  0,  0,  0,  0,  0,  0,  0,  1,  0,  1,  0],
  [ 0,  1,  0,  0,  0,  1,  0,  0,  0,  0,  0,  0,  0,  0,  1],
  [ 0,  1,  0,  0,  0,  0,  1,  0,  0,  0,  1,  0,  1,  0,  0]],
 [ [ 0,  0,  1,  1,  0,  0,  0,  0,  0,  0,  1,  0,  0,  1,  0],
  [ 1,  0,  0,  1,  0,  0,  0,  0,  0,  0,  0,  1,  0,  1,  0],
  [ 0,  1,  0,  0,  0,  1,  0,  0,  0,  0,  0,  0,  0,  0,  1],
  [ 0,  1,  0,  0,  0,  0,  1,  0,  0,  0,  1,  0,  1,  0,  0]],
 [[ 0,  0,  1,  1,  0,  0,  0,  0,  0,  0,  1,  0,  0,  1,  0],
  [ 1,  0,  0,  1,  0,  0,  0,  0,  0,  0,  0,  1,  0,  1,  0],
  [ 0,  1,  0,  0,  0,  1,  0,  0,  0,  0,  0,  0,  0,  0,  1],
  [ 0,  1,  0,  0,  0,  0,  1,  0,  0,  0,  1,  0,  1,  0,  0]],
 [[ 0,  0,  1,  1,  0,  0,  0,  0,  0,  0,  1,  0,  0,  1,  0],
  [ 1,  0,  0,  1,  0,  0,  0,  0,  0,  0,  0,  1,  0,  1,  0],
  [ 0,  1,  0,  0,  0,  1,  0,  0,  0,  0,  0,  0,  0,  0,  1],
  [ 0,  1,  0,  0,  0,  0,  1,  0,  0,  0,  1,  0,  1,  0,  0.]],
 [[ 0,  0,  1,  1,  0,  0,  0,  0,  0,  0,  1,  0,  0,  1,  0],
  [ 1,  0,  0,  1,  0,  0,  0,  0,  0,  0,  0,  1,  0,  1,  0],
  [ 0,  1,  0,  0,  0,  1,  0,  0,  0,  0,  0,  0,  0,  0,  1],
  [ 0,  1,  0,  0,  0,  0,  1,  0,  0,  0,  1,  0,  1,  0,  0]]]

b=[[[ 0,  0,  1,  0,  0.],
  [ 1,  0,  0,  0,  0.],
  [ 0,  0,  0,  0,  0.],
  [ 0,  1,  0,  0,  0.]],
 [[ 0,  0,  1,  0,  0.],
  [ 1,  0,  0,  0,  0.],
  [ 0,  0,  0,  0,  0.],
  [ 0,  1,  0,  0,  0.]],
 [[ 0,  0,  1,  0,  0.],
  [ 1,  0,  0,  0,  0.],
  [ 0,  0,  0,  0,  0.],
  [ 0,  1,  0,  0,  0.]],
 [[ 0,  0,  1,  0,  0.],
  [ 1,  0,  0,  0,  0.],
  [ 0,  0,  0,  0,  0.],
  [ 0,  1,  0,  0,  0.]],
 [[ 0,  0,  1,  0,  0.],
  [ 1,  0,  0,  0,  0.],
  [ 0,  0,  0,  0,  0.],
  [ 0,  1,  0,  0,  0.]],
 [[ 0,  0,  1,  0,  0.],
  [ 1,  0,  0,  0,  0.],
  [ 0,  0,  0,  0,  0.],
  [ 0,  1,  0,  0,  0.]],
 [[ 0,  0,  1,  0,  0.],
  [ 1,  0,  0,  0,  0.],
  [ 0,  0,  0,  0,  0.],
  [ 0,  1,  0,  0,  0.]]]
dt = np.dtype(np.float32)
a=np.asarray(a,dtype=dt)
b=np.asarray(b,dtype=dt)
print(a.shape)
print(b.shape)

a имеет форму (7, 4, 15), а b имеет форму (7, 4, 5). Я хочу, чтобы c=np.dot(a,b) имел размер (7,5,15), как показано ниже:

c = np.zeros((7,15,5))
for i in range(7):
   c[i,:,:] = np.dot(a[i,:,:].T , b[i,:,:])

Но я ищу решение без цикла for. что-то типа:

c = np.tensordot(a.reshape(4,7,5),b.reshape(7,4,15),axes=([1,0],[0,1]))

но этот не работает, как ожидалось.

Я также пробовал это:

newaxes_a=[2,0,1]
newaxes_b=[1,0,2]

newshape_a=(-1,28)
newshape_b=(28,-1)
a_t = a.transpose(newaxes_a).reshape(newshape_a)
b_t = b.transpose(newaxes_b).reshape(newshape_b)
c = np.dot(a_t, b_t)

который не работал, как ожидалось.

Любые идеи?


person PickleRick    schedule 30.11.2015    source источник
comment
Что не так с циклом for? Если вы используете numpy с оптимизированным BLAS, это самая быстрая версия, опубликованная до сих пор.   -  person Daniel    schedule 30.11.2015
comment
@Ophion На самом деле, я ищу решение на основе Theano в конце. Я ответил на ваш комментарий в своем другом связанном вопросе, который я разместил.   -  person PickleRick    schedule 30.11.2015


Ответы (1)


Вы можете использовать np.einsum -

#to match the given example
c2 = np.einsum('ijk,ijl->ikl',a,b)
print np.allclose(c, c2)

Другой, использующий broadcasting -

c = (a[:,:,None,:]*b[...,None]).sum(1)
person Divakar    schedule 30.11.2015
comment
о, круто! :) Есть ли аналогичная функция и в theano? Мне также нужно реализовать это в theano. - person PickleRick; 30.11.2015
comment
@Anxam Как насчет трансляции на theano? Проверьте решение, основанное на этом. - person Divakar; 30.11.2015
comment
здесь представлено решение: stackoverflow.com/questions/30305891/ Но я не уверен, сработает ли это для меня или нет. - person PickleRick; 30.11.2015
comment
@Anxam Условия немного отличаются, так как здесь вы вырезаете один размер и сохраняете один размер. В связанном вопросе речь идет только об вырезании одного диммера. Итак, если бы вы воспроизвели то же самое поведение здесь, вам нужно было бы изменить форму и транспонировать. Это было бы грязным решением. - person Divakar; 30.11.2015
comment
Ясно... что, если я сгенерирую матрицу, используя индексы, рассчитанные аналогично einsum, и построю большую матрицу, используя эти индексы, чтобы передать их в мою функцию theano? я не совсем уверен, как это будет работать, но, может быть, лучше работать с двумя матрицами, которые, применяя theano.dot, приводят к тому, что я хочу. - person PickleRick; 30.11.2015
comment
@Anxam Просто любопытно и не по теме вашего вопроса: работало ли это решение на основе вещания на theano? - person Divakar; 30.11.2015
comment
Я еще не смог найти решение на основе теано. когда мне это удастся, я опубликую решение здесь или в другом своем сообщении: stackoverflow.com/questions/34005271/ - person PickleRick; 30.11.2015
comment
Давайте продолжим обсуждение в чате. - person PickleRick; 30.11.2015
comment
@Ophion нашел решение: tc = T.batched_tensordot(ta, tb, axes=[[1],[1]]) f_c= theano.function(inputs=[ta,tb], outputs=tc) print(np.shape( f_c(a,b))) - person PickleRick; 01.12.2015
comment
Знаете ли вы аналогичное решение для np.divide вместо скалярного произведения? что-то, что работает аналогичным образом, чтобы делить, а не умножать? - person PickleRick; 03.12.2015