学习机器学习的同学在学习过程中会经常遇到一个问题,那就是对目标函数进行求微分,线性回归这类简单的就不说、复杂的如神经网络类那些求导过程的酸爽。像我还是那种比较粗心的人往往有十九错,所以说自动求导就十分有必要了,本文主要介绍几种求导的方式。假设我们的函数为\(f(x,y)=x^2y+y+2\),目标是求出偏导\(\frac{\partial{f}}{\partial{x}}\)和\(\frac{\partial{f}}{\partial{y}}\)。求导的方式主要分为以下几种

手动求导法(Manual Differentiation)###

首先准备一张纸和一支笔,根据上学时候学到的求导法则,开始计算。最终得到的结果

\(\frac{\partial{f}}{\partial{x}}=2xy\)

\(\frac{\partial{f}}{\partial{y}}=x^2+1\)

上面这个小例子比较简单,口算即可得到答案,但如果方程比较复杂那就难说了。幸好有自动求导的方法,例如符号求导方法。

符号求解法(Symbolic Differentiation)###

符号求导是根据一些求导法则,进行求导。例如我们大学高数学习的\((uv)\prime=u'v+v'u\),\((u+v)'=u'+v'\),\((\frac{u}{v})'=\frac{u'v-v'u}{v^2}\)等等,下图是\(g(x,y)=5+xy\)的符号求导工作流程。



原公式在图的左边,求导公式在图的右半部分,求导的过程是先求叶子节点,自下向上。最终对节点进行见之得到求导结果\(\frac{\partial{g}}{\partial{x}}=y\),这个例子固然简单,但是对于一个更复杂的公式,那么求导符号图将会十分的庞大(表达式膨胀),另外对于一些变化的公式(硬代码)这种方法就无能为力了:

def fun(a,b):
z=0
for i in range(100):
z = a * np.cos(z + i) + z * np.sin(b - i)
return z

数值求导法(Numerical Differentiation)###

导数的定义是当自变量的增量趋于零时,因变量的增量与自变量的增量之商的极限。

其中\(\varepsilon\)是一个无穷小的数,所以我们可以计算在x=3,y=4这一点对x的偏导数,\(f'(x=3,y)=\frac{f(3+\varepsilon,4)-f(3,4)}{\varepsilon}\),对应的代码如下:

def f(x, y):
return x**2*y + y + 2
def derivative(f, x, y, x_eps, y_eps):
return (f(x + x_eps, y + y_eps) - f(x, y)) / (x_eps + y_eps)
df_dx = derivative(f, 3, 4, 0.00001, 0)
df_dy = derivative(f, 3, 4, 0, 0.00001)
>>print(df_dx)
24.000039999805264
>>print(df_dy)
10.000000000331966

通过上面的结果我们发现,得出的结果不是十分的精确,并且在对x和y求偏导的整个过程中,至少需要计算3次\(f()\),也就是说如果有1000个参数,那么至少需要计算1001次\(f()\),在神经网络中,参数巨多,这样计算效率会比较差。不过这种方法常被用到进行检验得到的求导结果是否正确。

前向自动求导法(Forward-Mode Autodiff)###

前向求导是依赖于数值求导和符号求导的一种求解方法,给定公式\(a+{\varepsilon}b\),这种被称作dual number,其中ab是实数,\(\varepsilon\)是一个无穷小的数,并且\({\varepsilon}^2=0\),举个栗子,\(42 + 24\varepsilon\),我们可以把它看成42.00000000...24的数值.我们可以通过这种方法(42.0,24.0)来表示,dual number满足以下的运算法则:

  • 1.\(\lambda(a+b\varepsilon) = a\varepsilon + b{\lambda}\varepsilon\)
  • 2.\((a+b\varepsilon)+(c+d\varepsilon) = (a+c)+(b+d)\varepsilon\)
  • 3.\((a+b\varepsilon)\times(c+d\varepsilon) = ac+(ad+bc)\varepsilon+(bd){\varepsilon}^2=ac+(ad+bc)\varepsilon\)

还有一点就是\(h(a+b\varepsilon)=h(a)+b{\times}h'(a)\varepsilon\)。



上图给出了使用前向求导方法计算出\(f(x,y)\)在x=3,y=4这一点\(\frac{\partial{f}}{\partial{x}}(3,4)\)的偏导,同理求出\(\frac{\partial{f}}{\partial{y}}(3,4)\),图中的思路很清晰就不赘述。前向求导方法相对数值求导来说准确率较高,当和数值求导方法一样如果参数过多的时候效率会比较差,因为这种方法需要遍历整个图。

逆向自动求导法(Reverse-Mode Atuodiff)###

TensorFlow采用的是逆向自动求导方法,该方法首先正向遍历整个图,计算出每个节点的值;然后逆向(从上到下)遍历整个图,计算出节点的偏导值,步骤如下图所示;节点内蓝色的数值表示正向计算出的结果,为了方便表达,我们从下到上,从左到右依次标注为\(n_1\)到\(n_7\),可以看到最后的值\(n_7\)(顶部节点)为42。

在逆向求导过程中使用链式求导方法:

\(\frac{\partial{f}}{\partial{x}}=\frac{\partial{f}}{\partial{n_i}}{\times}\frac{\partial{n_i}}{\partial{x}}\)

先看节点\(n_7\),作为输出节点\(f=n_7\),所以导数值为\(\frac{\partial{f}}{\partial{n_7}}=1\),

接着向下计算\(n_5\),\(\frac{\partial{f}}{\partial{n_5}}=\frac{\partial{f}}{\partial{n_7}}{\times}\frac{\partial{n_7}}{\partial{n_5}}\),上一步计算出\(\frac{\partial{f}}{\partial{n_7}}=1\),现在我们只需要计算\(\frac{\partial{n_7}}{\partial{n_5}}\),从图中我们知道\(n_7=n_5+n_6\),可以得出\(\frac{\partial{f}}{\partial{x}}=1\)。所以\(\frac{\partial{f}}{\partial{n_5}}=1\),接下来的步骤可以看上面的图,这里就不赘述了。

逆向自动求导法这种方法十分强大且准确率较高,尤其是有却多的输入。这种发方法仅需要正向和逆向遍历一次即可,这种方法更强大的地方在于能够解决符号求解法硬代码的问题。

自动微分方法(auto diff)的更多相关文章

  1. MindSpore:自动微分

    MindSpore:自动微分 作为一款「全场景 AI 框架」,MindSpore 是人工智能解决方案的重要组成部分,与 TensorFlow.PyTorch.PaddlePaddle 等流行深度学习框 ...

  2. 附录D——自动微分(Autodiff)

    本文介绍了五种微分方式,最后两种才是自动微分. 前两种方法求出了原函数对应的导函数,后三种方法只是求出了某一点的导数. 假设原函数是$f(x,y) = x^2y + y +2$,需要求其偏导数$\fr ...

  3. <转>如何用C++实现自动微分

    作者:李瞬生转摘链接:https://www.zhihu.com/question/48356514/answer/123290631来源:知乎著作权归作者所有. 实现 AD 有两种方式,函数重载与代 ...

  4. (转)自动微分(Automatic Differentiation)简介——tensorflow核心原理

    现代深度学习系统中(比如MXNet, TensorFlow等)都用到了一种技术——自动微分.在此之前,机器学习社区中很少发挥这个利器,一般都是用Backpropagation进行梯度求解,然后进行SG ...

  5. 【tensorflow2.0】自动微分机制

    神经网络通常依赖反向传播求梯度来更新网络参数,求梯度过程通常是一件非常复杂而容易出错的事情. 而深度学习框架可以帮助我们自动地完成这种求梯度运算. Tensorflow一般使用梯度磁带tf.Gradi ...

  6. acm对拍程序 以及sublime text3的文件自动更新插件auto refresh

    acm等算法比赛常用---对拍 以及sublime text3的文件自动更新插件auto refresh 对拍 对拍即程序自动对比正确程序的运行结果和错误程序的运行结果之间的差异 废话少说, 直接上操 ...

  7. 分子动力学模拟之基于自动微分的LINCS约束

    技术背景 在分子动力学模拟的过程中,考虑到运动过程实际上是遵守牛顿第二定律的.而牛顿第二定律告诉我们,粒子的动力学过程仅跟受到的力场有关系,但是在模拟的过程中,有一些参量我们是不希望他们被更新或者改变 ...

  8. MindSpore多元自动微分

    技术背景 当前主流的深度学习框架,除了能够便捷高效的搭建机器学习的模型之外,其自动并行和自动微分等功能还为其他领域的科学计算带来了模式的变革.本文我们将探索如何用MindSpore去实现一个多维的自动 ...

  9. LibTorch 自动微分

    得益于反向传播算法,神经网络计算导数时非常方便,下面代码中演示如何使用LibTorch进行自动微分求导. 进行自动微分运算需要调用函数 torch::autograd::grad( outputs, ...

随机推荐

  1. JAVA基础-XML的解析

    一.XML的概述 XML的全名为可扩展标记语言(Extensible Markup Language),XML的作用为:1.传输,2.存取数据,3.软件的配置文件.传输现在都用更轻量的Json,而存储 ...

  2. 聊聊 Material Design 里,阴影的那些事儿!

    当你的设计师要求你在某个 View 上增加阴影效果,那你只需要认真阅读本文,阴影的问题就不再是问题. 一.前言 设计师的世界,与常人不同,有时候想要扁平化的风格,有时候又想要拟物化的风格.而在 Mat ...

  3. 用ajax的同步请求解决登陆注册需要根据服务器返回数据判断是否能提交的问题

    最近在写www.doubilaile.com的登陆注册.需要用ajax请求服务器判断用户名是否存在,用户名和密码是否匹配,进而提交数据.碰到的问题是异步请求都能成功返回数据,但是该数据不能作为紧接着的 ...

  4. BZOJ-1864-[Zjoi2006]三色二叉树(树形dp)

    Description Input 仅有一行,不超过500000个字符,表示一个二叉树序列. Output 输出文件也只有一行,包含两个数,依次表示最多和最少有多少个点能够被染成绿色. Sample ...

  5. this指向(匿名函数问题)

    1.匿名函数中 this一般指向window对象 2.闭包函数中的this,指向window var mod = { init: function(){ console.log('this',this ...

  6. JAVA 后台SSM框架接收安卓端的json数据

    最近项目上与安卓端做JSON数据交互,使用的SSM框架,刚开始的时候感觉很简单,想着不就是把安卓端的JSON数据封装为Bean类对象吗? 于是就这样写了 可是这样一直报400,百度原因是因为请求url ...

  7. Python 解LeetCode:654. Maximum Binary Tree

    用一个整型数组构建一个二叉树,根结点是数组中的最大值,左右子树分别是根结点的值在数组中左右两边的部分. 分析,这是二叉树中比较容易想到的问题了,直接使用递归就行了,代码如下: class Soluti ...

  8. C#模拟登录总结

    /// <summary>  登录        /// </summary>        /// <param name="url">< ...

  9. [转载] Redis之七种武器

    转载自http://blog.nosqlfan.com/html/2942.html?ref=rediszt 长生剑.孔雀翎.碧玉刀.多情环.离别钩.霸王枪.拳头是古龙笔下的七种武器,而本文打算将Re ...

  10. linux操作系统基础篇(八)

    shell脚本的变量以及正则表达式 一.变量 含义:程序的运行就是一些列状态的变量->用变量值的变化去表示. 命名规则 以字母或下划线开头,剩下的部分可以是:字母.数字.下划线. 最好遵循下述规 ...