PaddlePaddle/PaddleOCR · error · NotImplementedError
{} is not supported in MultiHead yet
Error message
{} is not supported in MultiHead yet What it means
MultiHead is a composite head that builds a CTC branch (plus optional SAR/NRTR branch) by dispatching on the name key of each entry in the config's Head list. Only known names take a dedicated construction path; any other name reaches the else and raises NotImplementedError.
Source
Thrown at ppocr/modeling/heads/rec_multi_head.py:130
out_channels=out_channels_list["NRTRLabelDecode"],
)
elif name == "CTCHead":
# ctc neck
self.encoder_reshape = Im2Seq(in_channels)
neck_args = self.head_list[idx][name]["Neck"]
encoder_type = neck_args.pop("name")
self.ctc_encoder = SequenceEncoder(
in_channels=in_channels, encoder_type=encoder_type, **neck_args
)
# ctc head
head_args = self.head_list[idx][name]["Head"]
self.ctc_head = eval(name)(
in_channels=self.ctc_encoder.out_channels,
out_channels=out_channels_list["CTCLabelDecode"],
**head_args,
)
else:
raise NotImplementedError(
"{} is not supported in MultiHead yet".format(name)
)
def forward(self, x, targets=None):
if self.use_pool:
x = self.pool(
x.reshape([0, 3, -1, self.in_channels]).transpose([0, 3, 1, 2])
)
ctc_encoder = self.ctc_encoder(x)
ctc_out = self.ctc_head(ctc_encoder, targets)
head_out = dict()
head_out["ctc"] = ctc_out
head_out["ctc_neck"] = ctc_encoder
# eval mode
if not self.training:
return ctc_out
if self.gtc_head == "sar":
sar_out = self.sar_head(x, targets[1:])View on GitHub (pinned to 2661c7c0ef)
Solutions
- Set each entry's name to "Multi" (CTC + optional SAR) or "SRNHead" exactly as MultiHead expects; check the canonical Multi config templates under configs/rec for the exact structure
- If you genuinely need a new head type inside MultiHead, add an elif branch in ppocr/modeling/heads/rec_multi_head.py that constructs it, mirroring the SRNHead path
- Print self.head_list in __init__ to confirm the parsed structure matches what you wrote in YAML
Example fix
# before (config yml)
Head:
name: Multi
Head list:
- name: CTCHead # not supported
Head: ...
# after
Head:
name: Multi
Head list:
- name: Multi # CTC branch built by SequenceEncoder path
Head: ...
- name: SARHead
Head: ... Defensive patterns
Strategy: validation
Validate before calling
SUPPORTED = {"Multi", "SRNHead"}
def validate_head_list(head_list):
names = [entry.get('name') if isinstance(entry, dict) else entry for entry in head_list]
bad = [n for n in names if n not in SUPPORTED]
if bad:
raise ValueError(f'MultiHead does not support head names {bad}; supported: {sorted(SUPPORTED)}') Type guard
def is_supported_head_name(name) -> bool:
return isinstance(name, str) and name in {'Multi', 'SRNHead'} Try / catch
try:
model = build_model(cfg)
except NotImplementedError as e:
if 'not supported in MultiHead' in str(e):
raise ValueError(f'check Head list names in config: {e}') from e
raise Prevention
- Start from an official Multi config template and only edit values, not names
- Assert head-list names against the supported set in a config unit test
- Beware YAML indentation: 'name' must sit under each Head-list entry
When it happens
Trigger: Configuring Multi with a Head list whose name is neither "Multi" nor "SRNHead" (those are the two dispatched names in __init__), e.g. name: "CTCHead", "NRHead", "Multi1", or a typo like "multi".
Common situations: Converting a single-head rec config to the Multi template and leaving the old head name in place; renaming heads during an upgrade; YAML indentation putting the name key at the wrong level so it is read as an unknown value.
Related errors
- RecResizeImg.image_shape is required in rec inference.yml
- Unexpected recognition channels: ${String(channels)}
- Unsupported interpolation type !!!
- {} is not supported in MultiLoss yet
- mode[{mode}_model] is not implemented!
AI-assisted analysis of PaddlePaddle/PaddleOCR@2661c7c0ef (2026-08-14).
Data as JSON: /api/errors/986a806a221a4e0b.
Report an issue: GitHub.