代码之家  ›  专栏  ›  技术社区  ›  user1095108

向量*矩阵产品效率问题

  •  1
  • user1095108  · 技术社区  · 10 年前

    就像Z玻色子 recommended ,我使用列主矩阵格式,以避免使用点积。不过,我看不出一种可行的方法来避免向量与矩阵相乘。矩阵乘法技巧需要有效提取行(或列,如果我们调换乘积)。为了将向量与矩阵相乘,因此我们转置:

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

    A 是矩阵, b 行向量,经过转置后,成为列向量。它的行只是单个标量,向量*矩阵积的实现成为(非转置)矩阵列的点积的低效实现 A. 具有 b 。有没有办法避免执行这些点积?我认为唯一可行的方法是行提取,这对于列主矩阵格式来说效率很低。

    1 回复  |  直到 7 年前
        1
  •  1
  •   Z boson    10 年前

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

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

    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).
    

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

    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计算机上高效地进行矩阵时间矢量,矩阵应按列主顺序存储。为了在SIMD计算机上实现向量时间矩阵的有效性,矩阵应按行主要顺序存储。

    据我所知,OpenGL使用列主排序和矩阵乘以向量,DirectX使用行主排序和向量乘以矩阵。 如果你有三个矩阵变换,你先按M1,然后按M2,然后按M3的顺序进行矩阵变换,矩阵乘以向量,你把它写成

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

    使用您编写的向量时间矩阵

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

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

    需要注意的是,对于矩阵*,行主存储与列主存储无关。

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