【问题标题】:Keras lambda layer for l2 norm用于 l2 范数的 Keras lambda 层
【发布时间】:2018-04-19 08:49:10
【问题描述】:

我只想实现一个自定义层来获取两个向量(当然是匹配维度)的 l2 范数,这两个向量是由 keras 中的 2 个不同模型输出的。我正在使用编写 keras 函数的功能 API 方法,所以我有类似的东西:

    inp1 = Input(someshape)
    X = Conv2D(someargs)(inp1)
    ...
    ...
    out1 = Dense(128)(X)

    inp2 = Input(someshape)
    Y = Conv2D(someargs)(inp2)
    ...
    ...
    out2 = Dense(128)(Y)

然后我想取 out1 和 out2 之间距离的 l2 范数并将其进一步输入另一个网络,所以我有一个 lambda 层,如:

    l2dist = keras.layers.Lambda(l2dist)(out1,out2)

其中 l2dist 是函数定义为:

    def l2dist(x,y):
        return K.sqrt(K.sum((x-y)**2))

但我收到 l2dist =... 行的错误:

    TypeError: __call__() takes 2 positional arguments but 3 were given

我明明只放了2个参数,out1和out2,为什么python认为我给了3个参数?
我已经尝试过使用 lambda 函数,例如:

    l2dist = keras.layers.Lambda(lambda x,y: K.sqrt(K.sum((x-y)**2)))(out1,out2)

但我得到了同样的错误。

【问题讨论】:

    标签: python keras


    【解决方案1】:

    我发现 keras 中的 Lambda 层只能接受一个参数作为输入,所以我必须将 lambda 函数作为一个函数输入到一个列表中,并将两个张量作为一个列表传入。我还意识到我不能使用 l2 范数,因为它只给了我 1 个数字来运行最后一层,我必须使用不同的距离函数,它可以给出元素距离而不是两个向量之间的欧几里得距离。我现在正在使用卡方距离,所以我的代码看起来像这样并且它运行(但它让我觉得 nan 作为一种损失,但我猜这是一个不同的问题。至少它运行):

        chisqdist = keras.layers.Lambda(lambda x: (x[0]-x[1])**2/(x[0]+x[1]))([out1,out2])
    

    【讨论】:

    • Nan 损失可能是由于模型中被零除。另外,每次我尝试在我的损失中使用K.sqrt 时,我都会得到 Nan 损失,我无法弄清楚为什么......
    • 是的,我发现这是因为除以 x[0]+x[1] 将导致 int 除以零,只要这两个值都为 0(在这种情况下,分子也是 0,但 0/0 仍然是 nan)。如果我使用 relu 激活函数,这些值经常为 0。如果我切换到 sigmoid 激活,一切都会奏效(但随后训练很容易卡住),所以我只是在分母上添加了一个小 epsilon,一切似乎都在运作。
    • @enumaris 你能指定如何将一个小 epsilon 添加到分母上吗?
    • @armstrongsubero 这是很久以前的事了,但我相信我只是通过法定货币添加的。 lambda x: (x[0]-x[1])**2/(x[0]+x[1]+epsilon) 其中epsilon 只是我设置为喜欢1e-8 或其他东西的一些参数。关键是当x[0]x[1] 都是0 然后你得到0 而不是nanepsilon 必须足够小以至于它不会正常影响除法。跨度>
    猜你喜欢
    • 2018-05-20
    • 2020-04-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-21
    • 1970-01-01
    • 2021-01-16
    • 2022-06-21
    相关资源
    最近更新 更多