You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PyTorch/Torchvision训练验证指标与损失计算的最佳实践咨询

PyTorch模型模式差异与最佳实践

情况是否属实?

你提到的困扰确实存在,但本质是对模型__call__方法的封装逻辑出了问题——PyTorch并没有强制要求模型在训练模式返回损失、评估模式返回输出,这是新手封装模型时容易踩的坑。只要调整封装方式,就能轻松解决这两个问题。

问题1:计算验证损失并绘制训练历史的最佳实践

别让模型的__call__同时干“算输出”和“算损失”两件事,把逻辑拆分开:

  • 模型的forward(也就是__call__实际调用的方法)只负责计算原始输出(比如分类任务的logits)。
  • 损失函数单独定义,训练和验证阶段分别调用:
    • 训练时:先拿模型输出,再丢给损失函数算损失,接着做反向传播。
    • 验证时:把模型切到eval()模式(自动关闭dropout、固定batch norm的统计量),同样先拿输出再算损失——这样既不会有统计偏差,代码也简洁得很,完全不用写百行代码。

示例代码:

import torch
import torch.nn as nn

# 模型只负责前向传播输出
class MyModel(nn.Module):
    def __init__(self):
        super().__init__()
        self.backbone = nn.Sequential(
            nn.Conv2d(3, 16, kernel_size=3),
            nn.BatchNorm2d(16),
            nn.ReLU(),
            nn.Dropout(0.5),
            nn.AdaptiveAvgPool2d(1),
            nn.Flatten(),
            nn.Linear(16, 10)
        )
    
    def forward(self, x):
        return self.backbone(x)

# 训练/验证流程
model = MyModel()
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters())

# 训练阶段
model.train()
for x, y in train_dataloader:
    outputs = model(x)
    loss = criterion(outputs, y)
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

# 验证阶段计算损失
model.eval()
val_loss = 0.0
with torch.no_grad():  # 验证时不需要计算梯度,节省内存
    for x, y in val_dataloader:
        outputs = model(x)
        loss = criterion(outputs, y)
        val_loss += loss.item() * x.size(0)
val_loss /= len(val_dataloader.dataset)

用这种方式,你可以轻松记录每一轮的训练/验证损失,直接用来绘制曲线,和TensorFlow的体验一致。

问题2:用TorchMetrics处理训练数据的最佳实践

完全不需要切到评估模式重新跑训练数据!TorchMetrics支持在训练模式下直接计算指标,注意两点就行:

  1. 训练时模型处于train()模式,但TorchMetrics的指标(比如准确率)是基于模型输出计算的,和dropout、batch norm的状态无关,不会影响结果。
  2. 对于需要累积统计的指标(比如Accuracy),每轮训练前重置指标,每一步更新,轮末计算结果即可。

示例代码:

from torchmetrics import Accuracy

model = MyModel()
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters())
train_acc = Accuracy(task="multiclass", num_classes=10)

model.train()
for epoch in range(10):
    train_acc.reset()  # 每轮开始重置指标
    epoch_loss = 0.0
    for x, y in train_dataloader:
        outputs = model(x)
        loss = criterion(outputs, y)
        
        # 更新训练准确率
        train_acc(outputs.argmax(dim=1), y)
        
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        
        epoch_loss += loss.item() * x.size(0)
    
    # 获取本轮训练的准确率
    epoch_acc = train_acc.compute()
    epoch_loss /= len(train_dataloader.dataset)
    print(f"第{epoch+1}轮: 损失={epoch_loss:.4f}, 准确率={epoch_acc:.4f}")

这样训练时就能同步计算指标,不用重复遍历训练数据,完全不浪费计算资源。

内容的提问来源于stack exchange,提问作者J Agustin Barrachina

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 06:17:02