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
- Make num_classes identical across all bbox heads and the model config
- Check that the loaded checkpoint's classifier shape matches config num_classes
- 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
- Keep num_classes consistent across every bbox_head/shared_head in the config
- After loading checkpoints, verify classifier layer shapes match config
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
- LoadImageFromFile is not found in the test pipeline
- Visualization needs the "visualizer" termdefined in the conf
- config must be a filename or Config object, but got {type(co
- Unrecognized dataset: {dataset}
- The `file_client_args` is deprecated, please use `backend_ar
AI-assisted analysis of open-mmlab/mmdetection@cfd5d3a985 (2026-08-27).
Data as JSON: /api/errors/7934fbb665988db8.
Report an issue: GitHub.