矩阵乘法在数值上是否最优?

时间:2019-07-08 11:33:41

标签: python numpy matrix-multiplication numerical-methods floating-accuracy

TL; DR:问题是关于乘法精度

我必须将矩阵A(100x8000),B(8000x27)和C(27x1)相乘。

由于矩阵BC是恒定的,而A是可变的,因此我更喜欢将其计算为:ABC = np.dot(A, np.dot(B, C))。但是,我想知道,就准确性而言,在数字上可能比np.dot(np.dot(a, B), C)更糟。

可能重要的是:矩阵AB包含8000个分别(分别)100个和27个相关特征的样本。

乘法是否有数字个最优顺序(就准确性而言)?如果可以,我该如何确定?

特殊情况

可以假设AB矩阵都是非负矩阵。 而且:

C = np.linalg.solve(cov(B, k), X)

其中X是27x1矩阵,其中包含27个(可能是相关的)未知分布的随机变量,cov = lambda X, k: np.dot(X.T, X) + k * np.eye(X.shape[1]),而k是使表达式最小化的非负常数:

sum((X[i, 0] - np.dot(np.dot(B[:, [i]].T, drop(B, i)),
                      np.linalg.solve(cov(drop(B, i), k),
                                      np.delete(X, i, axis=0))) **2
    for i in range(27))

drop()函数定义为lambda X, i: np.delete(X, i, axis=1)

更多特殊情况

可以假设np.cov(B.T, B)X的协方差矩阵,它遵循多元高斯分布。

4 个答案:

答案 0 :(得分:4)

目前(对于一组特定的矩阵),我最好的想法是执行以下数值实验:

  1. 将参考矩阵计算为高精度计算的乘积平均值(例如np.float128)。
  2. 计算精度较低的测试产品(np.float64np.float32,甚至np.float16
  3. 分析误差,计算为测试产品与参考矩阵之间的差异。随着精度的提高,预计误差会下降。

答案 1 :(得分:2)

建议使用导致浮点累积误差最小的公式。

  • (AB)C(AB)的每个元素都是A中每一行与B中每一列的点积。对于B中的每一列,找到最大元素与最小元素的比率,然后找到那些每个列比率的最大值。将此称为B_ratio
  • A(BC):让T = (BC)产生8000x1矩阵。 A(BC)的每个元素都是A中每一行与T中每一[one]列的点积。对于T中的每个[one]列,找到max元素与min元素的比率。将此称为T_ratio

假设A中值的分布均匀,则无论哪个上面的解决方案都具有较小的绝对比率,数值上的稳定性更高。也就是说,如果fabs(B_ratio) < fabs(T_ratio)那么(AB)C会更好。

合理性:将大小相加时会累积错误-较小数字的低位会“丢失”。通过将因素保持在较小的绝对分布范围内,损失单个小术语的贡献的可能性就会降低。

浮点详细信息

添加IEEE 754浮点数z = x + y时,可能会出现以下情况之一:

  1. z.exponent == max(x.exponent, y.exponent) && z.mantissa != max(x,y).mantissa,这意味着尾数之和不带进位。没有引入错误。
  2. z.exponent == max(x.exponent, y.exponent)+1,这意味着尾数加进位。最低的精度损失,导致引入了2^-(z.exponent - MANTISSA_BITS)的错误。
  3. z == max(x, y)表示x或y增大2 ^ MANTISSA_BITS,导致其他输入的总损耗(甚至低于噪声阈值)。< / li>

为保持数值稳定性,您可以通过以下方式使累积误差最小化:首先对数字进行排序,然后从最小到最大进行累积。这样可以避免上述情况3经常发生,尽管它仍然可能发生。

其他阅读

What Every Computer Scientist Should Know About Floating-Point Arithmetic

答案 2 :(得分:0)

三个矩阵相乘总是不会比两个相乘慢吗?

您实际上只有两个选择:(AB)CA(BC)。从BC = const开始,您可以拥有形状为T = BC的常数8000x1,然后将AT乘以而不用重新计算T

答案 3 :(得分:0)

嗯,我认为不同的乘法顺序在速度上没有区别。计算次数应该相同。 另外,我看不到像其他矩阵计算(例如,通过数组的迭代顺序)那样的缓存的可能改进。

唯一的问题是,如果np.dot(B,C)确实不会改变,并且您需要多次计算的结果,则可以将它们放在一个额外的矩阵中。