From 0e31237b794816fe4a3dc4e9c603572f3e9bff02 Mon Sep 17 00:00:00 2001 From: Philipp Date: Tue, 2 Dec 2025 09:55:50 +0100 Subject: [PATCH] training fix.add global settings --- backend/0815/27/exp_infer.py | 28 +++++++++ backend/asdf/5/exp_infer.py | 25 ++++++++ .../migration_add_image_dimensions.sql | 12 ++++ .../migration_fix_image_dimensions.sql | 12 ++++ backend/routes/api.py | 7 +-- backend/services/generate_json_yolox.py | 57 +++++-------------- backend/services/generate_yolox_exp.py | 20 ++----- 7 files changed, 96 insertions(+), 65 deletions(-) create mode 100644 backend/0815/27/exp_infer.py create mode 100644 backend/asdf/5/exp_infer.py create mode 100644 backend/database/migration_add_image_dimensions.sql create mode 100644 backend/database/migration_fix_image_dimensions.sql diff --git a/backend/0815/27/exp_infer.py b/backend/0815/27/exp_infer.py new file mode 100644 index 0000000..26bd2d1 --- /dev/null +++ b/backend/0815/27/exp_infer.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python3 +# -*- coding:utf-8 -*- +# Copyright (c) Megvii, Inc. and its affiliates. + +import os + +from yolox.exp import Exp as MyExp + + +class Exp(MyExp): + def __init__(self): + super(Exp, self).__init__() + self.data_dir = "/home/kitraining/To_Annotate/" + self.train_ann = "coco_project_27_train.json" + self.val_ann = "coco_project_27_valid.json" + self.test_ann = "coco_project_27_test.json" + self.num_classes = 80 + self.pretrained_ckpt = r'/home/kitraining/Yolox/YOLOX-main/pretrained/YOLOX-s.pth' + + + self.depth = 1.0 + self.width = 1.0 + self.input_size = (640.0, 640.0) + self.mosaic_scale = (0.1, 2.0) + self.random_size = (10, 20) + self.test_size = (640.0, 640.0) + self.exp_name = os.path.split(os.path.realpath(__file__))[1].split(".")[0] + self.enable_mixup = False diff --git a/backend/asdf/5/exp_infer.py b/backend/asdf/5/exp_infer.py new file mode 100644 index 0000000..de775e4 --- /dev/null +++ b/backend/asdf/5/exp_infer.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python3 +# -*- coding:utf-8 -*- +# Copyright (c) Megvii, Inc. and its affiliates. + +import os + +from yolox.exp import Exp as MyExp + + +class Exp(MyExp): + def __init__(self): + super(Exp, self).__init__() + self.data_dir = "/home/kitraining/To_Annotate/" + self.train_ann = "coco_project_5_train.json" + self.val_ann = "coco_project_5_valid.json" + self.test_ann = "coco_project_5_test.json" + self.num_classes = 4 + self.depth = 1.0 + self.width = 1.0 + self.input_size = (640, 640) + self.mosaic_scale = (0.1, 2) + self.random_size = (10, 20) + self.test_size = (640, 640) + self.exp_name = os.path.split(os.path.realpath(__file__))[1].split(".")[0] + self.enable_mixup = False diff --git a/backend/database/migration_add_image_dimensions.sql b/backend/database/migration_add_image_dimensions.sql new file mode 100644 index 0000000..02adc8a --- /dev/null +++ b/backend/database/migration_add_image_dimensions.sql @@ -0,0 +1,12 @@ +-- Migration: Add width and height columns to image table +-- Date: 2025-11-27 + +USE myapp; + +-- Add width and height columns to image table +ALTER TABLE `image` +ADD COLUMN `width` FLOAT NULL AFTER `image_path`, +ADD COLUMN `height` FLOAT NULL AFTER `width`; + +-- Verify the changes +DESCRIBE `image`; diff --git a/backend/database/migration_fix_image_dimensions.sql b/backend/database/migration_fix_image_dimensions.sql new file mode 100644 index 0000000..95f67fb --- /dev/null +++ b/backend/database/migration_fix_image_dimensions.sql @@ -0,0 +1,12 @@ +-- Migration to change width and height from FLOAT to INT in image table +-- Run this after updating the Images model + +-- First, backup the table (optional but recommended) +-- CREATE TABLE image_backup AS SELECT * FROM image; + +-- Alter the columns to INT type +ALTER TABLE image MODIFY COLUMN width INT; +ALTER TABLE image MODIFY COLUMN height INT; + +-- Verify the changes +DESCRIBE image; diff --git a/backend/routes/api.py b/backend/routes/api.py index 07cf0f2..182ac70 100644 --- a/backend/routes/api.py +++ b/backend/routes/api.py @@ -152,12 +152,7 @@ def start_yolox_training(): cmd = f'cmd /c ""{venv_activate}" && python tools\\train.py {train_args}"' else: # Linux: Use bash with source - # If venv path doesn't end with 'activate', assume it needs bin/activate - if not yolox_venv.endswith('activate'): - venv_activate = os.path.join(yolox_venv, 'bin', 'activate') - else: - venv_activate = yolox_venv - cmd = f'bash -c "source {venv_activate} && python tools/train.py {train_args}"' + cmd = f'bash -c "source {yolox_venv} && python tools/train.py {train_args}"' print(f'Training command: {cmd}') diff --git a/backend/services/generate_json_yolox.py b/backend/services/generate_json_yolox.py index 3592b55..57cf572 100644 --- a/backend/services/generate_json_yolox.py +++ b/backend/services/generate_json_yolox.py @@ -110,60 +110,31 @@ def generate_training_json(training_id): break # Construct ABSOLUTE path using data_dir - # Detect platform for proper path handling - import platform - is_windows = platform.system() == 'Windows' + # Normalize data_dir - ensure it uses backslashes for Windows + normalized_data_dir = data_dir.rstrip('/\\').replace('/', '\\') - # Normalize path separators in file_name to forward slashes first (OS-agnostic) - file_name = file_name.replace('\\', '/') - - # Normalize data_dir to use forward slashes - normalized_data_dir = data_dir.rstrip('/\\').replace('\\', '/') - - # Check if file_name is already an absolute path - is_absolute = False - if is_windows: - # Windows: Check for drive letter (C:/) or UNC path (//server/) - is_absolute = (len(file_name) > 1 and file_name[1] == ':') or file_name.startswith('//') - else: - # Linux/Mac: Check for leading / - is_absolute = file_name.startswith('/') - - if not is_absolute: + # Check if already absolute path + if not (file_name.startswith('\\\\') or (len(file_name) > 1 and file_name[1] == ':')): # It's a relative path, combine with data_dir - if normalized_data_dir.startswith('//'): - # UNC path on Windows - file_name = normalized_data_dir + '/' + file_name + # For UNC paths, we need to manually concatenate to preserve \\ + if normalized_data_dir.startswith('\\\\'): + # UNC path + file_name = normalized_data_dir + '\\' + file_name.replace('/', '\\') else: - # Regular path - use os.path.join but with forward slashes - file_name = os.path.join(normalized_data_dir, file_name).replace('\\', '/') - - # Final OS-specific normalization - if is_windows: - # Convert to Windows-style backslashes - file_name = file_name.replace('/', '\\') + # Regular path + file_name = os.path.join(normalized_data_dir, file_name.replace('/', '\\')) else: - # Keep as forward slashes for Linux/Mac - file_name = file_name.replace('\\', '/') + # Already absolute, just normalize separators + file_name = file_name.replace('/', '\\') # Get annotations for this image annotations = Annotation.query.filter_by(image_id=image.image_id).all() - # Ensure width and height are integers and valid - # If missing or invalid, skip this image or use default dimensions - img_width = int(image.width) if image.width else 0 - img_height = int(image.height) if image.height else 0 - - # Skip images with invalid dimensions - if img_width <= 0 or img_height <= 0: - print(f'Warning: Skipping image {file_name} with invalid dimensions: {img_width}x{img_height}') - continue - coco_images.append({ 'id': image_id, 'file_name': file_name, # Use absolute path - 'width': img_width, - 'height': img_height + 'width': image.width or 0, + 'height': image.height or 0 }) for annotation in annotations: diff --git a/backend/services/generate_yolox_exp.py b/backend/services/generate_yolox_exp.py index 0f30c91..ce0bc4c 100644 --- a/backend/services/generate_yolox_exp.py +++ b/backend/services/generate_yolox_exp.py @@ -174,10 +174,9 @@ def generate_yolox_inference_exp(training_id, options=None, use_base_config=Fals 'mixup_prob': training.mixup_prob, 'hsv_prob': training.hsv_prob, 'flip_prob': training.flip_prob, - # Convert single values to tuples for YOLOX augmentation parameters - 'degrees': (training.degrees, training.degrees) if training.degrees is not None and not isinstance(training.degrees, (list, tuple)) else training.degrees, - 'translate': (training.translate, training.translate) if training.translate is not None and not isinstance(training.translate, (list, tuple)) else training.translate, - 'shear': (training.shear, training.shear) if training.shear is not None and not isinstance(training.shear, (list, tuple)) else training.shear, + 'degrees': training.degrees, + 'translate': training.translate, + 'shear': training.shear, 'mixup_scale': mixup_scale, 'activation': training.activation, } @@ -256,22 +255,11 @@ class Exp(MyExp): # Format arrays def format_value(val): if isinstance(val, (list, tuple)): - # Convert float values to int for size-related parameters - formatted_items = [] - for item in val: - # Convert to int if it's a whole number float - if isinstance(item, float) and item.is_integer(): - formatted_items.append(str(int(item))) - else: - formatted_items.append(str(item)) - return '(' + ', '.join(formatted_items) + ')' + return '(' + ', '.join(map(str, val)) + ')' elif isinstance(val, bool): return str(val) elif isinstance(val, str): return f'"{val}"' - elif isinstance(val, float) and val.is_integer(): - # Convert whole number floats to ints - return str(int(val)) else: return str(val)