Я пытаюсь воспроизвести numpy.tensordot на С++. Пример в документации numpy показывает вложенный цикл, который я могу заставить работать, но что, если вместо
c = np.tensordot(a,b, axes=([1,0],[0,1]))
Я хочу делать:
c = np.tensordot(a,b, axes=([1,2],[0,1]))
Как будет выглядеть этот новый вложенный цикл в python? И есть ли более простой/быстрый способ выполнить эту операцию в С++? Прямо сейчас я использую те же вложенные циклы for с std::vector в С++. Я видел несколько библиотек, которые могут помочь, но я пытаюсь использовать только стандартную библиотеку С++.
Вот этот пример numpy и ссылка на документацию: https://numpy.org/doc/stable/reference/generated/numpy.tensordot.html
Examples
A “traditional” example:
>>>
a = np.arange(60.).reshape(3,4,5)
b = np.arange(24.).reshape(4,3,2)
c = np.tensordot(a,b, axes=([1,0],[0,1]))
c.shape
(5, 2)
c
array([[4400., 4730.],
[4532., 4874.],
[4664., 5018.],
[4796., 5162.],
[4928., 5306.]])
# A slower but equivalent way of computing the same...
d = np.zeros((5,2))
for i in range(5):
for j in range(2):
for k in range(3):
for n in range(4):
d[i,j] += a[k,n,i] * b[n,k,j]
c == d
array([[ True, True],
[ True, True],
[ True, True],
[ True, True],
[ True, True]])
Спасибо
Спасибо за быстрый ответ! Знаете ли вы, какие операции потребуются для изменения формы, транспонирования и расстановки точек в примере np.tensordot(a,b, axes=([1,2],[0,1]))? Даны два трехмерных массива.
Не с головы. Мне нужно время, чтобы поэкспериментировать и прочитать код. Я предпочитаю использовать np.einsum и np.matmul/@. tensordot — пережиток прошлого.





Я считаю, что сначала полезно переписать np.einsum, так как результирующий код цикла for концептуально выглядит очень похоже:
a = np.random.rand(16, 8, 2)
b = np.random.rand(8, 2, 1)
c = np.tensordot(a, b, axes=([1,2],[0,1]))
# same thing written with einsum
c_ein = np.einsum("ijk,jko->io", a, b)
# same thing done with for loops,
# notice how we can use the same letters and indexing as einsum
c_manual = np.zeros((16, 1))
for i in range(16):
for o in range(1):
# j and k are summed since they don't appear in output
total = 0
for j in range(8):
for k in range(2):
total += a[i, j, k] * b[j, k, o]
c_manual[i, o] = total
assert np.allclose(c, c_ein, c_manual)
Еще раз спасибо! Я еще не портировал на С++, но подозреваю, что это будет довольно легко. Я отпишусь, как только заработаю, но, похоже, это все, что мне нужно. Теперь я буду использовать Einsum.
np.tensordot— это сложный интерфейс кnp.dot. На основе значенийaxesон преобразует входные данные с помощьюreshapeиtranspose, сводя задачу к простому 2ddot. Затем он может преобразовать результат обратно. Я уверен, что есть библиотеки С++, которые уже реализуют базовое умножение матриц (что также должно зависеть от того, какую библиотеку массивов вы используете).