标签归档:机器学习

python中几种自动微分库

  简单介绍下python的几个自动求导工具,tangent、autograd、sympy;
  在各种机器学习、深度学习框架中都包含了自动微分,微分主要有这么四种:手动微分法、数值微分法、符号微分法、自动微分法,这里分别简单走马观花(hello world式)的介绍下下面几种微分框架;

sympy 强大的科学计算库,使用的是符号微分,通过生成符号表达式进行求导;求得的导数不一定为最简的,当函数较为复杂时所生成的表达式树异常复杂;

autograd自动微分先将符号微分用于基本的算子,带入数值并保存中间结果,后应用于整个函数;自动微分本质上就是图计算,容易做很多优化所以广泛应用于各种机器学习深度学习框架中;

tangent源到源(source-to-source)的自动微分框架,在计算函数f微分时他通过生成新函数f_grad来计算该函数的微分,与目前所存在的所有自动微分框架都有所不同;由于它是通过生成全新的函数来计算微分所以具有非常搞的可读性、可调式性这也是官方所说的与当前自动微分框架的重大不同;

sympy 求导

 def grad():
     # 定义表达式的变量名称
     x, y = symbols('x y')
     # 定义表达式
     z = x**2 +y**2
     # 计算z关于y对应的偏导数
     return diff(z, y)

 func = grad()

输出结果表达式z的导函数z‘=2*y

 print(func) 

把y 等于6 带入计算 结果 为12

 print(func.evalf(subs ={'y':3}))

Autograd求偏导

 import autograd.numpy as np
 from autograd import grad

 #表达式 f(x,y)=x^2+3xy+y^2
 #df/dx = 2x+3y
 #df/dy = 3x+2y
 #x=1,y=2
 #df/dx=8
 #df/dy=7
 def fun(x, y):
   z=x**2+3*x*y+y**2
   return z

 fun_grad = grad(fun)
 fun_grad(2.,1.)

输出:7.0

tangent求导

 import tangent
 def fun(x, y):
   z=x**2+3*x*y+y**2
   return z

默认为求z关于x的偏导数

 dy_dx = tangent.grad(fun)

输出偏导数值为 8 ,z’ = 2 * x,此处x传任何值都是一样的

 df(4, y=1)

可通过使用wrt参数指定求关于某个参数的偏导数,下面为求z关于y的偏导数

 df = tangent.grad(funs, wrt=([1]))

输出值为10 ,z’ = 2 *y,此处x传任何值都是一样的

 df(x=0, y=5)

上面说了那么多也没体现出tangent的核心:源到源(source-to-source)

在生成导函数的时候加入verbose=1参数,即可看到tangent为我们生成的用于计算导数的函数,默认情况下该值为0所以我们没感觉到tangent的求导与别的自动微分框架有什么区别;

 def df(x):
     z = x**2
     return z

 df = tangent.grad(df, verbose=1)
 df(x=2)

在执行完上述代码后,我们看到了tangent为我们所生成用于求导数的函数:

  def ddfdx(x, bz=1.0):
    z = x ** 2
    assert tangent.shapes_match(z, bz), 'Shape mismatch between return value (%s) and seed derivative (%s)' % (numpy.shape(z), numpy.shape(bz))
 # Grad of: z = x ** 2
  _bx = 2 * x * bz
  bx = _bx
  return bx

  ddfdx函数就是所生成的函数,从中我们也可以看到表达式z的导函数z’=2 * x,tangent就是通过执行该函数用于求得导数的;

  sympy 中的自动微分只是它强大的功能之一,autograd 从名字也可知它就是为了自动微分而生的,tangent初出茅庐2017年底Google才发布的自动微分方法也比较新颖,从17年发v0.1.8版本后也没见发版,源码更新也不够活跃;sympy、autograd比较成熟,tangent还有待观察;

反向传播算法—从四个基本公式说起

enter image description here
enter image description here

反向传播四公式:

enter image description here
enter image description here

  反向传播的最终目的是求得使代价C最小时w、b的最佳值,为了方便计算引入了神经单元误差δ_j^l,其定义为误差C关于某个神经单元z的关系;
enter image description here
  其定义如上所示,某神经元误差为代价C(总误差)关于z的偏导数,其中l为神经网络的层数,j为第几个神经元;
  这里的代价函数(损失函数)使用的是平方误差,因此C等于:
enter image description here

BP1

  此公式用于求神经网络最后一层神经元的误差,下面通过BP1公式用于求最后一层神经元(输出层)中第一个神经元的误差;
enter image description here

根据链式法则由此可得到上诉四个公式中得前面BP1

enter image description here
BP1中得L为神经网络得最后一层,而在我们此网络中最后一层为3,所以此处L=3;

BP2

  BP2与BP1类似,不同得是BP1用于求最后一层神经元误差,而BP2则是用于求L层前面某一层得神经元误差,下面通过BP2公式用于求第二层神经元中的第一个神经元的误差;
同样我们也可通过链式法则得出:
enter image description here
有:
enter image description here
因此可以得:
enter image description here
将公式转换为矩阵模式,第2层神经元得误差为:
enter image description here
我们将BP1与BP2带入即可得到BP3与BP4;
通过BP1与BP2公式即可通过BP3、BP4轻松得到w与B;

BP3

此公式用于求误差C关于某个权重的偏导数,在求得BP2后此处只需吧BP2带入到公式即可求得BP3;
enter image description here

BP4

  求误差C关于偏置b的偏导数,BP4与BP3一样得到BP2即可带入得出BP4;
enter image description here
  反向传播算法给出了一种用于计算代价函数(损失函数)梯度得方法,具体步骤如下:
enter image description here

数据计算

enter image description here

一、前向传播

1、计算第二层
  矩阵形式:
enter image description here
enter image description here
2、计算第三层
  矩阵形式:
enter image description here

二、计算误差

当前使用的为平方损失函数(代价函数);
enter image description here

三、计算输出层神经元误差

矩阵形式:
enter image description here
  输出层第一个神经元误差δ_1^3:
enter image description here
  输出层第一个神经元误差δ_2^3:
enter image description here

四、计算其余层神经元误差

矩阵形式:
enter image description here

五、计算误差C关于w、b的梯度

  此处用的是BP3与BP4公式,在计算出BP1与BP2后将其带入到公式中即可计算出C关于w、b的梯度;
矩阵形式:
enter image description here
矩阵形式:
enter image description here
更新w、b公式:
enter image description here
  在计算出误差C关于每个权重每个偏置的偏导数后再使用得到的值带入上述公式更新每一个w、b即可,在更新完成w、b后如误差达到指定精度或epochs则继续执行上述的2-5步骤直到误差满意或指定epochs为止;