指标是用于判断模型性能的函数。
指标函数类似于损失函数,但评估指标的结果不会用于训练模型。请注意,您可以将任何损失函数用作指标。
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()
# Iterate over the batches of a dataset.
for step, (x, y) in enumerate(dataset):
with tf.GradientTape() as tape:
logits = model(x)
# Compute the loss value for this batch.
loss_value = loss_fn(y, logits)
# Update the state of the `accuracy` metric.
accuracy.update_state(y, logits)
# Update the weights of the model to minimize the loss value.
gradients = tape.gradient(loss_value, model.trainable_weights)
optimizer.apply_gradients(zip(gradients, model.trainable_weights))
# Logging the current accuracy value so far.
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) # Note the `axis=-1`
model.compile(optimizer='adam', loss='mean_squared_error', metrics=[my_metric_fn])
在这种情况下,您在训练和评估期间跟踪的标量指标值是在给定时期(或在给定 model.evaluate()
调用期间)看到的所有批次的每个批次指标值的平均值。
Metric
的子类(有状态)并非所有指标都可以通过无状态的可调用对象来表示,因为指标在训练和评估期间针对每个批次进行评估,但在某些情况下,每个批次值的平均值并不是您感兴趣的。
假设您想计算给定评估数据集上的 AUC:每个批次 AUC 值的平均值与整个数据集上的 AUC 不相同。
对于此类指标,您需要对 Metric
类进行子类化,该类可以跨批次维护状态。这很容易
__init__
中创建状态变量update_state()
中根据 y_true
和 y_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'Intermediate result: {m.result().numpy()}')
m.update_state([1, 1, 1, 1], [0, 1, 1, 0])
print(f'Intermediate result: {m.result().numpy()}')