# 函数式微分编程¶

## 自动微分¶

$(f\circ g)^{'}(x)=f^{'}(g(x))g^{'}(x) \tag{1}$

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

$y=f(x_{1},x_{2})=ln(x_{1})+x_{1}x_{2}-sin(x_{2}) \tag{2}$

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

$(Y_{1},Y_{2},...,Y_{M})=F(X_{1},X_{2},...,X_{N}) \tag{3}$

$\begin{split}\left[ \begin{matrix} \frac{\partial Y_{1}}{\partial X_{1}}& ... & \frac{\partial Y_{1}}{\partial X_{N}} \\ ... & ... & ... \\ \frac{\partial Y_{M}}{\partial X_{1}} & ... & \frac{\partial Y_{M}}{\partial X_{N}} \end{matrix} \right] \end{split}\tag{4}$

### 前向自动微分¶

$\begin{split}\left[ \begin{matrix} \frac{\partial Y_{1}}{\partial X_{1}}\\ ... \\ \frac{\partial Y_{M}}{\partial X_{1}} \end{matrix} \right] \end{split}\tag{5}$

$(y_{1},y_{2},...,y_{m})=f(x_{1},x_{2},...,x_{n}) \tag{6}$

$\begin{split}\left[ \begin{matrix} \frac{\partial y_{1}}{\partial X_{i}}\\ ... \\ \frac{\partial y_{m}}{\partial X_{i}} \end{matrix} \right]=\left[ \begin{matrix} \frac{\partial y_{1}}{\partial x_{1}}& ... & \frac{\partial y_{1}}{\partial x_{n}} \\ ... & ... & ... \\ \frac{\partial y_{m}}{\partial x_{1}} & ... & \frac{\partial y_{M}}{\partial x_{n}} \end{matrix} \right]\left[ \begin{matrix} \frac{\partial x_{1}}{\partial X_{i}}\\ ... \\ \frac{\partial x_{n}}{\partial X_{i}} \end{matrix} \right] \end{split}\tag{7}$

### 反向自动微分¶

$\begin{split}\left[ \begin{matrix} \frac{\partial Y_{1}}{\partial X_{1}}& ... & \frac{\partial Y_{1}}{\partial X_{N}} \\ \end{matrix} \right] \end{split}\tag{8}$

$(y_{1},y_{2},...,y_{m})=f(x_{1},x_{2},...,x_{n}) \tag{9}$

$\begin{split}\left[ \begin{matrix} \frac{\partial Y_{j}}{\partial x_{1}}& ... & \frac{\partial Y_{j}}{\partial x_{N}} \\ \end{matrix} \right]=\left[ \begin{matrix} \frac{\partial Y_{j}}{\partial y_{1}}& ... & \frac{\partial Y_{j}}{\partial y_{m}} \\ \end{matrix} \right]\left[ \begin{matrix} \frac{\partial y_{1}}{\partial x_{1}}& ... & \frac{\partial y_{1}}{\partial x_{n}} \\ ... & ... & ... \\ \frac{\partial y_{m}}{\partial x_{1}} & ... & \frac{\partial y_{m}}{\partial x_{n}} \end{matrix} \right] \end{split}\tag{10}$

## grad实现¶

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

### grad算法设计¶

$f(g(x, y, z)) \tag{11}$

$$f()$$$$x$$的梯度为：

$\frac{df}{dx}=\frac{df}{dg}\frac{dg}{dx}\frac{dx}{dx}+\frac{df}{dg}\frac{dg}{dy}\frac{dy}{dx}+\frac{df}{dg}\frac{dg}{dz}\frac{dz}{dx}\tag{12}$

$$\frac{df}{dy}$$$$\frac{df}{dz}$$$$\frac{df}{dx}$$类似。

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

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


### grad算法实现¶

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对象


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

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

• MapFvObject是对自由变量的映射；

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

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

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

[1]:

import mindspore.ops as ops

@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的态射，建立起节点间的反向传播链接，实现梯度累加。

### grad示例¶

$f(x) = cos(sin(x)) \tag{13}$

$f'(x) = -sin(sin(x)) * cos(x) \tag{14}$

[2]:

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


## 前向自动微分实现¶

### 参考文献¶

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