Auto Byte

专注未来出行及智能汽车科技

微信扫一扫获取更多资讯

Science AI

关注人工智能与其他前沿技术、基础学科的交叉研究与融合发展

微信扫一扫获取更多资讯

2021-2022 机器之心年度趋势报告 | 趋势解读:AI框架中动静态图技术发展趋势探析

本文是《2021-2022 年度 AI 技术趋势发展报告》中计算工程篇章中关于AI 框架中动静态图技术发展的趋势解读,点击「机器之心2021-2022年度AI技术趋势报告 」,获取报告。


随着数字经济的发展,AI 成为了最受瞩目的驱动技术之一,而 AI 框架则被看做是智能经济时代的操作系统,是 AI 学术创新和产品落地应用的载体。

根据技术所处环节及定位,当前主流 AI 框架的核心技术可分为基础层、组件层和生态层,如图 1 所示。

图1 AI 框架核心技术体系[1]


AI 基础层是 AI 框架的基础支撑,包括编程开发、编译优化、硬件使能三个主要层次,本文聚焦于编译优化中的「动静转换」。

编译优化层是 AI 框架的关键部分,负责完成 AI 模型的编译优化并调度硬件资源完成计算。而动静转换具体是指编译过程中动态图和静态图的转换方式。静态图在定义执行前的所有操作和网络结构,并将其呈现给传感器流,在训练期间提供了更高的性能,代价则是不易于使用、不够灵活。动态图计算是即时执行的,提供了更大的灵活性和更容易的调试,其代价是性能较低。

从 TensorFlow、PyTorch,到PaddlePaddle、MindSpore、MegEngine,AI 框架的动静转换经历了动静分离、动静结合到动静统一的发展过程。短短十几年时间,动静转换的技术取得了长足的进步,大大提升了 AI 算法/模型的开发效率,提高了 AI 产品应用的便利性,实现了计算效率和灵活性的平衡。


AI 框架中的静态图、动态图

静态图(Static Computational Graph)和动态图(Dynamic Computational Graph)是指 AI 框架中不同的计算图表现形式。计算图是用来描述运算的有向无环图,由节点和边组成,其中节点表征数据、边表征关系。大部分深度学习框架都会涉及张量及张量操作,针对张量的关系描述影响了 AI 框架的执行效率和效果,包括操作执行顺序、冗余操作处理、与底层设备的协同等。计算图(Computational Graph)是专门为解决这一问题提出的[1]。

静态图表现形式意味着程序在编译执行时先生成神经网络的结构,然后再执行相应操作,即“先定义后执行”,define and run,先定义好图,每次运行时只是改变输入数据;动态图表现形式则意味着程序按照开发人员编写的命令顺序执行,define and run,每次编译时都需要构建一个新的计算图,即计算图和数据都改变。

早期的 AI 框架采用的是动静分离的方式,即支持动态图框架和支持动态图框架,其中静态图框架的代表有TensorFlow1.x、Caffe2等,动态图框架的代表则有TensorFlow2.x、PyTorch 等。

静态图框架将神经网络模型编译成一整张图,再次运行时无需重新构建计算图(编译),利用图优化技术提高运行性能,运行速度快、跨平台运行和大规模部署较为便利。但是表达上有很多限制,应用起来不够灵活。

动态图每次运算都会加载一遍计算图,所以运行速度慢,但是程序会按照开发人员编写的命令顺序执行,从而使得代码实现和调试更加容易。我们知道,在 AI 模型/算法的工业场景应用中,不但要看效果,还要看速度。因此将模型加速是必不可少的步骤。

如信通院白皮书介绍,AI 框架需要提供更为优质的动静态图转换能力,从而提升后端运行高效性。从开发者使用 AI 框架来实现模型训练和推理部署的角度看,AI 框架需要能够通过动态图的编程范式,来完成在模型训练的开发阶段的灵活易用的开发体验,以提升模型的开发效率;通过静态图的方式来实现模型部署时的高性能运行;同时,通过动态图转静态图的方式,来实现方便的部署和性能优化。目前,国际主流基本均已经实现动态图开发、静态图部署的编程范式,具备动静态图转换的能力,不过基于开发效率考虑,动态图与静态图的转换与统一需要持续迭代优化 [2]。

AI 框架中动静态图技术分析

AI 框架经历了动静分离、动静结合、动静统一三个发展阶段。

动静分离

动静分离阶段的代表性框架为 2017 年发布的 TensorFlow 1.0,默认静态图,硬件亲和性能高,易部署。2018 年发布的 PyTorch 1.0,默认动态图,学习成本低,方便 debug,开发效率高。

动静结合

提出动静结合的考虑主要是既然动态图不容易转换到静态图,能不能让开发者自己标识模型中的哪部分 Layer 或者代码需要加速并且可以实现动静转换。基本的实现方式是在需要静态图的代码块上加上装饰符。

TensorFlow pre-2.0 还在要求开发人员首先定义静态图,而不是建立运行图的会话。这种方法导致更多重复使用的样板代码,较难使用普通的 Python 流控制,并且因为必须在调用 TensorFlow 会话中使用图之前定义图,所以它们在训练期间不够灵活。

而 2019 年正式发布 TensorFlow 2.0 时已经支持动静态图的转化,TensorFlow 2.0 默认动态图,这是其最引人注目的特征。它允许将一部分 Python 语法转换为可移植、高性能、语言无关的 TensorFlow1.x 语法,通过这种方式完成 TensorFlow1.x 静态图和 TensorFlow2.x 动态图的切换。

动静统一

动静统一是最理想的状态,开发者希望能够根据需要灵活切换动态图与静态图。然而动态图和静态图的切换面临很大困难。静态图可以看作是一种特殊的 DSL,则该特殊 DSL 实际上可以看做是一种静态语言。我们都知道 Python 是一个动态类型的语言,因此,我们不可能将 Python 无损转化到静态语言中。

目前静态图主要有两种方式[12]:

  • Tracing模式:框架把Python代码假执行一遍,记住算子执行序列(Tensor相关操作),作为正向图,并以此进行自动微分生成反向图,并进行正反向图的编译优化,最后以图模式进行执行

  • AST转换:框架获取Python代码的AST,然后通过编译的技术转换成正向图(这里面有Parser、Resolver、Specialize、Optimize等),并基于此生成反向图,同时再进行编译优化,最后以图模式进行执行。


针对这两种静态图,转换为动态图所面临的的难点分别是:

  • Tracing模式:这种方式拿到的图实际上是平铺的一个执行流,所以很难处理控制流的情况,比如循环,对于Tracing来说就是展开,但是有些情况下循环无法展开,如循环条件根据训练的收敛情况/算子的执行结果等。

  • AST转换:这种方式拿到的图是从Python的AST转换而来,好处是控制流和Scope信息都可以保留,但是挑战是那么多Python的语法和数据结构都要转换到静态图的表达,更难的是Python是动态类型的,所以这个AST到静态图的转换中需要一个复杂的类型/值推导过程。

在解决动态图和静态图转换的问题时,主要有以下两条路径:

(1)从动态图出发,框架可以在运行过程中自动的JIT,无需用户用修饰符指定,主要的关键技术就是Lazy Tensor;

(2)从静态图出发,在编译过程中如果发现有不支持的语法,可以保留到运行时进行fallback到Python,主要的关键技术就是JIT fallback。



本小结我们从不同的产品角度介绍动静统一的实现。

即时编译(Just-in-time compilation,JIT)

即时编译(Just-in-time compilation)是源自编译(Compiling)中的概念。以传统的 C/C++ 语言为例,我们写完代码之后, 一般会通过编译器编译生成可执行文件,然后再执行该可执行文件获得执行结果。如果我们将从源代码编译生成可执行文件的过称为 build 阶段, 将执行可执行文件叫做 runtime 阶段的话,JIT 是没有 build 阶段的,只存在于 runtime 阶段。JIT 一般被用在解释执行的语言如 Python 中,JIT 会在代码执行的过程中检测热点函数(HotSpot), 随后对热点函数进行重编译,下次运行时遇到热点函数则直接执行编译结果即可。这样做可以显著加快代码执行的速度[8]。

AI框架的JIT fallback主要是在静态图编译的时候,如果发现是编译器不支持的Python语法,可以把相关语句保留下来,生成解释节点,然后在后面的处理中,fallback到Python去执行相关的语句,从而实现相关语法的支持。

JIT主要面临的技术问题是:

(1)不支持的Python语法的识别;

(2)解释节点的推导和执行,解释节点有两个运行时机:首先是编译期的推导,一般而言,解释节点尽量在这个实际执行;其次是运行期的执行。


Lazy Tensor

Lazy Tensor是一种将动态图和静态图有机结合的方式,为了实现将动态图执行模式和JIT编译有效的结合起来,在运行时进行JIT加速的方式,不用打装饰符标签,本质上相当于自动打装饰符,由AI框架自己来决定加速的代码段。

Lazy Tensor是一种针对特定领域编译器(domain specific compilers, DSC)的技术,本质上解决的是对接新硬件后端的有无问题[11],Lazy Tensor建立在动态图的异步执行基础上,通过缓存API操作序列(而并不是真正执行),在到达一个barrier API时,进行统一的编译优化和执行,这就类似于开发人员手工标记修饰符来确定静态图执行的范围的处理方式,只不过Lazy Tensor中是自动打标签的。

当遇到Tensor的操作(主要是算子),如果不需要查看Tensor的具体内容,框架可以把这算子缓存下来,不发到device执行,从深度学习的范式看,大概率会缓存一大串op的执行序列,缓存到一定程度,可以把这个序列进行JIT编译优化,然后通过图的方式执行。

Tensor相关的API需要分为两类,一种是可以被表达成中间表示(intermediate representation,IR)图的API以及另一种无法被表达成IR的API。任意一个返回一个或多个Tensor的API,都是可以被转换成IR图,而返回非Tensor类型的API则无法被转换成IR图。这样Lazy Tensor机制就可以根据这个标识来确定哪些op序列可以进行JIT优化。

Lazy Tensor机制的好处:

  • 用户无感,易用性好

  • 语法限制少,理论上只要找到合适的Tensor操作序列都可以进行加速。

Lazy Tensor机制的局限:

  • JIT编译的开销比较大,所以最好是首次的JIT编译结果能够缓存,方便下次重复使用,用在静态网络下比较合适。

  • 动态情况下,比如动态shape/控制流,每次变化都会触发新的编译,从性能上看得不偿失。

  • 判断哪些是需要JIT的程序块、如何缓存JIT代码,以及判断是否需要重新JIT难度很大。


国内自主研发的AI框架中动静态图技术概览


百度飞桨

2019 年 4 月 23 日,在 2019 年百度开发者峰会上,深度学习平台 PaddlePaddle 首次对外公布了全景图,并曝光中文名——飞桨,意为快速划动的桨,期望 PaddlePaddle 实现快速成长。在此次峰会上,百度提出了「实现动态图和静态图的灵活转换」的技术路线[3]。

图2 百度发布的技术趋势图[3]


2020 年 3 月,百度更新 PaddlePaddle 1.7.0,对框架功能层面进行了全面增强,预测部署能力全面提升。其中,动态图的功能进一步完善,性能大幅提升,对 data independent 的动态图模型提供转为静态图可预测部署模型的功能。

  • 静态图:1.7 版本对上一版本(1.6.0~1.6.3)完全兼容,1.6+ 版本训练的模型均可在 1.7 版本下进行训练或预测。

  • 动态图:1.7 版本作了大量提升易用性的优化,有部分升级无法兼顾兼容性,包括功能优化、性能优化以及动态图部署。支持 TracedLayer 接口,实现 data independent 的动态图模型转为静态图可预测部署的模型。


2020 年 5 月,最新发布的飞桨核心框架 1.8 版本,带来了重磅更新,总结下来包括两点:

(1)动态图性能更卓越,经过多个版本的持续深度优化,飞桨动态图的训练性能已经媲美静态图。

(2)动静更加统一,完备实现了一键式动转静、动静混合编程,使动态图开发可以无缝衔接部署,并能通过静态图执行模式对部分模型实现进一步的训练加速。这意味着开发者可以采用动态图模式编写和调试 AI 模型,享受便捷灵活的开发体验;并可实现和静态图相当的高性能训练,并无缝衔接模型存储和部署应用。

目前发布的飞桨框架 2.0 及以上版本默认的编程模式是动态图模式,包括使用高层 API 编程和基础的 API 编程。因此飞桨 2.0 以上版本的动静统一主要是指“动转静”,如果想将默认的动态图模式切换到静态图模式编程,可以在程序的开始执行 enable_static()  函数。如果程序已经使用动态图的模式编写了,想转成静态图模式训练或者保存模型用于部署,则可以使用装饰器 @to_static 进行转换。完整方案如下[4]:

图3 动态图转换为静态图的方案


图4 @to_static的基本执行流程[4]


MindSpore

2019 年 8 月,华为提出了 AI 计算框架MindSpore的概念。2020 年 3 月,MindSpore 正式发布开源 v0.1.0-alpha 版本,提出了 Graph mode 和 PyNative mode[5],分别对应静态图和动态图模式。

在 MindSpore 中,静态图模式又被称为 Graph 模式,比较适合网络固定且需要高性能的场景,可以通过context.set_context接口中,参数mode入参为context.GRAPH_MODE 来设置成静态图模式。在静态图模式下,MindSpore 通过源码转换的方式,将 Python 的源码转换成中间表达形式,也就是 IR(Intermediate Representation),并在此基础上对 IR 图进行优化,最终在硬件设备上执行优化后的图[6]。MindSpore 使用的是一种基于图表示的函数式 IR,称为 MindIR。静态图模式就是基于 MindIR 进行编译优化,使用静态图模式时,需要使用 nn.Cell 类并且在construct 函数中编写执行代码。

在 MindSpore 中,动态图模式又被称为PyNative模式,可以通过context.set_context 接口中,参数 mode 入参为 context.PYNATIVE_MODE 来设置成动态图模式。在动态图模式下,用户可以使用完整的 Python API,此外针对使用MindSpore提供的 API 时,框架会根据用户选择的不同硬件平台(Ascend/GPU/CPU)或环境信息,将算子 API 的操作在对应的硬件平台上执行,并返回相应的结果。

MindSpore 支持在动态图下使用静态编译的方式来进行混合执行,MindSpore 中动静结合的方式主要是通过 ms_function 这个装饰符来实现,即在需要静态图的代码块上加上装饰符,框架会将 ms_function 修饰的函数进行静态图处理。ms_function 支持在PyNative 模式下,让被 ms_function 修饰的程序以静态图的方式来运行。ms_function 会将修饰的程序通过静态编译的方式来生成可执行图,整体下发执行,从而提升该修饰部分的执行性能:

@ms_function 
def tensor_add_with_dec(x, y): 
    z = x + y 
    return z

虽然动静结合是当前框架的主流模式,但是动静图结合的方式对开发者并不友好,需要开发者自己去判断哪里可以转成静态图,意味着开发者能够清楚两个事情:一是哪些地方可以加速;二是哪些代码块可以转成静态图(代码块里面代码的语法符合静态图的约束)。

MindSpore 也在推进动静统一的编码方式,静态图模式是 MindSpore 的默认模式,而动态图模式用于调试等用途。MindSpore 一直聚焦于 JIT fallback 的工作,以解决不少动态图无法转化到静态图语法的问题。MindSpore 针对动态图和静态图模式,首先统一 API 表达,在两种模式下使用相同的 API;其次统一动态图和静态图的底层微分机制。

图5 MindSpore的框架简示


MindSpore 通过 set_context 来实现动静态图的一键式切换:设置 context.set_context(mode=context.PYNATIVE_MODE) 切换成动态图模式,设置 context.set_context(mode=context.GRAPH_MODE) 即可切换成静态图模式,用户可拥有更轻松的开发调试及性能体验。

2022 年发布的 MindSpore 1.6 初步构建了 JIT fallback 的能力,在 Python AST 转换到静态图的时候,如果有不认识的语法可以 fallback 到 Python 解释器,实现更多语法的兼容,这个特性当前还在持续完善中,不过已经取得了不错的效果[7]。

JIT fallback 是从静态图的角度出发考虑静态图和动态图的统一。通过 JIT fallback 特性,静态图可以支持尽量多的动态图语法,使得静态图提供接近动态图的语法使用体验,从而实现动静统一。为了便于用户选择是否使用JIT fallback特性的能力,提供了开关 MS_DEV_ENABLE_FALLBACK,当前默认已经打开。如果需要关闭,可以使用以下命令:

export MS_DEV_ENABLE_FALLBACK=0


MegEngine

2020年3月24日,AI独角兽旷视科技宣布开源天元(MegEngine)——训练推理一体化、动静态合一的工业级深度学习框架。MegEngine的默认模式是静态图,通过使用即时编译技术(JIT),将动态图编译成静态图,并支持序列化,具体为使用 trace 装饰器的JIT和使用Dump导出序列化模型文件两部分。

MegEngine 提供了很方便的动静态图转换的方法,几乎无需代码改动即可实现转换。假设我们写好了一份动态图代码,其中训练部分代码如下:

for epoch in range(total_epochs):
    total_loss = 0
    for step, (batch_data, batch_label) in enumerate(dataloader):
        data = mge.tensor(batch_data)
        label = mge.tensor(batch_label)

        with gm:
            logits = model(data)
            loss = F.loss.cross_entropy(logits, label)
            gm.backward(loss)
            optimizer.step().clear_grad()

        total_loss += loss.numpy().item()
    print("epoch: {}, loss {}".format(epoch, total_loss/len(dataloader)))


我们可以通过以下三步将上面的动态图转换为静态图:

(1)将循环内的前向计算、反向传播和参数优化代码提取成单独的函数,如下面例子中的 train_func() ;

(2)将网络所需输入作为训练函数的参数,并返回任意你需要的结果(如输出结果、损失函数值等);

(3)用 jit 模块中的 trace 装饰器来装饰这个函数,将其中的代码变为静态图代码。
修改后的代码如下:

from megengine.jit import trace

@trace
def train_func(data, label, *, opt, gm, net):
    with gm:
        logits = model(data)
        loss = F.loss.cross_entropy(logits, label)
        gm.backward(loss)
        opt.step().clear_grad()
    return loss

for epoch in range(total_epochs):
    total_loss = 0
    for step, (batch_data, batch_label) in enumerate(dataloader):
        data = mge.tensor(batch_data)
        label = mge.tensor(batch_label)

        loss = train_func(data, label, opt=optimizer, gm=gm, net=model)
        total_loss += loss.numpy().item()
    print("epoch: {}, loss {}".format(epoch, total_loss/len(dataloader)))


计图

2020 年 3 月 20 日,清华大学计算机系图形实验室开源 AI 框架—计图(Jittor),这是首个由中国学界开源的 AI 框架,直接对标 PyTorch。计图是一个基于统一计算图的深度学习框架,用户并不需要手动切换,计图可以动态的将计算图拆分成可以优化的子静态图。让计图在保持动态图灵活性的同时,还可以发挥出静态图的运算性能。Jittor 是一个采用元算子表达神经网络计算单元、完全基于动态编译 JIT 的深度学习框架。

静态计算图和动态计算图各有优缺点,静态计算图的优点是高效,缺点是灵活性差;动态计算图的优点是易用,灵活性高,缺点是效率高。易用性和高效性不可兼得。对此,计图做出了“统一计算图”的创新。


图6 计图的统一计算图-1



统一计算图兼顾高效和易用,除了统一静态图和动态图,统一计算图还完成了多种统一的计算图:

  • 统一管理前向反向图,支持高阶导数;传统机器学习框架区分前向和反向传播,统一计算图将多次迭代的前向和反向计算图拼接,节省了大量的重复计算,提升灵活性和优化空间。


图7 计图的统一计算图-2


  • 统一管理CPU-GPU内存,突破GPU显存限制统一;

  • 统一同步异步运行接口,使得数据读取,内存拷贝,模型计算可以同时进行,提升性能。

  • 统一管理多次迭代的计算图,使得框架可以实现跨迭代的融合优化。

统一图的执行提供了一个命令式的界面,具有与动态图相同的灵活性。而且,它也像静态图一样高效。下图比较了静态图、动态图和统一图的不同执行方法[10]。

图8 使用(a)静态图、(b)动态图和(c)统一图的执行方法的比较


静态图执行在运行前定义了模型,然后用成批的数据执行计划。

在图 7(a) 中,第 1 行使用一个占位符方法来表示整个计算图所需的数据输入。大多数静态执行框架都使用这种方法,例如,TensorFlow 的 tf.placeholder()。首先,将操作符添加到计算图 G 中(第1-6行),然后图 G 被优化并在多次运行中执行(第7和8行)。第 4 行是无效的:X2 不能被打印出来,因为在调用 session.run 之前没有执行任何东西。静态图的优点是它们很简单,容易优化和部署。例如,图 7(a) 中的图是在执行前由所有四个运算符构建的,允许首先执行运算符融合。缺点是缺乏灵活性:调试静态图很困难;例如,我们不能像第 4 行建议的那样在构建过程中打印中间结果。根据训练期间发现的中间结果来改变模型就更难了。用户必须重建整个图,而由此产生的性能下降是不可接受的。

与前面几种 AI 框架实现动静态图统一的技术路线不同,计图的统一图是对 Lazy Tensor的尝试。下图说明了动态图执行和统一图执行之间的区别。三种类型的元运算符被赋予不同的颜色。图中显示了两个运算符管道:椭圆表示按照用户创建的顺序将运算符添加到图中,当 Python 解释包含它们的行时,运算符就会被添加进来;方框表示运算符的优化和执行,并显示运算符的执行顺序。

第二部分显示了用户动态创建的计算图的一部分。op1 是一个 element-wise 运算符,其输入是先前运算符的输出。op2 是一个 reindex 运算符,其输入也来自先前的运算符。op6 的输入来自 op5。op7 的输入来自 op4 和 op6。op8 的输入来自 op7,其输出被接下来的运算符使用。

第三部分显示了一个动态图的执行管道。op1 在被创建后立即被执行,op2、op3、...也是如此。创建和执行是耦合的,所以没有优化的余地。

第四部分显示了统一图的执行流水线。这些运算符是不按顺序执行的:加法和执行顺序不同。有了这个改进,统一图的执行可以优化和融合运算符 on the fly。首先,op1 被创建,但由于 lazy 评估,它不会被立即执行。反过来,op2、op3、op4 也被依次创建。然而,使用我们以前的方法,op2、op3 和 op4 可以在执行前被融合。静态子图由JIT 编译器进一步优化。在 op2、op3、op4 被执行后,op5 和 op6 被创建,它们可以与 op1 融合并一起执行。虽然 op1 是在 op2 之前创建的,但它最终还是在 op2 之后被执行。这种 out-of-order 执行或 lazy 评估的方法允许 op1 与后续运算符融合。同样地,op7 和 op8 也不会被评估,直到被接下来的运算符需要。

图9 动态图和统一图的执行管道。统一图可以不按顺序执行;运算符的添加和执行是解耦的。这允许在静态子图中对运算符进行优化和融合


OneFlow

OneFlow 是一流科技拥有的完全自主知识产权的分布式深度学习框架,OneFlow 着重解决传统深度学习框架在“多机多卡”的场景下算力浪费的问题。作为世界首个面向大模型大数据打造的人工智能计算框架,也是世界首个专为深度学习打造的异构分布式流式系统,OneFlow 针对超大规模训练、分布式、异构等对深度学习框架带来的挑战提出了解决方案。

从 2016 年底立项之日起,OneFlow 就是为大规模分布式而生,特色之一为“静态图机制”。2020 年 7 月在 GitHub 上开源时还不支持动态图。2021 年 9月27日,在中关村论坛国际技术交易大会上,一流科技创始人& CEO 袁进辉宣布深度学习框架 OneFlow v0.5.0 正式上线 GitHub。v0.5.0 中实现了一段代码的动态图与静态图转换。OneFlow认为,「在编码调试阶段,动态图的编程模式的体验最好,但当模型稳定后,静态图模式在运行效率方面更有优势。因此,最理想的框架是同时支持二者,使用户在一个框架上享受到最佳的动、静态体验,并且最好动、静态图可以自由转换。」在 OneFlow v0.5.0 中,开发者只需把使用动态模式开发的代码用nn.Graph封装起来,就可以享受静态图的好处。当然,要想实现完全自动的动、静态转换,还需要进一步攻关。2022 年 4月 6 日发布的 OneFlow v0.7.0 持续完善 nn.Graph 的功能,已支持和 PyTorch 一模一样的 Eager 体验,也就是说,OneFlow 实现了同时支持动态图和静态图。

图10 中关村论坛国际技术交易大会上,一流科技创始人&CEO袁进辉宣布深度学习框架OneFlow v0.5.0正式上线GitHub


OneFlow 中的动态图和静态图分别称为 Eager 模式Graph 模式 。OneFlow 对两种方式均提供了支持,默认情况下是 Eager 模式。OneFlow 动静转换十分方便,动态图(Eager)模式的代码简单改动几行就能转换为静态图(nn.Graph)模式。关于OneFlow的动静态转换,机器之心做过专门的报道[14]。OneFlow 提供的 Eager 模式,与 PyTorch 对齐,让熟悉 PyTorch 的用户可以零成本直接上手。OneFlow 提供的 Graph 模式,也基于面向对象的编程风格,让熟悉 Eager 开发的用户,只需要改很少量的代码,就可以使用高效率的静态图[13]。

动态图转静态图执行后(nn.Graph),得到了约 25% 的性能加速。nn.Graph 是一个面向对象风格的静态图类,它代表一个完整的静态计算图。对于预测任务,nn.Graph 可以只包括前向计算;对于训练任务,还可以包括后向计算和模型更新。nn.Graph 的基础接口和 nn.Module 的行为比较类似,比如添加子 Module,自定义算法执行逻辑,调用以执行一次计算,保存模型等。被添加进入 nn.Graph 的 nn.Module 对象,在 nn.Graph 里执行时,就会采用静态图模式执行,如此动态图下的计算逻辑就可以被静态图直接复用,这样就实现了动静执行的切换。特殊一点的是,Optimizer 也可以添加进入静态图,这样前向、后向、模型更新可以被加入一个完整的静态图做联合优化。


小结

本文回顾了 AI 框架中动静态图的技术发展趋势。作为 AI 框架中的关键技术环境,动静态图的灵活转换直接影响了 AI 框架的执行效率效果。研究人员希望能够结合两者优点实现动静统一,在网络调试或者网络研究的时候,使用动态图实现较高的工作效率;在生产环境上,无缝切换到静态图实现较高的性能高,部署快。

通过第三章介绍的国内主要 AI 框架的动静态图技术发展情况,我们可以看到国内几大公司近年来都致力于实现“动静统一”,并通过不同的技术手段不断改进。不过目前完全无损的快速无缝动静态图转换还很难实现,动静统一的研究道路任重而道远。



参考引用的文献
[1]Yoshua Bengio, Learning Deep Architectures for AI, 2009
[2]AI 框架发展白皮书2022,中国信通院
http://www.caict.ac.cn/kxyj/qwfb/bps/202202/P020220226369908606520.pdf
[3]
https://www.infoq.cn/article/uN7_M8bUxUE52Q8YAVev
[4]https://www.paddlepaddle.org.cn/documentation/docs/zh/guides/04_dygraph_to_static/basic_usage_cn.html
[5]https://gitee.com/mindspore/mindspore/releases/v0.1.0-alpha
[6]https://www.mindspore.cn/tutorials/zh-CN/r1.7/advanced/pynative_graph/mode.html#%E6%A8%A1%E5%BC%8F%E9%80%89%E6%8B%A9
[7]https://www.mindspore.cn/docs/programming_guide/zh-CN/r1.6/jit_fallback.html
[8]https://www.megengine.org.cn/doc/stable/zh/user-guide/model-development/jit/index.html
[9]https://www.tsinghua.edu.cn/info/1683/79188.htm
[10]Shi-Min, Hu D , Liang G Y , et al. Jittor: a novel deep learning framework with meta-operators and unified graph execution[J]. Science China(Information Sciences), 2020, v.63(12):118-138.
[11]Suhan A , Libenzi D , Zhang A , et al. LazyTensor: combining eager execution with domain-specific compilers. 2021.https://arxiv.org/pdf/2102.13267.pdf
[12]
https://zhuanlan.zhihu.com/p/416643687
[13]https://docs.oneflow.org/master/basics/08_nn_graph.html
[14]https://www.jiqizhixin.com/articles/2022-04-26-5


点击「机器之心2021-2022年度AI技术趋势报告 」,获取报告。已获得「机器之心Pro 会员」全功能账号权限的用户可直接下载查看。如您还没有「机器之心Pro会员」,扫描下方二维码关注「机器之心Pro」服务号(id:almosthuman2014pro),进入服务号主页,点击对话框,编辑发送「机器之心Pro会员」咨询,客服值班时间为工作日的10:00 - 19:00。


研究报告框架
暂无评论
暂无评论~