【问题标题】:Custom loss function in Keras that penalizes output from intermediate layerKeras 中的自定义损失函数,用于惩罚中间层的输出
【发布时间】:2026-01-12 15:00:01
【问题描述】:

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

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

【问题讨论】:

  • 你用什么工具来制作这张图片?

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


【解决方案1】:

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

  • 权重正则化,对层的权重进行惩罚。通常,您可以在构造层以启用它时使用kernel_regularizerbias_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)
    

    请注意,您可以通过activity_regularizer 参数为所有层设置活动正则化,甚至自定义层。

在这两种情况下,惩罚都会被累加到模型的损失函数中,结果将是优化器在训练期间优化的最终损失值。

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

【讨论】:

  • 非常感谢!活动正则化器似乎正是我所需要的。
【解决方案2】:

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

扩展你的例子:

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

【讨论】:

  • 感谢您分享这个想法。这似乎肯定有帮助。我会为 x3 和 x2 指定单独的损失函数,还是将它们组合成一个损失函数?对于 x3,我希望最小化原始标签和预测标签 (y) 之间的分类交叉熵,对于 x2,我只想最小化平方和。谢谢!
  • 我更新了我的答案。这是一种损失函数,否则模型不知道如何组合它们(加法、乘法、...?)。老实说,我没有检查这段代码是否运行,但我希望这至少可以让你开始!从概念上讲,它肯定是正确的,但您可能需要做一些调试才能让 tensorflow 工作。希望对您有所帮助!
  • 非常感谢。你提出了一个很好的观点,从概念上讲这很有意义。我会玩这个。
  • @FrederikBode 这是一个不错的概念。谢谢。赞成。
【解决方案3】:

根据给定层的输入或计算添加损失的另一种方法是使用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

【讨论】: