3.3 模型评估指标 (Evaluation Metrics) 3.3 模型评估指标 (Evaluation Metrics) 3.3.1 引言 在机器学习和深度学习项目中,模型训练是至关重要的一步,但训练并非终点。为了确保我们构建的模型能够在实际应用中有效工作,模型评估 (Model Evaluation) 环节同样不可或缺。模型评估指标 (Evaluation Metrics) 正是我们在评估模型性能时所使用的量化工具。它们帮助我们理解模型在不同方面的表现,例如准确性、鲁棒性、泛化能力等,并指导我们进行模型优化和选择。 在 PyTorch 训练流程中,模型评估通常发生在验证集 (Validation Set) 和测试集 (Test Set) 上。
在机器学习和深度学习项目中,模型训练是至关重要的一步,但训练并非终点。为了确保我们构建的模型能够在实际应用中有效工作,模型评估 (Model Evaluation) 环节同样不可或缺。模型评估指标 (Evaluation Metrics) 正是我们在评估模型性能时所使用的量化工具。它们帮助我们理解模型在不同方面的表现,例如准确性、鲁棒性、泛化能力等,并指导我们进行模型优化和选择。
在 PyTorch 训练流程中,模型评估通常发生在验证集 (Validation Set) 和测试集 (Test Set) 上。验证集用于在训练过程中监控模型性能,进行超参数调整和模型选择;测试集则用于最终评估模型的泛化能力,衡量模型在未见过的数据上的表现。选择合适的评估指标至关重要,因为它直接影响我们对模型性能的判断,并最终决定模型的应用价值。
分类模型旨在将数据样本划分到预定义的类别中。针对不同的分类任务,我们需要选择合适的评估指标来衡量模型性能。以下是几种常用的分类模型评估指标:
定义: 准确率是最直观也是最常用的分类指标,它表示模型预测正确的样本数占总样本数的比例。
公式:
其中:
TP (True Positive): 真正例,模型预测为正例,实际也为正例。
TN (True Negative): 真反例,模型预测为反例,实际也为反例。
FP (False Positive): 假正例,模型预测为正例,实际为反例 (Type I error)。
FN (False Negative): 假反例,模型预测为反例,实际为正例 (Type II error)。
代码实践 (PyTorch):
import torch from torchmetrics import Accuracy # 假设 predictions 和 targets 是模型的预测结果和真实标签 predictions = torch.tensor([1, 0, 1, 1, 0, 1]) # 模型的预测类别 targets = torch.tensor([1, 0, 0, 1, 0, 1]) # 真实类别标签 accuracy_metric = Accuracy(task="binary") # task 可以是 "binary", "multiclass", "multilabel" accuracy = accuracy_metric(predictions, targets) print(f"Accuracy: {accuracy.item():.4f}")
代码详解:
我们使用 torchmetrics 库中的 Accuracy 类来计算准确率。 torchmetrics 提供了许多常用的评估指标,方便在 PyTorch 中使用。
Accuracy(task="binary") 初始化一个用于二分类任务的准确率计算器。
accuracy_metric(predictions, targets) 计算预测结果 predictions 和真实标签 targets 之间的准确率。
accuracy.item() 将返回的张量转换为 Python 数值,并使用 f-string 格式化输出。
优缺点和适用场景:
优点: 简单易懂,计算方便,是评估分类模型最基础的指标。
缺点:
类别不平衡问题: 当数据集类别分布不平衡时,准确率可能会产生误导。例如,在一个正负样本比例为 1:9 的数据集中,即使模型将所有样本都预测为负例,也能达到 90% 的准确率,但这显然不是一个好的模型。
不能反映模型在不同类别上的性能差异: 准确率只关注整体预测正确的比例,无法区分模型在不同类别上的表现。
适用场景: 在类别分布相对均衡,且对所有类别同等关注的情况下,准确率是一个不错的评估指标。
当类别不平衡或我们更关注模型在特定类别上的性能时,准确率就显得不足。 精确率 (Precision), 召回率 (Recall) 和 F1 分数 (F1-Score) 是更全面的评估指标,尤其适用于二分类和多分类任务。
精确率 (Precision): 表示模型预测为正例的样本中,真正例的比例。它衡量的是模型预测正例的准确程度,关注的是“预测为正例的样本中,有多少是真正的正例”。
公式:
召回率 (Recall): 表示实际为正例的样本中,被模型正确预测为正例的比例。它衡量的是模型对正例的识别能力,关注的是“所有真正的正例中,有多少被模型找出来了”。
公式:
F1 分数 (F1-Score): 是精确率和召回率的调和平均值,综合考虑了精确率和召回率,是二者的平衡。
公式:
代码实践 (PyTorch):
import torch from torchmetrics import Precision, Recall, F1Score predictions = torch.tensor([1, 0, 1, 1, 0, 1]) targets = torch.tensor([1, 0, 0, 1, 0, 1]) precision_metric = Precision(task="binary") recall_metric = Recall(task="binary") f1_metric = F1Score(task="binary") precision = precision_metric(predictions, targets) recall = recall_metric(predictions, targets) f1_score = f1_metric(predictions, targets) print(f"Precision: {precision.item():.4f}") print(f"Recall: {recall.item():.4f}") print(f"F1-Score: {f1_score.item():.4f}")
代码详解:
类似准确率,我们使用 torchmetrics 中的 Precision, Recall, F1Score 类来计算精确率、召回率和 F1 分数。
初始化时同样指定 task="binary" 用于二分类任务。
使用方法与 Accuracy 类似,将 predictions 和 targets 传入计算器即可。
精确率和召回率的权衡 (Precision-Recall Tradeoff):
精确率和召回率往往是相互制约的。为了提高精确率,模型可能会更倾向于预测把握性更高的正例,从而减少 FP,但同时也可能漏掉一些真正的正例,导致召回率降低。反之,为了提高召回率,模型可能会更积极地预测正例,从而增加 TP,但也可能引入更多的 FP,导致精确率下降。
F1 分数的意义: F1 分数是精确率和召回率的调和平均,它试图在精确率和召回率之间找到一个平衡点。当我们需要综合考虑精确率和召回率,或者希望在两者之间取得平衡时,F1 分数是一个很好的选择。
适用场景:
类别不平衡数据集: Precision, Recall, 和 F1-Score 比 Accuracy 更能反映模型在不平衡数据集上的性能。
关注特定类别性能: 当我们更关注模型在正例或负例上的表现时,例如在欺诈检测中,我们更关注模型能否尽可能地找出所有欺诈交易 (高召回率),即使误判一些正常交易 (较低的精确率),这时召回率就比准确率更重要。
综合评估模型性能: F1 分数提供了一个综合的指标,可以帮助我们更全面地评估模型性能。
定义: 混淆矩阵是一个表格,用于可视化分类模型的预测结果。它总结了模型在每个类别上的预测情况,包括正确和错误的预测数量。
图示 (Mermaid Graph TD):
代码实践 (PyTorch):
import torch from torchmetrics import ConfusionMatrix predictions = torch.tensor([1, 0, 1, 1, 0, 1]) targets = torch.tensor([1, 0, 0, 1, 0, 1]) confmat_metric = ConfusionMatrix(task="binary", num_classes=2) # num_classes 用于多分类 confmat = confmat_metric(predictions, targets) print("Confusion Matrix:") print(confmat)
代码详解:
使用 torchmetrics 中的 ConfusionMatrix 类创建混淆矩阵计算器。
ConfusionMatrix(task="binary", num_classes=2) 指定任务类型为二分类,类别数为 2。对于多分类任务,需要设置 num_classes 参数。
输出的 confmat 是一个张量,表示混淆矩阵。对于二分类,它是一个 2x2 的矩阵,元素分别对应 TP, FP, FN, TN。
解读混淆矩阵:
对于二分类问题,混淆矩阵通常是一个 2x2 的矩阵,如下所示:
| 预测为正例 (Positive) | 预测为反例 (Negative) | |
|---|---|---|
| 实际为正例 (Positive) | TP | FN |
| 实际为反例 (Negative) | FP | TN |
对角线元素 (TP, TN): 表示模型预测正确的数量。
非对角线元素 (FP, FN): 表示模型预测错误的数量。
通过观察混淆矩阵,我们可以更直观地了解模型在各个类别上的预测情况,以及错误分类的类型 (是将正例误判为反例,还是将反例误判为正例)。
适用场景:
可视化模型预测结果: 混淆矩阵提供了一种直观的方式来展示模型的预测结果。
分析模型错误分类: 通过观察混淆矩阵的非对角线元素,可以分析模型容易混淆的类别,从而帮助我们改进模型。
计算其他评估指标的基础: TP, FP, FN, TN 是计算精确率、召回率、F1 分数等指标的基础。
ROC 曲线 (Receiver Operating Characteristic Curve): ROC 曲线是以 假正例率 (FPR - False Positive Rate) 为横轴,真正例率 (TPR - True Positive Rate) 为纵轴绘制的曲线。它用于评估二分类模型在不同阈值下的性能表现。
真正例率 (TPR) 或 召回率 (Recall): 已在前面定义: TPR = Recall = \frac{TP}{TP + FN}
假正例率 (FPR): 表示实际为反例的样本中,被模型错误预测为正例的比例。
公式:
AUC (Area Under the ROC Curve): AUC 是 ROC 曲线下的面积,取值范围在 0 到 1 之间。 AUC 值越大,表示模型性能越好。
AUC = 1: 完美分类器,所有正例和反例都被正确分类。
AUC = 0.5: 随机猜测,模型性能与随机猜测没有区别。
AUC < 0.5: 模型性能比随机猜测还差,通常需要反思模型设计或数据问题。
ROC 曲线概念性图示 (Mermaid Graph TD):
代码实践 (PyTorch):
import torch from torchmetrics import AUROC # 注意:计算 ROC 和 AUC 需要模型的预测概率 (或置信度) 而不是硬分类结果 probabilities = torch.tensor([0.8, 0.2, 0.7, 0.9, 0.3, 0.6]) # 模型预测为正例的概率 targets = torch.tensor([1, 0, 0, 1, 0, 1]) auroc_metric = AUROC(task="binary") auc_roc = auroc_metric(probabilities, targets) print(f"AUC-ROC: {auc_roc.item():.4f}")
代码详解:
使用 torchmetrics 中的 AUROC 类计算 AUC-ROC。
重要: AUROC 的输入是模型的 预测概率 (probabilities) 或 置信度 (confidence scores),而不是硬分类结果 (0 或 1)。 这是因为 ROC 曲线和 AUC 是通过调整分类阈值来评估模型性能的,需要模型的概率输出。
auroc_metric(probabilities, targets) 计算预测概率 probabilities 和真实标签 targets 之间的 AUC-ROC 值。
AUC-ROC 的意义和适用场景:
评估模型排序能力: AUC-ROC 衡量的是模型将正例排在反例前面的能力。AUC 值越高,表示模型越能将正例排在前面,反例排在后面。
对类别不平衡问题鲁棒: AUC-ROC 对类别不平衡问题相对鲁棒,因为它关注的是模型对正例和反例的相对排序能力,而不是绝对的预测准确性。
选择最佳阈值: ROC 曲线可以帮助我们选择合适的分类阈值。通过观察 ROC 曲线,我们可以找到在 FPR 和 TPR 之间取得平衡的最佳阈值点。
适用场景:
二分类问题: AUC-ROC 主要用于二分类问题。
类别不平衡数据集: AUC-ROC 在类别不平衡数据集上表现良好。
需要评估模型排序能力: 当我们更关注模型对样本的排序能力,而不是绝对的分类准确性时,AUC-ROC 是一个很好的选择。
除了上述常用的分类指标外,还有一些其他指标可以用于更细致地评估分类模型,例如:
Specificity (特异度): 真反例率,表示实际为反例的样本中,被模型正确预测为反例的比例。 Specificity = \frac{TN}{TN + FP} = 1 - FPR
灵敏度 (Sensitivity): 与召回率 (Recall) 相同,也称为真正例率 (TPR)。
马修斯相关系数 (Matthews Correlation Coefficient - MCC): 综合考虑了 TP, TN, FP, FN 的指标,在类别不平衡数据集上比准确率和 F1 分数更可靠。
Cohen's Kappa 系数: 用于评估分类器之间一致性的指标,也可以用于评估模型与人工标注的一致性。
这些指标在特定的应用场景下可能会更有价值,可以根据具体需求选择使用。
回归模型旨在预测连续数值型的目标变量。与分类模型不同,回归模型的评估指标关注的是预测值与真实值之间的误差大小。以下是一些常用的回归模型评估指标:
定义: MAE 表示预测值与真实值之间绝对误差的平均值。
公式:
其中:
y_i 是第 i 个样本的真实值。
\hat{y}_i 是第 i 个样本的预测值。
n 是样本总数。
代码实践 (PyTorch):
import torch from torchmetrics import MeanAbsoluteError predictions = torch.tensor([3.2, 1.5, 4.8, 2.1, 3.9]) # 模型预测值 targets = torch.tensor([3.0, 1.8, 5.0, 2.5, 3.5]) # 真实值 mae_metric = MeanAbsoluteError() mae = mae_metric(predictions, targets) print(f"MAE: {mae.item():.4f}")
代码详解:
使用 torchmetrics 中的 MeanAbsoluteError 类计算 MAE。
mae_metric(predictions, targets) 计算预测值 predictions 和真实值 targets 之间的 MAE。
优缺点和适用场景:
优点:
易于理解和解释: MAE 的值直接表示平均预测误差的大小,单位与目标变量相同,易于理解。
对异常值不敏感: MAE 使用绝对误差,而不是平方误差,因此对异常值 ( outliers) 不太敏感。
缺点:
不可微: 绝对值函数在零点不可微,这在某些优化算法中可能会带来问题。
所有误差同等对待: MAE 对所有误差都给予相同的权重,没有区分误差的大小。
适用场景: 当我们希望评估模型预测误差的平均绝对值,并且对异常值不敏感时,MAE 是一个不错的选择。
定义: MSE 表示预测值与真实值之间平方误差的平均值。
公式:
代码实践 (PyTorch):
import torch from torchmetrics import MeanSquaredError predictions = torch.tensor([3.2, 1.5, 4.8, 2.1, 3.9]) targets = torch.tensor([3.0, 1.8, 5.0, 2.5, 3.5]) mse_metric = MeanSquaredError() mse = mse_metric(predictions, targets) print(f"MSE: {mse.item():.4f}")
代码详解:
使用 torchmetrics 中的 MeanSquaredError 类计算 MSE。
mse_metric(predictions, targets) 计算预测值 predictions 和真实值 targets 之间的 MSE。
优缺点和适用场景:
优点:
可微: 平方函数处处可微,方便使用梯度下降等优化算法。
对误差敏感: MSE 使用平方误差,会放大较大的误差,因此对误差更敏感。
缺点:
对异常值敏感: 由于平方误差会放大误差,MSE 对异常值非常敏感。
单位不直观: MSE 的单位是目标变量单位的平方,不太直观。
适用场景: 当我们希望模型对误差更敏感,并且可以容忍对异常值敏感时,MSE 是一个常用的选择。在模型训练过程中,MSE 经常被用作损失函数。
定义: RMSE 是 MSE 的平方根。
公式:
代码实践 (PyTorch):
import torch from torchmetrics import MeanSquaredError predictions = torch.tensor([3.2, 1.5, 4.8, 2.1, 3.9]) targets = torch.tensor([3.0, 1.8, 5.0, 2.5, 3.5]) rmse_metric = MeanSquaredError(squared=False) # squared=False 返回 RMSE rmse = rmse_metric(predictions, targets) print(f"RMSE: {rmse.item():.4f}")
代码详解:
使用 torchmetrics 中的 MeanSquaredError 类计算 RMSE。
MeanSquaredError(squared=False) 设置 squared=False 参数,使 MeanSquaredError 类返回 RMSE 而不是 MSE。
优缺点和适用场景:
优点:
单位直观: RMSE 的单位与目标变量相同,更易于理解和解释。
继承了 MSE 的优点: 可微,对误差敏感。
缺点:
适用场景: RMSE 综合了 MSE 的优点和 MAE 的易解释性,是回归模型常用的评估指标。当我们需要评估预测误差的大小,并且希望单位直观时,RMSE 是一个很好的选择。
定义: R 平方 (R²) 表示回归模型对目标变量方差的解释程度。它衡量的是模型预测值与真实值的拟合程度,取值范围在 0 到 1 之间,值越接近 1,表示模型拟合得越好。
公式:
其中:
SS_{res} (Sum of Squares of Residuals): 残差平方和,即 MSE 的分子部分,衡量模型预测值与真实值之间的差异。
SS_{tot} (Total Sum of Squares): 总平方和,衡量真实值与均值之间的差异。
\bar{y} 是真实值的平均值。
代码实践 (PyTorch):
import torch from torchmetrics import R2Score predictions = torch.tensor([3.2, 1.5, 4.8, 2.1, 3.9]) targets = torch.tensor([3.0, 1.8, 5.0, 2.5, 3.5]) r2_metric = R2Score() r2 = r2_metric(predictions, targets) print(f"R-squared: {r2.item():.4f}")
代码详解:
使用 torchmetrics 中的 R2Score 类计算 R 平方。
r2_metric(predictions, targets) 计算预测值 predictions 和真实值 targets 之间的 R 平方值。
优缺点和适用场景:
优点:
易于解释: R 平方值可以直接解释为模型对目标变量方差的解释程度,例如 R² = 0.8 表示模型可以解释 80% 的目标变量方差。
无量纲: R 平方是无量纲的,不受目标变量单位的影响,可以用于比较不同数据集或不同模型的性能。
缺点:
可能被误用: R 平方值高并不一定代表模型是好的,例如在高维数据或过拟合的情况下,R 平方值可能很高,但模型的泛化能力可能很差。
对模型形式敏感: R 平方假设模型是线性的,对于非线性模型,R 平方的解释性可能会降低。
适用场景: 当我们希望评估模型对目标变量方差的解释程度,并希望得到一个无量纲的、易于解释的指标时,R 平方是一个不错的选择。
除了上述常用的回归指标外,还有一些其他指标可以用于更细致地评估回归模型,例如:
平均绝对百分比误差 (MAPE - Mean Absolute Percentage Error): 表示预测值与真实值之间百分比误差的平均值。 MAPE = \frac{1}{n} \sum_{i=1}^{n} |\frac{y_i - \hat{y}_i}{y_i}| \times 100\% (注意当 y_i = 0 时需要处理,例如忽略或替换为小值)。 MAPE 的优点是易于理解,以百分比形式表示误差大小,但缺点是对真实值接近于 0 的样本非常敏感。
调整 R 平方 (Adjusted R-squared): 对 R 平方进行调整,考虑了模型中特征数量的影响,可以避免因增加特征而导致 R 平方值虚高的情况,更适合用于比较不同特征数量的模型。
这些指标在特定的应用场景下可能会更有价值,可以根据具体需求选择使用。
虽然 PyTorch 和 torchmetrics 提供了丰富的内置评估指标,但在某些特殊情况下,我们可能需要自定义评估指标来更准确地衡量模型性能。
为什么需要自定义指标?
特定业务需求: 某些业务场景可能需要特定的评估指标来反映业务目标,例如在推荐系统中,可能需要使用 NDCG (Normalized Discounted Cumulative Gain) 等指标来评估推荐列表的质量。
现有指标无法满足需求: 标准指标可能无法完全捕捉模型在特定任务上的性能,例如在一些复杂的任务中,可能需要结合多个指标或者自定义新的指标来更全面地评估模型。
如何在 PyTorch 中实现自定义指标 (概念性):
在 PyTorch 中,自定义评估指标通常需要以下步骤:
定义指标计算函数: 编写一个 Python 函数,该函数接受模型的预测结果和真实标签作为输入,并计算出所需的评估指标值。可以使用 PyTorch 张量操作来进行高效计算。
集成到训练/评估循环: 在训练或评估循环中,调用自定义的指标计算函数,并将计算结果记录下来。可以使用 PyTorch 的日志工具 (如 TensorBoard) 或自定义的日志系统来记录和可视化指标。
(可选) 封装成类: 如果需要更复杂的指标计算逻辑,例如需要维护状态 (例如累积 TP, FP, FN, TN 等),可以将自定义指标封装成一个类,继承 torchmetrics.Metric 类,并实现 update, compute 和 reset 方法。 这样可以更好地与 torchmetrics 库集成,并方便在 PyTorch 训练流程中使用。
自定义评估指标的具体实现方式取决于指标的复杂程度和具体需求。对于简单的指标,可以直接使用函数实现;对于复杂的指标,可以考虑封装成类。
选择合适的评估指标至关重要,它直接影响我们对模型性能的判断和模型优化方向。选择指标时需要考虑以下几个方面:
任务类型: 首先要根据任务类型 (分类或回归) 选择合适的指标。 分类任务通常使用准确率、精确率、召回率、F1 分数、AUC-ROC 等指标;回归任务通常使用 MAE, MSE, RMSE, R 平方等指标。
数据特点: 例如,如果数据集类别不平衡,Accuracy 就不是一个好的指标,应该考虑使用 Precision, Recall, F1-Score, AUC-ROC 等更鲁棒的指标。如果数据中存在异常值,MAE 比 MSE 或 RMSE 更合适。