diff --git a/chapter_backend_and_runtime/overview.md b/chapter_backend_and_runtime/overview.md index 1707f22..77a0dc8 100644 --- a/chapter_backend_and_runtime/overview.md +++ b/chapter_backend_and_runtime/overview.md @@ -4,7 +4,7 @@ 如 :numref:`compiler-backend-architecture`所示,编译器后端处于前端和硬件驱动层中间,主要负责计算图优化、算子选择和内存分配的任务。首先,需要根据硬件设备的特性将IR图进行等价图变换,以便在硬件上能够找到对应的执行算子,该过程是计算图优化的重要步骤之一。前端IR生成是解析用户代码,属于一个较高的抽象层次,隐藏一些底层运行的细节信息,此时无法直接对应硬件上的算子(算子是设备上的基本计算序列,例如MatMul、Convolution和ReLU等),需要将细节信息进行展开后,才能映射到目标硬件上的算子。对于某些前端IR的子集来说,一个算子便能够执行对应的功能,此时可以将这些IR节点合并成为一个计算节点,该过程称之为算子融合;对于一些复杂计算,后端并没有直接与之对应的算子,但是可以通过几个基本运算的算子组合达到同样的计算效果,此时可以将前端IR节点拆分成多个小算子。然后,我们需要进行算子选择。算子选择是在得到优化的IR图后,需要选取最合适的目标设备算子。针对用户代码所产生的IR往往可以映射成多种不同的硬件算子,但是生成不同的算子执行效率往往有很大的差别,如何根据前端IR选择出最高效的算子,是算子选择的核心问题。算子选择本质上是一个模式匹配问题。其最简单的方法就是每一个IR节点对应一个目标硬件的算子,但是这种方法往往对目标硬件的资源利用比较差。目前来说对于现有的编译器一般都对每一个IR节点提供了多个候选的算子,算子选择目标就是从中选择最优的一个算子作为最终执行在设备上的算子。总的来说,在机器学习系统中,对前端生成的IR图上的各个节点进行拆分和融合,让前端所表示的高层次IR逐步转换为可以在硬件设备上执行的低层次IR。得到了这种更加贴合硬件的IR后,对于每个单节点的IR可能仍然有很多种不同的选择,例如可以选择不同的输入输出格式和数据类型,我们需要对IR图上每个节点选择出最为合适的算子,算子选择过程可以认为是针对IR图的细粒度优化过程,最终生成完整的算子序列。最后,遍历算子序列,为每个算子分配相应的输入输出内存,然后将算子加载到设备上执行计算。 -![编译器后端总体架构简图](../img/ch05/compiler-backend-architecture.jpeg) +![编译器后端总体架构简图](../img/ch05/compiler-backend-architecture.png) :width:`800px` :label:`compiler-backend-architecture` diff --git a/img/ch05/compiler-backend-architecture.jpeg b/img/ch05/compiler-backend-architecture.jpeg deleted file mode 100644 index 1b50bcc..0000000 Binary files a/img/ch05/compiler-backend-architecture.jpeg and /dev/null differ diff --git a/img/ch05/compiler-backend-architecture.png b/img/ch05/compiler-backend-architecture.png new file mode 100644 index 0000000..adfbba1 Binary files /dev/null and b/img/ch05/compiler-backend-architecture.png differ