c++ - vector * matrix 乘积效率问题

标签 c++ c matrix sse simd

就像 Z 玻色子一样 recommended ,我使用列主矩阵格式以避免必须使用点积。不过,我没有看到在将 vector 与矩阵相乘时避免它的可行方法。矩阵乘法技巧需要有效提取行(或列,如果我们转置乘积)。因此,要将 vector 乘以矩阵,我们需要转置:

(b * A)^T = A^T * b^T

A 是矩阵,b 是行 vector ,转置后成为列 vector 。它的行只是单个标量, vector * 矩阵乘积实现成为(非转置)矩阵 Ab 的列点积的低效实现。有没有办法避免执行这些点积?我认为可以做到这一点的唯一方法是涉及行提取,这对于列优先矩阵格式来说效率低下。

最佳答案

这可以从关于这个的原始帖子中理解(我在 SO 上的第一篇) efficient-4x4-matrix-vector-multiplication-with-sse-horizontal-add-and-dot-prod .其余讨论适用于 4x4 矩阵。

这里有两种方法来做矩阵时间 vector (v = Mu,其中 v 和 u 是列 vector )

method 1) v1 = dot(row1, u), v2 = dot(row2, u), v3 = dot(row3, u), v4 = dot(row4, u)
method 2) v = u1*col1 + u2*col2 + u3*col3 + u4*col4.

第一种方法在数学课上更常见,而第二种方法对于 SIMD 计算机更有效。第二种方法使用矢量化数学(如 numpy),例如

u1*col1 = (u1x*col1x, u1y*col1y, u1z*col1z, u1w*col1w).

现在让我们看看 vector 乘以矩阵(v = uM,其中 v 和 u 是行 vector )

method 1) v1 = dot(col1, u), v2 = dot(col2, u), v3 = dot(col3, u), v4 = dot(col4, u)
method 2) v = u1*row1 + u2*row2 + u3*row3 + u4*row4.

现在列和行的角色已经互换,但方法 2 仍然是在 SIMD 计算机上使用的有效方法。

要在 SIMD 计算机上高效地执行矩阵乘法 vector ,矩阵应按列优先顺序存储。要在 SIMD 计算机上有效地执行 vector 乘以矩阵,矩阵应按行优先顺序存储。

据我了解,OpenGL 使用列优先排序并执行矩阵乘以 vector ,而 DirectX 使用行优先排序并执行 vector 乘以矩阵。 如果你有三个矩阵变换,你先按顺序执行 M1 然后 M2 然后 M3 矩阵时间 vector 你把它写成

v = M3*M2*M1*u //u and v are column vectors - OpenGL form

用你写的 vector 时间矩阵

v = u*M1*M2*M3 //u and v are row vectors - DirectX form

就效率而言,这两种形式都不比另一种形式好。这只是一个符号问题(并且会引起混淆,这在您有竞争时很有用)。

请务必注意,对于矩阵*矩阵,行优先存储与列优先存储无关。

如果你想知道为什么垂直 SIMD 指令比水平指令快,这是一个应该问的单独问题,但简而言之,水平指令实际上是串行而不是并行的,并且被分解成几个微操作(这就是为什么具有讽刺意味的是 dppddpps 更快)。

关于c++ - vector * matrix 乘积效率问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25805126/

相关文章:

c++ - QMainWindow 正在处理应该被 QDialog 捕获的事件

c - 字符串常量存储

c - 打印off_t

c++ - C/C++ #define 宏里面的宏?

opencv - 将选择的行复制到新矩阵中

algorithm - 如何将一组线像素化为矩阵

c++ - boost::math:quadrature::sinh_sinh 中的错误?

c++ - 针对错误的 OpenMP 并行

C++ strtok 跳过第二个标记或连续分隔符

c++ - 2个变量进入CUDA内核