MegEngine Inference 卷积优化之 Im2col 和 winograd 优化
作者:于雄雄 陈其友 | 旷视 MegEngine 架构师
背景
在 CV 领域中,卷积计算是扩充像素的感受野的有效方法,模型大多数的计算量都是卷积操作贡献的。因此在 CV 模型的推理性能优化中,最重要的一项工作是对卷积的优化。MegEngine 在长期的工业界实践和反馈的基础上总结得出卷积优化的基本方法有:
- 直接卷积计算优化
该方法的计算过程为逐通道进行卷积滑窗计算并累加,该优化方法对卷积的参数敏感,为了达到最优的性能,会根据各个卷积参数分别进行 kernel 优化,通用性弱,但是在 Depthwise 的卷积中却是最高效的方法。
- FFT 卷积计算优化
根据卷积的性质,利用傅立叶变换可以将卷积转换为频域上的乘法,在频域上的计算对应乘法,再使用傅立叶变换逆变换,就可以得到卷积对应的计算结果。该方法使用高性能的傅立叶变换算法,如 FFT,可以实现卷积计算的优化,算法性能完全取决于傅立叶变换的性能以及相应卷积参数。
- Im2col+matmul 卷积计算优化
由于卷积计算中有大量的乘加运算,和矩阵乘具有很多相似的特点,因此该方法使用 Im2col 的操作将卷积运算转化为矩阵运算,最后调用高性能的 Matmul 进行计算。该方法适应性强,支持各种卷积参数的优化,在通道数稍大的卷积中性能基本与 Matmul 持平,并且可以与其他优化方法形成互补。
- Winograd 卷积计算优化
Winograd 方法是按照 Winograd 算法的原理将卷积运行进行转变,达到减少卷积运算中乘法的计算总量。其主要是通过将卷积中的乘法使用加法来替换,并把一部分替换出来的加法放到 weight 的提前处理中,从而达到加速卷积计算的目的。Winograd 算法的优化局限为在一些特定的常用卷积参数才支持。
由于 direct 卷积可以直接由公式得来,而 FFT 卷积对于当前业界用到的各种参数的卷积,其性能优势远没有其他优化方法明显,对于这两者本文不做详细展开。这里主要讲述 Im2col 和 Winograd 算法的实现以及优化方法。
Im2col+Matmul 优化
Im2col 算法简介
Im2col+Matmul 方法主要包括两个步骤:
- 使用 Im2col 按照卷积核的需要将输入矩阵展开一个大的矩阵,矩阵的每一列表示卷积核需要的一个输入数据。
- 使用上面转换的矩阵进行 Matmul 运算,得到的数据就是最终卷积计算的结果。
具体 Im2col 的步骤如上图所示:
- 将输入数据按照卷积窗进行展开并存储在矩阵的列中,多个输入通道的对应的窗展开之后将拼接成最终输出 Matrix 的一列。
- 以卷积的 stride 为步长展开后续的卷积窗并存在 Matrix 的下一列中。
完成 im2col 的操作之后会得到一个输入矩阵,卷积的 weights 也可以转换为一个矩阵,此时对 weights 的矩阵和 Im2col 的输出矩阵进行 Matmul 计算,就可以得到最终的卷积计算结果。
算法优化
上面介绍的过程是原始 Im2col+Matmul 的过程,实际处理器在执行上面的过程中性能达不到最优,以输入 Tensor 的 shape 为 (1, IC, IH, IW),weights 的 shape 为 (OC,IC,Fh,Fw),输出 Tensor 的 shape 为 (1, OC, OH, OW) 为例,主要原因在于:
- Im2col 的输入 Tensor 需要的 CPU 内存大小为 IC*IH*IW,而按照上面 Im2col 之后所需要的内存大小为 IC*Fh*Fw*OH*OW,当卷积的 stride=1 的时候,Im2col 之后需要的内存比之前大很多。
- 由于 Im2col 之后的数据量比较大,难以全部保存在 CPU 的 Cache 中,造成后续 Matmul 计算时,读取数据会存在 Cache Miss。
- Im2col 过程中会将输入进行 relayout 操作,而在后续 Matmul 的计算中,需要对该数据进行 Pack,Pack 操作会引入非必要的读写过程。影响算法实际性能。
优化 1:对 Im2col+Matmul 过程进行分块
上面提到在 Im2col 之后,消耗的内存会超过 CPU 的 Cache 的容量,为了使这部分数据能够保存在 Cache 中,需要对 Im2col+Matmul 的整个过程进行分块,每次 Im2col+Matmul 都只对一个分块进行操作,这样就可以解决内存占用过大,超过 CPU Cache 后造成 Cache Miss 的问题。
分块优化如上图所示:Im2col 每次只对 block_size 大小的数据进行计算,得到的 Fh*Fw*IC*block_size 的数据可以保存在 Cache 中。Im2col 得到数据后,对其直接进行 Matmul 计算,将计算得到的结果写入到输出 Tensor 对应的 block_size 处就可以得到该分块处卷积的计算结果。计算完该分块之后,依次进行下一个 block_size 的计算,直到整个输入计算完成。
结合 Matmul 的相关优化知识,在进行 Matmul A*B=C 计算时将分块 Im2col 得到的数据视作 B 矩阵,A 矩阵为卷积的权重矩阵,根据 sgemm 的分块规则,以及 cache 的性质,A 矩阵会被调度并保存在 L2 上,B 矩阵基于最内层分块的一列和 A 矩阵基于最内存分块的一行以及 C 矩阵基于最内层的部分分块会被调度保存在 L1 上,因此可以通过 L1,L2 的大小以及 A 矩阵的大小,计算出所有的分块大小。下面是分块优化性能的试验结果,可以看出分块优化能有效的减少存储使用,而且还可以提升算子的计算性能。
优化 2:融合 Im2col 和 Matmul PACK 数据操作部分
Im2col 过程中将多个窗的展开同时进行时,实际上是对内存的 copy 以及数据的 relayout 的过程,后续 Matmul 的 Pack 操作业是对数据的 copy 的 relayout,因此可以将上面两次数据的 copy 和 relayout 进行合并优化,减少该过程中对内存的读写次数。
如上图所示 Im2col+Matmul 的 algo 中实现了将 Im2col 和 Matmul 的 Pack 融合的优化,这样能够减少一次数据的读写操作。由于该 fuse 过程和卷积的参数直接相关,不同的卷积参数将对应不同的融合 kernel,所以不具备通用性。通用情况下我们会使用之前的 Im2col+Matmul 的做法,另外针对一些通用的卷积如:kernel=3x3,stride=2 等,因为参数固定,因此可以直接进行上述融合优化,利用这样的组合优化,既可以保证 im2col 算法的通用性,也可以确保大部分常见的卷积的性能。
对融合之后的卷积进行性能测试,如下所示为对应的计算吞吐:
可以看出,大多数情况下,融合之后卷积会有明显的性能提升。
Winograd 优化
Winograd 算法简介
Winograd 算法能够优化卷积计算的乘法计算量,乘法计算量的优化原理可以参考相关论文。在此就不做过多介绍了。虽然 Winograd 可以优化乘法的计算量,但是会增加加法的计算量,优化这些加法的存在可以进一步提高 Winograd 算法的性能。如可以把一部分加法计算提前到 weights 的预处理中,可以把部分加法隐藏在 Winograd 预处理中的 relayout 中。类似这样的优化可以达到减少卷积计算量的目的。
如下图所示为 Winograd 卷积算法的基本步骤,主要包括:
- 把输入的 feature map 和 weight 进行 Winograd 转换;
- 把转换后 feature map 和 weight 做批量 Matmul;
- 把矩阵乘的结果进行输出转换,得到最终结果。
在这些主要步骤中,要如何进行 Winograd 转换,如何 relayout,以及如何进行输出转换呢?下面以 Winograd F(2x2, 3x3) 为例,详细说明下这些过程。
如上图所示,上半部分是 weights 的转换,下半部分是输入 FeatureMap 的转换。其中包括了 Winograd 转换以及 relayout 的过程。
对于 weights 的转换,首先通过 Winograd 变换矩阵 G 和 GT 分别将 3x3 的 weight 转换为 4x4 的矩阵,然后将该矩阵中相同位置的点(如图中蓝色为位置 1 的点)relayout 为一个 IC*OC 的矩阵,最终形成 4x4=16 个转换之后 weights 矩阵。
对于 FeatureMap 的转换,首先将输入 FeatureMap 按照 4x4 tile 进行切分,然后将每个 tile 通过 B 和 BT 转换为 4x4 的矩阵,矩阵 B 和 BT 为 FeatureMap 对应的 Winograd 变换矩阵,然后进行与 weight 处理相似的 relayout,转换为 16 个 nr_tiles*IC 的 FeatureMap 矩阵。
如上图所示,将上述转换后两批矩阵做矩阵乘,得到 16 个 nr_tiles*OC 的矩阵,然后将相同位置的 16 个点转换为 nr_tiles*OC 个 4x4 矩阵,再使用输出的 Winograd 变换矩阵 A 和 AT 将这些 4x4 的矩阵转换为 2x2 的输出矩阵,最后将这些矩阵写回输出矩阵中就可以得到 Winograd 卷积的最终结果。
算法优化
优化 1:weight 提前处理
在上述 Winograd 算法的基础上,鉴于模型中的权重数据在整个 Inference 的时候已经是常量不会再改变,因此可以在真正 Inference 之前就可以对模型进行了 weights 的转换,这样可以优化在 Inference 的时候 weights 转换的开销,特别是在 IC 和 OC 较大时,weight 转换的开销非常大,所以 weights 提前转换,尤其对 Winograd 优化特别重要,下图是 Winograd 中进行 weight 提前转换和不进行 weight 提前转换时各自的性能:
从上图可以看出 weight 转换在 Winograd 中耗时占比很大,进行 weight 提前转换可以带来很大的性能收益。
优化 2:Winograd 分块优化
上述的 Winograd 算法,还会有以下缺点:
- 输入转换需要跨 channel 读写整个 feature map,数据读写对 Cache 不友好。
- feature map 转换之后,矩阵乘时需要再 PACK,数据访存增加。
针对这些问题,可以对 Winograd 算法的整个计算流程做进一步的优化,这些优化主要包括:
- 输入转换时,分块 feature map 的 tiles 进行分块,每次只进行一定数量的 tiles 计算;
- 调整分块大小适配 CPU L1 Cache,使得矩阵乘不需要 PACK;
对整个输入 feature map 进行分块后,每次只计算一个分块的 nr 个 tiles,这样就可以保证每个批量矩阵的输入数据(除了转换之后的 weight 数据)保存于 L1 Cache,不会出现 Cache miss, 而且矩阵乘时不需要 PACK。
下面是分块优化前后的速度对比,可以看出分块优化对性能有显著的提升。
总结
CPU 上 Inference 中有关卷积的优化有很多的途径,这里我们主要介绍了 Im2col+matmul 卷积以及 Winograd 卷积中的一些进一步优化的技术手段,通过这些方法可以进一步加速卷积计算的性能,从而加速整个模型的 Inference 性能。如下图所示是 float32 的经典网络开启相关优化后,在骁龙 855 上的测试速度:
对于具体的优化细节,大家可以结合 MegEngine 的代码实现进行研究,欢迎大家提出宝贵意见。
更多 MegEngine 信息获取,您可以:查看文档、 深度学习框架 MegEngine 官网和 GitHub 项目,或加入 MegEngine 用户交流 QQ 群:1029741705

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
Kafka牛逼在哪里?
一、Kafka存在哪些方面的优势 1. 多生产者 可以无缝地支持多个生产者,不管客户端在使用单个主题还是多个主题。 2. 多消费者 支持多个消费者从一个单独的消息流上读取数据,而且消费者之间互不影响。 3. 基于磁盘的数据存储 支持消费者非实时地读取消息,由于消息被提交到磁盘,根据设置的规则进行保存。当消费者发生异常时候,意外离线,由于有持久化的数据保证,可以实现联机后从上次中断的地方继续处理消息。 4. 伸缩性 用户在开发阶段可以先试用单个broker,再扩展到包含3个broker的小型开发集群,然后随着数据量不断增长,部署到生产环境的集群可能包含上百个broker。 5. 高性能 Kafka可以轻松处理巨大的消息流,在处理大量数据的同事,它还能保证亚秒级的消息延迟。 二、Kafka常见的使用场景 1. 消息 kafka更好的替换传统的消息系统,消息系统被用于各种场景(解耦数据生产者,缓存未处理的消息等),与大多数消息系统比较,kafka有更好的吞吐量,内置分区,副本和故障转移,这有利于处理大规模的消息。 根据我们的经验,消息往往用于较低的吞吐量,但需要低的端到端延迟,并需要提供强大...
- 下一篇
“2022 年度优秀开源技术团队” 公布
弹指瞬间,转眼 2022 年已经来到了尾声。在过去的一年里,国内开源力量继续蓬勃发展、稳步向前;与此同时,越来越多的团队开始聚焦于开源社区的运营。 作为本土开源技术社区,OSCHINA 也一直在不遗余力地助力着国内开源发展,为构建良好的中国开源生态献一分微薄之力;平台有一套完整的模式与能力帮助开源项目社区进行运营。 开源项目社区与技术团队是开源生态发展进程中不可或缺的中坚力量,OSCHINA 矢志不渝地为这些群体提供发声渠道,不断向开发者传播最新开源与开发技术的信息,让更多开发者关注到优秀的开源项目与技术。 2022 年,我们综合了 OSCHINA 平台上各大认证官方技术团队、开源社区帐号年度发表的内容频率及质量、开展各种活动运营积极性等多方面的表现,颁发 OSCHINA“2022 年度优秀开源技术团队”奖项,以鼓励大家的积极性与辛勤付出,一起让中国的开源生态更加乐观向上。开源生态的发展离不开你们。这也是OSCHINA推出该奖项的第二年,欢迎有更多的技术团队、开源项目社区参与到 OSCHINA 的交流当中来。 具体名单如下(按首字母顺序排名,不分先后): Alluxio 官方 ...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Windows10,CentOS7,CentOS8安装MongoDB4.0.16
- Linux系统CentOS6、CentOS7手动修改IP地址
- CentOS7编译安装Gcc9.2.0,解决mysql等软件编译问题
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- SpringBoot2整合Redis,开启缓存,提高访问速度
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7
- MySQL8.0.19开启GTID主从同步CentOS8
- Mario游戏-低调大师作品
- CentOS7安装Docker,走上虚拟化容器引擎之路