我想在Python中高效地执行一系列矩阵向量乘法,numpy.einsum
函数似乎是最佳选择。然而,我不知道链中矩阵操作数 N 的数量,因此没有简单的方法来写subscripts
字符串传递给einsum
。
为了更清楚,让我们考虑 N=3 矩阵 A,B 和 C 以及初始向量v的简单情况。numpy.einsum
调用如下:
result = numpy.einsum('ij,jk,kl,l', A, B, C, v)
如何将此操作推广到任意 N?一种可能性是以编程方式创建subscripts
字符串,但numpy.einsum
只支持52个不同的标签(26个字母,小写和大写),这在我的情况下代表了一个限制,因为我事先不知道操作数的数量。
是否有一种方法可以通过使用基于不同numpy
函数的另一种方法来尽可能有效地做到这一点?
3条答案
按热度按时间nc1teljy1#
这里有两个递归解决方案,一个基于“原子归纳法”,也就是对每个矩阵乘法做一个einsum:
这里是一个基于“块归纳”的解决方案,在1处对每个最大块进行einsum。请注意,我从
string.ascii_letters
开始使用函数vocab中的所有52个字母,但我遇到了错误,所以我不得不将其减少到11
,15
确实工作,但速度很慢。请注意,它们适用于两种情况:
liwlm1x92#
我想在Python中高效地执行一系列矩阵向量乘法,
numpy.einsum
函数似乎是最佳选择。但最好的选择似乎是
numpy.linalg.multi_dot
,其中一些文档如下所示:在单个函数调用中计算两个或多个数组的点积,同时自动选择最快的计算顺序。
multi_dot
链接numpy.dot
并使用矩阵的最佳括号[1][2]。根据矩阵的形状,这可以大大加快乘法。如果第一个参数是1-D,则将其视为行向量。如果最后一个参数是1-D,则将其视为列向量。其他参数必须是二维的。
将
multi_dot
视为:这个函数通过简单地将你的矩阵放在一个列表中来解决未知数量的操作的问题。同时,它的性能看起来比
einsum
更好,一个相对随意的基准测试如下:ncecgwcz3#
如注解中所述,您可以使用(未记录?)交错模式,以便于生成下标。就像这样:
根据2018年的错误修复,这应该可以达到~50,但是它对我来说不适用于~30。
正如@learning-is-a-mess所建议的,你也可以分块来做:把你的矩阵列表分成N个大小的块,用前一个块的输出作为它的第一个输入,通过
einsum
运行每个块。不过,最好的选择可能只是使用
opt_einsum
。这可以显著提高einsum
的速度,并且还支持任意数量的索引: