趋近智
训练神经网络 (neural network)时,优化器的主要目标是最小化损失函数 (loss function)。然而,损失值本身,特别是对于交叉熵等复杂函数,不总能直观地衡量模型在其预期任务上的表现。此时,性能指标就显得很重要。准确率、精确率、召回率或 F1 分数等指标能让你更清楚地了解模型的能力。
如果你习惯使用 TensorFlow Keras,你会很熟悉在 model.compile() 方法中方便地指定指标:
# Keras 示例
model.compile(optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy', tf.keras.metrics.Precision()])
Keras 会在训练 (model.fit()) 和评估 (model.evaluate()) 期间自动计算并报告这些指标。这些 Keras 指标,例如 tf.keras.metrics.Accuracy(),是带状态的对象。它们会自动在各个批次中累积值(例如,正确预测总数和样本总数),并计算最终指标值。
PyTorch 遵循其更明确的设计理念,要求你更多地参与到指标计算过程中。PyTorch 没有与 Keras 自动指标追踪系统直接对应、内置且与训练循环结构集成的功能。相反,你通常需要自行完成这些计算。
对于简单的指标,在训练或评估循环中直接进行张量操作通常就足够了。例如,要在分类任务中计算一个批次的准确率:
# PyTorch 手动计算批次准确率
# outputs: 模型输出的原始 logits
# labels: 真实标签
_, predicted_classes = torch.max(outputs.data, 1)
correct_predictions = (predicted_classes == labels).sum().item()
batch_accuracy = correct_predictions / labels.size(0)
为了得到一个周期的准确率,你需要将该周期内所有批次的 correct_predictions 和样本总数 (labels.size(0)) 相加,然后进行除法运算:
# 累积以获得周期级别准确率
# 在周期循环前初始化
epoch_total_correct = 0
epoch_total_samples = 0
# 在批次循环内部(获取 correct_predictions 和 labels.size(0) 后)
# epoch_total_correct += correct_predictions
# epoch_total_samples += labels.size(0)
# 在周期循环之后
# epoch_accuracy = epoch_total_correct / epoch_total_samples
这种手动方法让你有充分的控制权,但可能会变得重复且容易出错,特别是对于像 AUC 或 F1 分数这样需要在批次间细致管理状态的复杂指标。
为了弥补这一不足并为指标提供更便捷、类似 Keras 的体验,PyTorch 生态系统提供了 TorchMetrics。这个由 PyTorch Lightning 团队开发的库,可以在任何 PyTorch 项目中独立使用。它提供了多种常用的机器学习 (machine learning)指标,它们具有以下特点:
你首先需要安装它:
pip install torchmetrics
下面是在多类别分类问题中使用 TorchMetrics 计算准确率的示例:
import torch
import torchmetrics
# 定义类别数量和设备
NUM_CLASSES = 10 # CIFAR-10 示例
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
# 初始化指标,确保它在正确的设备上
accuracy_metric = torchmetrics.Accuracy(task="multiclass", num_classes=NUM_CLASSES).to(device)
# --- 在你的训练或评估循环内部 ---
# for images, labels in data_loader:
# images, labels = images.to(device), labels.to(device)
# outputs = model(images) # 获取模型预测 (logits)
#
# # 使用当前批次的预测和目标更新指标状态
# # TorchMetrics 通常期望分类任务的原始 logits
# # 或根据指标及其参数的概率。
# # 对于 'multiclass' 任务的 Accuracy,它在内部应用 argmax。
# accuracy_metric.update(outputs, labels)
# --- 批次循环结束 ---
# 处理完一个周期中的所有批次后:
# 计算所有累积批次的指标
epoch_accuracy = accuracy_metric.compute()
print(f"周期准确率: {epoch_accuracy.item():.4f}")
# 重置指标的内部状态,以便进行下一个周期或评估阶段
accuracy_metric.reset()
使用 TorchMetrics 主要涉及以下四个步骤:
torchmetrics.Accuracy、torchmetrics.Precision、torchmetrics.F1Score)。通常需要指定 task 参数 (parameter)(例如,“二分类”、“多类别”或“多标签”)以及适用的 num_classes。将指标对象发送到与你的数据和模型相同的设备上。update(predictions, targets) 方法。这会累积当前批次的必要统计数据。compute() 方法以获取最终指标值。reset() 来清除指标的内部状态,使其为下一个周期或新的评估运行做好准备。TorchMetrics 提供了一套全面的分类、回归、图像分析等指标,显著简化了 PyTorch 中的指标追踪。
另一种方法,特别是当 TorchMetrics 中没有特定指标或需要快速、临时评估时,是使用 sklearn.metrics。由于 scikit-learn 函数在 NumPy 数组上操作,你需要:
.detach() 从计算图中分离张量。.cpu() 将它们移到 CPU。.numpy() 将它们转换为 NumPy 数组。from sklearn.metrics import precision_score
# 假设 all_preds_list 和 all_labels_list 包含
# 一个周期的所有预测和标签,它们都收集为 CPU 张量
# 例如,all_preds_cpu = torch.cat(all_preds_list).cpu().numpy()
# all_labels_cpu = torch.cat(all_labels_list).cpu().numpy()
# precision = precision_score(all_labels_cpu, all_preds_cpu, average='macro')
# print(f"Scikit-learn 精确率 (macro): {precision:.4f}")
虽然这种方法可行,但与 TorchMetrics 相比,它在 GPU 加速的训练循环中进行逐批更新的效率通常较低。它通常更适用于周期结束或最终模型评估。
让我们将其整合起来,看看 TorchMetrics 如何融入标准的 PyTorch 评估循环:
# 假设:model, val_dataloader, criterion (损失函数), device 已定义
# 并且已初始化一个 TorchMetrics 指标:
# val_accuracy = torchmetrics.Accuracy(task="multiclass", num_classes=NUM_CLASSES).to(device)
# val_f1 = torchmetrics.F1Score(task="multiclass", num_classes=NUM_CLASSES, average="macro").to(device)
model.eval() # 将模型设置为评估模式
running_val_loss = 0.0
# 在评估开始时重置指标
val_accuracy.reset()
# val_f1.reset() # 如果使用多个指标
with torch.no_grad(): # 禁用评估的梯度计算
for inputs, labels in val_dataloader:
inputs, labels = inputs.to(device), labels.to(device)
outputs = model(inputs)
loss = criterion(outputs, labels)
running_val_loss += loss.item() * inputs.size(0)
# 更新指标
val_accuracy.update(outputs, labels)
# val_f1.update(outputs, labels)
# 遍历所有验证数据后计算最终指标
epoch_val_loss = running_val_loss / len(val_dataloader.dataset)
final_val_accuracy = val_accuracy.compute()
# final_val_f1 = val_f1.compute()
print(f"验证损失: {epoch_val_loss:.4f}")
print(f"验证准确率: {final_val_accuracy.item():.4f}")
# print(f"验证 F1 分数: {final_val_f1.item():.4f}")
在这个示例中,model.eval() 很重要,因为它会将 Dropout 和 Batch Normalization 等层设置为评估模式。torch.no_grad() 会禁用梯度计算,这会加速推理 (inference)过程并减少内存使用。指标是按批次更新的,并在最后统一计算一次。
下表总结了指标处理的主要不同之处:
Keras 和 PyTorch 中指标处理的比较。PyTorch 提供精细的控制,而
TorchMetrics则提供方便的、类似 Keras 的有状态指标对象。
TorchMetrics 提供了许多此类指标。TorchMetrics 通常要求指定 task(例如,“二分类”、“多类别”或“回归”)以及其他参数 (parameter),如 num_classes 或 average(用于 F1/精确率/召回率)。torch.utils.tensorboard.SummaryWriter)或 Weights & Biases。通过掌握如何在 PyTorch 中手动或借助 TorchMetrics 等辅助库计算和追踪性能指标,你能更全面地了解模型的学习过程及其真实表现,而不仅仅是训练损失。这种显式控制,虽然比 Keras 的 compile/fit 模式需要更多的设置,但与 PyTorch 赋予开发者对其模型训练流程完全透明和掌控的理念是一致的。
这部分内容有帮助吗?
© 2026 ApX Machine Learning用心打造