
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人
2.6 矩阵乘法
如果矩阵对同一向量做线性变换,就会得到一个变换后的向量;如果矩阵对两个向量或者一组向量做变换,所做的就是矩阵乘法,如下式所示是矩阵A和B相乘,得到了矩阵C。
A×B=C
在二维空间内,可以把两个矩阵相乘看作其中一个矩阵所包含的两个向量,分别对另一个矩阵做线性变换后再叠加,结果矩阵就是叠加后的矩阵。
如图2-10所示,矩阵2M和M1相乘,等价于M2对M1的两个向量和
分别进行线性变换。

图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)计算卷积是早期深度学习框架的一个普遍做法,虽然有些新计算方式有后来居上的势头,但是广义矩阵乘法仍然是非常重要的基础知识。