本文主要参考了: The Deep Learning Compiler: A Comprehensive Survey
本文主要回答以下几个问题:
dl compiler
dl framwwork
有哪些dl compiler
的关键组件和技术dl compiler
都有哪些,从四个方向说下它们优缺点dl
的研究方向和价值为了解决 DL 库和工具的缺点,以及减轻在每个 DL 硬件上手动优化 DL 模型的负担。
DL 编译器将 DL 框架中描述的模型定义作为输入,并在各种 DL 硬件上生成高效的代码实现作为输出。模型定义和具体代码实现之间的转换针对模型规范和硬件架构进行了高度优化。具体来说,它们结合了面向 DL 的优化,例如层和运算符融合,从而实现高效的代码生成。此外,现有的 DL 编译器还利用了来自通用编译器(例如 LLVM )的成熟工具链,这在不同的硬件架构之间提供了更好的可移植性。与传统编译器类似,深度学习编译器也采用了包括前端、中间表示(IR)和后端的分层设计。然而,DL 编译器的独特之处在于多级 IR 的设计和 DL 特定的优化。
TensorFlow: 在所有 DL 框架中,TensorFlow 对语言接口的支持最全面,包括 C++、Python、Java、Go、R 和 Haskell。 TensorFlow 使用了一个原始算子的数据流图,该算子用受限控制边扩展来表示可微程序 [78]。 TensorFlow Lite 专为移动和嵌入式深度学习而设计,并提供 Android 神经网络 API。为了降低使用 TensorFlow 的复杂性,Google 采用 Keras 作为 TensorFlow 核心的前端。此外,TensorFlow 中的 Eager-mode 应用了类似于 PyTorch 的方法来更好地支持动态计算图。
Keras :Keras [19] 是一个高级神经网络库,用于快速构建 DL 模型,用纯 Python 编写。虽然 Keras 本身不是一个 DL 框架,但它提供了一个与 TensorFlow、MXNet、Theano 和 CNTK 集成的高级 API。借助 Keras,深度学习开发人员只需几行代码即可构建神经网络。此外,Keras 可以与其他常见的 DL 包集成,例如 scikit-learn。但是,Keras 由于过度封装,不够灵活,使得添加算子或获取底层数据信息变得过于困难
PyTorch: Facebook 用 Python 重写了基于 Lua 的深度学习框架 Torch,并在 Tensor 级别重构了所有模块,这导致了 PyTorch 的发布。作为最流行的动态框架,PyTorch 嵌入了用于在 Python 中构建动态数据流图的原语,其中控制流在 Python 解释器中执行。 PyTorch 1.0 集成了 PyTorch 0.4 和 Caffe2 的代码库,创建了一个统一的框架。这使得 PyTorch 能够吸收 Caffe2 的优势,以支持高效的图形执行和移动部署。 FastAI [39] 是基于 PyTorch 上层封装的高级 API 层。它完全借用 Keras 来简化 PyTorch 的使用。
Caffe/Caffe2: Caffe [42] 由加州大学伯克利分校设计用于深度学习和图像分类。 Caffe 具有命令行、Python 和 MATLAB API。 Caffe 的简洁性使得源代码易于扩展,适合开发者深入分析。所以,主要定位于研究,这使它从开始流行到现在。 Caffe2 建立在原始的 Caffe 项目之上。 Caffe2 在代码结构上与 TensorFlow 类似,但 API 更轻,更容易访问计算图中的中间结果
MXNet : MXNet 支持多种语言 API,包括 Python、C++、R、Scala、Julia、Matlab 和 JavaScript。它旨在具有可扩展性,并从减少数据加载和 I/O 复杂性的角度进行设计 [16]。 MXNet 提供了不同的范例:像 Caffe 和 Tensorflow 这样的声明式编程以及像 PyTorch 这样的命令式编程。 2017 年 12 月,亚马逊和微软联合发布了基于 MXNet 的 Gluon [69],这是一个类似于 Keras 和 FastAI 的高级接口。 Gluon 支持灵活的动态图和高效的静态图。
CNTK: CNTK 可以通过 Python、C++ 和 C# API 或它自己的脚本语言(即 BrainScript)来使用。 CNTK 被设计为易于使用且可用于生产中的大规模数据 [37]。但是,CNTK 还不支持 ARM 架构,这限制了它在移动设备上的使用。它使用类似于 TensorFlow 和 Caffe 的静态计算图,其中 DL 模型被视为通过有向图的一系列计算步骤。
PaddlePaddle: PaddlePaddle [11] 的原始设计类似于 Caffe,其中每个模型都可以表示为一组层。然而,PaddlePaddle v2 参考了 TensorFlow 采用了算子的概念,将层分解为更细粒度的算子,从而支持更复杂的 DL 模型。 PaddlePaddle Fluid 与 PyTorch 类似,因为它提供了自己的解释器,从而避免了 Python 解释器的有限性能。
ONNX: 开放式神经网络交换(ONNX)[66] 定义了一个可扩展的计算图模型,因此由不同 DL 框架构建的计算图可以很容易地转换为 ONNX。使用 ONNX,在 DL 框架之间转换模型变得更加容易。例如,它允许开发人员构建一个 MXNet 模型,然后使用 PyTorch 运行该模型进行推理。如图 1 所示,ONNX 已经集成到 PyTorch、MXNet、PaddlePaddle 等。对于尚不直接支持的几个 DL 框架(例如 TensorFlow 和 Keras),ONNX 为其添加了转换器
Historical Frameworks : 由于 DL 社区的快速发展,许多历史上的 DL 框架不再活跃。例如,PyTorch 已经取代了 Torch [20]。作为最古老的深度学习框架之一,Theano [86] 不再处于维护状态。 Deeplearning4J [85] 是一个基于 Java 和 Scala 的分布式深度学习框架,但是由于缺乏大型开发人员社区而变得不活跃。 Chainer [87] 曾经是动态计算图的首选框架,但被具有相似功能的 MXNet、PyTorch 和 TensorFlow 所取代
深度学习模型最具代表性的通用硬件是图形处理单元(GPU),它通过多核架构实现了高并行性。例如,自 Volta 架构以来,Nvidia GPU 就引入了张量核心。张量核可以并行加速混合精度矩阵乘法和累加计算,这在训练和推理期间广泛用于 DL 模型。与硬件协同优化,NVIDIA 还推出了高度优化的 DL 库和工具,例如 cuDNN [18] 和 TensorRT [73],以进一步加速 DL 模型的计算
专用硬件为深度学习计算完全定制,以将性能和能源效率提高到极致。 DL 应用程序和算法的快速扩展促使许多初创公司开发专用的 DL 硬件(例如 Graphcore GC2、Cambricon MLU270)。此外,传统硬件公司(如英特尔 NNP、高通 Cloud AI 100)和云服务商(如谷歌 TPU、亚马逊 Inferentia、阿里巴巴含光)也在这一领域进行了投资。最著名的专用 DL 硬件是 Google 的 TPU 系列。 TPU 包括矩阵乘法器单元 (MXU)、统一缓冲区 (UB) 和激活单元 (AU),它们由主机处理器使用 CISC 指令驱动。 MXU 主要由一个脉动阵列组成,该阵列在执行矩阵乘法时针对功率和面积效率进行了优化。与 CPU 和 GPU 相比,TPU 仍然是可编程的,但使用矩阵作为基元而不是向量或标量。 Amazon Inferentia 最近也备受关注。该芯片有四个神经核,专为张量级操作而设计,并且它具有大的片上缓存以避免频繁的主内存访问
神经形态芯片使用电子技术来模拟生物大脑。这类代表产品是 IBM 的 TrueNorth 和英特尔的 Loihi。神经形态芯片(例如 TrueNorth)在其人工神经元之间具有非常高的连接性。神经形态芯片还复制了类似于脑组织的结构:神经元可以同时存储和处理数据。传统芯片将处理器和内存分布在不同的位置,但神经形态芯片通常有很多微处理器,每个微处理器都有少量的本地内存。相比 TrueNorth,Loihi 的学习能力更类似于大脑。 Loihi 引入了脉冲时间依赖性突触可塑性模型 (STDP),这是一种通过突触前和突触后脉冲的相对时间来调节突触强度的机制。然而,神经形态芯片距离大规模商业化生产还很遥远。尽管如此,在计算机科学领域,神经形态芯片可以帮助捕捉被常规深度学习模型忽略的快速、终身学习的过程,而在神经学领域,它们有助于弄清楚大脑的各个部分是如何工作的共同创造思想、感觉甚至意识
dl compiler
的关键组件和技术1. **High-level IR : 负责抽象硬件无关的图结构**
为了克服传统编译器采用的 IR 限制 DL 模型中使用的复杂计算的表达的限制,现有的 DL 编译器利用具有特殊设计的高级 IR(称为图形 IR)来进行有效的代码优化。
图 IR 的表示。图 IR 的表示影响图 IR 的表达能力,也决定了 DL 编译器分析图 IR 的方式。
低级 IR 的实现。低级 IR 以比高级 IR 更细粒度的表示形式描述了 DL 模型的计算,这通过提供接口来调整计算和内存访问来实现目标相关的优化。
构建计算图后,前端应用图级优化。许多优化更容易在图级别识别和执行,因为图提供了计算的全局视图。这些优化只适用于计算图,而不是后端的实现。因此它们是独立于硬件的,可以应用于各种后端目标。前端优化通常由 pass 定义,并且可以通过遍历计算图的节点并执行图转换来应用。前端提供
1)从计算图中捕获特定特征和
2)重写图以进行优化的方法。除了预定义的通行证,开发人员还可以在前端定义自定义的通行证。一旦将 DL 模型导入并转换为计算图,大多数 DL 编译器就可以确定每个操作的输入张量和输出张量的形状。此功能允许 DL 编译器根据形状信息执行优化。
前端优化分为三类:1)节点级优化,2)块级(窥孔,本地)优化,3)数据流级(全局)优化
DL 编译器的后端通常包括各种特定于硬件的优化、自动调整技术和优化的内核库。特定于硬件的优化可以为不同的硬件目标高效地生成代码。然而,自动调整在编译器后端是必不可少的,以减轻手动获取最佳参数配置的工作。此外,高度优化的内核库也广泛用于通用处理器和其他定制的深度学习加速器
DL 编译器的通用设计架构主要包含两部分:编译器前端和编译器后端,如图 2 所示。中间表示 (IR) 分布在前端和后端。通常,IR 是程序的抽象,用于程序优化。具体来说,DL 模型在 DL 编译器中被转换为多级 IR,其中高级 IR 驻留在前端,低级 IR 驻留在后端。基于高级 IR,编译器前端负责与硬件无关的转换和优化。基于低级 IR,编译器后端负责特定于硬件的优化、代码生成和编译。
dl compiler
都有哪些,从四个方向说下它们优缺点流行的DL compiler有: TVM、nGraph、Tensor Comprehension (TC)、Glow 和 XLA。
四个方向分别是: frontend,backend, IR, and optimizations
dl
的研究方向和价值动态模型在深度学习领域变得越来越流行,其输入形状甚至模型本身在执行过程中可能会发生变化。特别是在 NLP 领域,模型可以接受各种形状的输入,这对 DL 编译器来说是一个挑战,因为数据的形状在运行之前是未知的。现有的 DL 编译器需要更多的研究工作来有效地支持新兴动态模型的动态形状。此外,随着未来的 DL 模型变得更加复杂,它们的整个控制流程可能不可避免地包括复杂的预处理/后处理程序。目前,大多数 DL 编译器都使用 Python 作为其编程语言,当由 Python 解释器执行时,预处理/后处理可能会成为性能瓶颈。现有的深度学习编译器尚未考虑到这种潜在的性能瓶颈。支持 DL 编译器中的整个控制流,可以与 DL 模型一起表达和优化前/后处理,这为模型部署中的性能加速开辟了新的机会
现有的自动调整技术专注于优化单个算子。然而,局部最优的组合不会导致全局最优。例如,应用于不同数据布局的两个相邻运算符可以一起调整,而无需在两者之间引入额外的内存转换。此外,随着边缘计算的兴起,执行时间不仅是 DL 编译器的优化目标。在自动调整中还应考虑新的优化目标,例如内存占用和能耗。特别是对于基于 ML 的自动调整技术,有几个方向值得进一步探索。首先,机器学习技术可以应用于自动调整的其他阶段,而不是成本模型。例如,在选择编译器选项和优化计划的阶段,可以使用 ML 技术直接预测可能性并开发算法以确定最终配置。其次,可以基于领域知识改进基于 ML 的自动调整技术。例如,在自动调整技术中结合特征工程(选择特征来表示程序)[99] 可能是实现更好调整结果的潜在方向
在深度学习编译器的设计中结合多面体模型和自动调整技术以提高效率是一个很有前途的研究方向。一方面,可以应用自动调优,通过重用前面的方法来最小化多面体 JIT 编译的开销配置。另一方面,多面体模型可以用来进行自动调度,可以减少自动调优的搜索空间。在 DL 编译器中应用多面体模型的另一个挑战是支持稀疏张量。一般来说,稀疏张量的格式(例如 CSF [84])用不再是线性的索引数组(例如,a[b[i]])来表示循环索引。这种间接索引寻址会导致非仿射下标表达式和循环边界,从而禁止多面体模型的循环优化 [14, 90]。幸运的是,多面体社区在支持稀疏张量方面取得了进展 [94, 95],并且集成多面体模型的最新进展可以增加 DL 编译器的性能机会。
支持子图划分的 DL 编译器可以将计算图划分为多个子图,并且可以以不同的方式对子图进行处理。子图划分为 DL 编译器提供了更多的研究机会。首先,它开辟了集成图形库以进行优化的可能性。以 nGraph 和 DNNL 为例,DNNL 是一个 DL 库,它利用大量高度优化的内核进行图形优化。 DNNL 与 nGraph 的集成使 DNNL 能够加速 nGraph 生成的子图的执行。其次,它开辟了异构和并行执行的可能性。一旦计算图被划分为子图,不同子图的执行可以同时分配给异构硬件目标。以边缘设备为例,它的计算单元可能由 ARM CPU、Mail GPU、DSP 和可能的 NPU 组成。从有效利用所有计算单元的 DL 编译器生成子图可以显着加速 DL 任务。
DL 框架中应用的传统量化策略基于一组固定的方案和数据类型,几乎没有针对在不同硬件上运行的代码进行定制。然而,在 DL 编译器中支持量化可以在编译期间利用优化机会来获得更有效的量化策略。例如,Relay [78] 提供了一个量化重写流程,可以为各种方案自动生成量化代码。为了支持量化,DL 编译器需要解决几个挑战。第一个挑战是如何在没有大量工程工作的情况下实现新的量化算子。 AWS 的尝试指出了一个可能的方向,即利用方言的概念,在基本算子上实现新的算子,从而可以重用图级和算子级的优化。第二个挑战是编译期间量化和其他优化之间的相互作用。例如,确定量化的适当阶段以及与算子融合等优化进行协作需要未来的研究调查
尽管现有的深度学习编译器在计算图优化和硬件特定优化方面都采用了类似的设计,但每种编译器在某些方面都有自己的优势。缺少一种共享最先进优化的方法,以及跨现有编译器对新兴硬件目标的支持。我们提倡统一现有 DL 编译器的优化,以便可以重用每个 DL 编译器中采用的最佳实践。此外,统一深度学习编译器的优化可以积累强大的力量来影响通用和专用深度学习加速器的设计,并为深度学习编译器和硬件的高效协同设计提供环境。目前,Google MLIR 是朝着这个方向发展的一个很有前景的举措。它提供了多级 IR 的基础设施,并包含 IR 规范和工具包,用于在每个级别跨 IR 执行转换。它还提供灵活的方言,以便每个 DL 编译器都可以为高级和低级 IR 构建其定制的方言。通过跨方言的转换,一个深度学习编译器的优化可以被另一个编译器重用。然而,方言的转变需要进一步的研究努力,以减少对精致设计的依赖。
可微编程是一种编程范式,其中程序是完全可微的。用可微分编程范式编写的算法可以自动微分,这对 DL 社区很有吸引力。许多编译器项目都采用了可微分编程,例如 Myia [89]、Flux [40] 和 Julia [13]。不幸的是,现有的深度学习编译器几乎不支持差分编程。对于现有的深度学习编译器来说,支持差分编程是相当具有挑战性的。困难不仅来自数据结构,还来自语言语义。例如,要实现从 Julia 到 XLA HLO IR 的转换,挑战之一 [24] 是 Julia 使用的命令式语言和 XLA 使用的符号语言之间的控制流不同。为了高效地使用 HLO IR,编译器还需要为 Julia 提供操作抽象,以支持 XLA 的特定语义,例如 MapReduce 和广播。此外,Julia 和 XLA 区分语义的差异,也需要编译器设计的重大改变
在边缘云系统中,DL模型通常被分成两半,每个部分模型分别运行在边缘设备和云服务上,这样可以提供更好的响应延迟和更少的通信带宽消耗。然而,边缘云系统的缺点之一是用户隐私变得容易受到攻击。原因是攻击者可以截获从边缘设备发送到云端的中间结果,然后使用中间结果训练另一个可以揭示偏离原始用户任务的隐私信息的模型。为了保护边缘云系统中的隐私,现有方法 提出在中间结果中添加具有特殊统计属性的噪声,这可以降低攻击者任务的准确性,而不会严重降低用户任务的准确性。然而,困难在于确定应该插入噪声的层,这需要大量的劳动来确定最佳层。上述困难为 DL 编译器提供了一个很好的机会来支持隐私保护,因为编译器维护了 DL 模型的丰富信息,可以自动引导跨层的噪声插入
通常,当前的 DL 编译器对模型训练的支持要少得多。总之,当前的深度学习编译器主要专注于弥合将深度学习模型有效地部署到各种硬件上的差距,因此他们选择推理作为主要优化目标。然而,扩展 DL 编译器的能力以支持模型训练将开辟大量研究机会,例如梯度算子的优化和高阶自动微分。