矩阵向量乘法的更快实现【并行计算】

Posted

技术标签:

【中文标题】矩阵向量乘法的更快实现【并行计算】【英文标题】:Faster Implementation of Matrix-Vector Multiplication [Parallel Computation] 【发布时间】:2013-02-27 10:14:08 【问题描述】:

我有这段代码可以执行用 php 编写的矩阵向量乘法。

这是一个sn-p:

for($i = 0; $i < sizeof($transposed_matrix); $i++) 
            $vector[$i] = 0;
            for($j = 0; $j < sizeof($new_vector); $j++) 
                $vector[$i] += ($transposed_matrix[$i][$j] * $new_vector[$j]);
            
        

我想知道有没有办法让这段代码运行得更快?

【问题讨论】:

将循环外的 sizeof() 存储在一个变量中。因为每个循环都会调用 sizeof() 。此外,使用 ++$i 代替 $i++。前增量比后增量快。 如果你想做严肃的高性能算术,选择 PHP 以外的语言。以一种缓慢的语言开始只是在踢自己的脚。 (你可以以某种方式从 PHP 调用 C)。 感谢艾拉。我现在正在尝试连接 PHP 和 C/JAVA/SciLab 【参考方案1】:

一种优化是在for 之前计数:

$size = sizeof($transposed_matrix);
$size2 = sizeof($new_vector);
for($i = 0; $i < $size; $i++) 
    $vector[$i] = 0;        
    for($j = 0; $j < $size2; $j++) 
        $vector[$i] += ($transposed_matrix[$i][$j] * $new_vector[$j]);
    

【讨论】:

【参考方案2】:

PHP 没有为您提供足够的控制来进行一些严重的优化。提议的改进可能会产生相对较小的影响,除非您将巨大的矩阵和向量相乘(在这种情况下,您一开始就不应该使用 PHP)。

除了预先计算大小和使用计数器的预增量(如 Tjoene 所建议的那样),在内循环中使用一个临时变量作为总和,如下所示:

$sum = 0;
for ($j = 0; $j < $numCols; ++$j) 
    $sum += $matrix[$i][$j] * $vector[$j];

$vector[$i] = $sum;

这将避免在 $vector 中多次计算正确的目标位置。

通过将矩阵数据存储在单个平面数组而不是您使用的嵌套结构中,可能会获得最大的性能提升。只需连接矩阵的行,您就可以使用单个索引遍历其元素,如下所示:

for ($i = 0, $n = 0; $i < $numRows; ++$i, ++$n)

    $sum = 0;
    for ($j = 0; $j < $numCols; ++$j) 
        $sum += $matrix[$n] * $vector[$j];
    
    $vector[$i] = $sum;

当然,这只会加快速度,前提是您不必在实际乘法之前转换为这种矩阵布局。

如果您不想更改矩阵布局,可以通过在外部循环中使用 foreach 来检索矩阵的行来加快速度。但是请注意,这会按照将这些行数组添加到矩阵的顺序遍历行集!如果矩阵和向量之间的顺序不同,结果将全错。所以,这可能不是一件可靠的事情,因为它很容易坏掉......

哦,您总是可以尝试部分展开循环。

【讨论】:

【参考方案3】:

PHP 数组有变慢的趋势,这是对散列机制的贡献。 PHP array performance。如果您有办法预先确定向量的大小,则可以展开循环并避免使用数组。如果您的代码是整个代码,那么这对您没有帮助,因为 $transposed_matrix 中的每个项目只被命中一次,您可以使用 $sum 技术来减少 $vector 的命中次数,如阿策·卡普特尼克。因此,您最终会将数组参数中的内容复制到局部变量,然后进行计算,然后再复制回来……这不仅会扼杀性能提升。

最后,您所能做的就是切换到一种完全不同的优化方法:像 HipHop 这样的 JIT 编译器或编译语言。 C 中的相同循环可能会以 10 到 100 倍的速度运行,减去分叉该进程的时间。

【讨论】:

我现在正在尝试将 php 桥接到 c/java/scilab 如果性能真的很重要,请选择 C。一方面,有多个高度优化的并行处理库可用。主要原因是从 PHP 分叉 C 调用引入了 LOT 比分叉 Java 客户端更少的开销。我没有使用 Scilab 的经验,但我希望它也比 C 效率低。编辑:我刚刚发现您可以从 PHP 调用 C DLL,而无需分叉。这可能是最有前途的道路。

以上是关于矩阵向量乘法的更快实现【并行计算】的主要内容,如果未能解决你的问题,请参考以下文章

利用MPI实现Cannon算法并行矩阵乘法

利用MPI实现Cannon算法并行矩阵乘法

python实现简单的并行矩阵乘法

并行计算-稠密矩阵计算复习(待续--待补一块内容和Cannon,DNS,Fox算法)

使用并行编程 C++ 计算/访问向量

OpenMP 矩阵向量乘法仅在一个线程上执行