tastynoob
Articles58
Tags18
Categories7
前向求导算法

前向求导算法

前向求导算法

在神经网络当中需要利用反向传播算法对神经网络进行训练

又或者利用梯度下降法求局部最优解

但是我们又不想去手动求导

对于复杂的函数求导是件很痛苦的事

所以像是pytorch这类神经网络框架都提供了自动求导,或者自动微分机制

这里就来介绍下一种最简单的自动求导算法:前向求导


首先我们定义$\epsilon$趋近于0,但是不等于0

因此
$\frac{f(x+\epsilon)-f(x)}{\epsilon}=f^{‘}(x)$
推导得
$f(x+\epsilon) = f(x) + f^{‘}(x)\epsilon$

更一般的
我们设二元数$a+b\epsilon$,则有
$f(a+b\epsilon) = f(a) + f^{‘}(a)b\epsilon$

至此我们就得到了一个求导的普遍公式

$f(a+b\epsilon) = f(a) + f^{‘}(a)b\epsilon$
其中$a\in R,b\in R,\epsilon\to0$

为了方便计算,我们设二元数$a+b\epsilon$
其有如下特征
$(a+b\epsilon)+(c+d\epsilon)=(a+c)+(b+d)\epsilon$
由于$\epsilon\to0$,所以我们可以认为$\epsilon^2=0$
类似于虚数单位$i^2=-1$
所以有乘法公式
$(a+b\epsilon)(c+d\epsilon)=ac+(ad+bc)\epsilon$

更进一步,根据$f(a+b\epsilon) = f(a) + f^{‘}(a)b\epsilon$可以推导得
$n^{(a+b\epsilon)} = n^a+(bn^a\ln{n})\epsilon,n\in R$
$(a+b\epsilon)^n = a^n + (nba^{n-1})\epsilon,n\in R$

这就意味着二元数$a+b\epsilon$满足所有的数学运算

只要我们已知函数$f(x)$
我们通过代入二元数$f(a+\epsilon)=f(a)+f^{‘}(a)\epsilon$
就能求得该点的函数值和导数

这就是前向求导算法

具体代码可有python实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
import numpy as np
import math
#定义二元数,前向模式算法
class Dual:
a=0
e=0#无穷小量的系数
def __init__(self,a,e):
self.a = a
self.e = e
def __add__(self,other):
if type(other)!=Dual:
return Dual(self.a+other,self.e)
return Dual(self.a+other.a,self.e+other.e)
def __radd__(self,other):
return self.__add__(other)
def __sub__(self,other):
if type(other)!=Dual:
return Dual(self.a-other,self.e)
return Dual(self.a-other.a,self.e-other.e)
def __rsub__(self,other):
return self.__sub__(other)
def __mul__(self,other):
if type(other)!=Dual:
return Dual(self.a*other,self.e*other)
return Dual(self.a*other.a,self.a*other.e+self.e*other.a)
def __rmul__(self,other):
return self.__mul__(other)
def __truediv__(self,other):
if type(other)!=Dual:
return Dual(self.a/other,self.e/other)
return Dual(self.a/other.a,(self.e*other.a-self.a*other.e)/(other.a**2))
def __rtruediv__(self,other):
return Dual(other/self.a, -other*self.e/self.a**2)
#dual**x
def __pow__(self,other):
return Dual(self.a**other,other*self.a**(other-1)*self.e)
#x**dual
def __rpow__(self,other):
return Dual(other**self.a,other**self.a*self.e*math.log(other))
#定义比较运算符
def __eq__(self,other):
return self.a==other.a and self.e==other.e
def __ne__(self,other):
return not self.__eq__(other)
def __gt__(self,other):
return self.a>other.a
def __ge__(self,other):
return self.a>=other.a
def __lt__(self,other):
return self.a<other.a
def __le__(self,other):
return self.a<=other.a
def __str__(self):
return str(self.a) + ('+' if self.e >= 0 else '') +str(self.e)+'E'
def __repr__(self):
return str(self.a) + ('+' if self.e >= 0 else '') + str(self.e)+'E'

def F(X):
return 0.05*4*X**4 + 5.2*3*X**3 - 0.005*2*X**2 + 2.3*1*X + 12.3

a = Dual(10,1)

print(a)
print(F(a))
Author:tastynoob
Link:https://tastynoob.github.io/1970/01/01/%E7%AE%97%E6%B3%95/%E5%89%8D%E5%90%91%E6%B1%82%E5%AF%BC%E7%AE%97%E6%B3%95/
版权声明:本文采用 CC BY-NC-SA 3.0 CN 协议进行许可
×