从 CNN 性能优化说起(一)

对于做深度学习系统的行内人来说,CNN 的性能优化是一个老话题。但是新人仍然经常震撼于一个事实 —— 手写一个 convolution layer 的七层循环和Caffe的实现相比,性能差距100多倍。

本文详解贾杨清于2014年写了一篇简短的 memo,描述了他的通过把 CNN 变成矩阵乘的加速方法 https://github.com/Yangqing/caffe/wiki/Convolution-in-Caffe:-a-memo 。这个被扬清谦虚地称为“临时方案”的做法被后来的各种深度学习框架复现,甚至影响了深度学习编译器的研究。

本文复用了一篇很不错但读者不多的英语博客中的叙事顺序和图示;其原文在 https://sahnimanas.github.io/post/anatomy-of-a-high-performance-convolution ,并且修正了一些借用的图示。此外,本文增加对 convolution 计算过程的介绍,以承上。并且简单介绍 TVM 和 MLIR 背后的思路,以启下。

Convolution 的计算过程

先得知道 convolution layer 的计算过程才好优化。Convolution layer 对一幅图像 A 做 convolution,结果输出为图像 B。所谓的 convolution 操作是指给定一个 K x K 的小矩阵(kernel),把图 A 中每个 K x K 个像素构成的小片(patch)中的每个像素值乘以 kernel 中对应的数值,然后所有乘积加起来,作为图像 B 中一个像素的值。大致过程如下图。其中左边的大矩阵是图像 A,右边的大矩阵是图像 B,中间的 3×3 的小矩阵是 kenel。

https://sahnimanas.github.io/post/anatomy-of-a-high-performance-convolution 的记录,即使用 C 写,-O3 加上 -Ofast,对于 CIFAR10 数据集,每个 minibath 里的每张图需要 2.2 秒。而 Caffe 的实现只需要 18ms。差距 100 多倍。如果不开编译优化,则差距是 1000 多倍。

贾杨清的加速法

扬清在 Caffe 的 memo 里记录的方法是把图像 A 里的每个 patch 都展开成一个向量,然后把所有向量拼成一个大矩阵 A’。类似的,把 Cb 个 kernel 也展开成一个大矩阵 K’。则 convolution 就可以变成这两个矩阵相乘 A’ x K’。得到的大矩阵就是 B。

王益:从 CNN 性能优化说起(二)zhuanlan.zhihu.com图标