- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
我们在《数值分析》课程中已经学过许多经典的数值微分方法。许多经典的数值微分算法非常快,因为它们只需要计算差商。然而,他们的主要缺点在于他们是数值的,这意味着有限的算术精度和不精确的函数求值,而这些都从根本上限制了求解结果的质量。因此。充满噪声的、复杂多变的函数很难得到精准的数值微分.
自动微分技术(称为“automatic differentiation, autodiff”)是介于符号微分和数值微分的一种技术,它是在计算效率和计算精度之间的一种折衷。自动微分不受任何离散化算法误差的约束,它充分利用了微分的链式法则和其他关于导数的性质来准确地计算它们.
我们先来计算简单的前向自动微分。假设我们有两个变量 \(u\) 和 \(v\) ,使用浮点数存储。我们将变量 \(u′=du/dt\) 和 \(v′=dv/dt\) 和这些变量一起存储,这里 \(t\) 是独立的变量。在一些程序设计语言(如Python)中,我们可以选择定义一种新的数据类型来存储 \([u,u′]\) 和 \([v,v′]\) 这类数对。我们可以在这些数对上定义一种代数运算,这些代数运算编码了一些经典的操作:
在进行前向自动微分之前,我们需要先将计算 \(f(t)\) 所产生的操作序列表示为计算图。接着,采用自底向上的递推算法的思想,从做为递推起点的数对 \(t≡[t_0,1]\) (因为 \(dt/dt= 1\) )开始,我们能够按照我们上述编码规则同时对函数 \(f(t)\) 和它的导数 \(f′(t)\) 进行求值。我们在编程语言中可以选择令数对重载运算符,这样额外的求导数运算就可以对用户透明地执行了.
例1 比如,对于函数 \(f(x) = \exp(x^2 - x)/{x}\) ,想要依次计算 \({dy}_i/dx\) (这里 \(y_i\) 为所有计算中间项)。则我们先从 \(x\) 开始将表达式分解为计算图:
然后前向递推地按照我们之前所述的编码规则来进行求导 。
注意链式法则(chain rule)告诉我们:
所以我们对 。
有 。
事实上,我们也能够处理有多个输入的函数 \(g\) :
多元微分链式法则如下:
比如,对于 。
我们有 。
下面展示了一个对二元函数模拟前向自动微分的过程.
例2 设 \(f(x_1, x_2) = x_1\cdot \exp(x_2) - x_1\) ,模拟前向微分过程.
接下来我们看如何用Python代码来实现单变量函数的前向自动微分过程。为了简便起见,我们下面只编码了几个常用的求导规则.
import math
class Var:
def __init__(self, val, deriv=1.0):
self.val = val
self.deriv = deriv
def __add__(self, other):
if isinstance(other, Var):
val = self.val + other.val
deriv = self.deriv + other.deriv
else:
val = self.val + other
deriv = self.deriv
return Var(val, deriv)
def __radd__(self, other):
return self + other
def __sub__(self, other):
if isinstance(other, Var):
val = self.val - other.val
deriv = self.deriv - other.deriv
else:
val = self.val - other
deriv = self.deriv
return Var(val, deriv)
def __rsub__(self, other):
val = other - self.val
deriv = - self.deriv
return Var(val, deriv)
def __mul__(self, other):
if isinstance(other, Var):
val = self.val * other.val
deriv = self.val * other.deriv + self.deriv * other.val
else:
val = self.val * other
deriv = self.deriv * other
return Var(val, deriv)
def __rmul__(self, other):
return self * other
def __truediv__(self, other):
if isinstance(other, Var):
val = self.val / other.val
deriv = (self.deriv * other.val - self.val * other.deriv)/other.val**2
else:
val = self.val / other
deriv = self.deriv / other
return Var(val, deriv)
def __rtruediv__(self, other):
val = other / self.val
deriv = other * 1/self.val**2
return Var(val, deriv)
def __repr__(self):
return "value: {}\t gradient: {}".format(self.val, self.deriv)
def exp(f: Var):
return Var(math.exp(f.val), math.exp(f.val) * f.deriv)
例如,我们若尝试计算函数 \(f(x) = \exp(x^2 - x)/{x}\) 在 \(x=2.0\) 处的导数 \(f'(2.0)\) 如下:
fx = lambda x: exp(x*x - x)/x
df = fx(Var(2.0))
print(df)
打印输出:
value: 3.694528049465325 deriv: 9.236320123663312
可见,前向过程完成计算得到 \(f(2.0)\approx 3.69\) , \(f'(2.0)\approx 9.24\) .
我们前面介绍的前向自动微分方法在计算 \(y = f(t)\) 的时候并行地计算 \(f'(t)\) 。接下来我们介绍一种“反向”自动微分方法,相比上一种的方法它仅需要更少的函数求值,不过需要以更多的内存消耗和更复杂的实现做为代价.
同样,这个技术需要先将计算 \(f(t)\) 所产生的操作序列表示为计算图。不过,与之前的从 \(dt/dt = 1\) 开始,然后往 \(dy/dt\) 方向计算不同,反向自动求导算法从 \(dy/dy = 1\) 开始并且按与之前同样的规则往反方向计算,一步步地将分母替换为 \(dt\) 。反向自动微分可以避免不必要的计算,特别是当 \(y\) 是一个多元函数的时候。例如,对 \(f(t_1, t_2) = f_1(t_1) + f_2(t_2)\) ,反向自动微分并不需要计算 \(f_1\) 关于 \(t_2\) 的微分或 \(f_2\) 关于 \(t_1\) 的微分.
例3 设 \(f(x_1, x_2) = x_1\cdot \exp(x_2) - x_1\) ,模拟反向自动微分过程.
可见若采用反向自动微分,我们需要存储计算过程中的所有东西,故内存的使用量会和时间成正比。不过,在现有的深度学习框架中,对反向自动微分的实现进行了进一步优化,我们会在深度学习专题文章中再进行详述.
自动微分被广泛认为是一种未被充分重视的数值技术, 它可以以尽量小的执行代价来产生函数的精确导数。它在软件需要计算导数或Hessian来运行优化算法时显得格外有价值,从而避免每次目标函数改变时都去重新手动计算导数。当然,做为其便捷性的代价,自动微分也会带来计算的效率问题,因为在实际工作中自动微分方法并不会去化简表达式,而是直接应用最显式的编码规则.
[1] Solomon J. Numerical algorithms: methods for computer vision, machine learning, and graphics[M]. CRC press, 2015. 。
[2] S&DS 631: Computation and Optimization Automatic Differentiation 。
最后此篇关于数值计算:前向和反向自动微分(Python实现)的文章就讲到这里了,如果你想了解更多关于数值计算:前向和反向自动微分(Python实现)的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我正在开发一个 Java 脚本,为此我需要正则表达式来检查文本框中输入的文本是否应该是字母和数值的组合。 我尝试了 Java 脚本的 NaN 函数,但字符串的最小长度和最大长度应为 4,并以字母作为第
我给出了两个长方体,其中只有一个轴对齐(另外两个不需要对齐)和顶点坐标(在全局坐标系中),我知道它们相交。我正在寻找一种可以计算路口体积的算法。 为了检查交点,我使用了分离轴定理。 最佳答案 可以通过
我有一个类似这样的对象的 json 列表 [{ "something": "bla", "id": 2 }, { "something": "yes", "id": 1
这是一篇很长的文章,但请留在我身边... 我有一个字典,它将“PO”保存为Key,将“SO”保存为项目(在某些情况下,某个“PO”可能有多个“SO”) . 工作表中的我的 Excel 数据,字典在其中
我的问题是是否有办法使用 terms include在 numeric field在 elasticsearch aggregation . 我在 Elasticsearch 中对多个字段使用通用查询
我有一个 perl 代码片段 use JSON::XS; $a = {"john" => "123", "mary" => "456"}; print encode_json($a),"\n"; 输出
我想对 python 进行一个条件测试,以检查给定输入数字的值是否等于或小于 9,并且大于或等于 0。 number =input( "Please enter a number! :" ) Plea
我有一个这样的对象: var rock = { 5: 0.5, 0: 0.8, 10: 0.3, 2: 1.0, } 我有一个像 4.3 这样的数字,我需要前后数字的索引和值。在这个例子中我会
对于 iOS 中的 Objective-C: 如果我有一个字符串,如何读取单个字符的 unicode 数值? 例如,如果我的字符串是:“Δ”,unicode 字符是 U+0394,那么我如何读取该字符
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 要求我们推荐或查找工具、库或最喜欢的场外资源的问题对于 Stack Overflow 来说是偏离主题的,
我有这样的数组 var arrayVal_Int = ["21", "53", "92", "79"]; var arrayVal_Alpha = ["John", "Christine", "L
就像标题暗示我需要做这样的事情...... $i++;//we all know this. $value = 'a'; increment($value);// i need this functi
我有一个文件,其中包含一些不同值的概率,例如: 1 0.1 2 0.05 3 0.05 4 0.2 5 0.4 6 0.2 我想使用此分布生成随机数。是否存在处理此问题的现有模块?自己编写代码相当简单
因此,我在从使用 RCPP 创建的函数返回值时遇到了一些问题。它只返回 NumericVector 的第一个值。问题是当我在自身内部调用函数并将 NumericVector 传递回 out 变量时。任
我有下面的数字 vector 模板类(用于数值计算的 vector )。我正在尝试使编写 D=A+B+C 成为可能,其中所有变量都是 Vector 对象。 A、B 和 C 不应修改。我的想法是使用 V
本文实例讲述了mysql常用函数。分享给大家供大家参考,具体如下: 本文内容: mysql函数的介绍 聚集函数 avg count max
我正在尝试使用 python(无关)为我的公司自动化一些事情,这就是我的问题。首先,我正在从邮箱中的特定文件夹创建数据框。(到这里没问题)” RangeIndex: 36 entries, 0 to
我在让 Angular ng-if 工作时遇到了一些麻烦。我希望我的 DOM 元素之一在 $scope.week = 1 时消失。 在我的 Controller 中我设置了 $scope.week =
我正在阅读 Ingersoll、Morton 和 Farris 撰写的 Taming Text,但我不明白 solr 的数字 trie 实现如何帮助搜索文本?我对 solr.TrieField fie
这个问题已经有答案了: What is the difference between client-side and server-side programming? (3 个回答) 已关闭 9 年前
我是一名优秀的程序员,十分优秀!