如何为Neural ODEs(神经常微分方程)的损失函数添加L1惩罚项
你的实现逻辑是正确的,只需要正确关联你定义的待训练参数即可,具体修改方式如下:
1. 核心实现逻辑
L1正则的标准实现就是在原有损失基础上加入「超参数λ × 所有待正则参数的绝对值之和」,你的推导完全正确,不需要额外调整逻辑。
2. 损失函数修改示例
假设你要拟合的18个微分方程参数全部存储在变量p中(也就是你代码里Flux.params(p)对应的参数集合),直接按如下方式修改损失函数即可:
# 正则权重超参数,可根据实际效果调整,推荐从1e-4、1e-3、1e-2、0.1、1依次尝试 const LAMBDA = 0.01 function loss_func() pred = net() # 原有拟合损失 fit_loss = sum(abs2, truth[1] .- pred[1,:]) + sum(abs2, truth[2] .- pred[2,:]) + sum(abs2, truth[3] .- pred[3,:]) # L1惩罚项,仅针对微分方程的18个参数 l1_penalty = LAMBDA * sum(abs, p) return fit_loss + l1_penalty end
如果你需要给三个方程的参数设置不同的正则权重,可以拆分参数单独计算:
const LAMBDA1 = 0.01 # 第一个方程参数的正则权重 const LAMBDA2 = 0.01 # 第二个方程参数的正则权重 const LAMBDA3 = 0.01 # 第三个方程参数的正则权重 function loss_func() pred = net() fit_loss = sum(abs2, truth[1] .- pred[1,:]) + sum(abs2, truth[2] .- pred[2,:]) + sum(abs2, truth[3] .- pred[3,:]) # p1、p2、p3分别对应三个微分方程的待训练参数 l1_penalty = LAMBDA1 * sum(abs, p1) + LAMBDA2 * sum(abs, p2) + LAMBDA3 * sum(abs, p3) return fit_loss + l1_penalty end
3. 训练代码调整
训练代码不需要做大幅修改,沿用你现有逻辑即可,确保Flux.params()传入的是你需要训练、需要加正则的参数集合:
callback_func = function () loss_value = loss_func() println("Loss: " , loss_value) end # 仅把需要训练的18个微分方程参数传入,不要包含其他不需要正则的网络层参数 fparams = Flux.params(p) Flux.train!(loss_func, fparams, data, optimizer, cb = callback_func)
注意事项
- 正则权重不要设置过大,否则会过度压制参数导致拟合效果变差,建议从极小值开始逐步上调,平衡拟合精度和参数稀疏度
- 如果你的网络中除了微分方程参数还有其他层参数,且不需要给这些参数加正则,不要把这些参数放到
Flux.params()的传入列表中,避免误惩罚 - 训练后可以直接打印
p查看参数值,接近0的参数可以直接归零,得到稀疏的微分方程组
内容的提问来源于stack exchange,提问作者Illari
相关产品推荐
相关产品推荐

