huggingface/pytorch-image-models · error · NotImplementedError

MobileNetV5Encoder does not support classification use cases

Error message

MobileNetV5Encoder does not support classification use cases.

What it means

MobileNetV5Encoder is an encoder-only timm model exposing multi-scale features through an MSFA (multi-scale feature aggregation) module. It deliberately implements forward_head to raise NotImplementedError since there is no classifier head; any code path that calls forward_head on it fails.

Source

Thrown at timm/models/mobilenetv5.py:594

    def forward_features(self, x: torch.Tensor) -> torch.Tensor:
        feat_idx = 0    # offset by one from blocks index due to stem feature
        intermediates = []

        x = self.conv_stem(x)
        if feat_idx in self.msfa_indices:
            intermediates.append(x)

        for blk in self.blocks:
            feat_idx += 1
            # FIXME fix grad checkpointing
            x = blk(x)
            if feat_idx in self.msfa_indices:
                intermediates.append(x)

        return self.msfa(intermediates)

    def forward_head(self, x: torch.Tensor) -> torch.Tensor:
        raise NotImplementedError("MobileNetV5Encoder does not support classification use cases.")

    def forward(self, x: torch.Tensor) -> torch.Tensor:
        return self.forward_features(x)


def checkpoint_filter_fn(
        state_dict: Dict[str, torch.Tensor],
        model,
) -> Dict[str, torch.Tensor]:
    """ convert weights from gemma encoders """
    state_dict = state_dict.get('model', state_dict)
    state_dict = state_dict.get('state_dict', state_dict)
    if 'model.vision_tower.timm_model.conv_stem.conv.weight' in state_dict:
        prefix = 'model.vision_tower.timm_model.'
        state_dict = {k.replace(prefix, ''): v for k, v in state_dict.items() if prefix in k}
    return state_dict

View on GitHub (pinned to 9a5261e31b)

Solutions

  1. Use the non-encoder MobileNetV5 model if you need built-in classification
  2. Consume the encoder output (from forward/forward_features) with your own task head
  3. Guard shared pipelines with hasattr(model, 'forward_head') checks and skip head application for encoders

Example fix

# before
enc = timm.create_model('mobilenetv5_encoder_100', features_only=True)
logits = enc.forward_head(enc.forward_features(x))
# after
feats = enc(x)  # multi-scale features from MSFA
logits = my_head(feats)
Defensive patterns

Strategy: type-guard

Validate before calling

is_encoder = getattr(type(model), '__name__', '').endswith('Encoder')
if is_encoder or not hasattr(model, 'head'):
    feats = model(x)  # encoder output; apply custom head
    out = my_head(feats)
else:
    out = model(x)

Type guard

def is_encoder_only(model) -> bool:
    return type(model).__name__.endswith('Encoder')

Try / catch

try:
    logits = model.forward_head(x)
except NotImplementedError:
    logits = my_head(model(x))

Prevention

When it happens

Trigger: Calling model.forward_head(x) on a MobileNetV5Encoder instance, or generic classification code that does logits = model.forward_head(model.forward_features(x)).

Common situations: Plugging a timm features_only/encoder backbone into a classifier that assumes the full Model API; library helpers (e.g. timm's build_model_with_cfg pre_logits wiring or downstream frameworks) probing the head; migrating from a full MobileNetV3 to the V5 encoder without adapting the head code.

Related errors


AI-assisted analysis of huggingface/pytorch-image-models@9a5261e31b (2026-08-27). Data as JSON: /api/errors/54c81e9df9904f0f. Report an issue: GitHub.