TVM: End-to-End Optimization Stack for Deep Learning论文阅读

摘要

很多目前最为流行的深度学习框架,如 TensorFlow、MXNet、Caffe 和 PyTorch,支持在有限类型的服务器级 GPU 设备上获得加速,这种支持依赖于高度特化、供应商特定的 GPU 库。然而,专用深度学习加速器的种类越来越多,这意味着现代编译器与框架越来越难以覆盖所有的硬件。TVM旨在架起多种深度学习前端框架与后端硬件之间的桥梁,能够将深度学习模型高效地部署到异构的后端上并进行自动调优。轻松地将深度学习工作负载部署到各种硬件目标上,包括嵌入式设备、gpu、fpga和asic(例如TPU),它们在内存组织、计算等方面存在显著差异。

1. 引言

深度学习模型现在可以识别图像,处理自然语言,并在具有挑战性的策略游戏中击败人类。现代硬件稳步提升的计算能力在深度学习中存在的普遍性和在许多问题领域的相关性中发挥了突出作用。许多最流行的深度学习框架,如TensorFlow,MXNet,Caffe和PyTorch,通过将支持集中在一小类服务器级GPU设备上来利用现代硬件的强大功能 - 这种支持取决于高度工程化的使用和供应商特定的GPU库。然而,专业深度学习加速器的数量和多样性在野外迅速增加。这些加速器引入了采用挑战,因为它们引入了现代编译器和框架无法处理的新硬件抽象。

在当前特定方式中为各种硬件后端提供各种深度学习框架的支持是不可持续的。最终,目标是轻松地将深度学习工作负载部署到各种硬件目标,包括嵌入式设备,GPU,FPGA和ASIC(例如TPU),这在内存组织,计算等方面存在显着差异,如图1所示。鉴于这些要求,开发可以将深度学习程序的高级规范降低到任何硬件后端的低级优化代码的优化框架至关重要。

当前的深度学习框架依赖于计算图形中间表示来实现优化,例如自动微分和动态内存管理[3,7,4]。但是,图形级优化通常过于高级,无法处理硬件后端特定的操作员级转换。另一方面,深度学习框架所依赖的当前运营商级库过于严格且专业化,无法轻松跨硬件设备移植。为了解决这些弱点,我们需要一个编译器框架,它可以在图形和操作员级别上公开优化机会,从而在硬件后端提供有竞争力的性能。

图 1:CPU、GPU 与类 TPU 加速器需要不同的片上存储架构和计算基元。在生成优化代码时我们必须考虑这一问题
图2:TVM堆栈图。当前的堆栈支持:来自许多深度学习框架的描述,并针对主要的CPU,GPU和专用加速器。

基本优化挑战深度学习的优化编译器需要公开高级和低级优化。我们总结了计算图级别和张量运算符级别的四个基本挑战:

  • 高级数据流重写:不同的硬件设备可能具有截然不同的内存层次结构,因此启用运算符融合和优化数据布局的策略对于优化内存访问至关重要。
  • 跨线程的内存重用:现代GPU和专用加速器具有可跨计算内核共享的内存。传统的无共享嵌套并行模型不再是最优的。优化内核需要加载共享内存上的线程之间的协作。
  • Tensorized计算内在函数:最新的硬件提供超越向量运算的新指令,如TPU中的GEMM运算符或NVIDIA Volta中的张量核。因此,调度过程必须将计算分解为张量算术内在函数而不是标量或向量代码。
  • 延迟隐藏:虽然具有同步多线程和自动管理缓存的传统架构隐含地隐藏了现代CPU / GPU中的延迟,但专门的加速器设计通常倾向于更精简控制并且将大部分调度复杂性转移到编译器堆栈。但是,必须谨慎执行调度以隐藏内存访问延迟。

TVM:端到端优化堆栈我们提供TVM(如图2所示),这是一个端到端优化编译器堆栈,用于降低和调整深度学习工作负载到各种硬件后端。TVM旨在分离算法描述,调度和硬件接口。这个原则受到Halide [22]的计算/调度分离的启发,但通过将调度与目标硬件内在函数分离来扩展概念。这种额外的分离支持新型专用加速器及其相应的新内在函数。TVM提供了两个优化层:用于解决第一个调度挑战的计算图优化层,以及具有新调度原语的张量优化层,以解决剩余的三个挑战。通过组合这些优化层,TVM可以从大多数深度学习框架中获取模型描述,执行联合高级和低级优化,并为后端生成特定于硬件的优化代码,例如Raspberry Pi,GPU和基于FPGA的专用加速器。我们的论文做出了以下贡献:

  • 我们构建了一个端到端的编译优化堆栈,允许将高级框架(包括Caffe,MXNet,PyTorch,Caffe2,CNTK)中指定的深度学习工作负载部署到各种硬件后端(包括CPU,GPU和基于FPGA的加速器)。
  • 我们确定了在跨多种硬件后端为深度学习工作负载提供性能可移植性方面的主要优化挑战。我们引入了新颖的调度原语,以利用跨线程内存重用,新颖的硬件内在函数和延迟隐藏。
  • 我们在基于FPGA的通用加速器上评估TVM,以提供有关如何针对专用加速器进行最佳定位的具体案例研究。
  • 我们的编译器生成的可部署代码与最先进的供应商特定库具有竞争性,并且可以针对新的专用加速器后端。在本文的其余部分安排如下。我们在第2节中描述了图优化,在第3节中描述了张量算子调度。我们在这两个部分中包含实验结果,以定量评估我们提出的优化。我们将在第4节讨论运行时支持。我们的端到端评估在第5节中。相关工作在第6节中讨论。 
图3:双层卷积神经网络的示例计算图。图中的每个节点表示消耗一个或多个张量并产生一个或多个张量的操作。可以通过属性来参数化张量操作以配置其行为(例如,填充或步幅)。

2. 优化计算图

计算图计算图是在深度学习框架中表示程序的常用方法[3, 6, 7, 4]。图3示出了两层卷积神经网络的示例计算图表示。这种高级表示与低级编译器IR(如LLVM)之间的主要区别在于中间数据项是大型多维张量。TVM利用计算图形表示来应用高级优化:节点表示静态已知维度的张量上的操作,边缘表示张量操作之间的数据流数据依赖性。

计算图提供了计算任务的全局视图,但避免指定每个计算任务需要如何实现。可以在图上执行静态存储器规划传递以预分配存储器以保持每个中间张量。图6:融合的操作张量化操作之间的比较指示数据布局变换。

图4:TVM中的高级数据流优化
图5:操作融合传递的规则
图6 卷积、批量卷积、RELU的融合与非融合操作在NVIDIA Tesla K80上的表现,二者都由TVM生成
图7:数据布局要求可能受到张量的影响:这里是2×2

结果。此分配阶段类似于传统编译器中的寄存器分配过程。与LLVM IR类似,可以将计算图转换为功能等效的图以应用优化。例如,可以应用常量折叠传递来预先计算可以静态确定的图形部分,从而节省执行成本。图4概述了在TVM中实现的新颖图形级优化:运算符融合和数据布局转换。

操作员融合将多个操作员融合在一起是一种优化,可以大大缩短执行时间,特别是在GPU和专用加速器中。我们的想法是将多个运算符组合在一起,而不会将中间结果保存回全局内存。具体而言,我们认识到四类图运算符:内射(一对一映射),简化,复杂可熔(可以融合元素映射到输出)和不透明(不能融合)。我们应用图5中列出的规则将计算图转换为融合版。图6通过比较三个工作负载中融合和非融合版本的性能来演示此优化的影响。

数据布局转换张量操作是计算图的基本运算符。涉及计算的张量可以在不同的操作中具有不同的布局要求。例如,深度学习加速器可能会利用4 \times 4张量化操作,要求将数据平铺到块中以优化访问位置。图7显示了如何转换矩阵的数据布局以适应其数据上的张量化操作。优化数据布局首先要指定每个运算符的首选数据布局,因为约束条件规定了它们在硬件中的实现。然后,如果数据布局不匹配,我们将在生产者和消费者之间执行适当的布局转换。

图8:TVM中用于算法描述的张量表达式语言。每个计算操作都包含输出张量的形状,以及描述如何计算输出张量的每个元素的表达式。

图形级优化的局限性虽然高级数据流图优化可以极大地提高深度学习工作负载的效率,但它们只能与运算库提供的一样有效。目前,支持运算符融合的少数深度学习框架要求运算符库提供融合模式的实现。随着定期引入更多网络运营商,可能的融合内核数量可能会急剧增长。当针对越来越多的硬件后端时,这种方法不再可持续,因为所需数量的融合模式实现与需要支持的数据布局,数据类型和硬件加速器内在函数的数量组合增长。为后端特定运营商的这个庞大空间手工操作运算符内核是不可行的。为此,我们提出了一种代码生成方法,可以在下一节中生成张量运算符。

3. 张量优化操作

本节介绍了TVM如何为各种硬件后端生成相同运算符的精细版本。

3.1. 张量表达式语言

我们引入了一种数据流量张量表达式语言来支持自动代码生成。与高级计算图语言不同,其中张量操作的实现是不透明的,每个操作都以索引公式表达式语言描述,如图8所示。

我们的张量表达语言来自Halide [22],Darkroom [13]和TACO [18]等语言。我们的张量表达式语言支持常见语言(如C语言)中的常见算术和数学运算。我们明确地引入了一个可交换减少运算符,以便轻松地跨多个线程安排可交换减少。我们进一步介绍了一种高阶扫描运算符,它可以组合基本的计算运算符,以便随着时间的推移形成循环计算。TVM计算操作还支持缩放元组之间的减少,从而可以轻松支持argmax等功能。该表示可以描述高级数据流图中使用的所有张量操作,并涵盖深度学习中展示的常见模式。

3.2. 时间表空间

给定张量表达式,为每个硬件后端创建高性能实现仍然具有挑战性。作为示例,图9突出显示了应用于CPU,GPU和深度学习加速器设计的典型优化。每个优化的低级程序都是调度策略的不同组合的结果,给内核编写者带来了很大的负担。我们采用从Halide [22]中解决计划描述与计划优化的原则。计划是将计算描述降低到后端优化实现的特定规则。我们的想法是正式建模时间表空间和用于遍历此空间的转换,从而提供生成低级代码的不同方法。TVM的调度空间如图10所示。

图9:矩阵乘法代码示例,说明每个硬件后端公开的突出优化挑战。CPU需要跨并行组进行平铺和工作分配,以优化缓存局部性。GPU需要线程协作以允许线程组之间的共享内存重用。ASIC和FPGA加速器利用张量计算并依赖显式同步来隐藏内存访问延迟。

为了快速浏览计划空间,我们需要提供有效的计划基元来转换计划。图11显示了TVM中使用的常见调度基元的集合。许多这些原语反映了高性能计算中的实践。我们采用Halide的有用调度原语,并引入新的原语来解决GPU和专用硬件加速器带来的挑战。我们将在接下来的三个小节中详细描述这些原语。

3.3. 嵌套并行与合作

并行编程是提高深度学习工作负载中计算密集型内核的效率的关键。现代GPU提供大规模并行性,要求我们将并行编程模型烘焙到调度转换中。大多数现有解决方案采用并行编程模型,称为嵌套并行程序,这是一种fork-join并行机制。具体而言,我们可以使用并行调度原语来并行化数据并行任务。每个并行任务可以进一步递归地细分为子任务以利用目标体系结构上的多级线程层次结构(例如,GPU中的线程组)。

我们将此模型称为无共享嵌套并行性,因为一个工作线程无法在同一并行计算阶段查看其兄弟的数据。兄弟线程之间的交互发生在连接阶段,当子任务完成时,下一阶段可以消耗前一阶段产生的数据。该编程模型不允许线程彼此协作以便在同一并行级内执行集体任务。

图12提供了证明此限制的矩阵乘法示例。GPU上的矩阵乘法需要将工作划分为在线程组之间分布的切片,然后分配给每个单独的线程。在无共享嵌套并行性下,每个线程必须在还原阶段独立地获取其计算块所需的数据。1无共享方法的更好替代方案是跨线程协同获取数据。这种模式在使用CUDA,OpenCL和Metal等语言的GPU编程中是众所周知的,但尚未实现为调度原语。我们将内存范围的概念引入调度空间,以便可以将阶段标记为共享。如果没有内存范围,自动范围推断会将相关阶段标记为线程本地,如图12所示。共享任务需要计算组中所有工作线程的依赖关系。通过使用线程绑定原语在同一组线程中分配加载任务,我们可以有效地调度输入数据加载。值得注意的是,我们被迫使用相同的线程来处理共享工作负载的划分,因此线程可以在负载和计算阶段持续存在。此改进的实现需要额外的编译器支持具体而言,绑定推理算法需要能够通过将所有协作线程的任务合并在一起来推断共享任务的界限。此外,需要正确插入内存同步障碍,以确保消费者可以看到共享的加载数据。

图10:在TVM中计划空间表示。此示例显示了显式平铺矩阵乘法。数据流表示提供指定每个张量元素的计算的表达式。轴关系超图定义了原始环轴和变换环轴之间的双射关系。调度树表示计算结构的循环嵌套结构和生产者存储位置。调度树表示源自Halide [22],特别强调商店位置关系。数据流表示,轴关系图和调度树一起描述了可以降低到最右侧面板中显示的代码的调度。
图11:TVM中使用的计划基元(即转换)
图12:协作嵌套并行性的时间表。引入了内存范围,以实现并行作业之间的任务共享。由此产生的新计划可以更好地利用现代GPU中的共享内存层次结构。
图13 协作并行程序的内存装载图
图14:矩阵乘法性能比较,使用Halide,TVM有和没有合作的合作并行程序子的存储器加载模式,以及Nvidia K80上的cuBLAS。通过采用新的schedule原语,我们可以生成一个接近vendoroptimized性能的内核。

3.4. Tensorization:推广硬件接口

深度学习工作负载具有高算术强度,通常可以分解为张量运算符,如矩阵-矩阵乘法或1D卷积。这些自然分解导致了最近添加超出向量指令的张量计算基元的趋势。新兴的计算内在函数非常多样化,包括矩阵-矩阵乘法[17],矩阵-向量乘积[1]和1D卷积[9]等示例。这些新原语为张量运算符调度创建了新的挑战:调度必须使用这些原语来加速。我们将此称为张量化问题,类似于SIMD架构的矢量化问题。

Tensorization与矢量化显着不同。张量计算基元的输入是多维的,具有固定或可变长度,并指示不同的数据布局。更重要的是,我们不能求助于一套固定的原语,因为新的深度学习加速器正在出现,带有自己的张量指令。因此,我们需要一种能够支持新一代专用加速器的未来解决方案。 

为了解决这一挑战,我们将硬件接口与计划分开。具体而言,我们引入了张量内在声明机制。我们可以使用张量表达式语言来声明每个新硬件内在的行为,以及与之相关的降低规则。另外,我们引入了一个tensorize schedule原语来用相应的张量内在函数替换计算单元。编译器将计算模式与硬件声明匹配,并将其降低到相应的硬件内部。图15显示了张量化的示例。

张量表达式语言描述了用户的预期计算描述和硬件公开的抽象。Tensorization将时间表与特定的硬件原语分离,使TVM易于扩展以支持新的硬件架构。生成的张量调度代码与高性能计算中常见的实践一致:将复杂操作分解为重复的微内核调用序列。因此,我们也可以使用tensorize原语来利用手工组装微内核,这在某些平台上可能是有益的。例如,在AMD Vega GPU上将半精度GEMM张量化为4 \times 4手工微内核可以比最佳非张量版本产生超过的加速。

图16:具有显式同步的低级程序。此示例演示如何计算。硬件包含两个需要显式同步的指令流。仔细制作同步消息可以在指令流之间执行重叠。
图17:降低使用虚拟线程转换高级并行程序到显式同步程序模型的过程。

3.5. 编译器支持延迟隐藏

延迟隐藏是指通过计算重叠内存操作以最大化内存和计算利用率的过程。它需要不同的策略,具体取决于所针对的硬件后端。在CPU上,内存延迟隐藏是通过同步多线程[11]或硬件预取技术[16,8]隐式实现的。GPU依赖于许多线程的快速上下文切换,以最大限度地利用功能单元[26]。另一方面,专门的深度学习加速器通常倾向于更精简控制并将此问题转移到编译器堆栈。

图16演示了如何期望编译器显式处理遵循解耦访问/执行原理的流水线深度学习加速器的数据依赖性[23,17]。我们假设硬件流水线由内存和计算阶段组成,这些阶段可以在每个阶段由独立指令流控制的情况下同时执行。显式同步指令用于在流水线级之间发送信号,以指示给定任务何时完成,以便下一个从属级可以开始消耗或覆盖数据。这种类型的显式依赖性跟踪在具有FIFO队列的硬件中实现,并且直接控制程序员和编译器如何执行硬件任务。通过使用硬件公开的低级同步原语,我们可以有效地隐藏延迟。

使用显式同步操作在如此低级别的硬件编程是一项艰巨而艰巨的任务。为了减轻程序员的负担,我们提供了一个虚拟线程调度原语,允许程序员指定一个高级数据并行程序,TVM自动降低到低级显式数据依赖程序。降低过程如图17所示。算法以高级并行程序开始,然后插入必要的同步指令以保证每个线程内操作的正确执行顺序。最后,将所有虚拟线程的操作交错到一个单独的线程中。

图18:降低过程可视为虚拟化。降低是正确的。降低后,保留原始虚拟流中每个发送者/接收者对之间的顺序。
图19:延迟隐藏在基于FPGA的硬件线程本地指令上的影响流到硬件中较少量的物理指令流。只要加速器设计运行ResNet推断

虚拟线程降低的正确性虚拟线程的错误交错可能导致死锁。从概念上讲,在降低之前,每个线程都有自己的私有虚拟指令流。降低过程将这些虚拟指令流的指令映射到有限的物理指令流中。此过程需要正确性保证,因为物理指令流之间的物理消息队列需要在线程之间共享以传递依赖性。只要根据图18中显示的规则保留排序,我们就可以证明降低是正确的。以下定理为这种降低过程的正确性提供了必要且充分的条件。

定理3.1。设<降低后指令的部分顺序,S = \left \{ (x_i, y_i)) \right \}在降低之前设置所有成对的推送弹出指令。发送者发送的每个推送消息都会被相应的pop指令接收(降低是正确的),当且仅当

换句话说,同步消息的接收者的相对顺序需要与每个发送 - 接收对的发送者的相对顺序相同。证明了这种情况。

证明。矛盾证明。让a成为物理队列中的第一个发送者,将其消息发送给错误的接收者d。然后是\exists (a, b), (c, d) \in S

a < c,因为a是发送错误消息的第一个发件人。

由于定理条件,b < d

这意味着b在某些发送方h之前从队列中弹出消息,而由于消息队列的FIFO属性而在h < a中弹出消息。

这与以下事实相矛盾:a是队列中的第一个发送方发送给错误的接收方(h也发送给错误的接收方)。

当每个虚拟指令流降低到物理指令流时,可以通过以循环方式迭代虚拟线程来强制执行该条件。这种情况不仅适用于两个物理指令流的情况,而且还可用于将线程虚拟化为任意数量的物理指令流。

图20:TVM运行时中的RPC支持,可以轻松交叉编译,部署和配置嵌入式设备。

延迟隐藏的硬件评估我们证明了延迟隐藏在自定义硬件加速器设计上的有效性,我们将在5.3小节中对其进行更深入的描述。我们在加速器上运行ResNet的每一层,并使用TVM生成两个时间表:一个具有延迟隐藏,一个没有。具有延迟隐藏的调度在程序上应用虚拟线程以隐藏内存访问延迟。结果显示在图19中。通过隐藏将数据加载到加速器中的一些延迟,总体延迟隐藏在每个内核上实现了7%到54%的延迟减少。在计算资源方面,没有延迟隐藏最多可以获得52%的利用率,而延迟隐藏可以获得高达74%的利用率。

4. 代码生成与运行支撑

在优化计划之后,剩下的任务是生成可以在目标平台上运行的代码,并促进生成的内核的部署和配置。

代码生成对于数据流声明,轴关系超图和调度树的特定元组,我们可以通过迭代遍历调度树来生成降低的代码,推断输入张量的相关边界(使用轴关系超图),并在低级代码中生成循环嵌套。代码被降低为命令式C风格循环程序的内存表示。我们在此过程中重用了Halide的变体循环程序数据结构。我们重复使用Halide中的传递以用于常见的降低基元,例如存储器注册和展开,以及添加GPU /加速器特定的转换,例如同步点检测,虚拟线程注入和模块生成。最后,循环程序转换为LLVM或CUDA / Metal / OpenCL源代码。

运行时支持对于GPU程序,我们单独构建主机和设备模块,并提供运行时模块系统以使用相应的驱动程序API启动内核。我们使用C运行时API为我们的评估中使用的基于FPGA的深度学习加速器构建驱动程序库,该运行时API可以构造指令并将它们推送到目标加速器以供执行。然后,我们的代码生成算法将加速器程序转换为对运行时API的一系列调用。 

自动调整本文着重于提供一种新颖的优化框架,以实现深度学习系统的性能竞争编译。我们提供的优化为编译器提供了大量的时间表来探索,以便生成具有性能竞争力的代码。我们探索了初步的自动调度技术和自动内联运算的传递。高维卷积,矩阵乘法和深度卷积等复杂操作通过一组计划模板自动调整。我们相信将我们的优化与更复杂的搜索技术相结合[20]可以在未来产生进一步的改进。 

表1:在Raspberry Pi上ResNet的卷积运算符上的TVM和NNPack的比较。H / W表示高度和宽度,IC表示输入通道,OC表示输出通道,K表示内核大小,S表示步幅大小。
表2:Raspberry Pi上MobileNet的深度卷积运算符的TVM和MXKernel(MXNet中的本地运算符)的比较。H / W表示高度和宽度,C表示通道,M表示乘数,K表示内核大小,S表示步幅大小。由于深度卷积架构相对较新且尚未通过DNN库进行优化,因此我们选择了MXNet中的简单实现。TVM生成的运营商在MXNet中胜过执行。

远程部署Profling TVM还包括用于在嵌入式设备上轻松实现配置和自动调整的基础架构。传统上,针对嵌入式设备进行调优需要在主机端进行交叉编译,复制到目标设备,并对执行进行计时。此过程必须手动完成,并阻止编译,运行和自动调整流程的自动化。我们在编译器堆栈中提供远程函数调用支持:通过RPC接口,我们可以在主机编译器上编译程序,上传到远程嵌入式设备,远程运行函数,并在主机上的相同脚本中访问结果(图20)。我们发现这种方法非常有助于优化嵌入式设备(如Raspberry Pi和基于FPGA的加速器)的工作负载。

5. 评估

我们在三种类型的平台上评估TVM--嵌入式CPU,服务器级GPU以及在基于低功耗FPGA的SoC上实现的深度学习加速器。基准测试基于真实世界的深度学习推理工作负载,包括ResNet [12]和MobileNet [15]。我们将我们的方法与现有的深度学习框架进行比较,包括依赖于高度设计的供应商特定库的MxNet [7]和TensorFlow [2]。

5.1. Raspberry Pi评估

我们在Raspberry Pi 3B(四核1.2GHz)上评估了TVM的性能。我们使用Apache MXNet(commit:35ceea)作为我们的基线系统。MXNet使用NNPack中最先进的运算符(commit:57fc2c)进行卷积,使用OpenBLAS进行矩阵乘法。我们仔细调整了基线以获得最佳性能。我们还在NNPack实现中启用了Winograd卷积,用于3x3卷积和多线程。

表3:Raspberry Pi的端到端实验结果
图21:NVIDIA Tesla K80和GTX 1080上的TVM,MXNet,Tensor流媒体和Tensor流媒体XLA之间的ResNet和MobileNet工作负载的GPU端到端比较。

表1和表2显示了TVM张量运算符与ResNet和MobileNet的手动优化运算符之间的比较。我们观察到,TVM生成的运算符优于针对神经网络工作负载的手动优化NNPack版本。结果还证明了TVM能够快速优化新兴的张量运算符,例如现有DNN库不支持的深度[15]卷积运算符。最后,表3显示了两个网络工作负载的端到端比较,其中TVM分别比ResNet和MobileNet的基线性能高出2倍和12倍。

5.2. GPU评估

我们首先在NVIDIA Tesla K80和GTX 1080 GPU上比较TVM,MXNet,Tensor流量和Tensor流量XLA的ResNet和MobileNet工作负载的端到端性能。MXNet和Tensor流程都使用cuBLAS v8和cuDNN v7用于ResNet工作负载,并在MobileNet工作负载中实现自己的深度卷积版本,因为此操作相对较新,并且最新库尚不支持。另一方面,Tensor fl ow XLA使用JIT编译。图21显示,除了GTX 1080上的ResNet工作负载(其中TVM比MXNet稍微慢一点 (1.6%))之外,TVM在几乎所有配置下的端到端执行时间都优于其他框架。与Tesla K80上ResNet和MobileNet的第二次最佳实施相比,TVM将推理时间缩短了22%和5%,而GTX 1080上的MobileNet则推迟了7.7%。

我们对Nvidia Tesla K80的Resnet和MobileNet阶段进行了细分比较,如表4和表5所示。我们可以看到,与特定供应商相比,TVM可以生成具有竞争力的GPU内核。这是因为TVM具有大的设计空间来搜索以生成优化的时间表。更重要的是,对于深度卷积等新操作(表5),TVM可以生成优化良好的GPU内核。

AMD GPU案例研究为了突出TVM针对多个GPU后端的能力,我们尝试将现有的时间表移植到AMD Vega FE Air (gfx900)。从默认的GPU计划模板开始,我们处于GTX 1080性能的一个数量级,分别为ResNet和MobileNet实现10.2 ms和3.3 ms的端到端时间。在几个小时内快速调整计划进一步提高了ResNet性能约40%,MobileNet性能提高了约10%。这些结果强调,尽管AMD和NVIDIA GPU具有表面上不同的架构和不同的指令,但TVM通常足以捕捉它们的相似之处:主要在于它们的内存层次结构和线程组织。尽管如此,我们仍然期望通过AMD GPU特定结构更改默认计划进一步提高性能。

5.3. FPGA加速器评估 

Vanilla Inference Tensor Accelerator我们演示了TVM如何处理我们在FPGA上原型化的通用推理加速器设计中的加速器特定代码生成。我们介绍了Vanilla Inference Tensor Accelerator (VITA),它将以前的加速器提案[19,9,17]的特征提炼成极简主义的硬件架构。我们在此评估中使用VITA来演示TVM生成高效计划的能力,这些计划可以针对专门的加速器。图22显示了VITA体系结构的高级硬件组织。VITA被编程为张量处理器,以便以高计算强度(例如,矩阵乘法,高维卷积)有效地执行操作。VITA可以执行加载/存储操作,将阻塞的三维张量从DRAM带入SRAM的连续区域。VITA还为网络参数,层输入(窄数据类型)和层输出(宽数据类型)提供专用的片上存储器。最后,VITA为连续的加载,计算和存储操作提供显式同步控制,以最大化内存和计算操作之间的重叠。

方法我们在低功耗PYNQ板上实现VITA设计,该板采用时钟频率为667MHz的ARM Cortex A7双核CPU和基于Artix-7的FPGA架构。在适当的FPGA资源上,我们实现了一个时钟频率为200MHz的16 \times 16矩阵向量单元,它执行8位值的乘积,并在每个周期将它们累加到32位寄存器中。这种VITA设计的理论峰值吞吐量约为102.4GOPS / s。我们为激活存储分配32kB资源,为参数存储分配32kB,为微代码缓冲区分配32kB,为寄存器文件分配128kB。这些片上缓冲器远远不足以为单层ResNet提供足够的片上存储,因此可以进行有效内存重用和延迟隐藏的案例研究。

端到端的ResNet评估我们利用TVM在PYNQ平台上生成ResNet推理内核,并尽可能多地向VITA提供层。我们利用TVM生成仅用于CPU和CPU + FPGA实现的调度。由于其较浅的卷积深度,第一个ResNet卷积层无法在FPGA上有效地进行淹没,而是在CPU上进行计算。然而,ResNet中的所有其他卷积层都适合于絮凝。由于VITA不支持这些操作,因此还在CPU上执行残差层,批量标准化和激活等操作。

图23显示了仅CPU执行和CPU + FPGA执行之间的ResNet推理时间细分。大部分计算都花费在可以转换为VITA的卷积层上。对于那些卷积层,实现的加速是40倍。遗憾的是,由于Amdahl定律,FPGA加速系统的整体性能受到必须在CPU上执行的工作负载部分的瓶颈。我们设想扩展VITA设计以包含对这些。

图22的支持:VITA硬件设计概述。
图23:我们将ResNet工作负载中的卷积转换为基于FPGA的加速器。灰色条对应于不能加速的图层

由FPGA驱动,因此必须在CPU上运行。FPGA可以通过ARM Cortex A9在浮动卷积层上提供40倍的加速度。

其他运营商将进一步减少推理时间。这个基于FPGA的实验展示了TVM适应新架构的能力以及它们所暴露的硬件内在函数。

6. 相关工作

深度学习框架[3, 6, 7, 4]为用户提供了方便的界面,以表达深度学习工作负载,并在不同的硬件后端轻松部署它们。虽然现有框架目前依赖供应商特定的运营商库来执行其工作负载,但他们可以利用TVM的堆栈来生成更大的硬件设备的优化代码。

高级计算图DSL是表示和执行高级优化的典型方式。Tensorflow的XLA [3]和最近推出的DLVM [27]属于这一类。这些工作中计算图的表示是相似的,本文还使用了高级计算图DSL。虽然图级别表示对于高级优化是一个很好的选择,但它们太高级别,无法在各种硬件后端下优化张量运算符。以前的工作依赖于特定的降低规则来直接生成低级LLVM或度假村到供应商制作的库。这些方法需要为每个硬件后端和运营商变体组合进行重大的工程设计。

Halide [22]介绍了计算和调度之间的分离原则。我们采用Halide的洞察力,并在我们的编译器中重用其现有的有用调度原语。张量运算符调度还与GPU上的其他工作有关[24, 14],也适用于基于多面体的循环变换[5,25]。TACO [18]介绍了一种在CPU上生成稀疏张量运算符的通用方法。Weld [21]是用于数据处理任务的DSL。我们特别关注解决GPU和专用加速器深度学习工作负载的新调度挑战。在这些工作中,我们的调度原语可能被用于优化管道。更重要的是,我们提供了一个端到端的堆栈,可以直接从深度学习框架中获取描述,并与高级堆栈一起进行联合优化。

尽管趋势域特定的加速器用于深度学习[17,10],但尚不清楚如何构建编译堆栈以有效地针对这些设备。评估中使用的VITA设计提供了一种通用的方法来总结这些加速器的属性,并且能够进行关于如何对加速器进行此类编译的具体案例研究。本文提供了一种通用的解决方案,通过张量化和编译器驱动的延迟隐藏有效地针对专用加速器。

7. 结论

我们的工作提供端到端堆栈,以解决各种硬件后端的基本优化挑战。我们希望我们的工作可以鼓励更多的编程语言研究,编译,并为深度学习系统开辟硬件协同设计技术的新机会。我们开源了我们的编译器堆栈,并将开源VITA设计以鼓励进一步研究这个方向。

参考文献

TVM: End-to-End Optimization Stack for Deep Learning

TVM: End-to-End Optimization Stack for Deep Learning - 灰信网(软件开发博客聚合)

陈天奇等人提出TVM:深度学习自动优化代码生成器_网易订阅

TVM: End-to-End Optimization Stack for Deep Learning_诗蕊的博客-CSDN博客_tvm end to end

https://tongtianta.site/paper/39342

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值