我一直在尝试将一组微分方程拟合到我拥有的一些数据上,这些方程有18个参数需要拟合,但理想情况下,其中一些参数应该为零或趋向于零。在谷歌搜索过程中,我发现了一种将DE层构建到神经网络中的方法,并且我找到了几个包含Julia代码示例的Github仓库,然而我对Julia和神经ODE都很陌生。特别是,我一直在修改这个示例中的代码:
https://computationalmindset.com/en/neural-networks/experiments-with-neural-odes-in-julia.html
不同之处在于:我有3个DE系统,而不是2个,我有18个参数,并且我导入了两个CSV文件来拟合数据,而不是生成一个玩具数据集来拟合。
我的困境:在谷歌搜索时,我遇到了LASSO/L1正则化,希望通过在成本函数中添加L1惩罚,我可以“清零”一些参数。问题是我不知道如何修改成本函数来包含它。我现在的损失函数只是
function loss_func() pred = net() sum(abs2, truth[1] .- pred[1,:]) + sum(abs2, truth[2] .- pred[2,:]) + sum(abs2, truth[3] .- pred[3,:])end
但我想将L1惩罚纳入其中。对于L1回归,我找到了成本函数的方程:J′(θ;X,y) = J(θ;X,y)+aΩ(θ)
,其中“θ
表示可训练参数,X
表示输入… y
表示目标标签。a
是一个超参数,用于加权范数惩罚的贡献”,而对于L1正则化,惩罚项是Ω(θ) = ∣∣w∣∣ = ∑∣w∣
(来源:https://theaisummer.com/regularization/)。我理解右侧的第一项是损失J(θ;X,y)
,是我已经拥有的,a
是一个我选择的超参数,可以是0.001,0.1,1,100000000等,L1惩罚是参数绝对值的总和。我不明白的是如何将a∑∣w∣
项添加到我当前的函数中 – 我想将其编辑为类似这样的形式:
function cost_func(lambda) pred = net() penalty(lambda) = lambda * (sum(abs(param[1])) + sum(abs(param[2])) + sum(abs(param[3])) ) sum(abs2, truth[1] .- pred[1,:]) + sum(abs2, truth[2] .- pred[2,:]) + sum(abs2, truth[3] .- pred[3,:]) + penalty(lambda)end
其中param[1], param[2], param[3]
指的是我尝试学习的DEu[1], u[2], u[3]
的参数。不过,我不确定这种逻辑是否正确或者是否是实现它的正确方式,而且我不知道如何/在哪里访问学习到的参数。我怀疑答案可能在于这段代码的某个地方
callback_func = function () loss_value = loss_func() println("Loss: ", loss_value)endfparams = Flux.params(p)Flux.train!(loss_func, fparams, data, optimizer, cb = callback_func);
但我不确定或者即使这是答案,我也不知道如何使用它。
回答:
我一直在摆弄这个,并且查看了其他一些NODE实现(特别是这个),并调整了我的成本函数,使其变为:
function cost_fnct(param) prob = ODEProblem(model, u0, tspan, param) prediction = Array(concrete_solve(prob, Tsit5(), p = param, saveat = trange)) loss = Flux.mae(prediction, data) penalty = sum(abs, param) loss + lambda*penalty end;
其中lambda
是调节参数,并且使用L1惩罚定义为参数绝对值的总和。然后,对于训练:
lambda = 0.01resinit = DiffEqFlux.sciml_train(cost_fnct, p, ADAM(), maxiters = 3000)res = DiffEqFlux.sciml_train(cost_fnct, resinit.minimizer, BFGS(initial_stepnorm = 1e-5))
其中p
最初只是我的参数“猜测”,即一个与我尝试拟合的参数数量长度相同的全1向量。
如果你在查看我最初帖子中的第一个链接(这里),你可以重新定义损失函数以添加这个惩罚项,然后在回调函数和后续训练之前定义lambda
:
lambda = 0.01callback_func = function () loss_value = cost_fnct() println("Loss: ", loss_value) println("\nLearned parameters: ", p)endfparams = Flux.params(p)Flux.train!(cost_fnct, fparams, data, optimizer, cb = callback_func);
当然,这一切都不包括任何形式的交叉验证和调节参数优化!我将接受我的问题的回答,因为我了解到未回答的问题会被推动以鼓励回答,我希望避免堵塞标签,但如果有人有不同的解决方案,或者想评论,请随时继续进行。