DNNFusion: Accelerating Deep Neural Networks Execution with Advanced Operator Fusion

DNNFusion:通过先进的算子融合加速深度神经网络的执行

作者/机构: Wei Niu (William & Mary, USA), Jiexiong Guan (William & Mary, USA), Yanzhi Wang (Northeastern University, USA), Gagan Agrawal (Augusta University, USA), Bin Ren (William & Mary, USA)

A1 主要贡献

深度神经网络(DNN)已成为移动设备上许多主流应用的核心。为了达到高精度,DNN模型变得越来越深,导致推理过程中的内存和计算需求很高。算子融合是提高DNN推理效率的关键优化手段,但现有框架(如TensorFlow, TVM)通常采用基于特定模式的融合方法,这些方法限制性太强,无法覆盖多样的算子和层连接,尤其是在极深模型中。而基于多面体(Polyhedral)的循环融合技术则在低层计算视图上工作,缺乏算子级别的信息,也可能错失融合机会。

为解决此挑战,本文提出了一个新颖且广泛的循环融合框架DNNFusion。其核心思想是在DNN的算子视图上工作,但通过对单个算子及其组合进行分类来扩展融合机会。本文的主要贡献如下:
* 高层抽象设计:设计了包括映射类型分析和扩展计算图(ECG)在内的高层抽象,用于算子融合。该方法利用高层DNN算子信息,能够处理多样的算子,并实现激进的优化。
* 基于数学属性的图重写:提出了一种新颖的基于数学属性的图重写框架,以简化ECG结构,优化DNN计算,并为后续的融合计划生成提供便利。
* 集成融合计划生成:提出了一种集成的融合计划生成方法,结合了高效的与机器无关的映射类型分析的优点,同时利用了分析结果数据库。
* 优化的融合代码生成:实现了优化的融合代码生成,将该方法集成到一个先进的端到端DNN执行框架中,并将优化后的框架称为DNNFusion。

通过对15个DNN模型的广泛评估,结果表明DNNFusion找到了高达8.8倍的融合机会,性能优于四种主流DNN执行框架,实现了9.3倍的加速。

A3 背景知识/关键Observation/设计原则

深层网络的祝福与诅咒

深层网络执行效率的挑战。本文通过一项研究揭示,高效执行深度神经网络(尤其是在资源受限的移动设备上)是一项挑战,其主要原因是高昂的内存和计算需求。随着DNN模型变得越来越深,机器学习研究人员通过减少每层的权重大小来训练更瘦更深的模型,以平衡计算负载和模型精度。然而,实验观察发现,模型的深度是影响执行效率的关键障碍。

深度对效率的影响分析。实验研究(表1)将执行效率与总计算量和层数相关联。例如,尽管DistilBERT和VGG-16的计算量相似,但拥有457层的DistilBERT的执行性能(78 GFLOPs/S)远差于只有51层的VGG-16(320 GFLOPs/S)。这主要有两个原因:首先,层数更多的模型通常会产生更多的中间结果,增加了内存/缓存压力。其次,深度模型通常每层的计算量不足,从而降低了处理器(尤其是GPU)的利用率。算子融合是减少内存需求和提高效率的有效技术,也是本文研究的重点。
表1. 一项旨在启发本工作的实证研究:多个DNN的总体计算、层数和执行效率之间的关系。结果是在高通Adreno 650 GPU上收集的,使用了一个优化的基线框架,该框架具有固定模式的算子融合功能,性能优于所有最先进的DNN执行框架(称为OurB+,稍后将介绍)。

DNN算子分类与融合机会分析

DNN算子分类

基于输入输出映射关系的分类。本工作研究了流行的DNN生态系统ONNX【47, Open Neural Network Exchange, 2017】支持的所有算子,发现每个算子的输入与输出之间的映射关系对于确定融合优化的盈利性和正确实现至关重要。基于输入元素和输出元素之间的关系,可以将所有算子分为五种高层抽象类型:一对一(One-to-One)、一对多(One-to-Many)、多对多(Many-to-Many,此处包含多对一)、重组(Reorganize)和洗牌(Shuffle)。这种分类是本文提出的融合框架的基础。表2展示了该算子分类的更多细节,并为每种映射类型提供了一两个代表性示例。如果一个算子只有一个输入,或者多个输入与输出的映射类型相同,则该算子的映射类型由其任意输入/输出对决定。如果存在多种映射类型的输入/输出对,则该算子的映射类型由更复杂的映射类型决定。
表2. DNN算子按映射类型的分类。这些算子在ONNX [47]中定义。

映射类型的数学定义。假设每个输入元素可以表示为$x[d_1, . . . , d_n]$,其中$x$是算子的操作数,$d_1, . . . , d_n$表示操作数元素的索引,一个输入和一个输出之间的映射类型分类如下:
* 一对一(One-to-One):存在一组函数$F, f_1, . . . , f_n$,使得
y[d_1,...,d_n] = F(x[f_1(d_1),...,f_n(d_n)])
并且每个$[d_1, . . . , d_n]$与用于计算它的相应$[f_1(d_1), . . . , f_n(d_n)]$之间存在一一映射关系。
* 一对多(One-to-Many):存在一组函数$F, f_1, . . . , f_n$,使得:
y[e_1,...,e_m] = F(x[f_1(d_1),...,f_n(d_n)])
其中 $m > n$,并且$[f_1(d_1), . . . , f_n(d_n)]$与$[e_1, . . . , e_m]$之间存在一对多的关系。
* 多对多(Many-to-Many):存在一组函数$F, f^1_{11}, . . . , f^1_{1n}, . . . f^k_{k1}, . . . , f^k_{kn}$,使得:
y[e_1,...,e_m] = F(x^1[f^1_1(d_1),...,f^1_n(d_n)],...,x^k[f^k_1(d_1),...,f^k_k(d_n)])
* 重组(Reorganize):我们有
y[e_1,...,e_m] = x[f_1(d_1),...,f_n(d_n)])
并且每个$[d_1, . . . , d_n]$与相应的$[f_1(d_1), . . . , f_n(d_n)]$之间存在一一对应关系。
* 洗牌(Shuffle):存在一组函数$F, f_1, . . . , f_n$,其中$F$是一个排列函数,使得:
y[e_1,...,e_n] = x[f_1(d_{F(1)}),...,f_n(d_{F(n)})]

融合机会分析

基于映射类型的融合分析。基于每个算子的映射类型,本工作提出了一种新的融合分析方法。其基本思想是,给定两个具有特定映射类型组合的候选融合算子,可以:1)推断出融合后操作的映射类型;2)简化该融合的盈利性评估和正确实现。

融合组合的分类。表3展示了该分析的细节。该表将不同映射类型的组合融合分为三组(分别显示为绿色、黄色和红色)。绿色表示这些融合是合法且有利可图的,无需进一步分析。红色表示这些融合已知是非法的或明显无利可图。黄色表示这些融合是合法的,但需要进一步的性能剖析来确定其盈利性。这种分析消除了对红色和绿色情况进行任何运行时分析或自动调优的需要。对于剩余的(黄色)情况,可以通过使用一个存储了各种融合组合离线收集的执行结果的性能剖析数据库来进一步加速编译。
表3. 映射类型分析。第一列和第一行(均无颜色)分别显示了融合前第一个和第二个算子的映射类型,而有色单元格显示了融合后算子的映射类型。绿色表示这些融合组合可以直接融合(即有利可图)。红色表示这些融合无利可图。黄色表示需要进一步的性能剖析来确定盈利性。

转换阻抗(Transformation Impedance)概念。这五种映射类型具有一系列所谓的转换阻抗(非正式定义为定性表达融合难度的度量),即当它们与另一种类型融合时,它们决定融合后映射类型的能力不同。“一对一”类型在所有五种类型中转换阻抗最低,而“重组”和“洗牌”的转换阻抗居中。“一对多”和“多对多”的转换阻抗最强,即当它们与其他算子融合时,结果的映射类型完全由它们决定。

代表性组合的解释
* 一对一与其他类型:当一个一对一算子与任何类型的算子融合时,由于其映射函数已知,对输出元素的内存访问可以映射到对输入元素的访问。DNN算子携带这种映射信息,保证了融合的正确性。这种融合通常需要有限的寄存器,且不会产生额外开销,因此是有利可图的。
* 重排或洗牌与其他类型:这两种类型是一对一的变体,具有特殊的输入输出映射函数。其正确性分析与一对一类似,但当与一对多或多对多类型算子融合时,可能引入数据复制、数据访问顺序改变或冗余计算,需要通过性能剖析来验证盈利性。例如,融合Expand(连续内存访问)和Transpose(按置换转置)可能会导致非连续的内存访问。
* 一对多与多对多:例如,Expand后接Conv。由于计算密集型的多对多算子(如Conv)期望以连续方式读取输入张量,而一对多算子可能会分散连续的输入张量元素,因此这种融合被认为是无利可图的。
* 多对多与多对多:例如,Conv后接另一个Conv。尝试合并执行会过于复杂,并可能对寄存器和缓存使用产生负面影响,因此被认为是无利可图的。
* 多对多与一对多:例如,Conv后接Expand或Resize。合并执行的数据访问模式可能有利也可能不利。Conv与Expand结合是可行的,因为Expand只扩展输入的单个维度。但如果Conv与一个沿不同维度复制输入张量的Resize结合,则可能对Conv的计算产生负面影响。因此,这类情况需要进一步的性能剖析。

扩展计算图(ECG)。基于以上分析,本文引入扩展计算图(ECG)作为中间表示(IR)。ECG在传统计算图【12, TVM: An automated end-to-end optimizing compiler for deep learning, OSDI 2018】的基础上,增加了更多与融合相关的信息,包括:mapping_type(表示每个算子的映射类型)、IR_removable(表示一个中间结果是否可以被完全移除),以及算子的数学属性,如是否满足结合律、交换律和/或分配律。

A2 方法细节

DNNFusion概览

三阶段优化流程。图1展示了DNNFusion的概览。它以基于编译器的DNN执行框架(如TVM、MNN)生成的计算图为输入,并添加关键信息创建扩展计算图(ECG)。基于ECG,DNNFusion的主要编译器优化和代码生成阶段包括三个组件:
1. 基于数学属性的图重写(第4.2节):优化ECG,消除不必要的操作和冗余计算。
2. 轻量级性能剖析驱动的融合计划探索(第4.3节):生成候选的融合块。
3. 融合代码生成及其他高级优化(第4.4节):为融合块生成优化代码,并执行块内和块间优化。
图1. DNNFusion概览。

基于数学属性的图重写

图重写的优化目标。DNNFusion首先采用一个基于数学属性的图重写过程来优化扩展计算图(ECG)。通过这个过程,DNNFusion能够:1)移除不必要的操作,2)消除冗余的中间数据拷贝,3)用更高效的算子(组合)替换昂贵的算子(组合)。这种图重写类似于经典的编译器优化“强度削减”【14, Operator strength reduction, ACM TOPLAS 2001】,但它作用于矩阵或张量上的复杂算子。这些规则比传统规则更复杂,并且是基于DNN中常见的操作。与现有工作(如TASO【28, TASO: optimizing deep learning computation with automatic generation of graph substitutions, SOSP 2019】)相比,我们的图重写旨在与算子融合协同工作,并为此特定目的识别了一组算子和规则。

重写规则示例。图2展示了利用数学属性(分配律、交换律和结合律)的具体示例。表4展示了更完整的规则集,并比较了重写前后的计算量(#FLOPS)。这些规则主要关注“一对一”映射类型的算子(如元素级乘法、加法等)和一些“多对多”的归约算子(如ReduceSum)。DNNFusion使用#FLOPS作为驱动图重写的度量标准,因为在大多数应用场景中,临时输出大小保持不变,或者在重写后通过融合成为非问题。
图2. 使用数学属性进行图重写的示例。结合律探索算子的最优执行顺序,并用更廉价的算子组合替换昂贵的组合。分配律探索算子的常见组合并简化计算结构。交换律切换算子的执行顺序以减少总体计算量。注:算子下方的字母(如(a)中Conv下的B)或矩形中的字母(如(b)中的C)表示该输入来自模型权重而非中间结果。菱形中的字母(如A)表示这是该算子块的输入。为了可读性,省略了块内的中间结果。
表4. 使用数学属性的图重写。由于空间限制,仅列出代表性的图重写规则。总的来说,DNNFusion在结合律、分配律和交换律类别中分别推导出了45、38和66条图重写规则。为了更好的可读性,我们省略了不相关的算子。⊙, +, −, abs, recip, square, sqrt 分别表示元素级乘法、加法、减法、绝对值、倒数、平方和平方根。BitShift 按元素计算给定张量元素的位移值。ReduceSum和ReduceProd 沿一个轴计算输入张量元素的归约求和与求积。Exp 按元素计算给定输入张量中元素的指数。#FLOPS 表示浮点运算次数。

具体规则阐述
* 结合律(Associative):通过利用结合律,图重写过程可以确定算子执行的优化顺序,从而用新的、更廉gao的组合替换昂贵的组合。如图2(a)所示,两个Recip和两个Mul算子的组合被一个Recip、一个Square和一个Mul的组合所取代,从而减少了一个Mul算子,并显著减小了中间结果的大小。
* 分配律(Distributive):应用分配律也能带来优化机会。如图2(b)所示,两个Mul算子和一个Add的组合可以被一个Add后跟一个Mul所取代,从而消除一个不必要的操作。
* 交换律(Commutative):该属性保证了交换两个算子位置的合法性,这通常能减少计算量。如图2(c)所示,BitShift和ReduceSum满足交换律,因此ReduceSum可以被安排在BitShift之前执行,减少了BitShift操作所应用的元素数量。

重写候选的识别。DNNFusion采用模式匹配【36, Compilation of pattern matching with associative-commutative functions, 1991】, 【37, Non-linear associative-commutative many-to-one pattern matching with sequence variables, arXiv 2017】来识别重写候选。然而,结合律和交换律的匹配是NP完全问题【5, Complexity of matching problems, J. Symbolic Computation 1987】。因此,DNNFusion首先将整个扩展计算图划分为许多子图,将不具备结合律、交换律或分配律的算子作为图中的分割点。在每个子图内,由于算子数量有限,DNNFusion可以探索所有可能的模式和模式组合。具体来说,会考虑分区内的所有匹配规则,并应用导致#FLOPS减少最多的规则。这个过程会重复进行,直到分区内没有更多的匹配规则。DNNFusion选择这种贪心策略以保持较低的优化开销。

轻量级性能剖析驱动的融合计划探索

核心思想。最优的融合计划生成需要巨大的搜索空间,并且已被证明是NP完全问题。为了控制成本,DNNFusion采用了一种基于其扩展计算图(ECG)IR和算子映射类型分类的新的轻量级(贪心)方法来探索融合计划。其高层思想如下:首先,DNNFusion从ECG中选择起始算子(称为融合种子算子)来限制搜索空间,选择标准是“一对一”映射类型的算子,因为它们具有较低的转换阻抗,可能产生更多融合,且内存需求较少。其次,从这些种子算子开始,DNNFusion分别沿着其后继和前驱探索融合机会。第三,DNNFusion基于一种结合了与机器无关的映射类型分析和性能剖析结果数据库的方法来创建融合计划。

图3. 融合计划探索示例。假设Add、Conv、Relu、Mul和Sub具有相同的输出形状和IRS大小。
图3. 融合计划探索示例。假设Add、Conv、Relu、Mul和Sub具有相同的输出形状和IRS大小。

融合计划生成算法。列表1展示了详细的融合计划探索算法,其目标是生成候选融合块,这些块在融合代码生成前会由后续的块内优化(第4.4节)进一步优化。图3用一个简化的例子说明了其基本思想。该算法包括三个主要步骤:

1 def generate_seed ( ops ) :
2   # find all one_to_one mapping operators
3   oto_ops = find_all_one_to_one ( ops )
4   # find the operator with minimum IRS size
5   return min ( op . IRS_size for op in oto_ops )
6 
7 def fuse_successor ( op , successor , block ) :
8   # Step 2.1: check the mapping relationship
9   relation = mapping_check ( op , successor )
10  # return if successor can not be fused
11  if relation == fuse_break : return
12  # Step 2.2: check the constraint requirement
13  if not check_constraint ( op , successor , block ) :
14    return
15  # fuse by profile - based selection
16  if relation == fuse_depend :
17    # Step 2.3: get latency w/ database / runtime
18    temp_latency = latency ( block + successor )
19    if temp_latency > latency ( block , successor ) :
20      return
21  block = op + successor
22  # Step 2.4: recursively head to successor
23  for fusing_op in successors ( successor ) :
24    fuse_successor ( successor , fusing_op , block )
25 
26 # Similar with fuse_successor
27 def fuse_predecessor ( op , predecessor , block ) :
28   # Similar with step 2.1 , 2.2 , 2.3 , 2.4
29 
30 # <Algorithm Entry >
31 unfused_ops = all_operators
32 # Step 1: start fuse from the selected seed
33 while ( sp = generate_seed ( unfused_ops ) )
34   block = [ sp ]
35   # Step 2: head to successor
36   for successor in successors ( sp ) :
37     fuse_successor ( sp , successor , block )
38   # Step 3: head to predecessor
39   for predecessor in predecessors ( sp ) :
40     fuse_predecessor ( sp , predecessor , block )
41   unfused_ops = unfused_ops - block

步骤 I:融合种子算子选择。DNNFusion选择具有最小中间结果的“一对一”算子作为融合种子(列表1第1-5行)。该启发式策略的目的是最终实现更多的融合。从具有较小中间结果的一对算子开始,为融合更多(较小的)算子创造了机会,从而增加了整体计算粒度,为整个DNN计算实现更高的并行度和更好的负载均衡。在图3中,Add、Relu、Mul和Sub都是“一对一”类型,Add被选为第一轮融合计划探索的种子。

步骤 II:沿种子后继的传播探索。DNNFusion首先逐个处理种子算子的后继(列表1第7-24行)。此步骤大致如下:首先,映射类型分析(步骤2.1)根据表3将潜在的融合结果分为三类:fuse_break(红色情况,中止融合)、fuse_through(绿色情况,直接进行)和fuse_depend(黄色情况,需要查询性能剖析数据)。其次,约束检查(步骤2.2)分析进一步融合是否可能不可取(例如,导致过多的寄存器溢出)。如果满足条件,DNNFusion会递归地继续探索融合候选。图3展示了此步骤中将Add与Conv及其他算子融合的示例。此步骤后,生成的候选融合块的映射类型为“多对一”,并包括五个算子(Add、Conv、Relu、Mul和Sub)。

步骤 III:沿种子前驱的传播探索。在处理完种子的后继方向后,DNNFusion使用与步骤II相同的算法处理其前驱方向(列表1第38-40行)。一个区别是,如果一个算子有多个直接前驱,可以选择与其中部分而非全部前驱融合。在图3的示例中,当前候选融合块与GEMM的首次融合尝试失败,因为它们都是“多对一”映射类型,根据表3这是一个fuse_break情况。

迭代。DNNFusion通过以上步骤完成一轮融合计划生成。如果还存在更多融合种子,它将从步骤II开始,用下一个种子进行迭代,直到没有可用的融合种子为止。

融合代码生成与优化

融合代码生成。一旦算法选定了融合块,DNNFusion会为每个融合块生成融合代码。这是通过一个从ECG构建的数据流树(DFT)和一组预定义的代码生成规则来完成的。DNNFusion分别为移动CPU和移动GPU生成C++和OpenCL代码。具体来说,DNNFusion遍历DFT,并利用基于抽象映射类型的代码生成规则为每对要融合的算子生成融合代码。为移动CPU和GPU各定义了23条代码生成规则,每条规则对应表3中的一个绿色或黄色单元格。其基本思想是,只要算子属于同一类型,相同的规则就能生成高效的代码。在融合两个以上算子时,每次融合两个算子都会调用这些规则。随后的代码优化(如向量化、展开、分块等)由现有的PatDNN框架【46, Patdnn: Achieving real-time dnn execution on mobile devices with pattern-based weight pruning, ASPLOS 2020】处理。
图4. 代码生成。

数据流树(DFT)遍历。图4展示了代码生成的示例。DNNFusion首先从ECG生成一个数据流树(DFT)。该DFT表示最终输出(Out)、所有中间结果(IRS)和所有输入(A, B, C, D),其边的方向与ECG相反。在融合代码生成期间,DNNFusion递归地遍历此DFT以识别输入/输出数据依赖关系(并融合相应的ECG操作)。例如,它首先识别出Out依赖于IRS3 + IRS5,然后识别出IRS3依赖于IRS2的倒数,依此类推,直到到达输入。DNNFusion还可以通过公共子树识别来发现DFT中的冗余计算,并在代码生成期间消除它们。

代码生成规则的应用。在DFT遍历期间,DNNFusion应用预定义的代码生成规则来为每对要融合的算子生成代码。例如图4中,DNNFusion首先将Add与其左输入分支Recip融合。Add和Recip都属于“一对一”映射,因此融合后的算子也是“一对一”。接着,DNNFusion继续将Mul(一对一)与这个新融合的算子融合,结果仍然是“一对一”。然后,这个新生成的算子与GEMM(多对一)融合,生成一个新的“多对一”算子。沿着Add的右输入分支也采取类似的步骤,直到所有算子都融合成一个新的“多对一”算子。DNNFusion依靠DFT遍历来确定输入/输出数据依赖,并利用算子映射类型来处理索引映射关系和生成适当的嵌套循环结构。

其他与融合相关的优化。DNNFusion还包括几种由其融合分析和融合代码生成启用的高级优化。
* 块内优化(Intra-block Optimizations):在代码生成前对ECG执行。Shuffle和Reorganize映射类型的算子通常涉及密集的数据移动。观察到当转换后的数据仅被一个后续算子使用时,这些耗时/耗内存的数据操作可以被消除,因为数据转换带来的局部性改善无法补偿中间结果生成和存储的开销。如图5所示,DNNFusion将这些数据转置和切片操作替换为改变数据索引的操作。
图5. 数据移动算子优化。
* 块间优化(Inter-block Optimization):对生成的融合代码执行。不同的算子偏好不同的数据格式。DNNFusion在全局层面考虑数据格式选择,从而避免冗余或不必要的转换。目前,DNNFusion采用一种启发式方法:对于一个特定的融合块,它识别出一个主导算子(其性能受布局选择影响最大,如CONV、GEMM),然后将该操作的最佳布局用于整个融合块。

A4 实验环境

  • 模型与数据集:评估涵盖15个主流DNN模型,包括图像分类(EfficientNet-B0, VGG-16)、目标检测(MobileNetV1-SSD, YOLO-V4)、动作识别(C3D, S3D)、图像分割(U-Net, Mask R-CNN, FasterRCNN)和自然语言处理(TinyBERT, DistilBERT, ALBERT, BERT-BASE, MobileBERT, GPT-2)等5种任务类型。数据集包括ImageNet, MS COCO, UCF-101, PASCAL VOC 2007, BooksCorpus和English Wikipedia。
  • 硬件配置
    • 主要平台:三星Galaxy S20手机,搭载高通骁龙865处理器(八核Kryo 585 CPU和Adreno 650 GPU)。
    • 可移植性测试平台:三星Galaxy S10(骁龙855,Kryo 485 CPU,Adreno 640 GPU)和荣耀Magic 2(麒麟980,ARM八核CPU,Mali-G76 GPU)。
  • 软件配置
    • 实现基于PatDNN【46, Patdnn: Achieving real-time dnn execution on mobile devices with pattern-based weight pruning, ASPLOS 2020】框架。
    • 所有CPU执行使用8个线程。
    • GPU运行使用16位浮点数,CPU运行使用32位浮点数。
    • 对比框架:MNN【29, MNN: A Universal and Efficient Inference Engine, MLSys 2020】, TVM【12, TVM: An automated end-to-end optimizing compiler for deep learning, OSDI 2018】, TensorFlow Lite (TFLite)【1, TensorFlow: A system for large-scale machine learning, OSDI 2016】, 和Pytorch-Mobile【48, Pytorch: An imperative style, high-performance deep learning library, 2019】。
    • 基线:OurB(关闭所有融合优化)和OurB+OurB基础上实现TVM的固定模式融合)。

A4 实验结果

  • 融合率:如表5所示,DNNFusion在支持所有目标模型方面是唯一的框架。与其他框架相比,DNNFusion的融合率更高,分别比MNN、TVM、TFLite和Pytorch高1.3-2.9倍、1.3-8.1倍、1.3-8.8倍和1.3-2.8倍。对于R-CNN和Transformer模型,融合率提升尤为明显(3.9-10.0倍),因为这些模型包含更多属于One-to-One, Shuffle, Reorganize类型的内存密集型层,为融合提供了更多机会。
    表5. 融合率评估:所有评估的DNN的计算层数和中间结果大小。CIL(计算密集型层):每个输入使用超过一次,例如MatMul, CONV。MIL(内存密集型层):每个输入仅使用一次,例如Activation。IRS:中间结果。'-'表示此框架不支持此模型。

  • 执行延迟:如表6所示,在移动CPU上,DNNFusion相比MNN、TVM、TFLite和Pytorch分别实现了1.4-2.6倍、1.5-3.5倍、1.4-3.3倍和1.6-9.3倍的加速。在移动GPU上,相比MNN、TVM和TFLite的加速分别为1.7-2.6倍、2.0-3.1倍和1.6-4.0倍。与我们自身的基线相比,DNNFusion比OurB+(固定模式融合)在CPU和GPU上分别快1.4-2.5倍和1.5-3.9倍;比OurB(无融合)快1.5-5.8倍。GPU上的收益更大,因为GPU对中间数据减少、内核启动开销降低和处理器利用率提升更敏感。
    表6. 推理延迟比较:DNNFusion、MNN、TVM、TFlite和PyTorch在移动CPU和GPU上的表现。#FLOPS表示浮点运算次数。OurB是我们的基线实现,关闭了所有融合优化,OurB+是OurB加上了类似TVM的固定模式融合。DNNF是DNNFusion的缩写,即我们的优化版本。'-'表示该框架不支持此执行。

  • 与TASO的比较:如图6所示,将TASO【28, TASO: optimizing deep learning computation with automatic generation of graph substitutions, SOSP 2019】优化的模型在TFLite上执行,DNNFusion相比之下在移动CPU上实现了1.4-2.6倍的加速。这表明DNNFusion中专为融合设计的图重写比通用图替换方法更有效。
    图6. 在移动CPU上相对于TASO优化执行的加速比。模型(计算图)由TASO优化,然后在TFLite上执行。

  • 优化效果分解:如图7所示,相较于基线OurB,图重写(GR)带来1.2-1.5倍加速,融合(Fuse)在此基础上额外带来1.6-2.2倍加速,其他优化(Other)再带来1.3-1.8倍加速(CPU数据)。GPU上的增益更高。图重写不仅自身带来加速,还为融合创造了更多机会,使融合性能提升了1.4-2.0倍。
    图7. y轴上的优化分解:相对于OurB(即无融合优化的版本)的加速比。GR、Fuse和Other分别代表图重写、融合和其他与融合相关的优化。

  • 内存与缓存性能:如图8所示(以YOLO-V4为例),DNNFusion在总内存访问(MA)、内存消耗(MC)和数据/TLB缓存未命中数方面均优于其他框架,因为它消除了更多中间结果的物化。GPU上的优势更明显,因其缓存容量更小。
    图8. 内存(左)和缓存未命中(右)分析。MA和MC分别表示内存访问和内存消耗。在移动CPU上比较了L1/L2/L3数据缓存和L1/L2 TLB缓存的未命中次数,在移动GPU上仅比较了L1/L2数据缓存。所有值都相对于DNNF(最优版本)进行了归一化。

  • CPU/GPU利用率:如图9(a)所示,DNNFusion实现了最高的CPU和GPU利用率,因为它通过激进的融合将更多计算组合在一起,形成了粒度更粗的执行,减少了循环和并行调度的开销。
    图9. (a) 移动CPU和GPU利用率。CPU利用率是8核的平均值。(b) 编译时间。TVM和DNNF在移动CPU上对YOLO-V4的比较。DNNF (w/o db)表示没有现有性能剖析数据库的情况;DNNF (w/ db)假设这样的数据库是预先计算好的。融合部分由于在TVM和DNNF中耗时都很短,因此不可见。

  • 编译时间:如图9(b)所示,TVM的编译时间主要由性能调优(Tuning)主导。DNNFusion的编译时间包括融合、性能剖析(Profiling)和调优。在没有预先计算的性能剖析数据库时,编译需要约3小时;而有数据库时,性能剖析变得很快,总时间缩短至约1小时,显著快于TVM。

  • 可移植性:如图10所示,在三星Galaxy S10和荣耀Magic 2等其他手机上的评估结果显示,DNNFusion表现出稳定的性能优势。在资源更受限的旧设备上,由于其显著减少了层数和中间结果大小,性能优势更为突出。
    图10. 可移植性评估。在三星Galaxy S10和荣耀Magic 2上进行。左边两图是YOLO-V4,右边两图是GPT-2。只有TFLite支持在移动CPU上运行GPT-2(不支持移动GPU)。

A5 结论

本文提出了一个名为DNNFusion的新型循环融合框架。其关键优势包括:1)一个由算子及其组合的映射类型和扩展计算图组成的新高层抽象,以及基于这些抽象的分析;2)一种新颖的基于数学属性的图重写方法;3)一个集成的融合计划生成机制。在15个不同的DNN模型和多个移动设备上的广泛评估表明,DNNFusion的性能优于四种最先进的DNN执行框架,最高可达8.8倍的加速。它首次使得许多之前不被支持的前沿DNN模型能够在移动设备上高效(甚至实时)执行。此外,DNNFusion改善了缓存性能和设备利用率,并减少了编译时的性能调优时间。

未来的工作将通过将DNNFusion与最新的模型剪枝技术相结合来增强其性能,以期实现更好的效果。