Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@

All notable changes to this project will be documented in this file.

## 1.3.10

### Added

- Weight upload support for yolo26-sem semantic segmentation models via
`version.deploy()` and `workspace.deploy_model()`

## 1.3.9

### Added — Model evaluations SDK & CLI
Expand Down
2 changes: 1 addition & 1 deletion roboflow/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
CLIPModel = None # type: ignore[assignment,misc]
GazeModel = None # type: ignore[assignment,misc]

__version__ = "1.3.9"
__version__ = "1.3.10"


def check_key(api_key, model, notebook, num_retries=0):
Expand Down
1 change: 1 addition & 0 deletions roboflow/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ def get_conditional_configuration_variable(key, default):

TASK_DET = "det"
TASK_SEG = "seg"
TASK_SEM = "sem"
TASK_POSE = "pose"
TASK_CLS = "cls"
TASK_OBB = "obb"
Expand Down
12 changes: 6 additions & 6 deletions roboflow/util/model_processor.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,12 @@
TASK_OBB,
TASK_POSE,
TASK_SEG,
TASK_SEM,
TYPE_CLASSICATION,
TYPE_INSTANCE_SEGMENTATION,
TYPE_KEYPOINT_DETECTION,
TYPE_OBJECT_DETECTION,
TYPE_SEMANTIC_SEGMENTATION,
)
from roboflow.util.versions import print_warn_for_wrong_dependencies_versions

Expand All @@ -27,21 +29,18 @@ def task_of_model_type(model_type: str) -> str:
(e.g. 'yolov11-seg' -> TASK_SEG). Plain 'yolov11' / 'rfdetr-base' -> TASK_DET.
"""
s = model_type.lower()
for task in (TASK_SEG, TASK_POSE, TASK_CLS, TASK_OBB):
for task in (TASK_SEM, TASK_SEG, TASK_POSE, TASK_CLS, TASK_OBB):
if task in s:
return task
return TASK_DET


def validate_model_type_for_project(model_type: str, project_type: str, project_id: str) -> None:
"""Raise ValueError if model_type's task doesn't match the Roboflow project type.

No-op when project_type has no uploader-relevant task (e.g. semantic-segmentation).
"""
# TYPE_SEMANTIC_SEGMENTATION intentionally omitted — no uploader emits it.
"""Raise ValueError if model_type's task doesn't match the Roboflow project type."""
expected = {
TYPE_OBJECT_DETECTION: TASK_DET,
TYPE_INSTANCE_SEGMENTATION: TASK_SEG,
TYPE_SEMANTIC_SEGMENTATION: TASK_SEM,
TYPE_KEYPOINT_DETECTION: TASK_POSE,
TYPE_CLASSICATION: TASK_CLS,
}.get(project_type)
Expand Down Expand Up @@ -119,6 +118,7 @@ def _detect_yolo_task(model_instance) -> Optional[str]:
return {
"DetectionModel": TASK_DET,
"SegmentationModel": TASK_SEG,
"SemanticSegmentationModel": TASK_SEM,
"PoseModel": TASK_POSE,
"ClassificationModel": TASK_CLS,
"OBBModel": TASK_OBB,
Expand Down
20 changes: 20 additions & 0 deletions tests/test_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
TYPE_INSTANCE_SEGMENTATION,
TYPE_KEYPOINT_DETECTION,
TYPE_OBJECT_DETECTION,
TYPE_SEMANTIC_SEGMENTATION,
)
from roboflow.core.version import Version, unwrap_version_id
from tests.helpers import get_version
Expand Down Expand Up @@ -243,6 +244,25 @@ def test_keypoint_project_rejects_detection(self):
def test_classification_project_accepts_cls(self):
self._version(TYPE_CLASSICATION)._validate_against_project_type("yolov11-cls")

def test_semantic_seg_project_accepts_sem_model(self):
self._version(TYPE_SEMANTIC_SEGMENTATION)._validate_against_project_type("yolo26-sem")

def test_semantic_seg_project_rejects_detection(self):
with self.assertRaises(ValueError):
self._version(TYPE_SEMANTIC_SEGMENTATION)._validate_against_project_type("yolov11")

def test_semantic_seg_project_rejects_instance_seg(self):
with self.assertRaises(ValueError):
self._version(TYPE_SEMANTIC_SEGMENTATION)._validate_against_project_type("yolov11-seg")

def test_instance_seg_project_rejects_sem_model(self):
with self.assertRaises(ValueError):
self._version(TYPE_INSTANCE_SEGMENTATION)._validate_against_project_type("yolo26-sem")

def test_detection_project_rejects_sem_model(self):
with self.assertRaises(ValueError):
self._version(TYPE_OBJECT_DETECTION)._validate_against_project_type("yolo26-sem")

def test_classification_project_rejects_detection(self):
with self.assertRaises(ValueError):
self._version(TYPE_CLASSICATION)._validate_against_project_type("yolov11")
8 changes: 7 additions & 1 deletion tests/util/test_model_processor.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import unittest
from types import SimpleNamespace

from roboflow.config import TASK_CLS, TASK_DET, TASK_OBB, TASK_POSE, TASK_SEG
from roboflow.config import TASK_CLS, TASK_DET, TASK_OBB, TASK_POSE, TASK_SEG, TASK_SEM
from roboflow.util.model_processor import (
_detect_rfdetr_task,
_detect_yolo_task,
Expand Down Expand Up @@ -38,6 +38,9 @@ def test_pose(self):
def test_classify(self):
self.assertEqual(task_of_model_type("yolov11-cls"), TASK_CLS)

def test_semantic(self):
self.assertEqual(task_of_model_type("yolo26-sem"), TASK_SEM)

def test_obb(self):
self.assertEqual(task_of_model_type("yolov11-obb"), TASK_OBB)

Expand All @@ -54,6 +57,9 @@ def test_ultralytics_class_names(self):
for cls_name, expected in cases.items():
self.assertEqual(_detect_yolo_task(_make_fake(cls_name)), expected, cls_name)

def test_semantic_segmentation_model(self):
self.assertEqual(_detect_yolo_task(_make_fake("SemanticSegmentationModel")), TASK_SEM)

def test_unrecognized_returns_none(self):
self.assertIsNone(_detect_yolo_task(_make_fake("SomeOtherModel")))
self.assertIsNone(_detect_yolo_task(None))
Expand Down
Loading