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

PyTorch目标检测:不平衡数据集的带权重训练方案咨询

针对不平衡数据集的带权重训练调整方案

你当前使用的TorchVision Faster RCNN默认损失是在模型的roi_heads模块中计算的,分类损失采用不带权重的交叉熵损失。针对不平衡数据集,我们可以通过给分类损失添加类别权重来优化,具体步骤如下:

1. 计算类别权重

先统计训练数据集中每个类别的目标数量,再基于逆频率(或平方逆频率)计算对应权重,代码示例:

import torch

def calculate_class_weights(train_dataset, num_classes, ignore_background=True):
    # 初始化类别计数数组
    class_counts = torch.zeros(num_classes, dtype=torch.float32)
    # 遍历数据集统计每个类别的目标数量
    for idx in range(len(train_dataset)):
        _, targets = train_dataset[idx]
        labels = targets['labels']
        for label in labels:
            class_counts[label.item()] += 1
    # 避免类别计数为0导致除以0,给空类别设为1
    class_counts[class_counts == 0] = 1
    total_samples = class_counts.sum()
    
    if ignore_background:
        # 背景类(类别0)权重设为1,仅给自定义类别计算权重
        weights = torch.ones(num_classes, dtype=torch.float32)
        # 从类别1开始计算逆频率权重
        for cls in range(1, num_classes):
            weights[cls] = total_samples / ((num_classes - 1) * class_counts[cls])
    else:
        # 所有类别(包括背景)计算逆频率权重
        weights = total_samples / (num_classes * class_counts)
    
    return weights.to(DEVICE)

# 计算类别权重
class_weights = calculate_class_weights(train_dataset, num_classes, ignore_background=True)

2. 修改模型的分类损失函数

TorchVision的Faster RCNN默认分类损失不带权重,我们通过猴子补丁替换为带权重的交叉熵损失:

import torch.nn.functional as F
from torchvision.models.detection.roi_heads import fastrcnn_loss

# 创建带权重的交叉熵损失函数
cls_loss_fn = torch.nn.CrossEntropyLoss(weight=class_weights)

def weighted_fastrcnn_loss(class_logits, box_regression, labels, regression_targets):
    labels = torch.cat(labels, dim=0)
    regression_targets = torch.cat(regression_targets, dim=0)
    
    # 使用带权重的分类损失
    classification_loss = cls_loss_fn(class_logits, labels)
    
    # 边界框回归损失保持默认逻辑不变
    sampled_pos_inds_subset = torch.where(labels > 0)[0]
    labels_pos = labels[sampled_pos_inds_subset]
    N, num_classes = class_logits.shape
    box_regression = box_regression.reshape(N, -1, 4)

    box_loss = F.smooth_l1_loss(
        box_regression[sampled_pos_inds_subset, labels_pos],
        regression_targets[sampled_pos_inds_subset],
        beta=1 / 9,
        reduction="sum",
    )
    box_loss = box_loss / labels.numel()

    return classification_loss, box_loss

# 替换模型原有的损失计算函数
model.roi_heads.fastrcnn_loss = weighted_fastrcnn_loss

3. 保持原有训练流程不变

你的训练代码无需额外修改,模型在训练时会自动使用带权重的分类损失计算loss_dict中的loss_classifier项,后续的损失求和、反向传播逻辑完全兼容。

补充说明

  • 如果数据集的边界框数量也存在严重不平衡(比如某些类别的框极少),可以考虑给边界框回归损失也添加权重,但通常分类损失的权重调整对不平衡数据集的性能提升更明显。
  • 权重计算方式可按需调整,比如使用平方逆频率(weights = torch.sqrt(total_samples / ((num_classes - 1) * class_counts[cls]))),避免少数类权重过大导致模型过拟合。

内容的提问来源于stack exchange,提问作者mad

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 22:48:53