Keras 3 API 文档 / 指标

指标

指标是用于评估模型性能的函数。

指标函数类似于损失函数,不同之处在于评估指标的结果不会用于训练模型。 请注意,您可以将任何损失函数作为指标使用。

可用指标

基础度量类

准确性指标

概率度量

回归评估指标

基于True/False正类和负类的分类指标

图像分割指标

Hinge metrics for "maximum-margin" classification

指标包装器和归约指标


compile()fit() 的使用

compile() 方法接受一个 metrics 参数,该参数是指标列表:

model.compile(
    optimizer='adam',
    loss='mean_squared_error',
    metrics=[
        metrics.MeanSquaredError(),
        metrics.AUC(),
    ]
)

fit() 期间将显示指标值,并记录到 fit() 返回的 History 对象中。 它们也会被 model.evaluate() 返回。

请注意,监控训练期间指标的最佳方式是通过 TensorBoard

要以特定名称跟踪指标,可以将 name 参数传递给指标构造函数:

model.compile(
    optimizer='adam',
    loss='mean_squared_error',
    metrics=[
        metrics.MeanSquaredError(name='my_mse'),
        metrics.AUC(name='my_auc'),
    ]
)

所有内置指标也可以通过它们的字符串标识符传递(在这种情况下,使用默认构造函数参数值,包括默认指标名称):

model.compile(
    optimizer='adam',
    loss='mean_squared_error',
    metrics=[
        'MeanSquaredError',
        'AUC',
    ]
)

独立使用

与损失不同,指标是有状态的。您可以使用 update_state() 方法更新它们的状态,并使用 result() 方法查询标量指标结果:

m = keras.metrics.AUC()
m.update_state([0, 1, 1, 1], [0, 1, 0, 0])
print('Intermediate result:', float(m.result()))

m.update_state([1, 1, 1, 1], [0, 1, 1, 0])
print('Final result:', float(m.result()))

可以通过 metric.reset_states() 清除内部状态。

以下是如何将指标用作简单自定义训练循环的一部分:

accuracy = keras.metrics.CategoricalAccuracy()
loss_fn = keras.losses.CategoricalCrossentropy(from_logits=True)
optimizer = keras.optimizers.Adam()

# 遍历数据集的批次。
for step, (x, y) in enumerate(dataset):
    with tf.GradientTape() as tape:
        logits = model(x)
        # 计算此批次的损失值。
        loss_value = loss_fn(y, logits)

    # 更新 `accuracy` 指标的状态。
    accuracy.update_state(y, logits)

    # 更新模型的权重以最小化损失值。
    gradients = tape.gradient(loss_value, model.trainable_weights)
    optimizer.apply_gradients(zip(gradients, model.trainable_weights))

    # 记录到目前为止的当前准确率值。
    if step % 100 == 0:
        print('Step:', step)        
        print('Total running accuracy so far: %.3f' % accuracy.result())

创建自定义指标

作为简单的可调用对象(无状态)

与损失函数类似,任何具有签名 metric_fn(y_true, y_pred) 的可调用对象,返回一个损失数组(输入批次中的一个样本),都可以作为指标传递给 compile()。 请注意,任何此类指标都自动支持样本加权。

这是一个简单的示例:

from keras import ops

def my_metric_fn(y_true, y_pred):
    squared_difference = ops.square(y_true - y_pred)
    return ops.mean(squared_difference, axis=-1)  # 注意 `axis=-1`

model.compile(optimizer='adam', loss='mean_squared_error', metrics=[my_metric_fn])

在这种情况下,在训练和评估过程中您跟踪的标量指标值 是给定 epoch(或在给定调用 model.evaluate() 时)期间查看的所有批次的每批指标值的平均值。

作为 Metric 的子类(有状态)

并非所有指标都可以通过无状态的可调用对象表示,因为 在训练和评估期间会对每个批次评估指标,但在某些情况下 每批值的平均值不是您关心的。

假设您想要计算给定评估数据集的 AUC:每批 AUC 值的平均值 并不等于整个数据集的 AUC。

对于这样的指标,您需要创建 Metric 类的子类, 它可以在批次之间维护状态。这很简单:

  • __init__ 中创建状态变量
  • update_state() 中根据 y_truey_pred 更新变量
  • result() 中返回标量指标结果
  • reset_states() 中清除状态

以下是一个简单的示例,计算二元真阳性:

class BinaryTruePositives(keras.metrics.Metric):

  def __init__(self, name='binary_true_positives', **kwargs):
    super().__init__(name=name, **kwargs)
    self.true_positives = self.add_weight(name='tp', initializer='zeros')

  def update_state(self, y_true, y_pred, sample_weight=None):
    y_true = ops.cast(y_true, "bool")
    y_pred = ops.cast(y_pred, "bool")

    values = ops.logical_and(ops.equal(y_true, True), ops.equal(y_pred, True))
    values = ops.cast(values, self.dtype)
    if sample_weight is not None:
      sample_weight = ops.cast(sample_weight, self.dtype)
      values = values * sample_weight
    self.true_positives.assign_add(ops.sum(values))

  def result(self):
    return self.true_positives

  def reset_state(self):
    self.true_positives.assign(0)

m = BinaryTruePositives()
m.update_state([0, 1, 1, 1], [0, 1, 0, 0])
print(f'中间结果: {m.result().numpy()}')

m.update_state([1, 1, 1, 1], [0, 1, 1, 0])
print(f'中间结果: {m.result().numpy()}')