Skip to content

Validate task type before model upload#457

Draft
leeclemnet wants to merge 1 commit intomainfrom
fix/task-type-validation
Draft

Validate task type before model upload#457
leeclemnet wants to merge 1 commit intomainfrom
fix/task-type-validation

Conversation

@leeclemnet
Copy link
Copy Markdown

Summary

Uploading a segmentation .pt with model_type="yolov11" (or any other detect↔seg/pose/cls/obb mismatch) previously succeeded silently and crashed at first inference with ValueError: not enough values to unpack (expected 2, got 1). Same failure mode for rfdetr-* vs rfdetr-seg-*. The .pt always knew its task — nothing in the SDK or the server conversion was reading it.

This change adds client-side task validation on two axes:

  1. .ptmodel_type reconciliation inside model_processor.process():

    • Ultralytics: detects task via type(model_instance).__name__ (SegmentationModel / PoseModel / ClassificationModel / OBBModel / DetectionModel) — works across v8/v10/v11/v12/yolo26.
    • RF-DETR: detects via args.segmentation_head today, with an args.task string path already wired in for future rfdetr-pose/obb/cls variants.
    • YOLO: auto-appends the correct suffix when the user omitted it (so model_type="yolov11" + seg .pt"yolov11-seg"). Raises ValueError on conflict.
    • RF-DETR: raises on conflict (no auto-append, model_type needs explicit size).
  2. model_type ↔ project type cross-check inside Version.deploy(). Catches uploads like rfdetr-seg-medium to an object-detection project. Not added to Workspace.deploy_model() since that path takes a project_ids list and would need extra fetches.

A single substring scanner (_task_from_substring) drives the class-name check, the rfdetr args.task path, and the deploy model_type parse — keeping the logic future-proof (rfdetr-pose-medium, rfdetr-obb-large, etc. resolve correctly with zero SDK change when they ship).

Also adds TYPE_CLASSIFICATION to roboflow/config.py; the typo'd TYPE_CLASSICATION is retained as a backwards-compat alias.

Changes

  • roboflow/util/model_processor.py — new helpers (_task_from_substring, task_of_model_type, _detect_task_from_pt); _process_yolo and _process_rfdetr reconcile model_type against the loaded .pt; process() now returns (zip_file_name, model_type) so callers can use the corrected value.
  • roboflow/core/version.py — unpack tuple, call new _validate_against_project_type.
  • roboflow/core/workspace.py — unpack tuple.
  • roboflow/config.py — add TYPE_CLASSIFICATION.
  • tests/util/test_model_processor.py (new) — 15 cases covering task_of_model_type and _detect_task_from_pt including future-proofing for rfdetr-pose/obb.
  • tests/test_version.py — 11 cases covering _validate_against_project_type.

Test plan

  • python -m unittest — 446/446 pass
  • ruff check roboflow — clean
  • ruff format roboflow — applied
  • Manual: deploy a YOLOv11l-seg .pt with model_type="yolov11" on a segmentation project → model_artifacts.json contains "model_type": "yolov11-seg", upload URL uses modelType=yolov11-seg, inference returns masks
  • Manual: deploy same seg .pt with model_type="yolov11-pose"ValueError at client
  • Manual: deploy model_type="yolov11-seg" on a detection project → ValueError at client
  • Manual: regression — detection .pt + model_type="yolov11" on a detection project deploys cleanly
  • Manual (rfdetr): rfdetr seg .pt + model_type="rfdetr-medium"ValueError (reads args.segmentation_head=True)
  • Manual (rfdetr): model_type="rfdetr-seg-medium" on a detection project → ValueError

🤖 Generated with Claude Code

Uploading a segmentation .pt with model_type="yolov11" (or any other
detect↔seg/pose/cls/obb mismatch) previously succeeded silently and
crashed at first inference. Same failure mode for rfdetr-* vs
rfdetr-seg-*.

Both `Version.deploy()` and `Workspace.deploy_model()` now:
- Detect the .pt's task from the Ultralytics class name
  (SegmentationModel / PoseModel / etc.) or rfdetr's
  `args.segmentation_head` / future `args.task`.
- Auto-append the correct suffix (YOLO) when the user omitted it, or
  raise ValueError on a conflict.

`Version.deploy()` additionally cross-checks the model_type string
against the Roboflow project type, catching cases like uploading
`rfdetr-seg-medium` to an object-detection project.

A single substring scanner (`_task_from_substring`) drives both the
class-name check and the deploy model_type string parse. This keeps the
logic future-proof — `rfdetr-pose-medium`, `rfdetr-obb-large`, etc.
resolve to the right task the day they ship with zero SDK change.

Also adds `TYPE_CLASSIFICATION` to `roboflow/config.py` (with the
typo'd `TYPE_CLASSICATION` kept as a backwards-compat alias).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@leeclemnet leeclemnet marked this pull request as draft April 17, 2026 16:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant