不同的硬件平台有不同的特性和优化需求。在现有机制下,新的异构硬件设备接入深度学习框架需要手工实现几百个算子对应的硬件 Kernel 代码,开发的工作量非常大。如果利用深度学习编译器,理论上仅需实现新硬件 IR 层面的对接,以及相应的硬件 IR 优化计谋就能完成与深度学习框架的对接,相比于实现几百个硬件 Kernel,开发的工作量会大幅减少。 3. 提升开发服从
一样寻常来说编译器前端需要将不同框架和格式的深度学习模型转换为编译器的内部 IR 并进行图级别的优化,CINN 作为飞桨框架原生编译器,可以直接利用飞桨框架提供的模型加载和中心表示(Paddle IR,简称 PIR)组件,因此 CINN 前端的主要功能是基于 PIR 进行图层级别的优化,并对子图进行分别为后端高性能 Kernel 代码天生提供支持。CINN 前端关键的流程可分为三部分: a. 组合算子拆分
飞桨框架中将算子分别为根本算子(也称作原子算子,语义上该算子无法更进一步拆分成其他算子。根本算子语义上可以通过重组等价实现组合算子的逻辑)和非根本算子两类大,由于非根本算子数量较多,并且在编译器中较难辨认和处理惩罚,因此我们利用组合算子拆分的方式将非根本算子拆分为等价的根本算子组合,原始计算图经过组合算子拆分后可以大幅提升性能的可优化空间。 b. 图优化 Pass
在计算图层级进行 PIR 的 Pass 优化,常见的图优化 Pass 包罗:常量折叠、死代码消除(DCE)、公共子表达式消除(CSE)、冗余算子消除、算子计算归并等。 c. 算子融合
图 2 算子融合示例
我们有两个算子 Relu 和 Scale,由于两个算子都是 IO 麋集型算子(计算复杂度不高)。正常情况下我们需要读取 A 和 B 一次,写 B 和 C 一次。但是对于融合之后的 Kernel(右图)而言,我们只需要读取 A 和写 C 一次,这样我们通过算子融合可以取得更少的访存次数,在 IO 麋集算子而言,可以极大提高性能。 具体的算子融合计谋实现非常复杂,这里不做展开先容,感兴趣的读者可以阅读相干源码 #cinn_group_cluster_pass。 2. 编译器后端
编译器后端主要负责将前端处理惩罚后的 IR 转换为目标硬件可实行的代码或硬件形貌。主要功能包罗基于硬件特性的 IR 优化、高效内存管理和代码天生等。 2.1. CINN AST IR