Update configuration and test structure for improved clarity and functionality

- Modified `.gitignore` to include test fixture data while excluding test results.
- Updated `config.yaml` to change the model from 'yolo11m.yaml' to 'yolo26m.pt'.
- Enhanced `.cursor/rules/coderule.mdc` with additional guidelines for test environment consistency and infrastructure handling.
- Revised autopilot state management in `_docs/_autopilot_state.md` to reflect current progress and tasks.
- Removed outdated augmentation tests and adjusted dataset formation tests to align with the new structure.

These changes streamline the configuration and testing processes, ensuring better organization and clarity in the project.
This commit is contained in:
Oleksandr Bezdieniezhnykh
2026-03-28 06:11:55 +02:00
parent cdcd1f6ea7
commit a47fa135de
119 changed files with 824 additions and 774 deletions
@@ -1,12 +1,13 @@
import os
import shutil
import sys
from os import path, makedirs
import constants
import yaml
import asyncio
from rstream import Consumer, AMQPMessage, ConsumerOffsetSpecification, OffsetType, MessageContext
from rstream.amqp import amqp_decoder
from os import path, makedirs
from datetime import datetime, timedelta
import logging
from logging.handlers import TimedRotatingFileHandler
@@ -30,7 +31,6 @@ logger.addHandler(logging.StreamHandler(sys.stdout))
class AnnotationQueueHandler:
CONFIG_FILE = 'config.yaml'
OFFSET_FILE = 'offset.yaml'
QUEUE_ANNOTATION_STATUS_RECORD = b'AnnotationStatus'
QUEUE_EMAIL_RECORD = b'Email'
@@ -46,18 +46,14 @@ class AnnotationQueueHandler:
self.lbl_seed = path.join(h.data_seed_dir, h.labels_dir, f"{name}{h.TXT_EXT}")
def __init__(self):
with open(self.CONFIG_FILE, "r") as f:
config_dict = yaml.safe_load(f)
cfg = constants.config
self.data_dir = path.join(cfg.dirs.root, cfg.dirs.data)
self.data_seed_dir = path.join(cfg.dirs.root, cfg.dirs.data_seed)
self.images_dir = cfg.dirs.images
self.labels_dir = cfg.dirs.labels
root = config_dict['dirs']['root']
self.data_dir = path.join(root, config_dict['dirs']['data'])
self.data_seed_dir = path.join(root, config_dict['dirs']['data_seed'])
self.images_dir = config_dict['dirs']['images']
self.labels_dir = config_dict['dirs']['labels']
self.del_img_dir = path.join(root, config_dict['dirs']['data_deleted'], self.images_dir)
self.del_lbl_dir = path.join(root, config_dict['dirs']['data_deleted'], self.labels_dir)
self.del_img_dir = path.join(cfg.dirs.root, cfg.dirs.data_deleted, self.images_dir)
self.del_lbl_dir = path.join(cfg.dirs.root, cfg.dirs.data_deleted, self.labels_dir)
makedirs(path.join(self.data_dir, self.images_dir), exist_ok=True)
makedirs(path.join(self.data_dir, self.labels_dir), exist_ok=True)
@@ -68,12 +64,12 @@ class AnnotationQueueHandler:
makedirs(self.del_lbl_dir, exist_ok=True)
self.consumer = Consumer(
host=config_dict['queue']['host'],
port=config_dict['queue']['port'],
username=config_dict['queue']['consumer_user'],
password=config_dict['queue']['consumer_pw']
host=cfg.queue.host,
port=cfg.queue.port,
username=cfg.queue.consumer_user,
password=cfg.queue.consumer_pw
)
self.queue_name = config_dict['queue']['name']
self.queue_name = cfg.queue.name
try:
with open(self.OFFSET_FILE, 'r') as f:
-20
View File
@@ -1,20 +0,0 @@
api:
url: 'https://api.azaion.com'
email: 'uploader@azaion.com'
password: 'Az@1on_10Upl0@der'
queue:
host: '188.245.120.247'
port: 5552
consumer_user: 'azaion_receiver'
consumer_pw: 'Az1onRecce777ve2r'
name: 'azaion-annotations'
dirs:
root: '/azaion'
data: 'data-test'
data_seed: 'data-test-seed'
data_processed: 'data-test-processed'
data_deleted: 'data-test_deleted'
images: 'images'
labels: 'labels'
+35 -11
View File
@@ -3,13 +3,35 @@ from os import path
import yaml
from pydantic import BaseModel
_PROJECT_ROOT = path.dirname(path.dirname(path.abspath(__file__)))
class ApiConfig(BaseModel):
url: str = ''
email: str = ''
password: str = ''
class QueueConfig(BaseModel):
host: str = 'localhost'
port: int = 5552
consumer_user: str = ''
consumer_pw: str = ''
name: str = ''
class DirsConfig(BaseModel):
root: str = '/azaion'
data: str = 'data'
data_seed: str = 'data-seed'
data_processed: str = 'data-processed'
data_deleted: str = 'data_deleted'
images: str = 'images'
labels: str = 'labels'
class TrainingConfig(BaseModel):
model: str = 'yolo11m.yaml'
model: str = 'yolo26m.pt'
epochs: int = 120
batch: int = 11
imgsz: int = 1280
@@ -24,36 +46,38 @@ class ExportConfig(BaseModel):
class Config(BaseModel):
dirs: DirsConfig = DirsConfig()
api: ApiConfig = ApiConfig()
queue: QueueConfig = QueueConfig()
training: TrainingConfig = TrainingConfig()
export: ExportConfig = ExportConfig()
@property
def azaion(self) -> str:
def root(self) -> str:
return self.dirs.root
@property
def data_dir(self) -> str:
return path.join(self.dirs.root, 'data')
return path.join(self.dirs.root, self.dirs.data)
@property
def data_images_dir(self) -> str:
return path.join(self.data_dir, 'images')
return path.join(self.data_dir, self.dirs.images)
@property
def data_labels_dir(self) -> str:
return path.join(self.data_dir, 'labels')
return path.join(self.data_dir, self.dirs.labels)
@property
def processed_dir(self) -> str:
return path.join(self.dirs.root, 'data-processed')
return path.join(self.dirs.root, self.dirs.data_processed)
@property
def processed_images_dir(self) -> str:
return path.join(self.processed_dir, 'images')
return path.join(self.processed_dir, self.dirs.images)
@property
def processed_labels_dir(self) -> str:
return path.join(self.processed_dir, 'labels')
return path.join(self.processed_dir, self.dirs.labels)
@property
def corrupted_dir(self) -> str:
@@ -61,11 +85,11 @@ class Config(BaseModel):
@property
def corrupted_images_dir(self) -> str:
return path.join(self.corrupted_dir, 'images')
return path.join(self.corrupted_dir, self.dirs.images)
@property
def corrupted_labels_dir(self) -> str:
return path.join(self.corrupted_dir, 'labels')
return path.join(self.corrupted_dir, self.dirs.labels)
@property
def sample_dir(self) -> str:
@@ -115,4 +139,4 @@ SMALL_SIZE_KB = 3
CDN_CONFIG = 'cdn.yaml'
MODELS_FOLDER = 'models'
config: Config = Config.from_yaml(CONFIG_FILE)
config: Config = Config.from_yaml(path.join(_PROJECT_ROOT, CONFIG_FILE))
+33 -13
View File
@@ -132,13 +132,23 @@ def create_yaml():
def resume_training(last_pt_path):
model = YOLO(last_pt_path)
results = model.train(data=yaml,
resume=True,
epochs=constants.config.training.epochs,
batch=constants.config.training.batch,
imgsz=constants.config.training.imgsz,
save_period=constants.config.training.save_period,
workers=constants.config.training.workers)
results = model.train(data=yaml, # path to dataset YAML
resume=True, # continue from last checkpoint
epochs=constants.config.training.epochs, # total training epochs
batch=constants.config.training.batch, # batch size per GPU
imgsz=constants.config.training.imgsz, # input image size in pixels
save_period=constants.config.training.save_period, # save checkpoint every N epochs
workers=constants.config.training.workers, # dataloader worker threads
hsv_h=0.015, # hue shift fraction of the color wheel
hsv_s=0.7, # saturation shift fraction
hsv_v=0.4, # value (brightness) shift fraction
degrees=35.0, # max rotation degrees (+/- range)
translate=0.1, # max translation as fraction of image size
scale=0.5, # max scale gain (1 +/- scale)
shear=10.0, # max shear degrees (+/- range)
fliplr=0.6, # probability of horizontal flip
mosaic=1.0, # mosaic augmentation probability
mixup=0.0) # mixup augmentation probability (disabled)
def train_dataset():
@@ -147,12 +157,22 @@ def train_dataset():
model = YOLO(constants.config.training.model)
today_dataset = path.join(constants.config.datasets_dir, today_folder)
results = model.train(data=abspath(path.join(today_dataset, 'data.yaml')),
epochs=constants.config.training.epochs,
batch=constants.config.training.batch,
imgsz=constants.config.training.imgsz,
save_period=constants.config.training.save_period,
workers=constants.config.training.workers)
results = model.train(data=abspath(path.join(today_dataset, 'data.yaml')), # path to dataset YAML
epochs=constants.config.training.epochs, # total training epochs
batch=constants.config.training.batch, # batch size per GPU
imgsz=constants.config.training.imgsz, # input image size in pixels
save_period=constants.config.training.save_period, # save checkpoint every N epochs
workers=constants.config.training.workers, # dataloader worker threads
hsv_h=0.015, # hue shift fraction of the color wheel
hsv_s=0.7, # saturation shift fraction
hsv_v=0.4, # value (brightness) shift fraction
degrees=35.0, # max rotation degrees (+/- range)
translate=0.1, # max translation as fraction of image size
scale=0.5, # max scale gain (1 +/- scale)
shear=10.0, # max shear degrees (+/- range)
fliplr=0.6, # probability of horizontal flip
mosaic=1.0, # mosaic augmentation probability
mixup=0.0) # mixup augmentation probability (disabled)
model_dir = path.join(constants.config.models_dir, today_folder)