From 6e52ae8f5717abc288e4d868b6e8cf96a03f811b Mon Sep 17 00:00:00 2001 From: Tony Lampada Date: Fri, 28 Mar 2025 14:45:51 +0000 Subject: [PATCH 01/10] upload rfdetr --- roboflow/util/model_processor.py | 34 ++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/roboflow/util/model_processor.py b/roboflow/util/model_processor.py index b7c6a16e..fa6a804c 100644 --- a/roboflow/util/model_processor.py +++ b/roboflow/util/model_processor.py @@ -27,6 +27,7 @@ def _get_processor_function(model_type: str) -> Callable: "paligemma", "paligemma2", "florence-2", + "rfdetr", ] if not any(supported_model in model_type for supported_model in supported_models): @@ -60,6 +61,9 @@ def _get_processor_function(model_type: str) -> Callable: if "yolov12" in model_type: return _process_yolov12 + if "rfdetr" in model_type: + return _process_rfdetr + return _process_yolo @@ -236,6 +240,36 @@ def _process_yolov12(model_type: str, model_path: str, filename: str) -> str: return zip_file_name +def _process_rfdetr(model_type: str, model_path: str, filename: str) -> str: + if not os.path.exists(model_path): + raise FileNotFoundError(f"Model path {model_path} does not exist.") + + model_files = os.listdir(model_path) + pt_file = next((f for f in model_files if f.endswith(".pt")), None) + + if pt_file is None: + raise RuntimeError("No .pt model file found in the provided path") + + # Copy the .pt file to weights.pt if not already named weights.pt + if pt_file != "weights.pt": + shutil.copy(os.path.join(model_path, pt_file), os.path.join(model_path, "weights.pt")) + + required_files = ["weights.pt"] + + optional_files = ["results.csv", "results.png", "model_artifacts.json"] + + zip_file_name = "roboflow_deploy.zip" + with zipfile.ZipFile(os.path.join(model_path, zip_file_name), "w") as zipMe: + for file in required_files: + zipMe.write(os.path.join(model_path, file), arcname=file, compress_type=zipfile.ZIP_DEFLATED) + + for file in optional_files: + if os.path.exists(os.path.join(model_path, file)): + zipMe.write(os.path.join(model_path, file), arcname=file, compress_type=zipfile.ZIP_DEFLATED) + + return zip_file_name + + def _process_huggingface( model_type: str, model_path: str, filename: str = "fine-tuned-paligemma-3b-pt-224.f16.npz" ) -> str: From a454a9cd469fb9f9a581c6b5572ed7b6d6a0a991 Mon Sep 17 00:00:00 2001 From: Peter Robicheaux Date: Thu, 3 Apr 2025 10:44:18 -0700 Subject: [PATCH 02/10] Allow class_names.txt upload --- roboflow/util/model_processor.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/roboflow/util/model_processor.py b/roboflow/util/model_processor.py index fa6a804c..d1832beb 100644 --- a/roboflow/util/model_processor.py +++ b/roboflow/util/model_processor.py @@ -250,6 +250,10 @@ def _process_rfdetr(model_type: str, model_path: str, filename: str) -> str: if pt_file is None: raise RuntimeError("No .pt model file found in the provided path") + + class_names = get_classnames_txt_for_rfdetr(model_path, pt_file) + + # Copy the .pt file to weights.pt if not already named weights.pt if pt_file != "weights.pt": shutil.copy(os.path.join(model_path, pt_file), os.path.join(model_path, "weights.pt")) @@ -269,6 +273,26 @@ def _process_rfdetr(model_type: str, model_path: str, filename: str) -> str: return zip_file_name +def get_classnames_txt_for_rfdetr(model_path: str, pt_file: str) -> list[str]: + class_names_path = os.path.join(model_path, "class_names.txt") + if os.path.exists(class_names_path): + return class_names_path + + model = torch.load(os.path.join(model_path, pt_file), map_location="cpu", weights_only=False) + args = vars(model["args"]) + if "class_names" in args: + with open(class_names_path, "w") as f: + for class_name in args["class_names"]: + f.write(class_name + "\n") + return class_names_path + + raise FileNotFoundError( + f"No class_names.txt file found in model path {model_path}.\n" + f"This should only happen on rfdetr models trained before version 1.1.0.\n" + f"Please re-train your model with the latest version of the rfdetr library, or\n" + f"please create a class_names.txt file in the model path with the class names in new lines in the order of the classes in the model.\n" + ) + def _process_huggingface( model_type: str, model_path: str, filename: str = "fine-tuned-paligemma-3b-pt-224.f16.npz" From e6bfab72cedd62a848ca24b031aff989302c2af4 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 3 Apr 2025 17:45:23 +0000 Subject: [PATCH 03/10] =?UTF-8?q?fix(pre=5Fcommit):=20=F0=9F=8E=A8=20auto?= =?UTF-8?q?=20format=20pre-commit=20hooks?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- roboflow/util/model_processor.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/roboflow/util/model_processor.py b/roboflow/util/model_processor.py index d1832beb..afbba103 100644 --- a/roboflow/util/model_processor.py +++ b/roboflow/util/model_processor.py @@ -250,10 +250,8 @@ def _process_rfdetr(model_type: str, model_path: str, filename: str) -> str: if pt_file is None: raise RuntimeError("No .pt model file found in the provided path") - class_names = get_classnames_txt_for_rfdetr(model_path, pt_file) - # Copy the .pt file to weights.pt if not already named weights.pt if pt_file != "weights.pt": shutil.copy(os.path.join(model_path, pt_file), os.path.join(model_path, "weights.pt")) @@ -273,11 +271,12 @@ def _process_rfdetr(model_type: str, model_path: str, filename: str) -> str: return zip_file_name + def get_classnames_txt_for_rfdetr(model_path: str, pt_file: str) -> list[str]: class_names_path = os.path.join(model_path, "class_names.txt") if os.path.exists(class_names_path): return class_names_path - + model = torch.load(os.path.join(model_path, pt_file), map_location="cpu", weights_only=False) args = vars(model["args"]) if "class_names" in args: From e99dd1df4a05fa1700b3ece60363aad4a86b72c7 Mon Sep 17 00:00:00 2001 From: Tony Lampada Date: Mon, 7 Apr 2025 11:57:44 -0300 Subject: [PATCH 04/10] few bugfixes on roboflow-python --- roboflow/util/model_processor.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/roboflow/util/model_processor.py b/roboflow/util/model_processor.py index afbba103..91b31117 100644 --- a/roboflow/util/model_processor.py +++ b/roboflow/util/model_processor.py @@ -114,7 +114,7 @@ def _process_yolo(model_type: str, model_path: str, filename: str) -> str: print_warn_for_wrong_dependencies_versions([("ultralytics", ">=", "8.3.0")], ask_to_continue=True) - model = torch.load(os.path.join(model_path, filename)) + model = torch.load(os.path.join(model_path, filename), map_location="cpu") if isinstance(model["model"].names, list): class_names = model["model"].names @@ -241,14 +241,18 @@ def _process_yolov12(model_type: str, model_path: str, filename: str) -> str: def _process_rfdetr(model_type: str, model_path: str, filename: str) -> str: + _supported_types = ["rfdetr-base", "rfdetr-large"] + if model_type not in _supported_types: + raise ValueError(f"Model type {model_type} not supported. Supported types are {_supported_types}") + if not os.path.exists(model_path): raise FileNotFoundError(f"Model path {model_path} does not exist.") model_files = os.listdir(model_path) - pt_file = next((f for f in model_files if f.endswith(".pt")), None) + pt_file = next((f for f in model_files if f.endswith(".pt") or f.endswith(".pth")), None) if pt_file is None: - raise RuntimeError("No .pt model file found in the provided path") + raise RuntimeError("No .pt or .pth model file found in the provided path") class_names = get_classnames_txt_for_rfdetr(model_path, pt_file) @@ -258,7 +262,7 @@ def _process_rfdetr(model_type: str, model_path: str, filename: str) -> str: required_files = ["weights.pt"] - optional_files = ["results.csv", "results.png", "model_artifacts.json"] + optional_files = ["results.csv", "results.png", "model_artifacts.json", "class_names.txt"] zip_file_name = "roboflow_deploy.zip" with zipfile.ZipFile(os.path.join(model_path, zip_file_name), "w") as zipMe: @@ -272,11 +276,13 @@ def _process_rfdetr(model_type: str, model_path: str, filename: str) -> str: return zip_file_name -def get_classnames_txt_for_rfdetr(model_path: str, pt_file: str) -> list[str]: +def get_classnames_txt_for_rfdetr(model_path: str, pt_file: str): class_names_path = os.path.join(model_path, "class_names.txt") if os.path.exists(class_names_path): return class_names_path + import torch + model = torch.load(os.path.join(model_path, pt_file), map_location="cpu", weights_only=False) args = vars(model["args"]) if "class_names" in args: From 9a19ac21d866d3dabcd0e057bc609e6622158ea8 Mon Sep 17 00:00:00 2001 From: Peter Robicheaux Date: Fri, 11 Apr 2025 08:28:50 -0700 Subject: [PATCH 05/10] add background class --- roboflow/util/model_processor.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/roboflow/util/model_processor.py b/roboflow/util/model_processor.py index 91b31117..418ab8b1 100644 --- a/roboflow/util/model_processor.py +++ b/roboflow/util/model_processor.py @@ -279,6 +279,7 @@ def _process_rfdetr(model_type: str, model_path: str, filename: str) -> str: def get_classnames_txt_for_rfdetr(model_path: str, pt_file: str): class_names_path = os.path.join(model_path, "class_names.txt") if os.path.exists(class_names_path): + maybe_prepend_dummy_class(class_names_path) return class_names_path import torch @@ -289,6 +290,7 @@ def get_classnames_txt_for_rfdetr(model_path: str, pt_file: str): with open(class_names_path, "w") as f: for class_name in args["class_names"]: f.write(class_name + "\n") + maybe_prepend_dummy_class(class_names_path) return class_names_path raise FileNotFoundError( @@ -298,6 +300,16 @@ def get_classnames_txt_for_rfdetr(model_path: str, pt_file: str): f"please create a class_names.txt file in the model path with the class names in new lines in the order of the classes in the model.\n" ) +def maybe_prepend_dummy_class(class_name_file: str): + with open(class_name_file, "r") as f: + class_names = f.readlines() + + dummy_class = "background_class83422\n" + if dummy_class not in class_names: + class_names.insert(0, dummy_class) + with open(class_name_file, "w") as f: + f.writelines(class_names) + def _process_huggingface( model_type: str, model_path: str, filename: str = "fine-tuned-paligemma-3b-pt-224.f16.npz" From dd9d8e15f340c50ceac6e253c463928651ca0de8 Mon Sep 17 00:00:00 2001 From: Tony Lampada Date: Fri, 11 Apr 2025 16:34:02 +0000 Subject: [PATCH 06/10] yolov12 doesnt belong in this PR --- roboflow/util/model_processor.py | 43 -------------------------------- 1 file changed, 43 deletions(-) diff --git a/roboflow/util/model_processor.py b/roboflow/util/model_processor.py index 53f028d3..571910a0 100644 --- a/roboflow/util/model_processor.py +++ b/roboflow/util/model_processor.py @@ -58,9 +58,6 @@ def _get_processor_function(model_type: str) -> Callable: if "yolonas" in model_type: return _process_yolonas - if "yolov12" in model_type: - return _process_yolov12 - if "rfdetr" in model_type: return _process_rfdetr @@ -227,46 +224,6 @@ def _process_yolo(model_type: str, model_path: str, filename: str) -> str: return zip_file_name -def _process_yolov12(model_type: str, model_path: str, filename: str) -> str: - # For YOLOv12, since it uses a special Ultralytics version, - # state dict extraction and model artifacts are handled during model conversion - - print( - "Note: Model must be trained using ultralytics from https://github.com/sunsmarterjie/yolov12 " - "or through the Roboflow platform" - ) - - # Check if model_path exists - if not os.path.exists(model_path): - raise FileNotFoundError(f"Model path {model_path} does not exist.") - - # Find any .pt file in model path - model_files = os.listdir(model_path) - pt_file = next((f for f in model_files if f.endswith(".pt")), None) - - if pt_file is None: - raise RuntimeError("No .pt model file found in the provided path") - - # Copy the .pt file to weights.pt if not already named weights.pt - if pt_file != "weights.pt": - shutil.copy(os.path.join(model_path, pt_file), os.path.join(model_path, "weights.pt")) - - required_files = ["weights.pt"] - - optional_files = ["results.csv", "results.png", "model_artifacts.json"] - - zip_file_name = "roboflow_deploy.zip" - with zipfile.ZipFile(os.path.join(model_path, zip_file_name), "w") as zipMe: - for file in required_files: - zipMe.write(os.path.join(model_path, file), arcname=file, compress_type=zipfile.ZIP_DEFLATED) - - for file in optional_files: - if os.path.exists(os.path.join(model_path, file)): - zipMe.write(os.path.join(model_path, file), arcname=file, compress_type=zipfile.ZIP_DEFLATED) - - return zip_file_name - - def _process_rfdetr(model_type: str, model_path: str, filename: str) -> str: _supported_types = ["rfdetr-base", "rfdetr-large"] if model_type not in _supported_types: From 6c37378f0781a1459dd8924b0de573be9f435a58 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 11 Apr 2025 16:34:16 +0000 Subject: [PATCH 07/10] =?UTF-8?q?fix(pre=5Fcommit):=20=F0=9F=8E=A8=20auto?= =?UTF-8?q?=20format=20pre-commit=20hooks?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- roboflow/util/model_processor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roboflow/util/model_processor.py b/roboflow/util/model_processor.py index 571910a0..b628c2d0 100644 --- a/roboflow/util/model_processor.py +++ b/roboflow/util/model_processor.py @@ -286,7 +286,7 @@ def get_classnames_txt_for_rfdetr(model_path: str, pt_file: str): def maybe_prepend_dummy_class(class_name_file: str): - with open(class_name_file, "r") as f: + with open(class_name_file) as f: class_names = f.readlines() dummy_class = "background_class83422\n" From 930b8417a6dfe4ddd9b41e8f05ad8d3b6749f138 Mon Sep 17 00:00:00 2001 From: Tony Lampada Date: Fri, 11 Apr 2025 16:38:39 +0000 Subject: [PATCH 08/10] bump version --- roboflow/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roboflow/__init__.py b/roboflow/__init__.py index e754cf0f..37a44b09 100644 --- a/roboflow/__init__.py +++ b/roboflow/__init__.py @@ -15,7 +15,7 @@ from roboflow.models import CLIPModel, GazeModel # noqa: F401 from roboflow.util.general import write_line -__version__ = "1.1.60" +__version__ = "1.1.61" def check_key(api_key, model, notebook, num_retries=0): From 39fb4062ba302be1f1c631c225068fe24874d32e Mon Sep 17 00:00:00 2001 From: Tony Lampada Date: Fri, 11 Apr 2025 16:40:27 +0000 Subject: [PATCH 09/10] please the linter gods --- roboflow/util/model_processor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roboflow/util/model_processor.py b/roboflow/util/model_processor.py index b628c2d0..52628c3f 100644 --- a/roboflow/util/model_processor.py +++ b/roboflow/util/model_processor.py @@ -238,7 +238,7 @@ def _process_rfdetr(model_type: str, model_path: str, filename: str) -> str: if pt_file is None: raise RuntimeError("No .pt or .pth model file found in the provided path") - class_names = get_classnames_txt_for_rfdetr(model_path, pt_file) + get_classnames_txt_for_rfdetr(model_path, pt_file) # Copy the .pt file to weights.pt if not already named weights.pt if pt_file != "weights.pt": From 8cd79a5bd2a839e54fff86627462111666ce61a4 Mon Sep 17 00:00:00 2001 From: Tony Lampada Date: Fri, 11 Apr 2025 16:42:18 +0000 Subject: [PATCH 10/10] satisfy the lint gods --- roboflow/util/model_processor.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/roboflow/util/model_processor.py b/roboflow/util/model_processor.py index 52628c3f..b2db803e 100644 --- a/roboflow/util/model_processor.py +++ b/roboflow/util/model_processor.py @@ -281,7 +281,8 @@ def get_classnames_txt_for_rfdetr(model_path: str, pt_file: str): f"No class_names.txt file found in model path {model_path}.\n" f"This should only happen on rfdetr models trained before version 1.1.0.\n" f"Please re-train your model with the latest version of the rfdetr library, or\n" - f"please create a class_names.txt file in the model path with the class names in new lines in the order of the classes in the model.\n" + f"please create a class_names.txt file in the model path with the class names\n" + f"in new lines in the order of the classes in the model.\n" )