Julia Flux:根据提供的正则化系数编写正则化器
我正在编写一个脚本,将Python的Keras v1.1.0模型转换为Julia的Flux模型,我正在努力实现我读过的作为了解Julia的一种方式的正则化 因此,在Keras的json模型中,对于每个致密层,我有类似于:W_正则化器:{l2:0.0010000000474974513,名称:weightRegulationizer,l1:0.0}。我想用这些系数在通量模型中创建正则化。问题是,在通量中,它直接添加到损耗中,而不是被定义为层本身的属性 为了避免在这里发布太多代码,我将其添加到回购协议中。下面是一个小脚本,它接受json并创建一个通量链: 现在,我想用预定义的l1/l2系数为每个密集层创建一个惩罚。我试着这样做:Julia Flux:根据提供的正则化系数编写正则化器,julia,julia-flux,Julia,Julia Flux,我正在编写一个脚本,将Python的Keras v1.1.0模型转换为Julia的Flux模型,我正在努力实现我读过的作为了解Julia的一种方式的正则化 因此,在Keras的json模型中,对于每个致密层,我有类似于:W_正则化器:{l2:0.0010000000474974513,名称:weightRegulationizer,l1:0.0}。我想用这些系数在通量模型中创建正则化。问题是,在通量中,它直接添加到损耗中,而不是被定义为层本身的属性 为了避免在这里发布太多代码,我将其添加到回购协
using Pkg
pkg"activate /home/username/.julia/dev/Keras2Flux"
using Flux
using Keras2Flux
using LinearAlgebra
function get_penalty(model::Chain, regs::Array{Any, 1})
index_model = 1
index_regs = 1
penalties = []
for layer in model
if layer isa Dense
println(regs[index_regs](layer.W))
penalty(m) = regs[index_regs](m[index_model].W)
push!(penalties, penalty)
#println(regs[i])
index_regs += 1
end
index_model += 1
end
total_penalty(m) = sum([p(m) for p in penalties])
println(total_penalty)
println(total_penalty(model))
return total_penalty
end
model, regs = convert_keras2flux("examples/keras_1_1_0.json")
penalty = get_penalty(model, regs)
因此,我为每一个密集层创建一个惩罚函数,然后将其相加为总惩罚。但是,它给了我这个错误:
错误:LoadError:BoundersError:尝试访问索引[4]处的3元素数组{Any,1}
我明白这意味着什么,但我真的不知道如何修复它。因此,当我调用total_penaltymodel时,它使用index_regs==4,因此,index_regs和index_model的值在for循环之后。相反,我想使用他们的实际指数,当我把给定的惩罚推到惩罚列表中时
另一方面,如果我不是将其作为函数列表而是作为值列表,它也将是不正确的,因为我将损失定义为:
lossx,y=二进制交叉熵模型,y+总惩罚模型。如果我将其用作值列表,那么我将有一个静态的total_惩罚,而在模型训练期间,每次都应该重新计算每个密集层的total_惩罚
如果有一个有朱莉娅经历的人给我一些建议,我会很感激,因为我肯定无法理解它在朱莉娅身上是如何工作的,尤其是在不断变化中。我将如何创建训练期间自动重新计算的总惩罚?您的问题有几个部分,由于您是Flux和Julia的新手,我将分步骤回答。但我建议最后的解决方案是一种更干净的处理方法 首先,有一个问题是pm使用index_regs和index_model作为for循环后的值来计算惩罚。这是因为茱莉亚的性格。定义闭包penaltym=regs[index_regs]m[index_model].W时,index_regs绑定到get_惩罚中定义的变量。因此,随着index_regs的变化,pm的输出也随之变化。另一个问题是将函数命名为penaltym。每次运行这一行时,您都在重新定义惩罚和所有引用,您将其推到了惩罚上。相反,您应该更喜欢创建一个匿名函数。以下是我们如何整合这些变化:
function get_penalty(model::Chain, regs::Array{Any, 1})
index_model = 1
index_regs = 1
penalties = []
for layer in model
if layer isa Dense
println(regs[index_regs](layer.W))
penalty = let i = index_regs, index_model = index_model
m -> regs[i](m[index_model].W)
end
push!(penalties, penalty)
index_regs += 1
end
index_model += 1
end
total_penalty(m) = sum([p(m) for p in penalties])
return total_penalty
end
我在let块中使用I和index_模型来解释范围规则。我鼓励您用全局惩罚SYM=。。。并在let块之前删除对惩罚的赋值,以查看使用匿名函数和命名函数的区别
但是,如果我们回到原始问题,您希望使用存储的系数计算模型的正则化惩罚。理想情况下,这些应与每一致密层一起储存,如在Keras中。您可以在Flux中重新创建相同的功能:
using Flux, Functor
struct RegularizedDense{T, LT<:Dense}
layer::LT
w_l1::T
w_l2::T
end
@functor RegularizedDense
(l::RegularizedDense)(x) = l.layer(x)
penalty(l) = 0
penalty(l::RegularizedDense) =
l.w_l1 * norm(l.layer.W, 1) + l.w_l2 * norm(l.layer.W, 2)
penalty(model::Chain) = sum(penalty(layer) for layer in model)
最后,你可以这样计算你的损失函数:
loss(x, y, m) = binarycrossentropy(m(x), y) + penalty(m)
# ... later for training
train!((x, y) -> loss(x, y, m), training_data, params)
我们将损失定义为x,y,m的函数以避免损失
因此,最终,这种方法更简洁,因为在构建模型之后,您不需要传递一系列正则化函数,并找出如何使用相应的密集层正确索引每个函数
如果希望将正则化器和模型分开,即在模型链中具有标准密集层,则也可以这样做。如果您想要这个解决方案,请告诉我,但我暂时不提。您的问题有几个部分,由于您对Flux和Julia?不熟悉,我将分步骤回答。但我建议最后的解决方案是一种更干净的处理方法 首先,有一个问题是pm使用index_regs和index_model作为for循环后的值来计算惩罚。这是因为茱莉亚的性格。定义闭包penaltym=regs[index_regs]m[index_model].W时,index_regs绑定到get_惩罚中定义的变量。因此,随着index_regs的变化,pm的输出也随之变化。另一个问题是将函数命名为penaltym。每次运行这一行时,您都在重新定义惩罚和所有引用,您将其推到了惩罚上。相反,您应该更喜欢创建一个匿名函数。以下是我们如何整合这些变化:
function get_penalty(model::Chain, regs::Array{Any, 1})
index_model = 1
index_regs = 1
penalties = []
for layer in model
if layer isa Dense
println(regs[index_regs](layer.W))
penalty = let i = index_regs, index_model = index_model
m -> regs[i](m[index_model].W)
end
push!(penalties, penalty)
index_regs += 1
end
index_model += 1
end
total_penalty(m) = sum([p(m) for p in penalties])
return total_penalty
end
我在let块中使用I和index_模型来解释范围规则。我鼓励您替换le中的匿名函数
具有全局惩罚的t块ym=。。。并在let块之前删除对惩罚的赋值,以查看使用匿名函数和命名函数的区别
但是,如果我们回到原始问题,您希望使用存储的系数计算模型的正则化惩罚。理想情况下,这些应与每一致密层一起储存,如在Keras中。您可以在Flux中重新创建相同的功能:
using Flux, Functor
struct RegularizedDense{T, LT<:Dense}
layer::LT
w_l1::T
w_l2::T
end
@functor RegularizedDense
(l::RegularizedDense)(x) = l.layer(x)
penalty(l) = 0
penalty(l::RegularizedDense) =
l.w_l1 * norm(l.layer.W, 1) + l.w_l2 * norm(l.layer.W, 2)
penalty(model::Chain) = sum(penalty(layer) for layer in model)
最后,你可以这样计算你的损失函数:
loss(x, y, m) = binarycrossentropy(m(x), y) + penalty(m)
# ... later for training
train!((x, y) -> loss(x, y, m), training_data, params)
我们将损失定义为x,y,m的函数以避免损失
因此,最终,这种方法更简洁,因为在构建模型之后,您不需要传递一系列正则化函数,并找出如何使用相应的密集层正确索引每个函数
如果希望将正则化器和模型分开,即在模型链中具有标准密集层,则也可以这样做。如果您需要该解决方案,请告诉我,但我暂时不提。谢谢您提供如此详细的答案。我对Julia来说确实是个新手,这是我第一次在其中编写模块,我从你的回复中学到了很多。它不应该是m->regs[I]m[index_model]。W而不是m->regs[index_regs]m[index_model]。W如果我正确理解了let块,那是正确的!为了说明问题,我打了个错字。谢谢你这么详细的回答。我对Julia来说确实是个新手,这是我第一次在其中编写模块,我从你的回复中学到了很多。它不应该是m->regs[I]m[index_model]。W而不是m->regs[index_regs]m[index_model]。W如果我正确理解了let块,那是正确的!为了说明问题,我打了个错字。