跳转至

第二章 AI编译器架构

学习目标

  1. 理解AI编译器出现的背景和时代需求
  2. 掌握AI编译器的整体架构和核心设计思想
  3. 了解主流AI编译器(TVM、XLA、Glow、MLIR)的设计特点和适用场景
  4. 理解AI编译器与传统编译器的关系和区别
  5. 了解AI编译器的发展阶段和未来趋势

引言

在第一章中,我们深入学习了传统编译器的基础知识,包括编译器的基本工作流程、 GCC 和 LLVM 的架构设计、以及常量折叠、死代码消除等经典优化技术。这些知识为我们理解AI编译器奠定了坚实的理论基础。

本章我们将目光转向AI编译器——近年来在人工智能领域快速发展的一项重要技术。AI编译器是为了解决深度学习模型在多样化硬件上高效运行而诞生的,它的出现标志着编译器技术在人工智能时代的新发展。

随着深度学习技术的广泛应用,AI系统面临着前所未有的挑战:AI模型结构在快速演化,底层计算硬件技术层出不穷,开发者不仅要考虑如何在复杂多变的场景下有效地将算力发挥出来,还要应对AI框架的持续迭代。AI编译器正是为了应对这些问题而广受关注的技术方向。

通过本章的学习,读者将系统地理解AI编译器的出现背景、架构设计和主流实现,为后续深入学习AI编译器的前端优化和后端优化打下基础。

2.1 AI编译器出现的背景

2.1.1 深度学习框架的崛起与挑战

深度学习在过去的十年间取得了突飞猛进的发展。从2012年AlexNet在ImageNet竞赛中取得突破性成绩开始,深度学习迅速渗透到计算机视觉、自然语言处理、语音识别、推荐系统等各个领域,推动了人工智能技术的广泛应用。

随着深度学习技术的快速发展,各种深度学习框架应运而生。TensorFlow由谷歌开发维护,是最早也是最流行的深度学习框架之一;PyTorch由Facebook(现Meta)开发,以其动态计算图和易用性迅速获得了广泛的用户基础;MindSpore由华为开发,采用了静态图和动态图融合的设计;PaddlePaddle由百度开发,是国内较早的开源深度学习平台;OneFlowMegEngine等框架也各有特色。

这些框架的出现极大地降低了深度学习开发的门槛,使得研究者和工程师可以更专注于模型设计和算法创新,而不必过多关注底层的计算细节。然而,深度学习框架的繁荣也带来了新的问题:

模型部署的碎片化:不同的框架使用不同的模型格式和计算图表示。一个在PyTorch中训练的模型,想要部署到不同的硬件平台,可能需要经过复杂的转换过程。

硬件多样性的挑战:深度学习硬件加速器种类繁多,包括GPU(NVIDIA、AMD)、NPU(华为昇腾、Cambricon)、TPU(谷歌)、DPU(DeepWave)等。每种硬件都有其独特的编程模型和执行方式,为模型部署带来了巨大的复杂性。

性能优化的困难:深度学习模型通常包含大量的计算操作,如何将这些操作高效地映射到目标硬件上,是一个极具挑战性的问题。手工优化虽然可以获得最佳性能,但需要大量的人力和专业知识。

2.1.2 传统编译器的局限性

在第一章中,我们学习了传统编译器(如GCC、LLVM)的基本原理。传统编译器在通用程序的编译方面已经非常成熟,但面对深度学习这一特定领域,传统编译器显现出明显的局限性:

缺乏对张量运算的支持:传统编译器主要面向标量运算设计,而深度学习中的核心操作是张量(多维数组)运算,如矩阵乘法、卷积等。传统编译器无法有效表达和优化这些张量操作。

缺乏对神经网络特定优化的理解:深度学习编译器需要进行一些领域特定的优化,如算子融合、批量归一化融合、激活函数融合等。传统编译器不了解这些优化的语义,无法自动进行。

计算图层面的优化缺失:传统编译器的优化主要在函数或基本块级别进行,而深度学习模型的计算图可以在更高层面进行优化,如公共子表达式消除、死算子消除等。传统编译器无法获取计算图的整体信息。

硬件映射的困难:不同的深度学习硬件有不同的特性和编程接口。传统编译器无法理解这些硬件特有的调度策略和内存层次结构,难以生成高效的硬件代码。

自动微分支持的缺失:深度学习训练依赖于反向传播算法,需要自动计算梯度。传统编译器没有这方面的支持,需要借助深度学习框架自身的自动微分机制。

这些局限性促使了AI编译器的诞生和发展。AI编译器专门为深度学习领域设计,能够理解神经网络的计算图结构,进行领域特定的优化,并支持多种硬件平台的代码生成。

2.1.3 硬件碎片化与软件栈问题

近年来,AI硬件呈现出爆发式增长的态势。不同的芯片厂商推出了各种各样的AI加速器,这些硬件在架构设计、性能特性、编程接口等方面都有很大的差异。

从硬件类型来看,主要包括以下几类:

GPU:以NVIDIA的CUDA生态为主导,AMD的ROCm也在持续发展。GPU拥有大量的并行计算单元,适合深度学习的大规模矩阵运算。

NPU(神经网络处理器):专门为神经网络设计的ASIC芯片,如华为昇腾系列、寒武纪MLU系列等。NPU在特定任务上能提供极高的能效比。

TPU(张量处理器):谷歌开发的专用AI加速器,采用脉动阵列架构,在大规模推理任务中表现出色。

FPGA:可编程逻辑器件,可以通过硬件描述语言或高层综合工具实现定制的神经网络加速器。

DSP:数字信号处理器,适合某些特定的信号处理任务。

这种硬件碎片化带来了严重的软件碎片化问题。每个硬件厂商都需要开发自己的软件栈,包括运行时库、编译器、调度器等。这导致了几个严重的问题:

重复开发:类似的优化技术(如算子融合、内存优化)被不同厂商重复实现,造成了巨大的人力浪费。

互不兼容:不同厂商的编译器和运行时互不兼容,开发者在一个平台上开发的模型无法直接移植到另一个平台。

质量参差不齐:一些小众硬件平台的软件质量可能不如主流平台,影响用户体验和AI应用的稳定性。

学习成本高:开发者需要学习多个平台的软件工具,增加了学习成本和开发复杂度。

正如编译器领域在个人电脑时代有GCC统一编译生态,在AI时代也需要一个类似的统一编译基础设施来解决碎片化问题。AI编译器正是朝着这个方向迈出的重要一步。

2.1.4 AI编译器的设计目标

针对上述挑战,AI编译器应运而生。AI编译器的设计目标主要包括:

提供统一的模型表示:AI编译器定义了一种或多种标准化的中间表示(IR),用于表示神经网络模型的计算图。这种表示独立于源框架和目标硬件,成为各方共同的"交流语言"。

实现跨平台部署:通过将模型转换为统一的中间表示,AI编译器可以支持将一个框架训练的模型部署到不同的硬件平台,大大简化了部署工作。

自动化性能优化:AI编译器通过一系列自动化的优化技术,如算子融合、内存优化、调度优化等,提升模型在目标硬件上的执行效率。

降低开发门槛:AI编译器使得开发者可以使用高层API进行开发,而不必深入了解底层硬件细节。同时,编译器工程师可以专注于编译优化,而不必为每个硬件平台单独开发优化代码。

支持自动化调优:AI编译器可以通过自动调优技术,自动寻找最佳的优化参数配置,降低手工优化的工作量。

2.1.5 AI编译器的黄金时代

2019年,图灵奖获得者David Patterson发表了"计算机架构新的黄金年代"演讲,指出随着摩尔定律的放缓,领域特定架构(DSA)将成为未来计算发展的主要趋势。2021年,LLVM之父Chris Lattner发表了"编译器的黄金年代"演讲,指出随着AI硬件的爆发式增长,AI编译器将迎来前所未有的发展机遇。

这些观点得到了业界的广泛认同。当前,AI编译器领域正处于快速发展的阶段,各种技术路线百家争鸣,新的研究成果不断涌现。可以预见,在未来十年,AI编译器将成为计算机系统领域最重要的发展方向之一。

2.2 AI编译器架构

2.2.1 AI编译器整体架构

AI编译器的架构设计借鉴了传统编译器的分层思想,但在具体实现上有其独特之处。一个典型的AI编译器通常包括以下几个主要组成部分:

前端(Frontend):负责接收来自不同深度学习框架的模型,将模型转换为AI编译器内部的中间表示(IR)。前端还需要处理模型的验证、类型推导等工作。

图优化器(Graph Optimizer):对计算图进行高层优化,包括算子融合、常量折叠、死代码消除、公共子表达式消除等。这些优化不依赖于具体的硬件,是平台无关的优化。

后端(Backend):负责将优化后的计算图Lowering(降级)到特定硬件的低层次IR,并进行硬件相关的优化,如内存布局转换、指令调度、寄存器分配等。

代码生成器(Code Generator):将优化后的IR转换为目标硬件的可执行代码,可能直接生成硬件指令,也可能生成调用硬件SDK的代码。

运行时(Runtime):负责管理模型执行时的资源调度、内存分配、算子调度等。运行时是模型真正执行时发挥作用的部分。

这种分层架构的优势在于:

  • 模块化:各层之间通过清晰的接口交互,可以独立开发和测试
  • 可扩展性:可以方便地添加新的优化Pass、新的硬件支持、新的框架支持
  • 可复用性:优化层可以被不同的前端和后端复用

2.2.2 多层IR设计

AI编译器的一个核心设计是多层IR(中间表示)。与第一章介绍的LLVM IR不同,AI编译器通常使用多层IR来在不同抽象层次上表示模型。

高层IR(图IR):这一层IR关注的是神经网络的整体结构,用节点表示算子,用边表示张量的依赖关系。高层IR不关注算子的具体实现,只关注算子之间的数据流和控制流。

中层IR(算子IR):这一层IR关注的是单个算子的内部实现。它将高层IR中的算子节点展开为更细粒度的操作,如循环、分支、内存访问等。

低层IR(硬件IR):这一层IR非常接近硬件的编程模型,描述了具体的指令序列、寄存器使用、内存访问模式等。低层IR与目标硬件紧密相关。

使用多层IR的优势在于:

  • 分离关注点:不同层次的优化可以独立进行,每层优化关注其特有的问题
  • 渐进式Lowering:通过逐层Lowering,可以更容易地实现渐进式的优化和调试
  • 多目标支持:同一套高层IR可以Lowering到不同的低层IR,支持多硬件目标

以TVM为例,TVM使用了多层IR:

  1. Relay IR(高层IR):用于表示神经网络的完整计算图
  2. Tensor IR(TIR)(低层IR):用于表示算子的循环嵌套执行

从Relay IR到TIR的过程,就是一个逐步Lowering、逐步具体化的过程。

2.2.3 前端与后端分离

与LLVM的设计思想类似,AI编译器也强调前端与后端的分离。这种设计使得:

  • 多框架支持:可以编写不同的前端来支持不同的深度学习框架
  • 多硬件支持:可以编写不同的后端来支持不同的硬件平台
  • 优化复用:优化Pass可以在不同的前端和后端组合中复用

一个理想的多框架、多硬件AI编译器架构如下:

框架1(PyTorch) ──┐
框架2(TF)    ────┼──► 前端 ──► 图IR ──► 优化器 ──► 算子IR ──► 后端1(NVIDIA GPU)
框架3(ONNX)  ────┤                                        └──► 后端2(华为NPU)
框架N(其他) ────┘                                        └──► 后端3(AMD GPU)
                                                                └──► 后端N(其他)

2.2.4 表达层面的演进

AI编译器在表达层面经历了从朴素表达到灵活表达的发展过程。

朴素AI编译器阶段的代表是TensorFlow 1.x。这一阶段的编译器主要处理静态计算图,开发者需要预先定义完整的计算图结构。计算图在执行前被完整地定义和优化,这种方式有利于编译器进行全局优化,但缺乏灵活性。

主要特点:

  • 静态图执行模式:计算图在运行前完全定义
  • 算子粒度固定:算子的边界由框架预先定义
  • 优化相对简单:主要是图级别的优化
  • 对动态控制流支持较弱

专用AI编译器阶段的代表是TVM、XLA等。这一阶段的编译器开始支持更灵活的表达,能够处理动态形状、控制流等复杂情况。同时,编译器开始提供更丰富的优化手段。

主要特点:

  • 支持更灵活的表达:如动态形状、动态控制流
  • 打开图算边界:可以进行细粒度的算子融合
  • 更丰富的优化:如自动调度、多级并行
  • 开始支持自动调优

通用AI编译器阶段是未来发展的目标。这一阶段的AI编译器将实现真正的多框架、多硬件统一表示,以及全自动的优化。

主要特点:

  • 统一表达层:图和算子的统一表示
  • 全自动优化:自动调度、自动分块、自动代码生成
  • 动静统一:动态图和静态图的统一处理
  • 高度可扩展:便于添加新的优化和新的硬件支持

2.2.5 优化层面的演进

AI编译器的优化也经历了从简单到复杂的发展过程。

图级别优化(前端优化):这一层次的优化关注计算图的整体结构,包括:

  • 算子融合(Operator Fusion):将多个连续的算子合并为一个,减少内存访问和Kernel调度开销
  • 常量折叠(Constant Folding):在编译时计算只包含常量输入的算子
  • 死代码消除(Dead Code Elimination):删除不会影响最终结果的算子
  • 公共子表达式消除(Common Subexpression Elimination):消除重复的计算子图

算子级别优化(后端优化):这一层次的优化关注单个算子的执行效率,包括:

  • 循环优化:循环展开、循环分块、循环重排等
  • 向量化:利用SIMD指令进行数据级并行
  • 并行化:利用多核进行线程级并行
  • 内存优化:数据布局优化、存储层次优化

调度优化:这一层次的优化关注算子在硬件上的执行策略,包括:

  • 静态调度:在编译时确定算子的执行顺序和线程分配
  • 动态调度:在运行时根据实际情况动态调整执行策略

2.2.6 与传统编译器的关系

AI编译器并非凭空出现,而是建立在传统编译器数十年技术积累的基础之上。两者的关系可以概括为:

技术传承:AI编译器大量借鉴了传统编译器的技术,包括:

  • IR设计和Pass机制
  • 优化算法(如常量折叠、死代码消除)
  • 代码生成技术

互补关系:AI编译器在传统编译器的基础上进行了领域特定的扩展:

  • 计算图抽象:处理神经网络特有的计算图表示
  • 张量运算优化:针对大规模矩阵运算的特殊优化
  • 硬件映射:支持专用AI加速器的代码生成

依赖关系:某些AI编译器在实际代码生成时会调用传统编译器:

  • TVM可以Lowering到LLVM IR,调用LLVM进行最终的代码生成
  • MLIR可以Lowering到LLVM IR,利用LLVM的支持生成CPU/GPU代码

独立发展:AI编译器也发展出自己独特的技术,如:

  • 自动调度(Auto Tuning)
  • 算子融合的优化规则
  • 针对AI硬件的专用优化

2.3 主流AI编译器介绍

2.3.1 TVM

TVM(Tensor Virtual Machine) 是由华盛顿大学周有志博士等人发起的一个端到端的深度学习编译器项目,现在是Apache软件基金会的顶级项目。TVM的目标是优化深度学习模型在各种硬件平台上的执行效率。

2.3.1.1 TVM的设计理念

TVM的设计理念可以概括为"分离计算与调度"。在TVM中,算子的计算(Compute)描述了"做什么",即算子的数学定义;调度(Schedule)描述了"怎么做",即算子在硬件上的具体执行方式。

这种设计的优势在于:

  • 灵活性:同一计算可以有多种不同的调度实现
  • 可优化性:通过调整调度可以方便地进行性能优化
  • 可自动化:可以编写搜索算法自动寻找最优调度
# TVM中的计算定义
N = tvm.runtime.convert(1024)
A = te.placeholder((N,), name='A')
B = te.placeholder((N,), name='B')
C = te.compute((N,), lambda i: A[i] + B[i], name='C')

# 默认调度
s = te.create_schedule(C.op)

# 自定义调度:分块
xo, xi = s[C].split(s[C].op.axis[0], factor=32)

2.3.1.2 TVM的架构

TVM的整体架构可以分为几个主要部分:

Relay:TVM的图级别IR,用于表示神经网络的完整计算图。Relay支持:

  • 静态和动态形状
  • 控制流操作(如if、while)
  • 自动微分(用于训练)
  • 丰富的算子库

Tensor IR(TIR):TVM的张量级别IR,用于表示算子的循环执行。TIR是Lowering的目标,也是进行细粒度优化的基础。

优化Pass:TVM实现了丰富的优化Pass,包括:

  • 图优化:算子融合、常量折叠、死代码消除等
  • TIR优化:循环变换、指令调度、内存优化等

后端支持:TVM支持多种后端目标:

  • CPU:X86、ARM、RISC-V
  • GPU:NVIDIA CUDA、AMD ROCm
  • 专用加速器:通过插件支持

2.3.1.3 Auto Tuning

TVM的一个重要特性是其自动调优(Auto Tuning)功能。由于调度空间的巨大,手工寻找最优调度几乎是不可能的。TVM提供了自动调优工具,可以自动搜索最优的调度配置。

TVM的自动调优经历了多代发展:

AutoTVM:第一代自动调优系统,基于模板。开发者需要为每个算子编写调度模板,定义可调参数的空间。AutoTVM使用统计学习方法(XGBoost)作为代价模型,预测不同配置的性能。

Ansor(Auto Scheduler):第二代自动调优系统,无需手工编写模板。Ansor自动生成覆盖广泛的搜索空间,并使用进化搜索进行优化。

Meta Schedule:第三代自动调优系统,提供了统一的API,支持手动调度、AutoTVM风格和Auto Scheduler风格的调度。

2.3.1.4 TVM的应用场景

TVM被广泛应用于:

  • 模型部署:将训练好的模型部署到各种硬件
  • 性能优化:优化模型在特定硬件上的执行效率
  • 硬件设计空间探索:评估不同硬件配置的性能
  • 研究平台:作为深度学习编译器研究的实验平台

TVM也被多家厂商采用进行定制开发,如希姆计算基于TVM支持了其AI芯片,华为的TBE(Tensor Boost Engine)也基于TVM框架开发。

2.3.2 XLA

XLA(Accelerated Linear Algebra) 是谷歌开发的深度学习编译器,最初作为TensorFlow的一部分开发,现在也被其他框架使用。XLA的名字来自"加速线性代数",反映了其核心优化目标。

2.3.2.1 XLA的设计特点

XLA的设计特点是简单、高效、与TensorFlow紧密集成。作为TensorFlow的默认编译器,XLA的主要目标是在不显著增加编译时间的情况下,提升TensorFlow模型的执行效率。

XLA的核心思想包括:

HLO(High Level Optimizer):XLA使用HLO作为其中间表示。HLO是一种平台无关的IR,描述了算子的高层计算逻辑。XLA的优化主要在HLO层面进行。

依赖分析:XLA通过依赖分析理解算子之间的数据流关系,为优化提供基础。

内存规划:XLA在编译时进行内存规划,预分配所有中间缓冲区的内存,减少运行时的内存分配开销。

代码生成:XLA针对不同的硬件后端生成优化代码,包括CPU(通过LLVM)、GPU(通过CUDA或ROCm)。

2.3.2.2 XLA的优化技术

XLA实现了多种优化技术:

算子融合:XLA的核心优化之一。XLA能够自动识别可以融合的算子模式,将多个算子融合为一个 fused kernel,减少内存访问。

常量折叠:在编译时计算常量表达式,减少运行时的计算量。

指令调度:优化指令的执行顺序,减少GPU上的寄存器冲突和内存访问延迟。

内存优化:通过缓冲区共享减少内存占用,优化数据布局提高缓存命中率。

2.3.2.3 XLA与TensorFlow的集成

在TensorFlow中,XLA可以通过以下方式启用:

# 启用XLA JIT编译
# 方法1:在session配置中启用
config = tf.config.ConfigProto()
config.graph_options.optimizer_options.global_jit_level = tf.config.OptimizerOptions.ON_1
tf.compat.v1.Session(config=config)

# 方法2:使用 tf.function 的 JIT 编译
@tf.function(jit_compile=True)
def train_step(x, y):
    # 启用XLA编译
    ...

XLA支持多种执行模式:

  • JIT编译:实时编译执行的算子,适合交互式使用
  • AOT编译:提前编译整个计算图,生成可执行文件,适合部署场景

2.3.3 Glow

Glow 是Facebook(现Meta)开发的深度学习编译器,最初作为PyTorch的一部分,现已发展为独立的开源项目。Glow的名字来自"Graph Lowering",反映了其核心技术特点。

2.3.3.1 Glow的设计理念

Glow的设计理念是"图Lowering + 内存计划 + 代码生成"。Glow认为,深度学习编译器的主要任务是将高层次的图表示Lowering到低层次的、可以直接执行的指令。

Glow的关键技术特点包括:

两阶段Lowering:Glow将Lowering过程分为两个主要阶段:

  • 高期望Lowering:将神经网络算子Lowering到 Glow 的内部节点表示
  • 低期望Lowering:将内部节点Lowering到具体的硬件指令

内存计划:Glow在编译时进行完整的内存计划,计算所有中间张量的存储位置。这使得Glow可以:

  • 复用临时缓冲区
  • 将活跃张量映射到更快的存储层次
  • 减少内存分配开销

量化支持:Glow提供了优秀的量化(Quantization)支持,可以将float32模型转换为int8等低精度格式,在支持的硬件上大幅提升性能。

2.3.3.2 Glow的架构

Glow的架构可以分为几个主要层次:

图表示层:处理神经网络计算图的输入和高层优化。

节点表示层:定义了各种节点类型,如、张量操作、神经网络特定操作等。

降低层:将高层节点Lowering到低层节点,进行设备无关和设备相关的优化。

代码生成层:针对特定硬件生成可执行代码。

Glow支持的硬件后端包括:

  • CPU:X86、ARM
  • GPU:NVIDIA GPU(通过CUDA)
  • 专用加速器:Glow提供了插件机制支持新的硬件

2.3.3.3 Glow的应用

Glow主要应用在:

  • PyTorch Mobile:Glow是PyTorch Mobile模型量化和优化的核心组件
  • PyTorch Live:用于移动端和边缘设备的AI应用
  • ONNX支持:Glow支持ONNX模型的加载和优化

2.3.4 MLIR

MLIR(Multi-Level Intermediate Representation) 是谷歌在2019年开源的编译器基础设施。MLIR不仅仅是一个AI编译器,而是一个通用的编译器框架,旨在构建连接不同抽象层次的编译器生态。

2.3.4.1 MLIR的设计理念

MLIR的设计理念是"可扩展的、可组合的中间表示框架"。MLIR认为,理想的编译器基础设施应该能够:

  • 支持多种抽象层次:从高级语言到硬件指令
  • 允许多个IR共存并相互转换
  • 提供共享的优化基础设施

MLIR的核心概念包括:

Dialect(方言):MLIR允许定义多个"方言",每个方言代表一个特定抽象层次或领域的IR。例如:

  • std 方言:标准的算术和内存操作
  • linalg 方言:用于线性代数的操作
  • gpu 方言:GPU特定的操作
  • tensor 方言:张量操作
  • air 方言:用于AI加速器的操作

方言的设计使得MLIR可以灵活地表示不同层次和领域的概念。

Operation(操作):MLIR中的基本计算单元。每个操作可以有输入、输出、属性,可以附加rewrite规则。

Type(类型):MLIR支持丰富的类型系统,包括整数、浮点数、向量、张量等。

2.3.4.2 MLIR的架构

MLIR的架构包括:

框架层:MLIR核心框架,包括:

  • Dialect定义机制
  • Pass管理机制
  • Pattern rewrite机制
  • 模式匹配和转换工具

标准方言:MLIR提供了一组标准方言,如:

  • builtin:内置的基本类型和操作
  • cf:控制流操作
  • arith:算术操作
  • func:函数操作
  • scf:结构化控制流操作

工具链

  • mlir-opt:MLIR的优化工具,运行各种Pass
  • mlir-translate:MLIR的转换工具,进行格式转换
  • mlir-cpu-runner:CPU执行器
  • mlir-reduce:测试用例简化工具

硬件支持

  • CPU后端:通过LLVM生成代码
  • GPU后端:通过NVCC或ROCm生成CUDA/HIP代码
  • 其他:通过插件支持

2.3.4.3 MLIR的应用

MLIR的应用场景非常广泛:

TensorFlow:TensorFlow 2.x使用MLIR进行图优化和XLA代码生成。

PyTorch:PyTorch的TorchMLIR项目使用MLIR作为其中间表示。

AI加速器:多家AI芯片公司使用MLIR作为编译器框架,如:

  • 华为的CANN使用MLIR
  • Graphcore的编译器基于MLIR
  • 英特尔的多款产品使用MLIR

通用编译器:MLIR也被用于构建其他领域的编译器,如:

  • SPIRV-Tools用于Vulkan图形API
  • Flang用于Fortran编译器

2.3.4.4 MLIR与TVM的比较

MLIR和TVM都是深度学习编译器领域的重要项目,但它们的设计目标和侧重点不同:

特性 MLIR TVM
设计目标 通用的编译器框架 专用的深度学习编译器
核心特点 多层次IR、可扩展方言 计算与调度分离、自动调优
方言支持 内置多种方言,支持自定义 主要关注Relay和TIR
硬件支持 CPU、GPU、AI加速器 CPU、GPU、AI加速器
自动优化 有限的自动优化 强大的Auto Tuning
学习曲线 较陡(概念多、API复杂) 较平缓(概念清晰)
生态 快速增长中 成熟稳定

两者的关系不是竞争而是互补。TVM可以作为MLIR的一个硬件后端,MLIR的计算图可以Lowering到TVM的算子表示。

2.3.5 其他AI编译器

除了上述四个主流AI编译器,还有一些值得关注的项目:

Apache MXNet(启蒙):虽然主要是一个深度学习框架,但MXNet也包含了自己的图优化引擎(IR)。MXNet的NDC(NNVM Digital Compiler)是其图优化和代码生成的核心。

Tensor Comprehensions(TC):由Facebook开发的工具,可以从高级数学表达式自动生成高效的GPU代码。TC使用 polyhedral 模型进行优化。

GEEP:微软开发的深度学习编译器,作为Windows ML的一部分提供。

PaddlePaddle Lite:百度飞桨的端侧推理引擎,提供了模型优化和硬件适配能力。

MindSpore Lite:华为昇腾的推理引擎,提供了模型优化和硬件加速能力。

2.4 AI编译器与深度学习框架的关系

2.4.1 框架与编译器的协作

AI编译器与深度学习框架之间存在着紧密的协作关系。深度学习框架负责模型的构建和训练,而AI编译器负责模型的优化和部署。

一个典型的协作流程如下:

  1. 模型定义:开发者使用深度学习框架(如PyTorch、TensorFlow)定义和训练模型

  2. 模型导出:将训练好的模型导出为中间格式(如ONNX、 SavedModel)

  3. 编译器前端处理:AI编译器的前端加载模型表示,进行模型验证和转换

  4. 图优化:AI编译器的优化器对计算图进行各种优化

  5. 后端代码生成:AI编译器的后端生成目标硬件的可执行代码

  6. 部署执行:优化后的模型在目标硬件上执行推理

# 典型的框架+编译器工作流程(以PyTorch + TVM为例)

import torch
import torchvision
import tvm
from tvm import relay

# 1. 定义和训练模型
model = torchvision.models.resnet50(pretrained=True)
model.eval()

# 2. 准备输入
input_shape = (1, 3, 224, 224)
input_data = torch.randn(input_shape)

# 3. 导出为TorchScript
scripted_model = torch.jit.trace(model, input_data)
scripted_model.save("resnet50.pt")

# 4. 加载到TVM
mod, params = relay.frontend.from_pytorch(scripted_model, input_info)

# 5. 优化
with tvm.transform.PassContext(opt_level=3):
    lib = relay.build(mod, target="cuda", params=params)

# 6. 部署
from tvm.contrib import graph_executor
dev = tvm.cuda(0)
module = graph_executor.GraphModule(lib["default"](dev))
module.set_input("data", tvm.nd.array(input_data.numpy(), dev))
module.run()
output = module.get_output(0).numpy()

2.4.2 PyTorch 2.0与编译器

PyTorch 2.0的发布标志着深度学习框架开始全面拥抱编译器技术。PyTorch 2.0引入了几个重要的组件:

TorchDynamo:PyTorch 2.0的核心创新。TorchDynamo是一个Python级别的即时编译器,能够在运行时捕获PyTorch代码并将其转换为优化的计算图。TorchDynamo使用了多种技术来确保可靠地捕获各种Python代码模式。

torch.compile:用户使用torch.compile来启用PyTorch 2.0的编译功能:

@torch.compile(mode="reduce-overhead")
def train_step(x, y):
    output = model(x)
    loss = criterion(output, y)
    loss.backward()
    optimizer.step()
    return loss

Inductor:torch.compile的后端之一,使用Triton生成优化的GPU代码。

TorchDynamo + XLA:PyTorch也可以通过TorchDynamo与XLA集成,生成XLA格式的优化代码。

PyTorch 2.0的目标是让"PyTorch代码运行得更快",同时保持PyTorch的易用性和动态性。

2.4.3 TensorFlow与XLA

TensorFlow从1.x到2.x的演进中,XLA始终是其编译器技术的核心。

TensorFlow 1.x时期,XLA作为可选的JIT编译器使用,主要用于加速静态计算图的执行。

TensorFlow 2.x时期,TF Lite和TF Serving等部署工具都大量依赖XLA进行模型优化。

TensorFlow 2.x还引入了tf.function装饰器,允许用户用Python代码定义计算图,然后由XLA进行JIT编译:

@tf.function(jit_compile=True)
def train_step(x, y):
    with tf.GradientTape() as tape:
        output = model(x)
        loss = criterion(output, y)
    gradients = tape.gradient(loss, model.trainable_variables)
    optimizer.apply_gradients(zip(gradients, model.trainable_variables))
    return loss

2.4.4 ONNX作为桥梁

ONNX(Open Neural Network Exchange) 是微软、Facebook等公司共同推动的神经网络模型交换格式。ONNX定义了一组标准的算子和数据类型,使得不同框架训练的模型可以相互转换。

ONNX在AI编译器生态中扮演着"桥梁"的角色:

  • PyTorch → ONNX:PyTorch可以导出ONNX格式的模型
  • TensorFlow → ONNX:TensorFlow可以通过转换工具导出ONNX格式
  • ONNX → AI编译器:各种AI编译器(如TVM、ONNX Runtime)可以加载和优化ONNX模型
# PyTorch导出ONNX
torch.onnx.export(
    model,
    input_data,
    "model.onnx",
    export_params=True,
    opset_version=11,
    do_constant_folding=True,
    input_names=['input'],
    output_names=['output'],
    dynamic_axes={'input': {0: 'batch_size'}, 'output': {0: 'batch_size'}}
)

ONNX Runtime是微软开发的ONNX模型推理引擎,它也集成了AI编译器的优化技术,可以对ONNX模型进行图优化和硬件加速。

2.5 AI编译器的发展阶段与未来

2.5.1 AI编译器的发展阶段

AI编译器的发展可以划分为三个主要阶段:

第一阶段:朴素AI编译器

这一阶段的代表是TensorFlow 1.x。朴素AI编译器的主要特点是:

  • 采用静态图执行模式,计算图在运行前完整定义
  • 算子粒度和边界预先固定,优化空间有限
  • 主要依赖硬件厂商提供的算子库(如cuDNN、MKL-DNN)
  • 缺乏自动化的性能优化能力

第二阶段:专用AI编译器

这一阶段的代表是TVM、XLA、Glow等。专用AI编译器的主要特点是:

  • 支持更灵活的表达,包括动态形状和控制流
  • 打开图算边界,进行细粒度的算子融合优化
  • 提供自动调度和自动调优能力
  • 开始支持多种硬件后端

第三阶段:通用AI编译器

这是AI编译器发展的未来目标。通用AI编译器追求:

  • 统一表达:图和算子的统一表示
  • 全自动优化:自动调度、自动分块、自动代码生成
  • 动静统一:动态图和静态图的统一处理
  • 高度可扩展:便于添加新的优化和新的硬件支持
  • 跨平台部署:一次编译,多平台运行

2.5.2 当前技术挑战

尽管AI编译器取得了显著进展,但仍面临诸多技术挑战:

动态形状处理:动态形状(如变长序列、不规则张量)在实际应用中很常见,但对编译优化提出了挑战。静态分析难以获取准确的形状信息,影响优化的有效性。

复杂控制流:包含循环、条件分支的控制流使得计算图的分析和优化更加复杂。

自动调优的效率:自动调优可以找到最优配置,但搜索空间巨大,调优时间可能很长。如何加速调优过程是一个重要问题。

多硬件协同:在异构计算环境中,算子可能分布在不同的硬件上执行。如何优化跨硬件的数据传输和同步是一个挑战。

稀疏性优化:稀疏神经网络在实际应用中很常见,但现有编译器对稀疏性的利用还不够充分。

2.5.3 未来发展趋势

展望未来,AI编译器的发展趋势包括:

更高的自动化程度:通过机器学习技术,自动学习最优的优化策略和调度配置,减少人工干预。

更广泛的硬件支持:随着AI芯片的发展,编译器需要支持越来越多的硬件平台和新的执行单元。

编译时与运行时的融合:静态编译和动态编译的结合,在编译时进行尽可能多的优化,同时保留运行时动态调度的灵活性。

统一的技术生态:不同的AI编译器之间可能出现更多的技术融合和标准统一,形成更健康的技术生态。

与传统编译器的深度结合:AI编译器将更深入地利用传统编译器的技术,如LLVM的代码生成、Polly的循环优化等。

2.6 小结

本章系统地介绍了AI编译器的架构和主流实现。核心要点回顾:

  1. AI编译器出现的背景:深度学习框架的崛起带来了模型部署的碎片化挑战,传统编译器的局限性无法满足AI领域的特定需求,硬件的多样性催生了对统一编译基础设施的迫切需求。

  2. AI编译器的架构:典型的AI编译器采用多层IR设计,包括图IR、算子IR和硬件IR,通过前后端分离实现多框架多硬件的支持。优化分为图级别优化和算子级别优化两个层次。

  3. 主流AI编译器:TVM以计算与调度分离和Auto Tuning为特色;XLA与TensorFlow紧密集成;Glow强调图Lowering和内存计划;MLIR提供通用的可扩展编译器框架。

  4. 与深度学习框架的关系:AI编译器与深度学习框架协作完成从模型训练到部署的完整流程,ONNX作为桥梁促进不同框架之间的模型转换。

  5. 发展趋势:AI编译器正在从朴素阶段向专用阶段发展,未来将向通用AI编译器的目标迈进,实现更高的自动化、更广泛的硬件支持和更智能的优化。

思考与练习

  1. 请解释为什么传统编译器难以满足深度学习领域的特殊需求。
  2. AI编译器的多层IR设计有什么优势?请以TVM为例说明Relay IR和Tensor IR的作用。
  3. 请比较TVM和XLA的设计理念和优化策略,指出它们的主要区别。
  4. MLIR的Dialect机制是什么?为什么说MLIR不仅仅是一个AI编译器?
  5. 请描述AI编译器在PyTorch 2.0中所扮演的角色,以及torch.compile的工作方式。
  6. AI编译器当前面临哪些技术挑战?未来可能的发展方向是什么?

2.7 参考文献与扩展阅读

  1. Chen, T., Moreau, T., Jiang, Z., et al. (2018). TVM: An Automated End-to-End Optimizing Compiler for Deep Learning. OSDI. — TVM的原始论文。

  2. TensorFlow XLA Documentation. https://www.tensorflow.org/xla — XLA官方文档。

  3. Rotem, N. (2019). Glow: Graph Lowering Compiler for Neural Networks. SysML. — Glow的原始论文。

  4. Lattner, C., Amini, M., Bondhugula, U., et al. (2020). MLIR: A Compiler Infrastructure for the End of Moore's Law. arXiv. — MLIR的原始论文。

  5. The Deep Learning Compiler: A Comprehensive Survey. https://arxiv.org/abs/2002.03794 — 深度学习编译器的综述论文。

  6. PyTorch 2.0 Documentation. https://pytorch.org/tutorials/intermediate/torch_compile_tutorial.html — PyTorch 2.0编译功能的官方教程。

  7. ONNX Documentation. https://onnx.ai/ — ONNX官方网站,包含规范和使用指南。