open-mmlab/mmdetection · error · ValueError

num_classes={num_classes} is too small

Error message

num_classes={num_classes} is too small

What it means

AnchorHead.__init__ computes cls_out_channels (num_classes with sigmoid, num_classes+1 with softmax) and raises ValueError if it is <= 0. With sigmoid classification num_classes=0 yields 0 channels, which is invalid for a detection head.

Source

Thrown at mmdet/models/dense_heads/anchor_head.py:80

        loss_bbox: ConfigType = dict(
            type='SmoothL1Loss', beta=1.0 / 9.0, loss_weight=1.0),
        train_cfg: OptConfigType = None,
        test_cfg: OptConfigType = None,
        init_cfg: OptMultiConfig = dict(
            type='Normal', layer='Conv2d', std=0.01)
    ) -> None:
        super().__init__(init_cfg=init_cfg)
        self.in_channels = in_channels
        self.num_classes = num_classes
        self.feat_channels = feat_channels
        self.use_sigmoid_cls = loss_cls.get('use_sigmoid', False)
        if self.use_sigmoid_cls:
            self.cls_out_channels = num_classes
        else:
            self.cls_out_channels = num_classes + 1

        if self.cls_out_channels <= 0:
            raise ValueError(f'num_classes={num_classes} is too small')
        self.reg_decoded_bbox = reg_decoded_bbox

        self.bbox_coder = TASK_UTILS.build(bbox_coder)
        self.loss_cls = MODELS.build(loss_cls)
        self.loss_bbox = MODELS.build(loss_bbox)
        self.train_cfg = train_cfg
        self.test_cfg = test_cfg
        if self.train_cfg:
            self.assigner = TASK_UTILS.build(self.train_cfg['assigner'])
            if train_cfg.get('sampler', None) is not None:
                self.sampler = TASK_UTILS.build(
                    self.train_cfg['sampler'], default_args=dict(context=self))
            else:
                self.sampler = PseudoSampler(context=self)

        self.fp16_enabled = False

        self.prior_generator = TASK_UTILS.build(anchor_generator)

View on GitHub (pinned to cfd5d3a985)

Solutions

  1. Set num_classes to the real number of foreground classes (>=1)
  2. If using softmax classification (use_sigmoid_cls=False), remember background adds +1, but num_classes itself must still be positive
  3. Check config inheritance chains for num_classes=0 overrides

Example fix

// before
bbox_head=dict(type='AnchorHead', num_classes=0, use_sigmoid_cls=True)
// after
bbox_head=dict(type='AnchorHead', num_classes=80, use_sigmoid_cls=True)
Defensive patterns

Strategy: validation

Validate before calling

effective = num_classes if use_sigmoid_cls else num_classes + 1\nassert effective > 0, 'num_classes must be positive'

Prevention

When it happens

Trigger: AnchorHead(num_classes=0) with use_sigmoid_cls=True; passing a negative num_classes; configs where num_classes was left at default or overwritten by mistake.

Common situations: Copying a class-agnostic head config with num_classes=0; config inheritance overriding num_classes to 0; changing use_sigmoid_cls without adjusting num_classes semantics.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


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