我正在研究加速大部分C++代码的方法,这些代码具有用于计算jacobians的自动衍生产品.这涉及在实际残差中做一些工作,但大部分工作(基于异形执行时间)是在计算雅可比人.
这使我感到惊讶,因为大多数雅各比人都是从0和1向前传播,因此工作量应该是功能的2-4倍,而不是10-12倍.为了模拟大量的jacobian工作是什么样的,我用一个点积(而不是sin,cos,sqrt和更多将在真实情况下)制作了一个超级极小的例子,编译器应该能够优化到单个返回值:
#include <Eigen/Core>
#include <Eigen/Geometry>
using Array12d = Eigen::Matrix<double,12,1>;
double testReturnFirstDot(const Array12d& b)
{
Array12d a;
a.array() = 0.;
a(0) = 1.;
return a.dot(b);
}
Run Code Online (Sandbox Code Playgroud)
哪个应该是一样的
double testReturnFirst(const Array12d& b)
{
return b(0);
}
Run Code Online (Sandbox Code Playgroud)
我很失望地发现,如果没有启用快速数学运算,GCC 8.2,Clang 6或MSVC 19都无法对具有0的矩阵的天真点积进行任何优化.即使使用快速数学(https://godbolt.org/z/GvPXFy),GCC和Clang中的优化也很差(仍然涉及乘法和加法),并且MSVC根本不做任何优化.
我没有编译器的背景,但是有这个原因吗?我相当肯定,即使恒定折叠本身不会导致加速,在很大比例的科学计算中能够做更好的恒定传播/折叠会使更多的优化变得明显.
虽然我有兴趣解释为什么在编译器方面没有这样做,但我也对在实际方面可以做什么感兴趣,以便在面对这些模式时更快地使我自己的代码.
c++ compiler-construction automatic-differentiation eigen ceres-solver
我正在阅读神经转移pytorch教程,并对使用retain_variable(弃用,现在称为retain_graph)感到困惑.代码示例显示:
class ContentLoss(nn.Module):
def __init__(self, target, weight):
super(ContentLoss, self).__init__()
self.target = target.detach() * weight
self.weight = weight
self.criterion = nn.MSELoss()
def forward(self, input):
self.loss = self.criterion(input * self.weight, self.target)
self.output = input
return self.output
def backward(self, retain_variables=True):
#Why is retain_variables True??
self.loss.backward(retain_variables=retain_variables)
return self.loss
Run Code Online (Sandbox Code Playgroud)
从文档中
retain_graph(bool,optional) - 如果为False,将释放用于计算grad的图形.请注意,几乎在所有情况下都不需要将此选项设置为True,并且通常可以以更有效的方式解决此问题.默认为create_graph的值.
因此,通过设置retain_graph= True,我们不会释放在向后传递上为图形分配的内存.保持这种记忆的优势是什么,我们为什么需要它?
automatic-differentiation backpropagation neural-network conv-neural-network pytorch
我正在努力优化一个依赖于ads conjugateGradientDescent函数的程序来完成大部分工作.
基本上我的代码是用Matlab和C编写的旧论文代码的翻译.我没有测量它,但是代码每秒运行几次迭代.我的每次迭代大约为几分钟......
代码在此存储库中可用:
可以通过以下命令运行相关代码:
$ cd aer-utils
$ cabal sandbox init
$ cabal sandbox add-source ../aer
$ cabal run learngabors
Run Code Online (Sandbox Code Playgroud)
使用GHC分析设施我已经确认下降实际上是大部分时间都在使用的部分:

(此处为交互式版本:https://dl.dropboxusercontent.com/u/2359191/learngabors.svg)
-s 告诉我生产力很低:
Productivity 33.6% of total user, 33.6% of total elapsed
Run Code Online (Sandbox Code Playgroud)
根据我收集的内容,有两件事可能会带来更高的性能:
拆箱:目前我使用自定义矩阵实现(in src/Data/SimpleMat.hs).这是我可以ad使用矩阵的唯一方法(参见:如何在hmatrix上自动区分?).我的猜测是,通过使用矩阵类型,newtype Mat w h a = Mat (Unboxed.Vector a)由于拆箱和融合将获得更好的性能.我找到了一些代码,其中包含未ad装箱的矢量实例,但到目前为止我还没有能够使用这些代码conjugateGradientFunction.
矩阵导数:在目前我无法找到的电子邮件中,爱德华提到最好使用Forward矩阵类型的实例而不是填充Forward实例的矩阵.我对如何实现这一点有一个微弱的想法,但还没有弄清楚我是如何根据ads类类实现它的.
这可能是一个太宽泛而无法回答的问题,所以如果你愿意帮助我,请随时与我联系Github.
我似乎无法理解其中的差异.对我而言,看起来两者都只是通过一个表达并应用链规则.我错过了什么?
我在Haskell中看到的最接近相关的实现是http://hackage.haskell.org/packages/archive/fad/1.0/doc/html/Numeric-FAD.html上的前向模式.
最近的相关相关研究似乎是与http://www.bcl.hamilton.ie/~qobi/stalingrad/上与Scheme相关的另一种功能语言的反向模式.
我认为Haskell中的反向模式对于许多任务来说都是一种圣杯,希望它可以使用Haskell的嵌套数据并行性来在繁重的数值优化中获得良好的加速.
我听说McCarthy发明Lisp的原始动机之一是编写一个自动区分系统.尽管如此,我的Google搜索还没有为此做出任何库/宏.是否有任何Scheme/Common Lisp/Clojure库(宏)用于获取函数F并返回计算F的导数的函数dF/dx?
我希望它能用多个参数支持F'.用户可以选择哪个是x来区分.理想情况下,微分器甚至可以用于矢量值F和x.
编辑:有几个人提到了象征性的差异化.符号微分和自动微分之间的区别是微妙的,但它在维基百科中得到了很好的总结,特别是在这张图片中.这种区别在lisp中并不那么强烈,其中符号表达式可以按原样转换为工作程序,但仍存在潜在的困难:
符号微分要求表达式被区分为由具有已知衍生物的操作组成.例如,有人提到了SICP的一个宏的例子,它通过简单的性行为进行搅拌(+ y (* (x y))),并使用链规则,以及如何区分+和*返回代表衍生物的性别的知识.我需要使用表达式,例如(* (foo x y) (bar x)),where foo和barmay可以依次调用其微分时间不知道其衍生物的其他函数.
如果有采取类似的表达方式,这将是罚款(foo x y),并以其函数体替换,替换参数中的任何提及与x和y在卫生型的方式.在那儿?
此外,上述任何一个都没有解决在将向量值函数与向量值参数区分开来时出现的复杂情况......这是大多数自动微分实现的适应性.
lisp scheme clojure automatic-differentiation numerical-methods
我有Haskell功能,这导致了我的程序的所有分配的50%以上,导致60%的运行时间被GC占用.我运行一个小堆栈(-K10K)所以没有堆栈溢出,但是我可以更快地使用更少的分配来实现此功能吗?
这里的目标是通过向量计算矩阵的乘积.我不能使用hmatrix例如因为这是使用ad自动微分包的更大功能的一部分,所以我需要使用列表Num.在运行时,我想使用Numeric.AD模块意味着我的类型必须是Scalar Double.
listMProd :: (Num a) => [a] -> [a] -> [a]
listMProd mdt vdt = go mdt vdt 0
where
go [] _ s = [s]
go ls [] s = s : go ls vdt 0
go (y:ys) (x:xs) ix = go ys xs (y*x+ix)
Run Code Online (Sandbox Code Playgroud)
基本上我们遍历矩阵,乘以并添加一个累加器,直到我们到达向量的末尾,存储结果,然后再继续重新启动向量.我有一个quickcheck测试验证我得到的结果与hmatrix中的矩阵/矢量产品相同.
我有试过foldl,foldr等没事我试着让函数更快(有些事情就像foldr原因的内存泄露).
使用性能分析运行告诉我,除了大部分时间和分配所花费的功能之外,还有一些Cells正在创建的负载,即Cells来自ad包的数据类型.
一个简单的测试运行:
import …Run Code Online (Sandbox Code Playgroud) performance garbage-collection haskell list automatic-differentiation
用于计算梯度的反向传播算法已被多次重新发现,并且是在反向累积模式中称为自动微分的更通用技术的特殊情况.
有人可以用这个来解释这个问题吗?被区分的功能是什么?什么是"特例"?它是使用的伴随值本身还是最终的渐变?
algorithm automatic-differentiation calculus backpropagation neural-network
我正在尝试使用Numeric.AD和自定义Expr类型.我希望计算用户输入表达式的符号梯度.使用常量表达式的第一个试验非常有效:
calcGrad0 :: [Expr Double]
calcGrad0 = grad df vars
where
df [x,y] = eval (env [x,y]) (EVar "x"*EVar "y")
env vs = zip varNames vs
varNames = ["x","y"]
vars = map EVar varNames
Run Code Online (Sandbox Code Playgroud)
这有效:
>calcGrad0
[Const 0.0 :+ (Const 0.0 :+ (EVar "y" :* Const 1.0)),Const 0.0 :+ (Const 0.0 :+ (EVar "x" :* Const 1.0))]
Run Code Online (Sandbox Code Playgroud)
但是,如果我将表达式作为参数拉出:
calcGrad1 :: [Expr Double]
calcGrad1 = calcGrad1' (EVar "x"*EVar "y")
calcGrad1' e = grad df vars
where
df [x,y] = eval (env …Run Code Online (Sandbox Code Playgroud) Swift for Tensorflow项目的Swift 中添加了对差分编程的本机支持。Julia 与Zygote类似。
什么是可微分编程?
这些程序可以在整个过程中有所不同
但是,这是什么意思?