移动深度学习
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

2.6 矩阵乘法

如果矩阵对同一向量做线性变换,就会得到一个变换后的向量;如果矩阵对两个向量或者一组向量做变换,所做的就是矩阵乘法,如下式所示是矩阵AB相乘,得到了矩阵C

A×B=C

在二维空间内,可以把两个矩阵相乘看作其中一个矩阵所包含的两个向量,分别对另一个矩阵做线性变换后再叠加,结果矩阵就是叠加后的矩阵。

如图2-10所示,矩阵2MM1相乘,等价于M2M1的两个向量分别进行线性变换。

图2-10 矩阵M2和M1相乘

注意,只有在第一个矩阵的列数与第二个矩阵的行数相等的时候,矩阵的乘法才有意义。如果要求使用C++实现一个矩阵乘法,可以用下面这种最简单的方式来实现:采用三层for循环,实现了一个最基本的矩阵乘法。

    int aRow = 6;
    int aCol = 6;

    int bRow = 6;
    int bCol = 6;
    //第一个矩阵
    int matrix_a[aRow][aCol] = {
    {1,3,2,6,5,4},
    {6,2,4,3,5,1},
    {2,1,3,4,5,6},
    {5,2,3,4,1,6},
    {4,2,3,1,5,6},
    {3,2,1,4,6,5},
    };

    //第二个矩阵
    int matrix_b[bRow][bCol] = {
    {3,3,2,1,5,4},
    {1,2,4,3,5,5},
    {2,1,9,4,5,2},
    {5,2,6,4,1,1},
    {4,7,3,1,5,5},
    {3,8,1,4,6,4},
    };
    int matrix_c[6][6];
    //将矩阵的元素初始化为0
    for(autoi = 0; i < aRow; i++)
    {
        for(autoj = 0; j < bCol; j++)
        {
          matrix_c[i][j] = 0;
        }
    }

    for(autoi = 0; i < aRow; i++)
    {
        for(autoj = 0; j < bCol; j++)
        {
          for(autok = 0; k < bRow; k++)
          {
              matrix_c[i][j] += matrix_a[i][k] * matrix_b[k][j];
          }
        }
    }

这种实现可以完成计算,但是计算性能往往比较差。矩阵乘法的计算性能有很多优化方式,这些优化可以提升硬件在计算过程中的运行速度。第7章会详细介绍如何更高效地优化矩阵乘法的计算性能。

矩阵的乘法计算过程可以被分割成小块。例如,上面代码片段中的两个矩阵可以表示为下式,它们都可以被拆分为四个小块(如图2-11所示),分成对称的区块后,矩阵乘法法则同样适用。

图2-11 矩阵分块

将矩阵分块后得到子矩阵组,对它们做矩阵乘法,如下式所示。

深度学习程序是计算密集型的,在设计代码时往往需要考虑较多细节,以取得最佳性能,减小不必要的资源消耗。在卷积神经网络的运算过程中,使用广义矩阵乘法(GEMM)计算卷积是早期深度学习框架的一个普遍做法,虽然有些新计算方式有后来居上的势头,但是广义矩阵乘法仍然是非常重要的基础知识。