TVM学习(十)从relay到TOPI
judy 在 周一, 05/24/2021 - 09:42 提交Lower操作完成从高级算子(relay)到低级算子(TOPI)的转化。Lower开始于以下代码(src/relay/backend/graph_runtime_codegen.cc)
Lower操作完成从高级算子(relay)到低级算子(TOPI)的转化。Lower开始于以下代码(src/relay/backend/graph_runtime_codegen.cc)
TVM最大的特点是基于图和算符结构来优化指令生成,最大化硬件执行效率。其中使用了很多方法来改善硬件执行速度,包括算符融合、数据规划、基于机器学习的优化器等。它向上对接Tensorflow、Pytorch等深度学习框架,向下兼容GPU、CPU、ARM、TPU等硬件设备。
Pass是TVM中基于relay IR进行的优化,目的是去除冗余算子,进行硬件友好的算子转换,最终能够提高硬件运行效率。由tensorflow等深度学习框架生成的图机构中,含有很多可以优化的算子,比如expand_dim,len等,其实在编译阶段完全可以优化掉,从而能够减少硬件的计算,以及避免出现硬件不支持的算子。
上一章梳理了一遍TVM前端流程,前端完成了tensorflow算子到TVM算子的转换。这一章CNN网络中最普遍的卷积运算为例,看一下relay算子的表示
用了几章的篇幅写了一些粗读TVM代码的收获,虽然读了一点皮毛,但是还是掌握了TVM的基本架构和代码组成,算是给以后的精读打下了一点基础吧。从这章开始再从头捋一遍TVM代码,顺序是frontend-build-optimize-lower-target
Schedule是和硬件体系结构相关的一些列优化,Halide在其文章中对其做了以下定义,第一条是描述了数据计算顺序对性能的影响,第二条是数据的存储位置对性能影响,最后一条是多线程处理过程中,不同线程数据应该如何进行交互。
接着上一章继续深入代码,在BuildRelay中会调用Codegen函数。这个函数实现在src/relay/backend/graph_runtime_codegen.cc中。Codegen实现了内存的分配,IR节点到TIR节点的转换,tir图节点的一个调度优化。
TVM主要的编译过程如下图:Import:将tensorflow,onnx,pytorch等构建的深度学习模型导入,转化成TVM的中间层表示IR。Lower:将高层IR表示转化成低阶TIR表示。Codegen:内存分配和硬件可执行程序生成。
算符融合将多个计算单元揉进一个计算核中进行,减少了中间数据的搬移,节省了计算时间。TVM中将计算算符分成四种:
1 injective。一一映射函数,比如加法,点乘等。
2 reduction。输入到输出具有降维性质的,比如sum。
3 complex-out。这是计算比较复杂的,比如卷积运算等。
4 opaque。无法被融合的算符,比如sort。
使用FPGA进行神经网络加速需要编译器的支持,因为一个复杂的神经网络会产生大量的指令,手写指令不能满足通用化要求,费时又费力。编译器依据神经网络的图结构,产生硬件可执行指令序列。从广义上讲,编译器包括了前端和后端,前端主要实现从tensorflow等深度学习框架描述的网络结构形式到新表示的转化