{"record":{"id":"cd2dbb84e8ae3341","repo":"open-mmlab/mmdetection","slug":"the-num-classes-should-be-1-in-rpn-but-get-rpn","errorCode":null,"errorMessage":"The `num_classes` should be 1 in RPN, but get {rpn_head_num_classes}, please set rpn_head.num_classes = 1 in your config file.","messagePattern":"The `num_classes` should be 1 in RPN, but get (.+?), please set rpn_head\\.num_classes = 1 in your config file\\.","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"mmdet/models/detectors/rpn.py","lineNumber":48,"sourceCode":"    \"\"\"\n\n    def __init__(self,\n                 backbone: ConfigType,\n                 neck: ConfigType,\n                 rpn_head: ConfigType,\n                 train_cfg: ConfigType,\n                 test_cfg: ConfigType,\n                 data_preprocessor: OptConfigType = None,\n                 init_cfg: OptMultiConfig = None,\n                 **kwargs) -> None:\n        super(SingleStageDetector, self).__init__(\n            data_preprocessor=data_preprocessor, init_cfg=init_cfg)\n        self.backbone = MODELS.build(backbone)\n        self.neck = MODELS.build(neck) if neck is not None else None\n        rpn_train_cfg = train_cfg['rpn'] if train_cfg is not None else None\n        rpn_head_num_classes = rpn_head.get('num_classes', 1)\n        if rpn_head_num_classes != 1:\n            warnings.warn('The `num_classes` should be 1 in RPN, but get '\n                          f'{rpn_head_num_classes}, please set '\n                          'rpn_head.num_classes = 1 in your config file.')\n            rpn_head.update(num_classes=1)\n        rpn_head.update(train_cfg=rpn_train_cfg)\n        rpn_head.update(test_cfg=test_cfg['rpn'])\n        self.bbox_head = MODELS.build(rpn_head)\n        self.train_cfg = train_cfg\n        self.test_cfg = test_cfg\n\n    def loss(self, batch_inputs: Tensor,\n             batch_data_samples: SampleList) -> dict:\n        \"\"\"Calculate losses from a batch of inputs and data samples.\n\n        Args:\n            batch_inputs (Tensor): Input images of shape (N, C, H, W).\n                These should usually be mean centered and std scaled.\n            batch_data_samples (list[:obj:`DetDataSample`]): The batch\n                data samples. It usually includes information such","sourceCodeStart":30,"sourceCodeEnd":66,"githubUrl":"https://github.com/open-mmlab/mmdetection/blob/cfd5d3a985b0249de009b67d04f37263e11cdf3d/mmdet/models/detectors/rpn.py#L30-L66","documentation":"RPN constructor warns when rpn_head config sets num_classes != 1, then force-sets it to 1. RPN is class-agnostic by design (objectness only), so any other value is a config mistake.","triggerScenarios":"Building an RPN detector with rpn_head=dict(..., num_classes=80) in the config.","commonSituations":"Users copy a detector bbox_head config (with dataset num_classes) into the rpn_head section; adapting two-stage configs and forgetting RPN semantics.","solutions":["Set rpn_head.num_classes = 1 (or omit it — default is 1) in your config","Leave num_classes for dataset classes on the roi_head's bbox_head only"],"exampleFix":"# before\nrpn_head=dict(num_classes=80, ...)\n# after\nrpn_head=dict(num_classes=1, ...)  # or omit num_classes","handlingStrategy":"validation","validationCode":"rpn = cfg['model']['rpn_head']\nrpn['num_classes'] = 1  # RPN is class-agnostic\nassert rpn.get('num_classes', 1) == 1","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never copy dataset num_classes into rpn_head","Only roi_head.bbox_head carries dataset class counts"],"tags":["mmdet","rpn","config","two-stage"],"backgroundTag":"invalid-config-value","analyzedSha":"cfd5d3a985b0249de009b67d04f37263e11cdf3d","analyzedAt":"2026-08-27T20:54:20.183Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}