Skip to content

Commit 2b87fa6

Browse files
committed
Support deployment of RFDETRKeypointPreview weights
1 parent 107fb34 commit 2b87fa6

2 files changed

Lines changed: 22 additions & 6 deletions

File tree

roboflow/util/model_processor.py

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,13 @@ def task_of_model_type(model_type: str) -> str:
2727
2828
Non-detect tasks double as the model_type suffix token
2929
(e.g. 'yolov11-seg' -> TASK_SEG). Plain 'yolov11' / 'rfdetr-base' -> TASK_DET.
30+
31+
Keypoint/pose models may spell the token as either 'pose' (Ultralytics) or
32+
'keypoint' (rf-detr, e.g. 'rfdetr-keypoint-preview'); both map to TASK_POSE.
3033
"""
3134
s = model_type.lower()
35+
if "keypoint" in s:
36+
return TASK_POSE
3237
for task in (TASK_SEM, TASK_SEG, TASK_POSE, TASK_CLS, TASK_OBB):
3338
if task in s:
3439
return task
@@ -317,17 +322,22 @@ def _process_yolo(model_type: str, model_path: str, filename: str) -> tuple[str,
317322
def _detect_rfdetr_task(checkpoint) -> Optional[str]:
318323
"""Detect the training task of an rf-detr checkpoint.
319324
320-
rf-detr currently only supports weight upload for detection and instance
321-
segmentation. Modern checkpoints (rf-detr v1.7+) store the Python class
322-
name at `checkpoint["model_name"]` (e.g. 'RFDETRNano' vs 'RFDETRSegNano');
323-
older checkpoints — including those downloaded from Roboflow — lack that
324-
field but always carry `args.segmentation_head: bool`.
325+
rf-detr supports weight upload for detection, instance segmentation, and
326+
keypoint detection. Modern checkpoints (rf-detr v1.7+) store the Python
327+
class name at `checkpoint["model_name"]` (e.g. 'RFDETRNano' vs
328+
'RFDETRSegNano' vs 'RFDETRKeypointPreview'); older checkpoints — including
329+
those downloaded from Roboflow — lack that field but always carry
330+
`args.segmentation_head: bool`. Keypoint support is recent enough that those
331+
checkpoints always carry `model_name`, so no args fallback is needed for it.
325332
"""
326333
if not isinstance(checkpoint, dict):
327334
return None
328335
model_name = checkpoint.get("model_name")
329336
if isinstance(model_name, str):
330-
return TASK_SEG if TASK_SEG in model_name.lower() else TASK_DET
337+
name = model_name.lower()
338+
if "keypoint" in name:
339+
return TASK_POSE
340+
return TASK_SEG if TASK_SEG in name else TASK_DET
331341
args = checkpoint.get("args")
332342
if args is None:
333343
return None
@@ -356,6 +366,8 @@ def _process_rfdetr(model_type: str, model_path: str, filename: str) -> tuple[st
356366
"rfdetr-seg-large",
357367
"rfdetr-seg-xlarge",
358368
"rfdetr-seg-2xlarge",
369+
# Keypoint detection models
370+
"rfdetr-keypoint-preview",
359371
]
360372
if model_type not in _supported_types:
361373
raise ValueError(f"Model type {model_type} not supported. Supported types are {_supported_types}")

tests/util/test_model_processor.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ def test_segment(self):
3434

3535
def test_pose(self):
3636
self.assertEqual(task_of_model_type("yolov11-pose"), TASK_POSE)
37+
self.assertEqual(task_of_model_type("rfdetr-keypoint-preview"), TASK_POSE)
3738

3839
def test_classify(self):
3940
self.assertEqual(task_of_model_type("yolov11-cls"), TASK_CLS)
@@ -74,6 +75,9 @@ def test_detection_model_names(self):
7475
for name in ("RFDETRNano", "RFDETRSmall", "RFDETRMedium", "RFDETRLarge", "RFDETRXLarge"):
7576
self.assertEqual(_detect_rfdetr_task({"model_name": name}), TASK_DET, name)
7677

78+
def test_keypoint_model_names(self):
79+
self.assertEqual(_detect_rfdetr_task({"model_name": "RFDETRKeypointPreview"}), TASK_POSE)
80+
7781
def test_segmentation_head_fallback(self):
7882
# Roboflow-hosted rf-detr .pt downloads lack `model_name` but always carry
7983
# `args.segmentation_head`. Cover both namespace and dict shapes.

0 commit comments

Comments
 (0)