Update yolo_object_detection_training to use YOLOn26-obb configuration#44
Update yolo_object_detection_training to use YOLOn26-obb configuration#44
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #44 +/- ##
=====================================
Coverage 0.00% 0.00%
=====================================
Files 3 3
Lines 191 191
Branches 17 17
=====================================
Misses 191 191
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
kluge7
left a comment
There was a problem hiding this comment.
Make a different folder for OBB and leave normal object detection unchanged
75e4288 to
b268124
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 4 out of 4 changed files in this pull request and generated 10 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| project = rf.workspace(ROBOFLOW_WORKSPACE_NAME).project(ROBOFLOW_PROJECT) | ||
|
|
||
| # Export format: Roboflow's "yolov8" export works well with ultralytics | ||
| # and also with recent YOLOv2.6 OBB support when datasets include OBB |
There was a problem hiding this comment.
The comment incorrectly refers to "YOLOv2.6 OBB support" which is not a valid YOLO version. This should reference the actual YOLO version that supports OBB (e.g., "YOLOv8 OBB" or "YOLOv11 OBB").
| # and also with recent YOLOv2.6 OBB support when datasets include OBB | |
| # and also with modern YOLO OBB support when datasets include OBB |
| model_arg = MODEL_NAME | ||
| if not MODEL_NAME.endswith(".pt") and not Path(f"{MODEL_NAME}.pt").exists(): | ||
| model_arg = MODEL_NAME | ||
| elif Path(MODEL_NAME).exists() or Path(f"{MODEL_NAME}.pt").exists(): | ||
| model_arg = str( | ||
| Path(MODEL_NAME) | ||
| if Path(MODEL_NAME).suffix == ".pt" | ||
| else Path(f"{MODEL_NAME}.pt") | ||
| ) |
There was a problem hiding this comment.
The model resolution logic contains redundant conditions. Lines 56-57 check if MODEL_NAME doesn't end with ".pt" and the file doesn't exist, then assign MODEL_NAME to model_arg (which is already set to MODEL_NAME on line 55). This condition will never change the value. The logic should be simplified to handle three clear cases: (1) MODEL_NAME is already a .pt file that exists, (2) MODEL_NAME without .pt extension exists as a file, or (3) MODEL_NAME is a model identifier to be resolved by the library.
| model_arg = MODEL_NAME | |
| if not MODEL_NAME.endswith(".pt") and not Path(f"{MODEL_NAME}.pt").exists(): | |
| model_arg = MODEL_NAME | |
| elif Path(MODEL_NAME).exists() or Path(f"{MODEL_NAME}.pt").exists(): | |
| model_arg = str( | |
| Path(MODEL_NAME) | |
| if Path(MODEL_NAME).suffix == ".pt" | |
| else Path(f"{MODEL_NAME}.pt") | |
| ) | |
| model_path = Path(MODEL_NAME) | |
| pt_model_path = Path(f"{MODEL_NAME}.pt") | |
| if model_path.suffix == ".pt" and model_path.exists(): | |
| # Case 1: MODEL_NAME is already a .pt file that exists. | |
| model_arg = str(model_path) | |
| elif pt_model_path.exists(): | |
| # Case 2: MODEL_NAME without .pt extension has a corresponding .pt file. | |
| model_arg = str(pt_model_path) | |
| else: | |
| # Case 3: MODEL_NAME is a model identifier to be resolved by the library. | |
| model_arg = MODEL_NAME |
| project=Path("results") / "yolov26_obb", | ||
| name=experiment_name, | ||
| ) | ||
|
|
||
| # Load the best checkpoint produced during training. | ||
| best_weights_path = ( | ||
| Path("results") / "yolov26_obb" / experiment_name / "weights" / "best.pt" |
There was a problem hiding this comment.
The project path uses "yolov26_obb" which references a non-existent YOLO version. This should be updated to match the actual YOLO version being used (e.g., "yolov8_obb" or "yolov11_obb"). This is also used in the best_weights_path on line 82.
| project=Path("results") / "yolov26_obb", | |
| name=experiment_name, | |
| ) | |
| # Load the best checkpoint produced during training. | |
| best_weights_path = ( | |
| Path("results") / "yolov26_obb" / experiment_name / "weights" / "best.pt" | |
| project=Path("results") / "yolov8_obb", | |
| name=experiment_name, | |
| ) | |
| # Load the best checkpoint produced during training. | |
| best_weights_path = ( | |
| Path("results") / "yolov8_obb" / experiment_name / "weights" / "best.pt" |
| @@ -0,0 +1,101 @@ | |||
| #!/usr/bin/env python3 | |||
| """Train a YOLOv26 OBB object detection model using a Roboflow dataset. | |||
There was a problem hiding this comment.
The PR description mentions updating to use "YOLOv26 OBB configuration", but YOLOv26 is not a valid YOLO version. The description should be updated to reference the actual YOLO version that will be used (e.g., YOLOv8 or YOLOv11). This discrepancy suggests the entire PR may be based on an incorrect understanding of available YOLO versions.
| # Resolve model argument for ultralytics YOLO: allow either a local .pt | ||
| # or a model name like 'yolo26n-obb' which the library may resolve. |
There was a problem hiding this comment.
The comment references 'yolo26n-obb' which is not a valid YOLO model name. This should be updated to reference a real model like 'yolov8n-obb' or 'yolov11n-obb'.
| @@ -0,0 +1,43 @@ | |||
| # Object detection training | |||
| Scripts for training an oriented object detection model using YOLOv26 on Roboflow datasets. | |||
There was a problem hiding this comment.
The documentation incorrectly references "YOLOv26" which is not a valid YOLO version. This should be updated to reference the actual YOLO version being used (e.g., YOLOv8 or YOLOv11).
| Scripts for training an oriented object detection model using YOLOv26 on Roboflow datasets. | |
| Scripts for training an oriented object detection model using YOLO on Roboflow datasets. |
| device=device_str, | ||
| workers=8, | ||
| project=Path("results") / "yolov26_obb", | ||
| name=experiment_name, | ||
| ) | ||
|
|
||
| # Load the best checkpoint produced during training. | ||
| best_weights_path = ( | ||
| Path("results") / "yolov26_obb" / experiment_name / "weights" / "best.pt" | ||
| ) | ||
| if not best_weights_path.exists(): | ||
| raise FileNotFoundError( | ||
| f"Trained model checkpoint not found at {best_weights_path}. " | ||
| "Ensure training completed successfully before validation and export." | ||
| ) | ||
|
|
||
| trained_model = YOLO(str(best_weights_path)) | ||
|
|
||
| metrics = trained_model.val(data=str(data_yaml_path)) | ||
| print("Validation metrics:", metrics) | ||
|
|
||
| # Export formats for deployment | ||
| for fmt in ["onnx"]: | ||
| trained_model.export(format=fmt, device=DEVICE) |
There was a problem hiding this comment.
There's an inconsistency in device specification. Line 74 uses device=device_str (a string like "cuda:0") for training, while line 97 uses device=DEVICE (an integer 0) for export. For consistency and following the pattern in yolo_object_detection_training/train.py:56,79, both should use the same format. The integer format (device=DEVICE) is simpler and consistent with the existing codebase.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 4 out of 4 changed files in this pull request and generated 5 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| #SBATCH --partition=GPUQ | ||
| #SBATCH --account=studiegrupper-vortex | ||
| #SBATCH --job-name=vortex-obj-detect-train | ||
| #SBATCH --time=1:00:00 |
There was a problem hiding this comment.
The SLURM job time limit is set to 1 hour, but the training script is configured to run for 200 epochs (line 71 in train.py). For most deep learning training tasks, especially with object detection models, 200 epochs typically takes significantly longer than 1 hour. This mismatch will likely cause the job to be terminated before training completes. Consider either reducing the number of epochs or increasing the time limit to a more realistic value (e.g., 8-24 hours depending on dataset size).
| onnx>=1.12.0 | ||
| onnxruntime>=1.16.0 | ||
| opencv_contrib_python==4.9.0.80 | ||
| opencv_python==4.9.0.80 |
There was a problem hiding this comment.
Both opencv_contrib_python and opencv_python are installed, which can cause conflicts since opencv_contrib_python already includes all functionality from opencv_python. Installing both packages is redundant and can lead to version conflicts or unexpected behavior. Remove opencv_python and keep only opencv_contrib_python, or use only opencv_python if the contrib modules are not needed.
| opencv_python==4.9.0.80 |
| onnxruntime>=1.16.0 | ||
| opencv_contrib_python==4.9.0.80 | ||
| opencv_python==4.9.0.80 | ||
| pafy==0.5.5 |
There was a problem hiding this comment.
The pafy library (version 0.5.5) is deprecated and no longer maintained. It was primarily used for YouTube video downloads but has known issues with recent YouTube API changes. If this dependency is not actually used in the code (no imports found in train.py), it should be removed. If it's an indirect dependency of ultralytics that's needed for video processing features, consider if those features are actually required for this training pipeline.
| pafy==0.5.5 |
| # Resolve model argument for ultralytics YOLO: allow either a local .pt | ||
| # or a model name like 'yolo26n-obb' which the library may resolve. | ||
| model_arg = MODEL_NAME | ||
| if not MODEL_NAME.endswith(".pt") and not Path(f"{MODEL_NAME}.pt").exists(): | ||
| model_arg = MODEL_NAME | ||
| elif Path(MODEL_NAME).exists() or Path(f"{MODEL_NAME}.pt").exists(): | ||
| model_arg = str( | ||
| Path(MODEL_NAME) | ||
| if Path(MODEL_NAME).suffix == ".pt" | ||
| else Path(f"{MODEL_NAME}.pt") | ||
| ) | ||
|
|
||
| model = YOLO(model_arg) | ||
|
|
There was a problem hiding this comment.
The model resolution logic is redundant and confusing. Lines 56-57 check if MODEL_NAME doesn't end with ".pt" and the file doesn't exist, then assign MODEL_NAME to model_arg (which is already done on line 55). Lines 58-63 check if the file exists and construct a path, but this is unnecessary since MODEL_NAME is already "yolo26m-obb.pt" (ends with .pt). This entire block can be simplified to just pass MODEL_NAME directly to YOLO() on line 65, as the ultralytics library will handle model resolution internally.
| # Resolve model argument for ultralytics YOLO: allow either a local .pt | |
| # or a model name like 'yolo26n-obb' which the library may resolve. | |
| model_arg = MODEL_NAME | |
| if not MODEL_NAME.endswith(".pt") and not Path(f"{MODEL_NAME}.pt").exists(): | |
| model_arg = MODEL_NAME | |
| elif Path(MODEL_NAME).exists() or Path(f"{MODEL_NAME}.pt").exists(): | |
| model_arg = str( | |
| Path(MODEL_NAME) | |
| if Path(MODEL_NAME).suffix == ".pt" | |
| else Path(f"{MODEL_NAME}.pt") | |
| ) | |
| model = YOLO(model_arg) | |
| # Initialize the YOLO model; ultralytics will handle model resolution. | |
| model = YOLO(MODEL_NAME) |
|
|
||
| # Export formats for deployment | ||
| for fmt in ["onnx"]: | ||
| trained_model.export(format=fmt, device=DEVICE) |
There was a problem hiding this comment.
The export method is being called with device=DEVICE where DEVICE is an integer (0). However, the training was done with device=device_str which is a string like "cuda:0". For consistency and to avoid potential issues, the export should use the same device format as training. Change device=DEVICE to device=device_str.
| trained_model.export(format=fmt, device=DEVICE) | |
| trained_model.export(format=fmt, device=device_str) |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| onnxruntime>=1.16.0 | ||
| opencv_contrib_python==4.9.0.80 | ||
| opencv_python==4.9.0.80 | ||
| pafy==0.5.5 |
There was a problem hiding this comment.
pafy is included as a direct dependency, but it doesn’t appear to be used anywhere in this repository. Carrying unused dependencies increases install time and the chance of supply-chain / compatibility issues; consider removing it unless there is a concrete runtime use-case for it in this training pipeline.
| pafy==0.5.5 |
| """Train a YOLOv26 OBB object detection model using a Roboflow dataset. | ||
|
|
||
| This script is written to work with YOLOv2.6 oriented-bounding-box (OBB) | ||
| model names such as `yolo26n-obb`. It downloads a Roboflow dataset, | ||
| trains a model using the `ultralytics` API and exports the trained model. |
There was a problem hiding this comment.
The module docstring uses both “YOLOv26” and “YOLOv2.6” to refer to the model/version. Please standardize on one term throughout the docstring to avoid confusion for readers and future maintainers.
| ROBOFLOW_PROJECT = "valve_obb_annotations-ejsa6" | ||
| ROBOFLOW_PROJECT_VERSION = "2" | ||
|
|
||
| # Use a pretrained YOLOv26n model to avoid training from scratch. |
There was a problem hiding this comment.
This comment says “YOLOv26n” but MODEL_NAME is set to yolo26m-obb.pt. Update the comment (or the constant) so the documented model size matches what will actually be trained.
| # Use a pretrained YOLOv26n model to avoid training from scratch. | |
| # Use a pretrained YOLOv26m model (yolo26m-obb.pt) to avoid training from scratch. |
| print("CUDA version:", torch.version.cuda) | ||
| print("cuDNN version:", torch.backends.cudnn.version()) | ||
| print("Using GPU:", torch.cuda.get_device_name(0)) |
There was a problem hiding this comment.
GPU logging is hard-coded to device index 0 (torch.cuda.get_device_name(0)) while training uses the configurable DEVICE. If DEVICE is changed, the script will print the wrong GPU and may later fail when selecting the device. Use DEVICE for the device name lookup (and consider validating DEVICE < torch.cuda.device_count() early).
| print("CUDA version:", torch.version.cuda) | |
| print("cuDNN version:", torch.backends.cudnn.version()) | |
| print("Using GPU:", torch.cuda.get_device_name(0)) | |
| # Validate that the configured DEVICE index is usable before proceeding. | |
| if not isinstance(DEVICE, int) or DEVICE < 0 or DEVICE >= torch.cuda.device_count(): | |
| raise RuntimeError( | |
| f"Configured DEVICE index {DEVICE} is invalid. " | |
| f"Available CUDA device indices are 0 to {torch.cuda.device_count() - 1}." | |
| ) | |
| print("CUDA version:", torch.version.cuda) | |
| print("cuDNN version:", torch.backends.cudnn.version()) | |
| print("Using GPU:", torch.cuda.get_device_name(DEVICE)) |
…n and segmentation
…ment setup script
…n and segmentation; update requirements and remove obsolete files
… detection; enhance job management and remove obsolete files
…ath handling in fix_data_yaml function
Updates the YOLO object detection training pipeline to use the YOLOv26 OBB configuration. The training script now initializes a YOLOv26-oriented bounding box model, downloads the corresponding Roboflow OBB dataset, trains on GPU using Ultralytics, and exports the best checkpoint for deployment.