Keras中的自定义损失函数会惩罚中间层的输出

时间:2020-07-24 22:35:25

标签: tensorflow keras conv-neural-network keras-layer loss-function

想象一下,我有一个卷积神经网络来对MNIST数字进行分类,例如Keras example。这纯粹是出于实验目的,因此我没有明确的理由或理由说明为什么要这样做,但是让我说我​​想对中间层的输出进行正则化或惩罚。我意识到下面的可视化与MNIST CNN示例并不对应,而是具有几个完全连接的层。但是,为了使我的意思形象化,我想对第4层中的节点值强加一个惩罚(激活之前或之后都可以)。 enter image description here 除了具有多类分类中典型的分类交叉熵损失项外,我还想向损失函数添加另一个项,以使给定层的输出平方和最小。这在概念上与12正则化有些相似,不同之处在于12正则化会惩罚网络中所有权重的平方和。相反,我只对给定层(例如第4层)的值感兴趣,而不对网络中的所有权重感兴趣。

我意识到这需要使用keras后端编写自定义损失函数以结合分类交叉熵和惩罚项,但是我不确定如何在损失函数中使用中间层作为惩罚项。我将不胜感激如何执行此操作。谢谢!

3 个答案:

答案 0 :(得分:2)

只需将隐藏层指定为附加输出。由于tf.keras.Model可以有多个输出,因此完全允许。然后使用这两个值定义您的自定义损失。

扩展您的示例:

input = tf.keras.Input(...)
x1 = tf.keras.layers.Dense(10)(input)
x2 = tf.keras.layers.Dense(10)(x1)
x3 = tf.keras.layers.Dense(10)(x2)
model = tf.keras.Model(inputs=[input], outputs=[x3, x2])

对于自定义损失函数,我认为是这样的:

def custom_loss(y_true, y_pred):
  x2, x3 = y_pred
  label = y_true # you might need to provide a dummy var for x2
  return f1(x2) + f2(y_pred, x3) # whatever you want to do with f1, f2

答案 1 :(得分:2)

实际上,您感兴趣的是正则化,在Keras中,大多数层都有两种不同的内置正则化方法(例如DenseConv1D,{{1} }等)

  • 权重正则化,它会惩罚图层的 weights 。通常,在构造层以启用它时可以使用Conv2Dkernel_regularizer参数。例如:

    bias_regularizer
  • 活动正则化,它会惩罚图层的输出(即激活)。为此,可以在构造图层时使用 l1_l2 = tf.keras.regularizers.l1_l2(l1=1.0, l2=0.01) x = tf.keras.layers.Dense(..., kernel_regularizer=l1_l2, bias_regularizer=l1_l2) 自变量:

    activity_regularizer

    请注意,您可以通过 l1_l2 = tf.keras.regularizers.l1_l2(l1=1.0, l2=0.01) x = tf.keras.layers.Dense(..., activity_regularizer=l1_l2) 自变量为所有图层(甚至是自定义图层)设置活动常规化。

在这两种情况下,惩罚都加到模型的损失函数中,结果将是最终损失值,该值将由优化器在训练过程中进行优化。

此外,除了内置的正则化方法(即L1和L2)之外,您还可以定义自己的自定义正则化方法(请参见Developing new regularizers)。与往常一样,documentation提供了可能也有帮助的其他信息。

答案 2 :(得分:0)

根据给定层的输入或计算添加损失的另一种方法是使用 the add_loss() API。如果您已经在创建自定义图层,则可以将自定义损失直接添加到图层中。或者可以创建一个自定义层,简单地接受输入,计算并添加损失,然后将未更改的输入传递给下一层。

这是直接从文档中获取的代码(以防链接被破坏):

from tensorflow.keras.layers import Layer

class MyActivityRegularizer(Layer):
  """Layer that creates an activity sparsity regularization loss."""

  def __init__(self, rate=1e-2):
    super(MyActivityRegularizer, self).__init__()
    self.rate = rate

  def call(self, inputs):
    # We use `add_loss` to create a regularization loss
    # that depends on the inputs.
    self.add_loss(self.rate * tf.reduce_sum(tf.square(inputs)))
    return inputs