Skip to content

Commit 97d4838

Browse files
authored
Merge pull request #361 from roboflow/lean/yolov12-upload
Adds support for YOLOv12 model upload
2 parents 2b06224 + 266a128 commit 97d4838

File tree

6 files changed

+59
-8
lines changed

6 files changed

+59
-8
lines changed

roboflow/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
from roboflow.models import CLIPModel, GazeModel # noqa: F401
1616
from roboflow.util.general import write_line
1717

18-
__version__ = "1.1.56"
18+
__version__ = "1.1.57"
1919

2020

2121
def check_key(api_key, model, notebook, num_retries=0):

roboflow/core/version.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
from roboflow.util.annotations import amend_data_yaml
3434
from roboflow.util.general import write_line
3535
from roboflow.util.model_processor import process
36-
from roboflow.util.versions import get_wrong_dependencies_versions
36+
from roboflow.util.versions import get_wrong_dependencies_versions, normalize_yolo_model_type
3737

3838
if TYPE_CHECKING:
3939
import numpy as np
@@ -477,6 +477,7 @@ def deploy(self, model_type: str, model_path: str, filename: str = "weights/best
477477
model_path (str): File path to the model weights to be uploaded.
478478
filename (str, optional): The name of the weights file. Defaults to "weights/best.pt".
479479
"""
480+
model_type = normalize_yolo_model_type(model_type)
480481
zip_file_name = process(model_type, model_path, filename)
481482

482483
if zip_file_name is None:

roboflow/core/workspace.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
from roboflow.util.image_utils import load_labelmap
2020
from roboflow.util.model_processor import process
2121
from roboflow.util.two_stage_utils import ocr_infer
22+
from roboflow.util.versions import normalize_yolo_model_type
2223

2324

2425
class Workspace:
@@ -596,6 +597,7 @@ def deploy_model(
596597
if project_id not in user_projects:
597598
raise ValueError(f"Project {project_id} is not accessible in this workspace")
598599

600+
model_type = normalize_yolo_model_type(model_type)
599601
zip_file_name = process(model_type, model_path, filename)
600602

601603
if zip_file_name is None:

roboflow/roboflowpy.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,8 @@ def upload_model(args):
8181

8282
if args.version_number is not None:
8383
# Deploy to specific version
84-
project = workspace.project(args.project)
84+
project_id = args.project[0] if isinstance(args.project, list) else args.project
85+
project = workspace.project(project_id)
8586
version = project.version(args.version_number)
8687
version.deploy(str(args.model_type), str(args.model_path), str(args.filename))
8788
else:

roboflow/util/model_processor.py

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,20 +15,18 @@ def process(model_type: str, model_path: str, filename: str) -> str:
1515

1616

1717
def _get_processor_function(model_type: str) -> Callable:
18-
if model_type.startswith("yolo11"):
19-
model_type = model_type.replace("yolo11", "yolov11")
20-
2118
supported_models = [
2219
"yolov5",
2320
"yolov7-seg",
2421
"yolov8",
2522
"yolov9",
23+
"yolov10",
24+
"yolov11",
25+
"yolov12",
2626
"yolonas",
2727
"paligemma",
2828
"paligemma2",
29-
"yolov10",
3029
"florence-2",
31-
"yolov11",
3230
]
3331

3432
if not any(supported_model in model_type for supported_model in supported_models):
@@ -59,6 +57,9 @@ def _get_processor_function(model_type: str) -> Callable:
5957
if "yolonas" in model_type:
6058
return _process_yolonas
6159

60+
if "yolov12" in model_type:
61+
return _process_yolov12
62+
6263
return _process_yolo
6364

6465

@@ -195,6 +196,46 @@ def _process_yolo(model_type: str, model_path: str, filename: str) -> str:
195196
return zip_file_name
196197

197198

199+
def _process_yolov12(model_type: str, model_path: str, filename: str) -> str:
200+
# For YOLOv12, since it uses a special Ultralytics version,
201+
# state dict extraction and model artifacts are handled during model conversion
202+
203+
print(
204+
"Note: Model must be trained using ultralytics from https://github.com/sunsmarterjie/yolov12 "
205+
"or through the Roboflow platform"
206+
)
207+
208+
# Check if model_path exists
209+
if not os.path.exists(model_path):
210+
raise FileNotFoundError(f"Model path {model_path} does not exist.")
211+
212+
# Find any .pt file in model path
213+
model_files = os.listdir(model_path)
214+
pt_file = next((f for f in model_files if f.endswith(".pt")), None)
215+
216+
if pt_file is None:
217+
raise RuntimeError("No .pt model file found in the provided path")
218+
219+
# Copy the .pt file to weights.pt if not already named weights.pt
220+
if pt_file != "weights.pt":
221+
shutil.copy(os.path.join(model_path, pt_file), os.path.join(model_path, "weights.pt"))
222+
223+
required_files = ["weights.pt"]
224+
225+
optional_files = ["results.csv", "results.png", "model_artifacts.json"]
226+
227+
zip_file_name = "roboflow_deploy.zip"
228+
with zipfile.ZipFile(os.path.join(model_path, zip_file_name), "w") as zipMe:
229+
for file in required_files:
230+
zipMe.write(os.path.join(model_path, file), arcname=file, compress_type=zipfile.ZIP_DEFLATED)
231+
232+
for file in optional_files:
233+
if os.path.exists(os.path.join(model_path, file)):
234+
zipMe.write(os.path.join(model_path, file), arcname=file, compress_type=zipfile.ZIP_DEFLATED)
235+
236+
return zip_file_name
237+
238+
198239
def _process_huggingface(
199240
model_type: str, model_path: str, filename: str = "fine-tuned-paligemma-3b-pt-224.f16.npz"
200241
) -> str:

roboflow/util/versions.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,3 +89,9 @@ def _wrapper(*args, **kwargs):
8989
return _wrapper
9090

9191
return _inner
92+
93+
94+
def normalize_yolo_model_type(model_type: str) -> str:
95+
model_type = model_type.replace("yolo11", "yolov11")
96+
model_type = model_type.replace("yolo12", "yolov12")
97+
return model_type

0 commit comments

Comments
 (0)