本文介绍 深度学习量化之GEMM通用矩阵乘法

深度学习量化之GEMM通用矩阵乘法

This article was original written by Jin Tian, welcome re-post, first come with https://jinfagang.github.io . but please keep this copyright info, thanks, any question could be asked via wechat: jintianiloveu

GEMM

深度学习走到最后,就得从理论到应用部署。除了一些网络设计,新的优化方法,新的任务,已有任务的指标刷新等领域以外,深度学习模型的量化是一个很重要的领域,这基本上是深度学习的根基了,就好像建造上层操作系统的底层优化库一般,没有它,别人的系统可以做的很优化有顺畅而你不行。

那么GEMM是什么?一种通用矩阵乘法。我们来看一看卷积的运算方式。

1561617543307

通过一个卷积核,对原图进行运算,每一个卷积核将得到一个固定的输出,请注意,不管原图的通道是多少,经过一个卷积核运算之后,都会变成一个维度的。最终featuremaps的channel取决于你用多少个卷积。

实际上这种算法在执行效率上会很低。即便是最老的caffe,人家用的也是im2col算法,啥是im2col?你卷积的时候,可以每个卷积区域拉伸为一个Patch,如下面所示:

1561617750179

如上所示,现在相当于是将每个待卷积区域拉伸为一个Patch。这样就可以变成矩阵的相乘:

1561617850804

基本上GEMM就是一个网络的核心,因为大多数的运算都集中在卷积和全连接,而这两者的本质就是矩阵的惩罚,上面也可以看到卷积通过转换可以直接变为矩阵的乘法。

我觉得从零实现一下GEMM也就是卷积算法,是有必要的.

我们用伪代码来写一下两个矩阵 A:mxk 和 B: kxn 的矩阵乘法:

for (int m=0; m < M; m++) {
for (int n=0; n < N; n++) {
C[m][n] = 0;
for (int k=0; k , K; k++) {
C[m][n] += A[m][k] * B[k][n];
}
}
}

这个简单易懂,即便用C数组去写,差不多也是这个写法。

这个算法不考虑任何优化的话,其实还有许多值得深入思考的问题,比如:

  • 同样是矩阵相乘,那么如果是不同的尺寸,效率有啥区别?比如,我们可以先遍历m,也可以先遍历n,如果m比n大应该用哪种顺序更好?

Winograd算法

winograd说白了,就是用加法来代替矩阵的乘法。那么如何用加法来代替乘法呢?

1561618157960

这图说明了,使用winnograd加速可以做到比CUDNN还快,实际上CUDNN中的实现是用GEMM实现的。