评估指标 #

指标概述 #

评估指标(Metrics)用于监控模型训练过程和评估模型性能。与损失函数不同,指标不参与模型优化,只用于观察和评估。

指标分类 #

text
┌─────────────────────────────────────────────────────────────┐
│                    评估指标分类                              │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  分类指标                                                    │
│  ├── Accuracy (准确率)                                      │
│  ├── Precision (精确率)                                     │
│  ├── Recall (召回率)                                        │
│  ├── F1-Score                                               │
│  ├── AUC                                                    │
│  └── Confusion Matrix                                       │
│                                                             │
│  回归指标                                                    │
│  ├── MAE (平均绝对误差)                                     │
│  ├── MSE (均方误差)                                         │
│  ├── RMSE (均方根误差)                                      │
│  └── R² (决定系数)                                          │
│                                                             │
│  其他指标                                                    │
│  ├── Mean                                                   │
│  ├── Sum                                                    │
│  └── 自定义指标                                             │
│                                                             │
└─────────────────────────────────────────────────────────────┘

分类指标 #

Accuracy #

python
import tensorflow as tf

model = tf.keras.Sequential([
    tf.keras.layers.Dense(64, activation='relu', input_shape=(784,)),
    tf.keras.layers.Dense(10, activation='softmax')
])

model.compile(
    optimizer='adam',
    loss='sparse_categorical_crossentropy',
    metrics=['accuracy']
)

# 稀疏分类准确率
model.compile(
    optimizer='adam',
    loss='sparse_categorical_crossentropy',
    metrics=[tf.keras.metrics.SparseCategoricalAccuracy(name='accuracy')]
)

# 分类准确率(one-hot 标签)
model.compile(
    optimizer='adam',
    loss='categorical_crossentropy',
    metrics=[tf.keras.metrics.CategoricalAccuracy(name='accuracy')]
)

# 二分类准确率
model.compile(
    optimizer='adam',
    loss='binary_crossentropy',
    metrics=[tf.keras.metrics.BinaryAccuracy(name='accuracy')]
)

Top-K 准确率 #

python
import tensorflow as tf

model = tf.keras.Sequential([
    tf.keras.layers.Dense(64, activation='relu', input_shape=(784,)),
    tf.keras.layers.Dense(10)
])

model.compile(
    optimizer='adam',
    loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
    metrics=[
        tf.keras.metrics.SparseCategoricalAccuracy(name='accuracy'),
        tf.keras.metrics.SparseTopKCategoricalAccuracy(k=5, name='top5_acc')
    ]
)

Precision 和 Recall #

python
import tensorflow as tf

model = tf.keras.Sequential([
    tf.keras.layers.Dense(64, activation='relu', input_shape=(100,)),
    tf.keras.layers.Dense(1, activation='sigmoid')
])

model.compile(
    optimizer='adam',
    loss='binary_crossentropy',
    metrics=[
        tf.keras.metrics.Precision(name='precision'),
        tf.keras.metrics.Recall(name='recall')
    ]
)

# 指定阈值
model.compile(
    optimizer='adam',
    loss='binary_crossentropy',
    metrics=[
        tf.keras.metrics.Precision(thresholds=0.5, name='precision'),
        tf.keras.metrics.Recall(thresholds=0.5, name='recall')
    ]
)

AUC #

python
import tensorflow as tf

model = tf.keras.Sequential([
    tf.keras.layers.Dense(64, activation='relu', input_shape=(100,)),
    tf.keras.layers.Dense(1, activation='sigmoid')
])

model.compile(
    optimizer='adam',
    loss='binary_crossentropy',
    metrics=[
        tf.keras.metrics.AUC(name='auc'),
        tf.keras.metrics.AUC(curve='PR', name='auc_pr')
    ]
)

F1 Score (自定义) #

python
import tensorflow as tf

class F1Score(tf.keras.metrics.Metric):
    def __init__(self, name='f1_score', **kwargs):
        super().__init__(name=name, **kwargs)
        self.precision = tf.keras.metrics.Precision()
        self.recall = tf.keras.metrics.Recall()
    
    def update_state(self, y_true, y_pred, sample_weight=None):
        self.precision.update_state(y_true, y_pred, sample_weight)
        self.recall.update_state(y_true, y_pred, sample_weight)
    
    def result(self):
        p = self.precision.result()
        r = self.recall.result()
        return 2 * p * r / (p + r + 1e-7)
    
    def reset_states(self):
        self.precision.reset_states()
        self.recall.reset_states()

model.compile(
    optimizer='adam',
    loss='binary_crossentropy',
    metrics=[F1Score()]
)

回归指标 #

MAE 和 MSE #

python
import tensorflow as tf

model = tf.keras.Sequential([
    tf.keras.layers.Dense(64, activation='relu', input_shape=(10,)),
    tf.keras.layers.Dense(1)
])

model.compile(
    optimizer='adam',
    loss='mse',
    metrics=[
        tf.keras.metrics.MeanAbsoluteError(name='mae'),
        tf.keras.metrics.MeanSquaredError(name='mse'),
        tf.keras.metrics.RootMeanSquaredError(name='rmse')
    ]
)

R² Score #

python
import tensorflow as tf

class R2Score(tf.keras.metrics.Metric):
    def __init__(self, name='r2_score', **kwargs):
        super().__init__(name=name, **kwargs)
        self.sum_squared_residual = self.add_weight(name='ssr', initializer='zeros')
        self.sum_squared_total = self.add_weight(name='sst', initializer='zeros')
        self.count = self.add_weight(name='count', initializer='zeros')
    
    def update_state(self, y_true, y_pred, sample_weight=None):
        y_true = tf.cast(y_true, tf.float32)
        y_pred = tf.cast(y_pred, tf.float32)
        
        residual = y_true - y_pred
        ssr = tf.reduce_sum(tf.square(residual))
        
        mean_true = tf.reduce_mean(y_true)
        sst = tf.reduce_sum(tf.square(y_true - mean_true))
        
        self.sum_squared_residual.assign_add(ssr)
        self.sum_squared_total.assign_add(sst)
        self.count.assign_add(tf.cast(tf.shape(y_true)[0], tf.float32))
    
    def result(self):
        return 1 - self.sum_squared_residual / (self.sum_squared_total + 1e-7)
    
    def reset_states(self):
        self.sum_squared_residual.assign(0.0)
        self.sum_squared_total.assign(0.0)
        self.count.assign(0.0)

model.compile(
    optimizer='adam',
    loss='mse',
    metrics=[R2Score()]
)

其他指标 #

Mean 和 Sum #

python
import tensorflow as tf

model.compile(
    optimizer='adam',
    loss='mse',
    metrics=[
        tf.keras.metrics.Mean(name='mean'),
        tf.keras.metrics.Sum(name='sum')
    ]
)

MeanMetricWrapper #

python
import tensorflow as tf

def mean_absolute_percentage_error(y_true, y_pred):
    y_true = tf.cast(y_true, tf.float32)
    diff = tf.abs((y_true - y_pred) / tf.maximum(tf.abs(y_true), 1e-7))
    return 100.0 * tf.reduce_mean(diff)

mape = tf.keras.metrics.MeanMetricWrapper(
    fn=mean_absolute_percentage_error,
    name='mape'
)

model.compile(optimizer='adam', loss='mse', metrics=[mape])

自定义指标 #

函数式自定义 #

python
import tensorflow as tf

def custom_metric(y_true, y_pred):
    return tf.reduce_mean(tf.abs(y_true - y_pred) / (tf.abs(y_true) + 1e-7))

model.compile(
    optimizer='adam',
    loss='mse',
    metrics=[custom_metric]
)

类式自定义 #

python
import tensorflow as tf

class CustomMetric(tf.keras.metrics.Metric):
    def __init__(self, name='custom_metric', **kwargs):
        super().__init__(name=name, **kwargs)
        self.total = self.add_weight(name='total', initializer='zeros')
        self.count = self.add_weight(name='count', initializer='zeros')
    
    def update_state(self, y_true, y_pred, sample_weight=None):
        values = tf.abs(y_true - y_pred)
        self.total.assign_add(tf.reduce_sum(values))
        self.count.assign_add(tf.cast(tf.size(values), tf.float32))
    
    def result(self):
        return self.total / self.count
    
    def reset_states(self):
        self.total.assign(0.0)
        self.count.assign(0.0)

model.compile(
    optimizer='adam',
    loss='mse',
    metrics=[CustomMetric()]
)

指标使用示例 #

训练时监控 #

python
import tensorflow as tf

model = tf.keras.Sequential([
    tf.keras.layers.Dense(64, activation='relu', input_shape=(784,)),
    tf.keras.layers.Dense(10, activation='softmax')
])

model.compile(
    optimizer='adam',
    loss='sparse_categorical_crossentropy',
    metrics=[
        'accuracy',
        tf.keras.metrics.SparseTopKCategoricalAccuracy(k=5, name='top5_acc')
    ]
)

history = model.fit(
    x_train, y_train,
    epochs=10,
    validation_data=(x_val, y_val)
)

print(f"训练指标: {history.history.keys()}")

手动更新指标 #

python
import tensorflow as tf

metric = tf.keras.metrics.MeanAbsoluteError()

y_true = tf.constant([[1.0], [2.0], [3.0]])
y_pred = tf.constant([[1.1], [1.9], [3.2]])

metric.update_state(y_true, y_pred)
print(f"MAE: {metric.result().numpy()}")

metric.reset_states()

多输出模型指标 #

python
import tensorflow as tf

inputs = tf.keras.Input(shape=(100,))
x = tf.keras.layers.Dense(64, activation='relu')(inputs)

output_a = tf.keras.layers.Dense(10, activation='softmax', name='classification')(x)
output_b = tf.keras.layers.Dense(1, name='regression')(x)

model = tf.keras.Model(inputs=inputs, outputs=[output_a, output_b])

model.compile(
    optimizer='adam',
    loss={
        'classification': 'sparse_categorical_crossentropy',
        'regression': 'mse'
    },
    metrics={
        'classification': ['accuracy'],
        'regression': ['mae']
    }
)

下一步 #

现在你已经掌握了评估指标,接下来学习 自定义层,了解如何创建自定义网络层!

最后更新:2026-04-04