在深度学习项目中,评价指标不仅是衡量模型性能的标尺,更直接影响模型选择与调优方向。本文将从一个可扩展的 OOP 设计出发,构建覆盖分类、分割、回归三大任务的评价指标体系。
基类设计
首先定义一个抽象基类,统一接口,方便后续扩展:
from abc import ABC, abstractmethod
import numpy as np
class BaseMetric(ABC):
@abstractmethod
def update(self, y_pred, y_true):
"""累积一批预测结果"""
pass
@abstractmethod
def compute(self):
"""计算并返回当前指标值"""
pass
@abstractmethod
def reset(self):
"""重置累积状态"""
pass
分类指标
对于二分类 / 多分类任务,核心指标均来自混淆矩阵:
class ClassificationMetrics(BaseMetric):
def __init__(self, num_classes):
self.num_classes = num_classes
self.reset()
def update(self, y_pred, y_true):
for p, t in zip(y_pred, y_true):
self.conf_mat[t][p] += 1
def compute(self):
tp = np.diag(self.conf_mat)
fp = self.conf_mat.sum(axis=0) - tp
fn = self.conf_mat.sum(axis=1) - tp
precision = tp / (tp + fp + 1e-8)
recall = tp / (tp + fn + 1e-8)
return {
'accuracy': tp.sum() / self.conf_mat.sum(),
'precision': precision.mean(),
'recall': recall.mean(),
'f1': (2 * precision * recall / (precision + recall + 1e-8)).mean()
}
def reset(self):
self.conf_mat = np.zeros((self.num_classes, self.num_classes))
AUC-ROC 可通过 sklearn.metrics.roc_auc_score 计算,适合评估模型在不同阈值下的排序能力。
分割指标
分割任务关注像素级预测与真实标注的重叠程度:
class SegmentationMetrics(BaseMetric):
def __init__(self, threshold=0.5):
self.threshold = threshold
self.reset()
def update(self, y_pred, y_true):
pred_bin = (y_pred > self.threshold).astype(int)
self.intersection += (pred_bin * y_true).sum()
self.union += ((pred_bin + y_true) > 0).sum()
self.total_pred += pred_bin.sum()
self.total_true += y_true.sum()
self.pixel_correct += (pred_bin == y_true).sum()
self.pixel_total += y_true.size
def compute(self):
iou = self.intersection / (self.union + 1e-8)
dice = 2 * self.intersection / (self.total_pred + self.total_true + 1e-8)
return {
'iou': iou,
'dice': dice,
'pixel_accuracy': self.pixel_correct / self.pixel_total
}
def reset(self):
self.intersection = self.union = 0
self.total_pred = self.total_true = 0
self.pixel_correct = self.pixel_total = 0
回归指标
回归任务常用指标:
class RegressionMetrics(BaseMetric):
def __init__(self):
self.reset()
def update(self, y_pred, y_true):
self.se += ((y_pred - y_true) ** 2).sum()
self.ae += np.abs(y_pred - y_true).sum()
self.n += y_true.size
self.y_true_all = np.append(self.y_true_all, y_true.flatten())
def compute(self):
mse = self.se / self.n
mae = self.ae / self.n
ss_res = self.se
ss_tot = ((self.y_true_all - self.y_true_all.mean()) ** 2).sum()
r2 = 1 - ss_res / (ss_tot + 1e-8)
return {'mse': mse, 'mae': mae, 'r2': r2}
def reset(self):
self.se = self.ae = self.n = 0
self.y_true_all = np.array([])
设计要点总结
- 统一接口:
update / compute / reset三元组适配训练循环,支持逐 batch 累积后统一计算; - 数值稳定:分母加
1e-8避免除零,尤其在类别不平衡时至关重要; - 可扩展性:新增指标只需继承基类并实现三个方法,不影响现有代码;
- 与 PyTorch 兼容:实际使用时可将
numpy替换为torch张量操作,保持梯度流。
一个设计良好的指标系统能让实验迭代更高效,也便于团队协作中统一评估标准。
评论