@Divakar 推荐np.tensordot,@hpaulj 和@Praveen 推荐np.einsum。还有一种方法是转轴:
(a @ b.transpose((2, 0, 1))).transpose((1, 2, 0))
对于您引用的小尺寸,np.einsum 和转置似乎更快。但是,一旦您开始放大要沿其相乘的轴的维度,np.tensordot 就会胜过其他两个。
import numpy as np
m, n, k, l = 8, 9, 12, 17
a = np.random.random((m, n))
b = np.random.random((n, k, l))
%timeit np.tensordot(a, b, axes=([1], [0]))
# => 10000 loops, best of 3: 22 µs per loop
%timeit np.einsum("ij,jkl->ikl", a, b)
# => 100000 loops, best of 3: 10.1 µs per loop
%timeit (a @ b.transpose((2, 0, 1))).transpose((1, 2, 0))
# => 100000 loops, best of 3: 11.1 µs per loop
m, n, k, l = 8, 900, 12, 17
a = np.random.random((m, n))
b = np.random.random((n, k, l))
%timeit np.tensordot(a, b, axes=([1], [0]))
# => 1000 loops, best of 3: 198 µs per loop
%timeit np.einsum("ij,jkl->ikl", a, b)
# => 1000 loops, best of 3: 868 µs per loop
%timeit (a @ b.transpose((2, 0, 1))).transpose((1, 2, 0))
# => 1000 loops, best of 3: 907 µs per loop
m, n, k, l = 8, 90000, 12, 17
a = np.random.random((m, n))
b = np.random.random((n, k, l))
%timeit np.tensordot(a, b, axes=([1], [0]))
# => 10 loops, best of 3: 21.7 ms per loop
%timeit np.einsum("ij,jkl->ikl", a, b)
# => 10 loops, best of 3: 164 ms per loop
%timeit (a @ b.transpose((2, 0, 1))).transpose((1, 2, 0))
# => 10 loops, best of 3: 166 ms per loop