Julia ReverseDiff: 如何仅对输入的子集求梯度?

在我的数据流中,我从数据库中查询一个小子集,使用这些结果构建大约十二个数组,然后根据一些参数值计算一个似然值。接着对数据库的另一个子集重复这一过程。我希望计算似然函数相对于参数而非数据的梯度。但是,ReverseDiff会计算相对于所有输入的梯度。我该如何解决这个问题?具体来说,我该如何构造一个ReverseDiff.Tape对象?

简而言之:如何将随机梯度下降与ReverseDiff结合?(我并不执着于使用ReverseDiff。它只是看起来像是这项工作的合适工具。)

这似乎应该是一个常见的编码模式。在我的领域中经常使用。但我似乎遗漏了什么。Julia的作用域规则似乎破坏了作用域/匿名函数的方法,而ReverseDiff在生成的磁带中保留了原始数据值,而不是使用修改后的值。

一些不工作的样本代码

using ReverseDiffusing Base.Testmutable struct data    X::Array{Float64, 2}endconst D = data(zeros(Float64, 2, 2))# 基线已知数据用于比较function f1(params)    X = float.([1 2; 3 4])    f2(params, X)end# X是数据,只想对params求导function f2(params, X)    sum(params[1]' * X[:, 1] - (params[1] .* params[2])' * X[:, 2].^2)end# 将感兴趣的数据存储在D.X中,以便我们只调用f2(params)就能得到我们的# 梯度f2(params) = f2(params, D.X)# 使用内部函数并替换Z的数据function scope_test()    function f2_only_params(params)        f2(params, Z)    end    Z = float.([6 7; 1 3])    f2_tape = ReverseDiff.GradientTape(f2_only_params, [1, 2])    Z[:] = float.([1 2; 3 4])    grad = ReverseDiff.gradient!(f2_tape, [3,4])    return gradendfunction struct_test()    D.X[:] = float.([6 7; 1 3])    f2_tape = ReverseDiff.GradientTape(f2, [1., 2.])    D.X[:] = float.([1 2; 3 4])    grad = ReverseDiff.gradient!(f2_tape, [3., 4.])    return gradendfunction struct_test2()    D.X[:] = float.([1 2; 3 4])    f2_tape = ReverseDiff.GradientTape(f2, [3., 4.])    D.X[:] = float.([1 2; 3 4])    grad = ReverseDiff.gradient!(f2_tape, [3., 4.])    return gradendD.X[:] = float.([1 2; 3 4])@test f1([3., 4.]) == f2([3., 4.], D.X)@test f1([3., 4.]) == f2([3., 4.])f1_tape = ReverseDiff.GradientTape(f1, [3,4])f1_grad = ReverseDiff.gradient!(f1_tape, [3,4])# 失败!使用第33行的值@test scope_test() == f1_grad# 失败,使用第42行的值@test struct_test() == f1_grad# 成功,所以,不是完全随机的@test struct_test2() == f1_grad

回答:

谢谢Alex,你的回答已经解决了90%的问题。AutoGrad(Knet在撰写时使用的东西)确实提供了一个非常好的界面,我认为对大多数用户来说这是自然的。然而,使用ReverseDiff的匿名函数实际上比AutoGrad采用的方法更快,原因我还不太明白。

如果你跟随你所链接的问题链,这似乎是ReverseDiff/ForwardDiff团队希望人们做的事情:

ReverseDiff.gradient(p -> f(p, non_differentiated_data), params)

不能在这种非常常见的使用场景中获得预编译的磁带确实令人失望,也许未来的工作会改变这一点。但这就是目前的情况。

对那些有兴趣进一步阅读的人提供一些参考资料:

Related Posts

Keras Dense层输入未被展平

这是我的测试代码: from keras import…

无法将分类变量输入随机森林

我有10个分类变量和3个数值变量。我在分割后直接将它们…

如何在Keras中对每个输出应用Sigmoid函数?

这是我代码的一部分。 model = Sequenti…

如何选择类概率的最佳阈值?

我的神经网络输出是一个用于多标签分类的预测类概率表: …

在Keras中使用深度学习得到不同的结果

我按照一个教程使用Keras中的深度神经网络进行文本分…

‘MatMul’操作的输入’b’类型为float32,与参数’a’的类型float64不匹配

我写了一个简单的TensorFlow代码,但不断遇到T…

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注