Julia 网络表达式 Flux
Julia network expression Flux
学习Julia元编程通过表达式自动构造ANN。虽然一切都适用于推理,但向后阶段会引发错误:
LoadError: Can't differentiate foreigncall expression
下一个代码显示了问题出现的位置。虽然 eval(net(x)) 运行良好,但出于某种原因,它会在梯度计算阶段抛出错误。
# define ANN by expression
net(x) = :($w2 * relu.($w1 * $x .+ $b1) .+ $b2)
# define loss and network evaluation
loss(x, y) = Flux.logitcrossentropy(eval(net(x)), y)
θ = Flux.Params([w1, b1, w2, b2])
# eval network and calculate gradients
gs = gradient(() -> loss(features, labels), θ) # where the problem appears
eval
是 Flux
无法区分的原语。你宁愿使用像
这样的东西
net = :($w2 * relu.($w1 * x .+ $b1) .+ $b2)
@eval loss(x, y) = Flux.logitcrossentropy($net, y)
构建 loss
的表达式并计算一次,而不是每次调用损失函数时都计算(并因此编译)同一段代码。
但是在元编程之前要三思。在求助于 eval
之前,尝试编写一个宏来生成您的网络和损失函数。
当然,如果目标是将仅在运行时可用的表达式组合在一起,那么这将不起作用。遗传编程,在运行时创建大量随机表达式,听起来像是一个合理的例外。但即便如此,也可能有其他选择,比如使用您自己的受限表示(例如,您可以首先符号化微分,然后 "compile" 到匿名函数)。
学习Julia元编程通过表达式自动构造ANN。虽然一切都适用于推理,但向后阶段会引发错误:
LoadError: Can't differentiate foreigncall expression
下一个代码显示了问题出现的位置。虽然 eval(net(x)) 运行良好,但出于某种原因,它会在梯度计算阶段抛出错误。
# define ANN by expression
net(x) = :($w2 * relu.($w1 * $x .+ $b1) .+ $b2)
# define loss and network evaluation
loss(x, y) = Flux.logitcrossentropy(eval(net(x)), y)
θ = Flux.Params([w1, b1, w2, b2])
# eval network and calculate gradients
gs = gradient(() -> loss(features, labels), θ) # where the problem appears
eval
是 Flux
无法区分的原语。你宁愿使用像
net = :($w2 * relu.($w1 * x .+ $b1) .+ $b2)
@eval loss(x, y) = Flux.logitcrossentropy($net, y)
构建 loss
的表达式并计算一次,而不是每次调用损失函数时都计算(并因此编译)同一段代码。
但是在元编程之前要三思。在求助于 eval
之前,尝试编写一个宏来生成您的网络和损失函数。
当然,如果目标是将仅在运行时可用的表达式组合在一起,那么这将不起作用。遗传编程,在运行时创建大量随机表达式,听起来像是一个合理的例外。但即便如此,也可能有其他选择,比如使用您自己的受限表示(例如,您可以首先符号化微分,然后 "compile" 到匿名函数)。