Mindspore函数式微分编程

class1lizp 2022-11-15 11:04:17
加精

自动微分

深度学习等现代AI算法,通过使用大量的数据来学习拟合出一个优化后带参模型,其中使用的学习算法,多是基于现实数据自模型中的经验误差来反向传播以更新模型的参数,自动微分技术(Automatic Differentiation,AD)正是其中的关键技术。

自动微分是一种介于数值微分与符号微分之间的一种求导方法。自动微分的核心思想是将计算机程序中的运算操作分解为一个有限的基本操作合集,且合集中基本操作的求导规则均为已知的。在完成每一个基本操作的求导后,使用链式求导法则将结果组合得到整体程序的求导结果。

链式求导法则:

(f∘g)′(x)=f′(g(x))g′(x)(1)(1)(f∘g)′(x)=f′(g(x))g′(x)

根据对分解后的基本操作求导和链式规则的组合不同,自动微分可以分为前向模式反向模式

  • 前向自动微分(Forward Automatic Differentiation,也叫做 tangent linear mode AD)或者前向累积梯度(前向模式)。

  • 后向自动微分(Reverse Automatic Differentiation,也叫做 adjoint mode AD)或者说反向累计梯度(反向模式)。

我们以公式 (2) 为例介绍前向微分与反向微分的具体计算方式:

y=f(x1,x2)=ln(x1)+x1x2−sin(x2)(2)(2)y=f(x1,x2)=ln(x1)+x1x2−sin(x2)

当我们使用前向自动微分求公式 (2) 在x1=2,x2=5x1=2,x2=5处的导数 ∂y∂x1∂y∂x1 时,前向自动微分的求导方向与原函数的求值方向一致,原函数结果与微分结果可以被同时获得。

forward

当使用反向自动微分时,反向自动微分的求导方向与原函数的求值方向相反,微分结果需要依赖原函数的运行结果。

backward

MindSpore先构建的是基于反向模式的自动微分,并在该方法的基础上实现了正向微分。

为了进一步说明前向微分与反向微分的区别,我们将被求导的原函数,泛化为具有N输入与M输出的函数F:

(Y1,Y2,...,YM)=F(X1,X2,...,XN)(3)(3)(Y1,Y2,...,YM)=F(X1,X2,...,XN)

函数 F()F() 的导数本身为一个雅可比矩阵(Jacobian matrix)。

⎡⎣⎢⎢⎢∂Y1∂X1...∂YM∂X1.........∂Y1∂XN...∂YM∂XN⎤⎦⎥⎥⎥(4)(4)[∂Y1∂X1...∂Y1∂XN.........∂YM∂X1...∂YM∂XN]

前向自动微分

在前向自动微分当中,我们是从输入开始向输出的方向计算的,因此每一次计算我们可以求得输出对某一输入的导数,即雅可比矩阵中的一列。

⎡⎣⎢⎢⎢∂Y1∂X1...∂YM∂X1⎤⎦⎥⎥⎥(5)(5)[∂Y1∂X1...∂YM∂X1]

为了求取该列的值,自动微分将程序分解为一系列求导规则已知的基本操作,这些基本操作也可以被泛化表达为具有nn输入和mm输出的函数ff:

(y1,y2,...,ym)=f(x1,x2,...,xn)(6)(6)(y1,y2,...,ym)=f(x1,x2,...,xn)

由于我们的已知基础函数 ff 的求导规则,即 ff 的雅可比矩阵是已知的。于是我们可以对ff计算雅可比向量积(Jvp, Jacobian-vector-product),并应用链式求导法则获得导数结果。

⎡⎣⎢⎢⎢∂y1∂Xi...∂ym∂Xi⎤⎦⎥⎥⎥=⎡⎣⎢⎢⎢∂y1∂x1...∂ym∂x1.........∂y1∂xn...∂yM∂xn⎤⎦⎥⎥⎥⎡⎣⎢⎢⎢∂x1∂Xi...∂xn∂Xi⎤⎦⎥⎥⎥(7)(7)[∂y1∂Xi...∂ym∂Xi]=[∂y1∂x1...∂y1∂xn.........∂ym∂x1...∂yM∂xn][∂x1∂Xi...∂xn∂Xi]

反向自动微分

在反向自动微分当中,我们是从输出开始向输入的方向计算的,因此每一次计算我们可以求得某一输出对输入的导数,即雅可比矩阵中的一行。

[∂Y1∂X1...∂Y1∂XN](8)(8)[∂Y1∂X1...∂Y1∂XN]

为了求取该列的值, 自动微分将程序分解为一系列求导规则已知的基本操作,这些基本操作也可以被泛化表达为具有n输入和m输出的函数ff:

(y1,y2,...,ym)=f(x1,x2,...,xn)(9)(9)(y1,y2,...,ym)=f(x1,x2,...,xn)

由于我们的已知基础函数ff的求导规则,即f的雅可比矩阵是已知的。于是我们可以对ff计算向量雅可比积(Vjp, Vector-jacobian-product),并应用链式求导法则获得导数结果。

[∂Yj∂x1...∂Yj∂xN]=[∂Yj∂y1...∂Yj∂ym]⎡⎣⎢⎢⎢∂y1∂x1...∂ym∂x1.........∂y1∂xn...∂ym∂xn⎤⎦⎥⎥⎥(10)(10)[∂Yj∂x1...∂Yj∂xN]=[∂Yj∂y1...∂Yj∂ym][∂y1∂x1...∂y1∂xn.........∂ym∂x1...∂ym∂xn]

GradOperation实现

MindSpore中GradOperation使用的是反向自动微分模式,即从正向网络的输出开始计算梯度。

GradOperation算法设计

设模型定义的原函数为:

f(g(x,y,z))(11)(11)f(g(x,y,z))

则f()f()对xx的梯度为:

dfdx=dfdgdgdxdxdx+dfdgdgdydydx+dfdgdgdzdzdx(12)(12)dfdx=dfdgdgdxdxdx+dfdgdgdydydx+dfdgdgdzdzdx

dfdydfdy和dfdzdfdz与dfdxdfdx类似。

应用链式求导法则,对每个函数(包括算子和图)定义梯度函数bprop: dout->(df, dinputs),这里df表示函数对自由变量(函数外定义的变量)的梯度,dinputs是对函数输入的梯度。在此基础上,应用全微分法则,将(df, dinputs)累加到对应的变量。

MindIR实现了分支,循环,闭包的函数表达式,所以对相应的算子实现正确的反向规则即可求得输入函数的梯度函数。

定义运算符K,反向自动微分算法可以简单表示如下:

v = (func, inputs)
F(v): {
    (result, bprop) = K(func)(K(inputs))
    df, dinputs = bprop(dout)
    v.df += df
    v.dinputs += dinputs
}

GradOperation算法实现

在自动微分流程中,需要进行自动微分的函数会被取出。并作为自动微分模块的输入,并输出对应的梯度图。

MindSpore的自动微分模块实现了从原函数对象到梯度函数对象的转换。转换后的对象为fprop形式的梯度函数对象。

fprop = (forward_result, bprop)forward_result是前向计算图的输出节点, bprop是以fprop的闭包对象形式生成的梯度函数,它只有dout一个入参, inputsoutputs是引用的fprop的输入和输出。

MapObject();    // 实现ValueNode/Parameter/FuncGraph/Primitive对象的映射
MapMorphism();  // 实现CNode的态射
res = k_graph(); // res就是梯度函数的fprop对象

在生成梯度函数对象的过程中,需要完成从原函数到梯度函数的一系列的映射, 即为每个原函数中的节点生成其所对应的梯度函数的节点,再按照反向自动微分的规则将这些节点连接在一起,生成梯度函数图。

每张原函数对象的子图都会都会生成一个Dfunctor对象,负责将该原函数对象映射为梯度函数对象。DFunctor主要需要经过 MapObjectMapMorphism两步来实现这种映射关系。

MapObject实现了原函数节点到梯度函数节点的映射,具体包括对自由变量,参数节点以及ValueNode的映射。

MapFvObject();    // 自由变量的映射
MapParamObject(); // 参数节点的映射
MapValueObject(); // ValueNode的映射
  • MapFvObject是对自由变量的映射;

  • MapParamObject是对参数节点的映射;

  • MapValueObject中主要对Primitive以及FuncGraph对象进行映射。

其中,对FuncGraph进行的映射同样需要为该子图创造相应的DFunctor,是一个递归的过程。 Primitive表明了算子的种类,为了支持自动微分,需要为每一种Primitive定义其对应的反向微分函数。

MindSpore将这些定义放在了Python侧,以sin算子为例:

import mindspore.ops as ops
from mindspore.ops._grad.grad_base import bprop_getters

@bprop_getters.register(ops.Sin)
def get_bprop_sin(self):
    """Grad definition for `Sin` operation."""
    cos = ops.Cos()

    def bprop(x, out, dout):
        dx = dout * cos(x)
        return (dx,)

    return bprop

x为原函数对象sin的输入,out为原函数对象sin的输出,dout为当前累加的梯度输入。

MapObject完成对以上节点的映射后,MapMorphism从原函数的输出节点开始以递归的方式实现对CNode的态射,建立起节点间的反向传播链接,实现梯度累加。

GradOperation示例

我们构建一个简单的网络来表示公式:

f(x)=cos(sin(x))(13)(13)f(x)=cos(sin(x))

并对公式(13)的输入x进行求导:

f′(x)=−sin(sin(x))∗cos(x)(14)(14)f′(x)=−sin(sin(x))∗cos(x)

在MindSpore中公式(13)的网络的结构实现为:

import mindspore.nn as nn

class Net(nn.Cell):
    def __init__(self):
        super(Net, self).__init__()
        self.sin = ops.Sin()
        self.cos = ops.Cos()

    def construct(self, x):
        a = self.sin(x)
        out = self.cos(a)
        return out

正向网络的结构为:

auto-gradient-foward

对该网络进行反向微分后,所得微分网络结构为:

auto-gradient-forward2

前向自动微分实现

除了支持反向自动微分的GradOperation之外,MindSpore还扩展实现了前向自动微分Jvp(Jacobian-Vector-Product)。

相比于反向自动微分,前向自动微分更适合于求取输入维度小于输出维度的网络的梯度。MindSpore的前向自动微分是基于反向自动微分接口GradOperation开发的。

auto-gradient-jvp

黑色为网络的正向流程,第一次求导为针对xx的求导,得到的是蓝色的图。第二次的为蓝色图针对vv的求导,得到的是黄色的图。

黄色的图就是我们所需要的前向模式自动微分的结果图。由于蓝色图可以视为关于vv的线性函数,蓝色节点与黄色节点之间不会存在连边。蓝色节点全部为悬空节点,会被消除,真正运行的就只有原函数节点以及前向微分的节点。因此,该方法不会有额外的运行开销。

参考文献

[1] Baydin, A.G. et al., 2018. Automatic differentiation in machine learning: A survey. arXiv.org. [Accessed September 1, 2021].

...全文
105 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复
今年的华为开发者大会 HDC 2020 上,除了**昇腾、鲲鹏等自研芯片硬件平台**之外,最令人期待的就是**深度学习框架 MindSpore 的开源**了。今天上午,华为 MindSpore **首席科学家陈雷**在活动中宣布这款产品正开源,我们终于可以在开放平台上一睹它的真面目。 本文是根据机器之心报道的MindSpore 的开源介绍而整理的.md笔记 作为一款支持**端、边、云独立/协同的统一训练和推理框架,华为希望通过这款完整的软件堆栈,实现**一次性算子开发、一致的开发和调试体验**,以此帮助开发者实现**一次开发,应用在所有设备上平滑迁移**的能力。 三大创新能力:新编程,执行模和协作方 由**自动微分、自动并行、数据处理**等功能构成 开发算法即代码、运行高效、部署态灵活**的**特点**, 三层核心:从下往上分别是**后端运行时、计算图引擎及前端表示层**。 最大特点:采用了业界最新的 **Source-to-Source 自动微分**,它能**利用编译器及编程语言的底层技术**,进一步**优化以支持更好的微分表达**。主流深度学习框架中主要有**三种自动微分技术,才用的不是静态计算图、动态计算图,而是基于**源码**转换:该技术源以**函数编程框架**为基础,以**即时编译(JIT)**的方**在中间表达(编译过程中程序的表达形)上做自动微分变换**,支持**复杂控制流场景、高阶函数和闭包**。 MindSpore 主要概念就是张量、算子、单元和模型 其代码有两个比较突出的亮点:计算图的调整,动态图与静态图可以一行代码切换;自动并行特性,我们写的串行代码,只需要多加一行就能完成自动并行。

164

社区成员

发帖
与我相关
我的任务
社区描述
AI技术分享以及交流
人工智能 其他
社区管理员
  • 跳楼梯企鹅
  • 平凡的人1
  • 微枫Micromaple
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧