open-mmlab/mmdetection · error · ValueError

The last dim of `cls_scores` should equal to `num_classes` o

Error message

The last dim of `cls_scores` should equal to `num_classes` or `num_classes + 1`,but got {}.

What it means

BBoxHead.refine_bboxes strips the background column from cls_scores when the last dim equals num_classes+1 and expects exactly num_classes otherwise. Any other last-dimension (e.g. a mismatched head num_classes vs bbox_head) raises this ValueError.

Source

Thrown at mmdet/models/roi_heads/bbox_heads/bbox_head.py:648

            ...                                  batch_img_metas)
            >>> print(bboxes_list)
        """
        pos_is_gts = [res.pos_is_gt for res in sampling_results]
        # bbox_targets is a tuple
        labels = bbox_results['bbox_targets'][0]
        cls_scores = bbox_results['cls_score']
        rois = bbox_results['rois']
        bbox_preds = bbox_results['bbox_pred']
        if self.custom_activation:
            # TODO: Create a SeasawBBoxHead to simplified logic in BBoxHead
            cls_scores = self.loss_cls.get_activation(cls_scores)
        if cls_scores.numel() == 0:
            return None
        if cls_scores.shape[-1] == self.num_classes + 1:
            # remove background class
            cls_scores = cls_scores[:, :-1]
        elif cls_scores.shape[-1] != self.num_classes:
            raise ValueError('The last dim of `cls_scores` should equal to '
                             '`num_classes` or `num_classes + 1`,'
                             f'but got {cls_scores.shape[-1]}.')
        labels = torch.where(labels == self.num_classes, cls_scores.argmax(1),
                             labels)

        img_ids = rois[:, 0].long().unique(sorted=True)
        assert img_ids.numel() <= len(batch_img_metas)

        results_list = []
        for i in range(len(batch_img_metas)):
            inds = torch.nonzero(
                rois[:, 0] == i, as_tuple=False).squeeze(dim=1)
            num_rois = inds.numel()

            bboxes_ = rois[inds, 1:]
            label_ = labels[inds]
            bbox_pred_ = bbox_preds[inds]
            img_meta_ = batch_img_metas[i]

View on GitHub (pinned to cfd5d3a985)

Solutions

  1. Make num_classes identical across all bbox heads and the model config
  2. Check that the loaded checkpoint's classifier shape matches config num_classes
  3. Verify custom heads output cls_scores with last dim num_classes (+1 for softmax background)

Example fix

# before
roi_head.bbox_head.num_classes=80, shared_head outputs 20-class scores
# after
roi_head=dict(bbox_head=dict(num_classes=80)), shared_head aligned to 80
Defensive patterns

Strategy: validation

Validate before calling

assert cls_scores.shape[-1] in (model.num_classes, model.num_classes + 1)

Prevention

When it happens

Trigger: Calling refine_bboxes during two-stage refinement (e.g. Cascade R-CNN, ConvFCBBoxHead with reg_with_fc / refine stages) when the cls_score tensor width is neither num_classes nor num_classes+1 — typically the shared head/roi head num_classes differs from the producing head.

Common situations: Changing num_classes in one config component (bbox_head) but not another (shared head or next-stage head); checkpoint loading from a model with a different class count.

Related errors


AI-assisted analysis of open-mmlab/mmdetection@cfd5d3a985 (2026-08-27). Data as JSON: /api/errors/7934fbb665988db8. Report an issue: GitHub.