# 函数式微分编程¶

## 自动微分简介¶

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

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

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

$\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}$

### 前向自动微分¶

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

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

$\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}$

### 反向自动微分¶

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

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

$\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}$

MindSporeIR实现了分支，循环，闭包的函数表达式，所以对相应的算子实现正确的反向规则即可求得输入函数的梯度函数。 定义运算符K，反向自动微分算法可以简单表示如下：

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


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


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

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


MapFvObject是对自由变量的映射， MapParamObject是对参数节点的映射。 MapValueObject中主要对Primitive以及FuncGraph对象进行映射。其中，对FuncGraph进行的映射同样需要为该子图创造相应的DFunctor，是一个递归的过程。 Primitive表明了算子的种类，为了支持自动微分，需要为每一种Primitive定义其对应的反向微分函数。 MindSpore将这些定义放在了Python侧，以sin算子为例：

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

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

return bprop


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

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

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. Available at: https://arxiv.org/abs/1502.05767 [Accessed September 1, 2021].