open-mmlab/mmdetection · error · ValueError
NUM_BRANCHES({num_branches}) != NUM_CHANNELS({len(num_channe
Error message
NUM_BRANCHES({num_branches}) != NUM_CHANNELS({len(num_channels)}) What it means
HRNet's _check_branches also requires len(num_channels) == num_branches for every stage in extra; each parallel branch needs its own channel width. A mismatch raises ValueError naming NUM_CHANNELS.
Source
Thrown at mmdet/models/backbones/hrnet.py:59
self.norm_cfg = norm_cfg
self.conv_cfg = conv_cfg
self.with_cp = with_cp
self.branches = self._make_branches(num_branches, blocks, num_blocks,
num_channels)
self.fuse_layers = self._make_fuse_layers()
self.relu = nn.ReLU(inplace=False)
def _check_branches(self, num_branches, num_blocks, in_channels,
num_channels):
if num_branches != len(num_blocks):
error_msg = f'NUM_BRANCHES({num_branches}) ' \
f'!= NUM_BLOCKS({len(num_blocks)})'
raise ValueError(error_msg)
if num_branches != len(num_channels):
error_msg = f'NUM_BRANCHES({num_branches}) ' \
f'!= NUM_CHANNELS({len(num_channels)})'
raise ValueError(error_msg)
if num_branches != len(in_channels):
error_msg = f'NUM_BRANCHES({num_branches}) ' \
f'!= NUM_INCHANNELS({len(in_channels)})'
raise ValueError(error_msg)
def _make_one_branch(self,
branch_index,
block,
num_blocks,
num_channels,
stride=1):
downsample = None
if stride != 1 or \
self.in_channels[branch_index] != \
num_channels[branch_index] * block.expansion:
downsample = nn.Sequential(
build_conv_layer(View on GitHub (pinned to cfd5d3a985)
Solutions
- Set num_channels to exactly num_branches entries, e.g. num_branches=3, num_channels=[48,96,192]
- Keep width progression consistent with in_channels of the next stage
- Prefer modifying pretrained official configs (w18/w32/w48) minimally
Example fix
# before stage3=dict(num_branches=3, num_channels=[32,64), num_blocks=[4,4,4]) # after stage3=dict(num_branches=3, num_channels=[32,64,128], num_blocks=[4,4,4])
Defensive patterns
Strategy: validation
Validate before calling
for stage in extra.values():
assert stage['num_branches'] == len(stage['num_channels']), 'num_channels length must equal num_branches' Type guard
def channels_match(stage: dict) -> bool:
return stage['num_branches'] == len(stage['num_channels']) Prevention
- One channel width per branch
- Keep widths aligned with in_channels of next stage
- Use reference w18/w32/w48 settings
When it happens
Trigger: num_branches=3 with num_channels=[32,64] (len 2); editing HRNet width lists without adding an entry when adding a branch.
Common situations: Building custom HRNet-W48 variants; changing stage3/stage4 branch counts; miscounting after merging configs.
Related errors
- NUM_BRANCHES({num_branches}) != NUM_BLOCKS({len(num_blocks)}
- NUM_BRANCHES({num_branches}) != NUM_INCHANNELS({len(in_chann
- type must be a str or valid type, but got {type(obj_type)}
- RandomCenterCropPad only support two testing pad mode:logica
- Not supported YouTubeVIS datasetversion: {dataset_version}
AI-assisted analysis of open-mmlab/mmdetection@cfd5d3a985 (2026-08-27).
Data as JSON: /api/errors/7d434adbebac170d.
Report an issue: GitHub.