diff --git a/backend/core/migrations/0009_alter_model_base_model.py b/backend/core/migrations/0009_alter_model_base_model.py new file mode 100644 index 000000000..4a72a6724 --- /dev/null +++ b/backend/core/migrations/0009_alter_model_base_model.py @@ -0,0 +1,18 @@ +# Generated by Django 5.2.1 on 2025-08-14 11:55 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0008_prediction_result_count'), + ] + + operations = [ + migrations.AlterField( + model_name='model', + name='base_model', + field=models.CharField(choices=[('RAMP', 'RAMP'), ('YOLO_V8_V1', 'YOLO_V8_V1'), ('YOLO_V8_V2', 'YOLO_V8_V2'), ('YOLO_V11', 'YOLO_V11'), ('YOLO_V11_SAM', 'YOLO_V11_SAM')], default='RAMP', max_length=50), + ), + ] diff --git a/backend/core/models.py b/backend/core/models.py index b599f5765..6cc6a44e4 100644 --- a/backend/core/models.py +++ b/backend/core/models.py @@ -67,6 +67,8 @@ class Model(models.Model): ("RAMP", "RAMP"), ("YOLO_V8_V1", "YOLO_V8_V1"), ("YOLO_V8_V2", "YOLO_V8_V2"), + ("YOLO_V11", "YOLO_V11"), + ("YOLO_V11_SAM", "YOLO_V11_SAM"), ) class ModelStatus(models.IntegerChoices): diff --git a/backend/core/tasks.py b/backend/core/tasks.py index a5b30a1a8..31ec44dcb 100644 --- a/backend/core/tasks.py +++ b/backend/core/tasks.py @@ -127,8 +127,16 @@ def _train_yolo(self, output_path): from hot_fair_utilities.preprocessing.yolo_v8_v2.yolo_format import ( yolo_format as v2, ) + from hot_fair_utilities.preprocessing.yolo_v11.yolo_format import ( + yolo_format as v11, + ) + from hot_fair_utilities.preprocessing.yolo_v11_sam.yolo_format import ( + yolo_format as v11_sam, + ) from hot_fair_utilities.training.yolo_v8_v1.train import train as train_v1 from hot_fair_utilities.training.yolo_v8_v2.train import train as train_v2 + from hot_fair_utilities.training.yolo_v11.train import train as train_v11 + from hot_fair_utilities.training.yolo_v11_sam.train import train as train_v11_sam ( inst, @@ -161,7 +169,7 @@ def _train_yolo(self, output_path): rasterize_options=["binary"], georeference_images=True, multimasks=(multimasks or self.model_type == "YOLO_V8_V1"), - epsg=4326 if self.model_type == "YOLO_V8_V2" else 3857, + epsg=4326 if (self.model_type == "YOLO_V8_V2" or self.model_type == "YOLO_V11" or self.model_type == "YOLO_V11_sam") else 3857, input_contact_spacing=4, input_boundary_width=2, ) @@ -169,23 +177,54 @@ def _train_yolo(self, output_path): inst.chips_length = get_file_count(os.path.join(prep, "chips")) inst.save() - with print_time("YOLO format"): - if self.model_type == "YOLO_V8_V1": - v1( - preprocessed_dirs=prep, - yolo_dir=model_dir, - multimask=True, - p_val=0.05, - ) - else: - v2(input_path=prep, output_path=model_dir) - - train_fn = train_v1 if self.model_type == "YOLO_V8_V1" else train_v2 - weights = ( - "yolov8s_v1-seg-best.pt" - if self.model_type == "YOLO_V8_V1" - else "yolov8s_v2-seg.pt" - ) + match self.model_type: + case "YOLO_V8_V1": + with print_time("YOLO format"): + v1( + preprocessed_dirs=prep, + yolo_dir=model_dir, + multimask=True, + p_val=0.05, + ) + weights = "yolov8s_v1-seg-best.pt" + case "YOLO_V8_V2": + with print_time("YOLO format"): + v2(input_path=prep, output_path=model_dir) + train_fn = train_v1 + weights = "yolov8s_v2-seg.pt" + case "YOLO_V11": + with print_time("YOLO format"): + v11(input_path=prep, output_path=model_dir) + train_fn = train_v11 + weights = "yolo11n-seg.pt" + case "YOLO_V11_SAM": + with print_time("YOLO format"): + v11_sam(input_path=prep, output_path=model_dir) + train_fn = train_v11_sam + weights = "yolo11n-seg.pt" + case _: + with print_time("YOLO format"): + v2(input_path=prep, output_path=model_dir) + train_fn = train_v2 + weights = "yolov8s_v1-seg-best.pt" + + # with print_time("YOLO format"): + # if self.model_type == "YOLO_V8_V1": + # v1( + # preprocessed_dirs=prep, + # yolo_dir=model_dir, + # multimask=True, + # p_val=0.05, + # ) + # else: + # v2(input_path=prep, output_path=model_dir) + + # train_fn = train_v1 if self.model_type == "YOLO_V8_V1" else train_v2 + # weights = ( + # "yolov8s_v1-seg-best.pt" + # if self.model_type == "YOLO_V8_V1" + # else "yolov8s_v2-seg.pt" + # ) model_path, acc = train_fn( data=base, diff --git a/backend/core/views.py b/backend/core/views.py index e1cc8d951..4d905d370 100644 --- a/backend/core/views.py +++ b/backend/core/views.py @@ -197,7 +197,7 @@ def create(self, validated_data): raise ValidationError( f"Batch size can't be greater than {settings.RAMP_BATCH_SIZE_LIMIT} on this server" ) - if model.base_model in ["YOLO_V8_V1", "YOLO_V8_V2"]: + if model.base_model in ["YOLO_V8_V1", "YOLO_V8_V2", "YOLO_V11", "YOLO_V11_SAM"]: if epochs > settings.YOLO_EPOCHS_LIMIT: raise ValidationError( f"Epochs can't be greater than {settings.YOLO_EPOCHS_LIMIT} on this server" diff --git a/backend/requirements.txt b/backend/requirements.txt new file mode 100644 index 000000000..ca9dfdb71 --- /dev/null +++ b/backend/requirements.txt @@ -0,0 +1 @@ +protobuf==3.20.2 diff --git a/frontend/requirements.txt b/frontend/requirements.txt new file mode 100644 index 000000000..ca9dfdb71 --- /dev/null +++ b/frontend/requirements.txt @@ -0,0 +1 @@ +protobuf==3.20.2 diff --git a/frontend/src/app/providers/models-provider.tsx b/frontend/src/app/providers/models-provider.tsx index 213f851a4..49dce07e3 100644 --- a/frontend/src/app/providers/models-provider.tsx +++ b/frontend/src/app/providers/models-provider.tsx @@ -149,6 +149,44 @@ export const FORM_VALIDATION_CONFIG = { min: 1, }, }, + [BASE_MODELS.YOLOV11]: { + epoch: { + max: 150, + min: 20, + }, + batchSize: { + max: 16, + min: 8, + }, + // These are not used + contactSpacing: { + max: 8, + min: 1, + }, + boundaryWidth: { + max: 8, + min: 1, + }, + }, + [BASE_MODELS.YOLOV11_SAM]: { + epoch: { + max: 150, + min: 20, + }, + batchSize: { + max: 16, + min: 8, + }, + // These are not used + contactSpacing: { + max: 8, + min: 1, + }, + boundaryWidth: { + max: 8, + min: 1, + }, + }, }; type FormData = { diff --git a/frontend/src/config/index.ts b/frontend/src/config/index.ts index e7e96dec1..d1117e803 100644 --- a/frontend/src/config/index.ts +++ b/frontend/src/config/index.ts @@ -393,6 +393,8 @@ export const PREDICTION_API_FILE_EXTENSIONS: Record = { [BASE_MODELS.RAMP]: ".tflite", [BASE_MODELS.YOLOV8_V1]: ".onnx", [BASE_MODELS.YOLOV8_V2]: ".onnx", + [BASE_MODELS.YOLOV11]: ".onnx", + [BASE_MODELS.YOLOV11_SAM]: ".onnx", }; /** @@ -490,6 +492,8 @@ export const FAIR_BASE_MODELS_PATH: Record = { [BASE_MODELS.RAMP]: `${FAIR_MODELS_BASE_PATH}/basemodels/ramp/baseline.tflite`, [BASE_MODELS.YOLOV8_V1]: `${FAIR_MODELS_BASE_PATH}/basemodels/yolo/yolov8s_v1-seg.onnx`, [BASE_MODELS.YOLOV8_V2]: `${FAIR_MODELS_BASE_PATH}/basemodels/yolo/yolov8s_v2-seg.onnx`, + [BASE_MODELS.YOLOV11]: `${FAIR_MODELS_BASE_PATH}/basemodels/yolo/yolov11-seg.onnx`, + [BASE_MODELS.YOLOV11_SAM]: `${FAIR_MODELS_BASE_PATH}/basemodels/yolo/yolov11-seg.onnx`, }; export const OPENAERIALMAP_MOSAIC_TILES_URL = diff --git a/frontend/src/constants/ui-contents/models-content.ts b/frontend/src/constants/ui-contents/models-content.ts index 24c9c3cfe..64855fa94 100644 --- a/frontend/src/constants/ui-contents/models-content.ts +++ b/frontend/src/constants/ui-contents/models-content.ts @@ -40,6 +40,10 @@ export const MODELS_CONTENT: TModelsContent = { "A well-balanced model offering good accuracy for detecting structures in major areas. Trained by the community.", [BASE_MODELS.YOLOV8_V2]: "Our most advanced model. Designed for detecting various features across different areas. Developed in collaboration with Omdena AI.", + [BASE_MODELS.YOLOV11]: + "YOLO11 is the latest iteration in the Ultralytics YOLO series of real-time object detectors, redefining what's possible with cutting-edge accuracy, speed, and efficiency.", + [BASE_MODELS.YOLOV11_SAM]: + "You can pair YOLO11 with SAM2 for segmentation within detected bounding boxes, enabling precise downstream tasks", }, }, modelDescription: { @@ -266,6 +270,8 @@ export const MODELS_CONTENT: TModelsContent = { RAMP: "https://rampml.global/", YOLO_V8_V2: "https://yolov8.com/ ", YOLO_V8_V1: "https://yolov8.com/ ", + YOLO_V11: "https://yolov11.com/", + YOLO_V11_SAM: "https://blog.roboflow.com/train-yolov11-instance-segmentation/", }, }, sourceImage: { diff --git a/frontend/src/enums/common.ts b/frontend/src/enums/common.ts index bf17a630e..df7d6ecdf 100644 --- a/frontend/src/enums/common.ts +++ b/frontend/src/enums/common.ts @@ -2,6 +2,8 @@ export enum BASE_MODELS { RAMP = "RAMP", YOLOV8_V1 = "YOLO_V8_V1", YOLOV8_V2 = "YOLO_V8_V2", + YOLOV11 = "YOLO_V11", + YOLOV11_SAM = "YOLO_V11_SAM", } export enum ButtonVariant { diff --git a/frontend/src/features/model-creation/components/model-details/model-details.tsx b/frontend/src/features/model-creation/components/model-details/model-details.tsx index 01ad48599..eb4eaf8da 100644 --- a/frontend/src/features/model-creation/components/model-details/model-details.tsx +++ b/frontend/src/features/model-creation/components/model-details/model-details.tsx @@ -34,6 +34,22 @@ const baseModelOptions = [ BASE_MODELS.YOLOV8_V2 ], }, + { + name: BASE_MODELS.YOLOV11, + value: BASE_MODELS.YOLOV11, + suffix: + MODELS_CONTENT.modelCreation.modelDetails.form.baseModel.suffixes[ + BASE_MODELS.YOLOV11 + ], + }, + { + name: BASE_MODELS.YOLOV11_SAM, + value: BASE_MODELS.YOLOV11_SAM, + suffix: + MODELS_CONTENT.modelCreation.modelDetails.form.baseModel.suffixes[ + BASE_MODELS.YOLOV11_SAM + ], + }, ]; const ModelDetailsForm = () => { diff --git a/frontend/src/features/start-mapping/components/replicable-models/model-selector.tsx b/frontend/src/features/start-mapping/components/replicable-models/model-selector.tsx index c6692a974..44ac0f237 100644 --- a/frontend/src/features/start-mapping/components/replicable-models/model-selector.tsx +++ b/frontend/src/features/start-mapping/components/replicable-models/model-selector.tsx @@ -69,6 +69,22 @@ export const ModelSelector = ({ PredictionModel.YOLOV8_V2 ], }, + { + value: PredictionModel.YOLOV11, + label: "YOLO v11", + tooltip: + MODELS_CONTENT.modelCreation.modelDetails.form.baseModel.suffixes[ + PredictionModel.YOLOV11 + ], + }, + { + value: PredictionModel.YOLOV11_SAM, + label: "YOLO v11+SAM", + tooltip: + MODELS_CONTENT.modelCreation.modelDetails.form.baseModel.suffixes[ + PredictionModel.YOLOV11_SAM + ], + }, { value: PredictionModel.CUSTOM, label: "Custom", @@ -92,6 +108,10 @@ export const ModelSelector = ({ FAIR_BASE_MODELS_PATH[PredictionModel.YOLOV8_V1], [PredictionModel.YOLOV8_V2]: FAIR_BASE_MODELS_PATH[PredictionModel.YOLOV8_V2], + [PredictionModel.YOLOV11]: + FAIR_BASE_MODELS_PATH[PredictionModel.YOLOV11], + [PredictionModel.YOLOV11_SAM]: + FAIR_BASE_MODELS_PATH[PredictionModel.YOLOV11_SAM], [PredictionModel.CUSTOM]: predictionModelCheckpoint, }), [predictionModelCheckpoint, modelInfo, predictionModel], diff --git a/frontend/src/types/ui-contents.ts b/frontend/src/types/ui-contents.ts index ae8ce7011..6eb851633 100644 --- a/frontend/src/types/ui-contents.ts +++ b/frontend/src/types/ui-contents.ts @@ -230,6 +230,8 @@ export type TModelsContent = { RAMP: string; YOLO_V8_V2: string; YOLO_V8_V1: string; + YOLO_V11: string; + YOLO_V11_SAM: string; }; }; sourceImage: {