深度学习评估指标实战:5大核心指标(Accuracy/Precision/Recall/F1/AUC)代码实现与对比

在深度学习模型开发过程中,评估指标的选择和实现直接决定了我们对模型性能的判断。本文将带您从代码层面深入理解五大核心评估指标的计算逻辑,并提供可直接运行的PyTorch实现方案。不同于理论公式的简单罗列,我们将通过完整的代码示例展示如何在实际项目中计算和应用这些指标。

1. 混淆矩阵:评估指标的基石

任何分类问题的评估都始于混淆矩阵。我们先实现一个高效的混淆矩阵计算函数:

import torch
import numpy as np

def confusion_matrix(y_true, y_pred, num_classes):
    """计算混淆矩阵"""
    conf_mat = np.zeros((num_classes, num_classes))
    for t, p in zip(y_true.numpy().flatten(), y_pred.numpy().flatten()):
        conf_mat[t, p] += 1
    return torch.from_numpy(conf_mat)

# 示例用法
y_true = torch.tensor([0, 1, 1, 0, 1])
y_pred = torch.tensor([0, 1, 0, 0, 1])
conf_mat = confusion_matrix(y_true, y_pred, num_classes=2)
print("混淆矩阵:\n", conf_mat)

混淆矩阵中的四个关键值:

  • TP (True Positive): 对角线上的正确预测
  • FP (False Positive): 列总和减去TP
  • FN (False Negative): 行总和减去TP
  • TN (True Negative): 总数减去其他三项

2. 五大核心指标实现

2.1 准确率(Accuracy)

def accuracy(y_true, y_pred):
    correct = torch.eq(y_true, y_pred).sum().item()
    return correct / len(y_true)

# 优化实现:支持多分类
def multi_class_accuracy(conf_mat):
    return conf_mat.diag().sum() / conf_mat.sum()

适用场景 :类别分布均衡时效果最好。当数据存在严重不平衡时(如欺诈检测中正样本仅占1%),准确率会严重失真。

2.2 精确率(Precision)

def precision(conf_mat):
    tp = conf_mat[1, 1]
    fp = conf_mat[0, 1]
    return tp / (tp + fp + 1e-6)  # 避免除零

# 多分类版本
def multi_class_precision(conf_mat):
    return conf_mat.diag() / (conf_mat.sum(dim=0) + 1e-6)

业务意义 :在垃圾邮件检测中,高精确率意味着被标记为垃圾的邮件确实大多是垃圾邮件。

2.3 召回率(Recall)

def recall(conf_mat):
    tp = conf_mat[1, 1]
    fn = conf_mat[1, 0]
    return tp / (tp + fn + 1e-6)

# 多分类版本
def multi_class_recall(conf_mat):
    return conf_mat.diag() / (conf_mat.sum(dim=1) + 1e-6)

实际案例 :在癌症筛查中,高召回率意味着尽可能少漏诊真正的患者。

2.4 F1分数

def f1_score(precision, recall):
    return 2 * (precision * recall) / (precision + recall + 1e-6)

# 综合实现
def compute_f1(conf_mat):
    prec = precision(conf_mat)
    rec = recall(conf_mat)
    return f1_score(prec, rec)

平衡艺术 :F1在信息检索中特别重要,需要在相关结果数量(Precision)和覆盖率(Recall)间取得平衡。

2.5 AUC实现

AUC的计算需要预测概率值而非硬标签:

from sklearn.metrics import roc_auc_score

def auc_score(y_true, y_prob):
    return roc_auc_score(y_true.numpy(), y_prob.numpy())

# 手动实现
def manual_auc(y_true, y_prob):
    pos = y_prob[y_true == 1]
    neg = y_prob[y_true == 0]
    count = 0
    for p in pos:
        count += (neg < p).sum()
    return count / (len(pos) * len(neg))

概率视角 :AUC可以理解为随机选取的正样本得分高于负样本得分的概率。

3. 指标对比与可视化

不同指标关注模型性能的不同方面,我们通过实际数据对比:

import matplotlib.pyplot as plt

# 模拟不同模型的预测结果
models = {
    'Model A': (torch.tensor([0.6, 0.7, 0.8, 0.4, 0.3]), 
                torch.tensor([1, 1, 1, 0, 0])),
    'Model B': (torch.tensor([0.9, 0.2, 0.7, 0.3, 0.5]), 
                torch.tensor([1, 0, 1, 0, 1]))
}

# 评估各模型
results = []
for name, (prob, pred) in models.items():
    y_true = torch.tensor([1, 0, 1, 0, 1])
    conf_mat = confusion_matrix(y_true, pred, 2)
    results.append({
        'name': name,
        'accuracy': accuracy(y_true, pred),
        'precision': precision(conf_mat),
        'recall': recall(conf_mat),
        'f1': compute_f1(conf_mat),
        'auc': auc_score(y_true, prob)
    })

# 可视化对比
metrics = ['accuracy', 'precision', 'recall', 'f1', 'auc']
x = np.arange(len(metrics))
width = 0.35

fig, ax = plt.subplots(figsize=(10, 6))
for i, model in enumerate(results):
    ax.bar(x + i*width, [model[m] for m in metrics], width, label=model['name'])

ax.set_ylabel('Score')
ax.set_title('Model Performance Comparison')
ax.set_xticks(x + width/2)
ax.set_xticklabels(metrics)
ax.legend()
plt.show()

4. 实际应用建议

  1. 样本不平衡时 :优先关注Recall和AUC,Accuracy可能产生误导
  2. 阈值选择 :使用ROC曲线找到最佳操作点:
    from sklearn.metrics import roc_curve
    
    fpr, tpr, thresholds = roc_curve(y_true, y_prob)
    optimal_idx = np.argmax(tpr - fpr)
    optimal_threshold = thresholds[optimal_idx]
    
  3. 多分类问题 :采用宏平均(Macro-average)或微平均(Micro-average)
    def macro_average(scores):
        return sum(scores) / len(scores)
    
    def micro_average(conf_mat):
        return conf_mat.diag().sum() / conf_mat.sum()
    

5. 完整评估流程示例

以下是一个完整的模型评估流程:

def evaluate_model(model, test_loader, device):
    model.eval()
    all_preds = []
    all_probs = []
    all_targets = []
    
    with torch.no_grad():
        for data, target in test_loader:
            data, target = data.to(device), target.to(device)
            output = model(data)
            probs = torch.softmax(output, dim=1)
            preds = torch.argmax(probs, dim=1)
            
            all_preds.append(preds.cpu())
            all_probs.append(probs.cpu())
            all_targets.append(target.cpu())
    
    y_pred = torch.cat(all_preds)
    y_prob = torch.cat(all_probs)
    y_true = torch.cat(all_targets)
    
    conf_mat = confusion_matrix(y_true, y_pred, num_classes=10)
    
    metrics = {
        'accuracy': multi_class_accuracy(conf_mat),
        'precision': macro_average(multi_class_precision(conf_mat)),
        'recall': macro_average(multi_class_recall(conf_mat)),
        'f1': macro_average(f1_score(
            multi_class_precision(conf_mat),
            multi_class_recall(conf_mat)
        ))
    }
    
    # 绘制混淆矩阵热力图
    plt.figure(figsize=(10, 8))
    sns.heatmap(conf_mat.numpy(), annot=True, fmt='g')
    plt.xlabel('Predicted')
    plt.ylabel('Actual')
    plt.show()
    
    return metrics

在实际项目中,我发现AUC指标对类别不平衡的数据集特别稳健,而F1分数则在需要平衡精确率和召回率时非常有用。根据具体业务需求选择合适的评估指标组合,比单纯追求单一指标的提升更有实际价值。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐