Julia Flux:根据提供的正则化系数编写正则化器

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}。我想用这些系数在通量模型中创建正则化。问题是,在通量中,它直接添加到损耗中,而不是被定义为层本身的属性 为了避免在这里发布太多代码,我将其添加到回购协

我正在编写一个脚本,将Python的Keras v1.1.0模型转换为Julia的Flux模型,我正在努力实现我读过的作为了解Julia的一种方式的正则化

因此,在Keras的json模型中,对于每个致密层,我有类似于:W_正则化器:{l2:0.0010000000474974513,名称:weightRegulationizer,l1:0.0}。我想用这些系数在通量模型中创建正则化。问题是,在通量中,它直接添加到损耗中,而不是被定义为层本身的属性

为了避免在这里发布太多代码,我将其添加到回购协议中。下面是一个小脚本,它接受json并创建一个通量链:

现在,我想用预定义的l1/l2系数为每个密集层创建一个惩罚。我试着这样做:

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块,那是正确的!为了说明问题,我打了个错字。