首页 > 其他分享 >转载:【AI系统】自动微分的挑战&未来

转载:【AI系统】自动微分的挑战&未来

时间:2024-12-12 18:24:21浏览次数:4  
标签:AI 程序 微分 自动 计算 转载 过程

在前面的文章里面,分别介绍了什么是自动微分、如何实现自动微分,以及更加深入的自动微分的基本数学原理,并贯以具体的代码实现例子来说明业界主流的 AI 框架在自动微分实现方法,希望让你更加好地掌握自动微分端到端能力。

虽然计算机实现自动微分已经发展了几十年,不过在自动微分的演进过程和未来发展,仍然遇到诸多挑战,这里主要总结两点:1)易用性;2)高效性能。针对这两点的改进,也是自动微分技术未来演进可以重点优化和改进的方向。

易用性

易用性将是挑战的首位,是因为自动微分的数学原理比较固定,相对其他更加复杂的凸优化、群和商群等的数学原理而言,自动微分自动微分本身的数学原理相对简单,但其实现的难点在于:

  • 理想中的自动微分是对数学表达的分解、微分和组合过程;

  • 实际中的自动微分是对程序表达的分界、微分和组合过程。

数学表达程序表达之间存在显著的差异。

控制流的表达

如下公式所示,为对公式 $l_1 = x$ 具体的数学表达式进行多次展开:

$$
l_1=x \ l_(n+1)=4l_n (1−l_1) \ f(x)=l_4=64x(1−x)(1−2x)2(1−8x+8x2)^2
$$

在程序的实现过程中,并不会针对上述公式展开成:

f_3(x):
    l_1 = x
    l_2 = 4 * l_1 * (1 - l_1)
    l_3 = 4 * l_2 * (1 - l_1)
    return l_3

在更加通用的场景,大部分开发者或者程序会更加习惯于使用 for 循环对代码进行累加乘:

f(x):
    v = x
    for i = 1 to 3:
        v = 4 * v * (1 - v)
    return v

通过公式和对应的代码可以看出,在针对数学表达式中,递归属于一种隐式的存在,特别是针对下标及子表达式关系中。而在程序表达中,递归则显式的表达为语言中的 for 循环和入参 x。

虽然从计算的角度看二者是等价的(即数学计算过程相同及其计算结果相同),但是从自动微分的角度看却是截然不同。自动微分的计算机程序必须感知到 for i = 1 to 3 这个循环条件的计算过程和明确的入参 x ,这些并不属于开发者希望进行自动微分的部分。

换而言之,自动微分系统必须能够识别程序表达中用于计算控制流(例如 for、while、loop、if、else 等)的运算部分,并将其排除在微分过程外。

在主流的自动微分实现方法中,基本表达式法、操作符重载法的实现方案,好处在于:原生地只对特定的数据进行运算执行对应封装好的 API 或者操作符定义了自动微分规则,因此可以直接排除数学微分无关的控制流部分,只关注于具体的数学计算逻辑部分。

但是上述方法带来的问题,就是没有办法使用程序来表示闭包(closed form)的数学表达式进行"自动微分"求解,打破了数学表示完整性,不能够将将整个问题转换为一个纯数学符号问题。此外通过代码转换法,则通常需要进行程序分析或微分规则的扩展定义来完成控制流部分的过滤处理。

复杂数据类型

在数学表达式的微分过程中,通常处理的是连续可微的实数类型数据。然而在程序表达中,现代高级编程语言(Python、C/C++、JAVA 等)通常提供了多种丰富特性,用于开发者自定义组合数据类型,如 tuple、record、struct、class、dict 等。

特别地,在这些封装的组合数据类型中,除了常规意义中可微的计算机浮点数据类型(如 FP32、FP16、INT8 等),还可能包含一些用于描述数据属性的字段,如索引值、名称、数据格式等等,而这些字段也应该被排除在微分过程外。

如下所示,针对源码转换法的第一性原理 ANF 定义和 Python、C++ 都有其复杂的数学类型没有办法通过数学计算来表达。

<aexp> ::= NUMBER | STRING | VAR | BOOLEAN | PRIMOP

Python ::= [List, Enum, Tuple, Dict, DefaultDict]
C++ ::= [size_t, whcar_t, enum, struct , STL::list]

因此在实际的实现过程中,基本表达式法、操作符重载法一般只能通过预定义数据类型(如张量 Tensor 数据结构)来指定数据类型中哪些字段需要被微分,哪些不需要被微调,需要有更多的细节约束,开发者可定制的自由度较低。源码转换法则可以结合编译器或解释器的扩展来暴露一些接口给开发者,用于指定自定义数据类型的微分规则,但是灵活度太高实现起来不容易。

语言特性

语言特性更多是关于设计,比如在设计一门高级的编程语言时,希望它有泛型有多态,实现过程中的特性就会包括泛型和多态。此外针对高级编程语言(High-level programming language)可以作为一种独立于机器,面向过程或对象的语言。

因此,自动微分使用程序表达的实现过程中,开发者还可以有许多其他非原数学表达、非业务逻辑的代码,特别是针对高级编程语言的多态性、面向对象实现、异常处理、调试调优、IO 输入输出等代码及其高级特性,这些部分也需要被自动微分程序特殊处理。否则会造成数学表达和程序表达之间的混乱。

在早期的 TensorFlow1.X 版本针对自动微分的实现逻辑来看,其定义了明确的前后向 API 及其严格符号定义,需要按照一定的符号规则才能执行自动微分功能。开发者根据符号定义来写完成程序后,TensorFlow 执行时需要记住在前向传递过程中哪些运算以何种顺序发生。随后,在后向传递期间,TensorFlow 以相反的顺序遍历此运算列表来计算梯度。这就造成了 TensorFlow 易用性成为诟病的原因之一。

需求重写

物理系统的可微分模拟可以帮助解决混沌理论、电磁学、地震学、海洋学等领域中的很多重要问题, 但又因为其对计算时间和空间的苛刻要求而对自动微分技术本身提出了挑战。

其中最大的技术挑战是对电磁学、海洋学和地震学等问题中最核心的微分方程求解过程的自动微分。这些微分方程常见的求解方法是先将问题的时空坐标离散化,并以数值积分的形式完成求解。要得到精确的结果,离散化后的网格需要设计得很稠密,从而对存储空间和计算时间的需求巨大。

与此同时, 在自动微分计算过程中,机器学习中主流的后向自动微分库,如 Jax 、 TensorFlow 和 PyTorch,需要很多额外的空间来缓存中间结果, 导致开发者无法直接用它们对具有一定规模的实际物理模拟问题求导。

针对诸如物理模拟、游戏引擎、气候模拟、计算机图形学中的应用等具有领域专用属性的自动微分程序,可能需要根据具体的需求,设计出适合该领域的自动微分程序实现。

高效性能

在前面的文章中,介绍了自动微分在实际的计算实现过程,会涉及到程序的分解、微分和组合。因此如何对程序进行分解、微分和组合,及其执行顺序则会决定自动微分的性能。

程序与微分表达

首先我们看看程序和自动微分计算过程的简单实现方案。如对公式 $f(x)=x^3$ 下面代码所示:

def fun(x):
    t = x * x * x
    return t

对公式进行微分可以表示为 $f'(x)=3x^2$,其微分的代码实现方式为:

def dfun(x):
    dx = 3 * x * x
    return dx

在计算机程序中,可以将原函数计算过程和微分结果过程进行融合,并完成类似公共子表达式的提取优化。如下面代码将同时完成原函数计算和微分结果计算:

def fun(x):
    t = x * x
    v = x * t
    dx = 3 * t
    return v, dx

额外中间变量

以在 AI 框架中更加常用的后向自动微分模式为例(目前作为更多 AI 框架的实现方式),其计算过程表达如下图所示,表的左列浅色为前向计算函数值的过程,与前向计算时相同,右面列深色为反向计算导数值的过程。

image

反向模式的计算过程如图所示,其中:

$$ \overline{v_i}=\dfrac{\delta y}{\delta v_i} $$

根据链式求导法则展开有:

$$ \frac{\partial f}{\partial x}=\sum_{k=1}^{N} \frac{\partial f}{\partial v_{k}} \frac{\partial v_{k}}{\partial \boldsymbol{x}} $$

可以看出,左侧是源程序分解后得到的基本操作集合,而右侧则是每一个基本操作根据已知的求导规则和链式法则由下至上计算的求导结果。在求解最后的倒数过程中,左侧的源程序分解后的变量,与右侧的由下至上的计算过程中,存在大量的变量在过程中被多次复用。

以更加通用的数学表示为例则二阶微分方程的一般形式为:

$$

标签:AI,程序,微分,自动,计算,转载,过程
From: https://www.cnblogs.com/xueaigc/p/18603141

相关文章

  • 转载:【AI系统】动手实现 PyTorch 微分
    这里记录一下使用操作符重载(OO)编程方式的自动微分,其中数学实现模式则是使用反向模式(ReverseMode),综合起来就叫做反向OO实现AD啦。基础知识下面一起来回顾一下操作符重载和反向模式的一些基本概念,然后一起去尝试着用Python去实现PyTorch这个AI框架中最核心的自动微分机......
  • 转载:【AI系统】计算图原理
    在前面的文章曾经提到过,目前主流的AI框架都选择使用计算图来抽象神经网络计算表达,通过通用的数据结构(张量)来理解、表达和执行神经网络模型,通过计算图可以把AI系统化的问题形象地表示出来。本文将会以AI概念落地的时候,遇到的一些问题与挑战,因此引出了计算图的概念来对神经网......
  • 转载:【AI系统】计算图基本介绍
    在AI框架发展的最近一个阶段,技术上主要以计算图来描述神经网络。前期实践最终催生出了工业级AI:TensorFlow和PyTorch,这一时期同时伴随着如Chainer、DyNet、CNTK、PaddlePaddle、JAX等激发了框架设计灵感的诸多实验课程。TensorFlow和PyTorch,特别是PyTorch代表了今天AI......
  • 转载:【AI系统】计算图与自动微分
    在前面的文章曾经提到过,目前主流的AI框架都选择使用计算图来抽象神经网络计算表达,通过通用的数据结构(张量)来理解、表达和执行神经网络模型,通过计算图可以把AI系统化的问题形象地表示出来。本文将会以AI概念落地的时候,遇到的一些问题与挑战,因此引出了计算图的概念来对神经网......
  • 转载:【AI系统】计算图的控制流实现
    计算图在数学上作为一个有向无环图(DAG,DirectedAcyclicGraph),能够把神经网络模型的概念抽象出来作为同一描述,不过在计算机的编程中,会遇到很多if、else、while、for等控制流语句,有向无环图改如何表示控制流变成了计算图中一个很重要的问题。好处在于,引入控制流之后,开发者可以向计......
  • 转载:【AI系统】计算图的调度与执行
    在前面的内容介绍过,深度学习的训练过程主要分为以下三个部分:1)前向计算、2)计算损失、3)更新权重参数。在训练神经网络时,前向传播和反向传播相互依赖。对于前向传播,沿着依赖的方向遍历计算图并计算其路径上的所有变量。然后将这些用于反向传播,其中计算顺序与计算图的相反。基于计算......
  • 转载:【AI系统】计算图挑战与未来
    目前主流的AI框架都选择使用计算图来抽象神经网络计算表达,通过通用的数据结构(张量)来理解、表达和执行神经网络模型,通过计算图可以把AI系统化的问题形象地表示出来。计算图与框架关系计算图回顾在AI框架中,其计算图的基本组成有两个主要的元素:1)基本数据结构张量和2)基本计......
  • 转载:【AI系统】动态图与静态图转换
    从TensorFlow、PyTorch,到PaddlePaddle、MindSpore、MegEngine,主流的AI框架动静态图转换,经历了动静分离、动静结合到动静统一的发展过程。兼顾动态图易用性和静态图执行性能高效两方面优势,均具备动态图转静态图的功能,支持使用动态图编写代码,框架自动转换为静态图网络结构执行计......
  • 转载:【AI系统】数据并行
    数据并行是一种广泛应用于分布式AI系统中的技术,旨在通过将数据集划分为多个子集并在不同计算节点上并行处理这些子集,以提高计算效率和速度。在大规模机器学习和深度学习训练过程中,数据并行可以显著加快模型训练速度,减少训练时间,提升模型性能。大部分的数据并行模型中,每个计算节......
  • 转载:【AI系统】并行训练基本介绍
    分布式训练是一种模型训练模式,它将训练工作量分散到多个工作节点上,从而大大提高了训练速度和模型准确性。虽然分布式训练可用于任何类型的AI模型训练,但将其用于大模型和计算要求较高的任务最为有利。本篇幅将围绕在PyTorch2.0中提供的多种分布式训练方式展开,包括并行训练,如:数......