自动微分方法(auto diff)
学习机器学习的同学在学习过程中会经常遇到一个问题,那就是对目标函数进行求微分,线性回归这类简单的就不说、复杂的如神经网络类那些求导过程的酸爽
。像我还是那种比较粗心的人往往有十导
九错,所以说自动求导就十分有必要了,本文主要介绍几种求导的方式。假设我们的函数为\(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
,其中a
和b
是实数,\(\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)的更多相关文章
- MindSpore:自动微分
MindSpore:自动微分 作为一款「全场景 AI 框架」,MindSpore 是人工智能解决方案的重要组成部分,与 TensorFlow.PyTorch.PaddlePaddle 等流行深度学习框 ...
- 附录D——自动微分(Autodiff)
本文介绍了五种微分方式,最后两种才是自动微分. 前两种方法求出了原函数对应的导函数,后三种方法只是求出了某一点的导数. 假设原函数是$f(x,y) = x^2y + y +2$,需要求其偏导数$\fr ...
- <转>如何用C++实现自动微分
作者:李瞬生转摘链接:https://www.zhihu.com/question/48356514/answer/123290631来源:知乎著作权归作者所有. 实现 AD 有两种方式,函数重载与代 ...
- (转)自动微分(Automatic Differentiation)简介——tensorflow核心原理
现代深度学习系统中(比如MXNet, TensorFlow等)都用到了一种技术——自动微分.在此之前,机器学习社区中很少发挥这个利器,一般都是用Backpropagation进行梯度求解,然后进行SG ...
- 【tensorflow2.0】自动微分机制
神经网络通常依赖反向传播求梯度来更新网络参数,求梯度过程通常是一件非常复杂而容易出错的事情. 而深度学习框架可以帮助我们自动地完成这种求梯度运算. Tensorflow一般使用梯度磁带tf.Gradi ...
- acm对拍程序 以及sublime text3的文件自动更新插件auto refresh
acm等算法比赛常用---对拍 以及sublime text3的文件自动更新插件auto refresh 对拍 对拍即程序自动对比正确程序的运行结果和错误程序的运行结果之间的差异 废话少说, 直接上操 ...
- 分子动力学模拟之基于自动微分的LINCS约束
技术背景 在分子动力学模拟的过程中,考虑到运动过程实际上是遵守牛顿第二定律的.而牛顿第二定律告诉我们,粒子的动力学过程仅跟受到的力场有关系,但是在模拟的过程中,有一些参量我们是不希望他们被更新或者改变 ...
- MindSpore多元自动微分
技术背景 当前主流的深度学习框架,除了能够便捷高效的搭建机器学习的模型之外,其自动并行和自动微分等功能还为其他领域的科学计算带来了模式的变革.本文我们将探索如何用MindSpore去实现一个多维的自动 ...
- LibTorch 自动微分
得益于反向传播算法,神经网络计算导数时非常方便,下面代码中演示如何使用LibTorch进行自动微分求导. 进行自动微分运算需要调用函数 torch::autograd::grad( outputs, ...
随机推荐
- C#匹配标签正则,获取标签的值
比如要获取: <color=#50cccc>头盔坐标:(-0.6, 1.0, 1.2)</color><color=#3d85c6>头盔方向(-0.2, 0.1, ...
- 一起来学linux:SSH远程登陆
p { margin-bottom: 0.25cm; line-height: 120% } a:link { } 在最早的远程连接技术,主要是telnet和RSH为主.缺点也很明显,就是明文传输.在 ...
- 通过 ODBC 访问数据库获取数据集
Step1:(window 中完成): 控制面板/管理工具/ODBC 数据源/用户 Step2:(window 中完成): 添加/SQL Server Step3:(window 中完成): 自己定义 ...
- ssh密钥创建分发(端口号非22)&脚本实现自动创建分发密钥
1.1 服务端端口号变化了,如何基于秘钥连接 1.1.1 环境准备 实验环境: [root@test ~]# cat /etc/redhat-release CentOS release 6.9 (F ...
- Linux分区规划与xshell使用排错
1.1 没有重要数据 /boot 200M 存放系统的引导信息 内核 swap 交换分区 防止内存用光了 临时的一个内存 如果你的内存小于8G swap是内存的1.5倍 如果你的 ...
- cloneNode克隆节点在不同浏览器的差异
cloneNode是用于克隆节点的,如果待克隆的节点还有子节点以及自定义属性.添加的有事件,那么克隆时,可以指定是克隆节点本身,还是将其所有子节点信息也克隆进去,这是通过给cloneNode传递一个布 ...
- JavaScript 中对变量和函数声明的“提前(hoist)”
hoist vt.升起,提起; vi.被举起或抬高; n.起重机,升降机; 升起; <俚>推,托,举; 这篇文章不讲英语,但是对于某些英语单词找不到很好的翻译,一上来就列出“hoist”这 ...
- 使用SQLPLUS创建用户名和表空间
用sqlplus为oracle创建用户和表空间用sqlplus为oracle创建用户和表空间用Oracle10g自带的企业管理器或PL/SQL图形化的方法创建表空间和用户以及分配权限是相对比较简单的, ...
- 《剑指offer》面试题的Python实现
<剑指Offer>是很多程序员面试前要看的书,但里面的算法都是基于C++实现的,最近用了三周左右时间,用Python完成了里面几乎所有的算法题,由于时间以及个人水平均有限,或许会有部分问题 ...
- spring+struts2+hibernate整合
web.xml需要配置 <context-param> <param-name>contextConfigLocation</param-name> <par ...