Python中Numpy两个矩阵部分维度相乘,有没有很快的方法?
例如,有两个三维矩阵 m1,m2,shape 都是 (10000, 2, 2)
m1 = array([x1, x2, ..., x9999])
m2 = array([y1, y2, ..., y9999])
xn, yn 都是 2x2 的矩阵。
希望得到的结果是:
res = array([dot(x1, y1), dot(x2, y2), ..., dot(x9999, y9999)])
目前我试过最快的方法是 map(循环、列表推导都试过,numpy.vectorize 没成功),但感觉还是不够快。各位有没有更好的方法?
Python中Numpy两个矩阵部分维度相乘,有没有很快的方法?
多进程试试
帖子没给具体例子,我猜你是想对两个矩阵的某些维度做逐元素乘,而不是矩阵乘。比如一个形状是 (a, b, c) 的矩阵 A 和一个形状是 (b, c) 的矩阵 B,你想让 B 自动广播到 A 的后两个维度上做乘法。
用 numpy 的广播机制就行,这是最快的方法。B 的形状 (b, c) 会被自动视为 (1, b, c),然后扩展成 (a, b, c) 和 A 逐元素相乘。代码很简单:
import numpy as np
# 假设 A 是 3维,B 是 2维,想让B广播到A的后两维
A = np.random.randn(10, 20, 30)
B = np.random.randn(20, 30)
# 直接乘,numpy自动处理广播
C = A * B
print(C.shape) # 输出 (10, 20, 30)
如果维度不对齐,比如 B 是 (a, c) 但你想和 A 的中间维度 b 相乘,就需要用 np.expand_dims 调整一下维度再广播:
# 另一种情况:B 形状 (a, c),想和A的中间维度b相乘?
A = np.random.randn(10, 20, 30)
B = np.random.randn(10, 30) # 注意第一维和A相同,但没有中间维度b
# 把B中间加一个维度,变成 (10, 1, 30),然后广播到 (10, 20, 30)
B_expanded = B[:, np.newaxis, :]
C = A * B_expanded
print(C.shape) # 输出 (10, 20, 30)
核心就是利用广播,这是 numpy 底层优化过的,速度最快。搞不清楚维度对齐的时候,就 np.newaxis 或者 reshape 调整一下。
总结:用广播机制。
Python 已经很快了底层做了很多优化,不行把矩阵拆开多进程大批量的情况下可以加快最后再组合回来。再不行试一下用 cpp。
放到 cython 里面用 prange 多线程算
https://software.intel.com/en-us/articles/numpyscipy-with-intel-mkl
试试这个,再不行就只能用 Matlab 了,不要尝试手写 cpp,几乎不可能比 MKL 更快的了
不知道是不是我理解的有问题,numpy.matmul 是可以实现多个矩阵对应元素相乘的。
按照我对 lz 的描述的理解,直接 np.matmul(m1, m2) 就可以达到目的。
https://docs.scipy.org/doc/numpy/reference/generated/numpy.matmul.html
If either argument is N-D, N > 2, it is treated as a stack of matrices residing in the last two indexes and broadcast accordingly.
意思是,如果输入大于 2d,会当做矩阵的数组 /矩阵…
所以直接乘就行了
有的有的,直接选择矩阵特定的切片元素相乘就好因为直接是矩阵计算不需要循环,性能可以的
加上 vectorize 的:
In [28]: def mydot(a, b):
…: return np.dot(a,b)
…:
…:
In [29]:
In [29]: vmydot = np.vectorize(mydot, signature=’(n,m),(m,n)->(n,n)’)
In [30]: e = vmydot(a, b)
In [31]: np.allclose(d,e)
Out[31]: True
In [32]: %timeit vmydot(a,b)
467 ms ± 4.4 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
非常感谢!看来我还是学艺不精
no.tensordot
打错,np.tensordot


