【问题标题】:Why is my Strassen Matrix multiplier so fast?为什么我的 Strassen 矩阵乘法器这么快?
【发布时间】:2011-10-19 20:32:20
【问题描述】:

作为一个实验,我实现了 Strassen 矩阵乘法算法,看看是否真的可以为大 n 带来更快的代码。

https://github.com/wcochran/strassen_multiplier/blob/master/mm.c

令我惊讶的是,对于较大的 n,它方式更快。例如,n=1024 的情况 使用传统方法耗时 17.20 秒,而仅耗时 1.13 秒 使用 Strassen 方法 (2x2.66 GHz Xeon)。什么——15 倍的加速!?它应该只是稍微快一点。事实上,它似乎也适用于 32x32 的小矩阵!?

我可以解释这么多加速的唯一方法是我的算法对缓存更友好——即,它专注于矩阵的小块,因此数据更加本地化。也许我应该尽可能零散地做我所有的矩阵算术。

关于为什么速度如此之快的任何其他理论?

【问题讨论】:

    标签: performance matrix strassen


    【解决方案1】:

    Strassen 的递归性质具有更好的内存局部性, 所以这可能是图片的一部分。递归正则 矩阵乘法也许是一个合理的事情 比较。

    【讨论】:

      【解决方案2】:

      第一个问题是“结果正确吗?”。如果是这样,您的“常规”方法可能不是一个好的实现。

      传统的方法是不使用 3 个嵌套的 FOR 循环按照你在数学课上学习的顺序扫描输入。一个简单的改进是在右侧转置矩阵,使其位于内存中,列是连贯的,而不是行。修改乘法循环以使用这种替代布局,它将在大型矩阵上运行得更快。

      标准矩阵库实现了更多考虑数据缓存大小的缓存友好方法。

      您还可以实现标准矩阵乘积的递归版本(细分为一半大小的 2x2 矩阵)。这将提供更接近最佳缓存性能的东西,这是 strassen 从递归中获得的。

      所以要么你做错了,要么你的常规代码没有优化。

      【讨论】:

      • 令我惊讶的是,第 1 版可以直接使用。我对正确性有很高的信心。您对细分标准算法的建议是接下来要测试的。我还将尝试转置技巧以使标准算法对缓存更友好。谢谢。
      【解决方案3】:

      传统乘法中的循环顺序是什么?如果你有

      for (int i = 0; i < new_height; ++i)
      {
          for (int j = 0; j < new_width; ++j)
          {
              double sum = 0.0;
              for (int k = 0; k < common; ++k)
              {
                  sum += lhs[i * common + k] * rhs[k * new_width + j];
              }
              product[i * new_width + j] = sum;
          }
      }
      

      那么您对缓存不是很好,因为您以非连续方式访问右侧矩阵。重新排序后到

      for (int i = 0; i < new_height; ++i)
      {
          for (int k = 0; k < common; ++k)
          {
              double const fixed = lhs[i * common + k];
              for (int j = 0; j < new_width; ++j)
              {
                  product[i * new_width + j] += fixed * rhs[k * new_width + j];
              }
          }
      }
      

      对最内层循环中的两个矩阵的访问是连续的,甚至是固定的。一个好的编译器可能会自动执行此操作,但我选择显式将其拉出来进行演示。

      您没有指定语言,但对于 C++,高级编译器甚至可以识别某些配置中不友好的循环顺序并重新排序。

      【讨论】:

        猜你喜欢
        • 2012-11-13
        • 2012-07-14
        • 2010-12-27
        • 1970-01-01
        • 1970-01-01
        • 2011-03-14
        • 1970-01-01
        • 1970-01-01
        • 2016-02-06
        相关资源
        最近更新 更多