bae705aa97
- Add NFC ePassport roadmap (ICAO 9303, eIDAS) - Add TensorFlow.js edge face detection (BlazeFace) - Add structured audit logger (GDPR-compliant) - Risk scoring support Part of KYC Apple Native UX v1.1.0
190 lines
5.8 KiB
Python
190 lines
5.8 KiB
Python
"""
|
|
Full Training Pipeline
|
|
Combine synthetic + quiXzoom data for production AI models
|
|
"""
|
|
|
|
import sys
|
|
sys.path.insert(0, '/home/bernt/.openclaw/workspace/iom')
|
|
|
|
from ai_pipeline.data_collection import DataCollector, SyntheticDataGenerator
|
|
from ai_pipeline.quixzoom_data_ingestion import QuixzoomDataIngestion
|
|
from ai_pipeline.training_pipeline import TrainingPipeline, TrainingConfig
|
|
|
|
import os
|
|
import shutil
|
|
|
|
|
|
def combine_datasets():
|
|
"""Combine synthetic and quiXzoom datasets"""
|
|
print("=== Combining Datasets ===\n")
|
|
|
|
# Create combined dataset
|
|
combined_path = "/tmp/iom_combined_dataset"
|
|
os.makedirs(combined_path, exist_ok=True)
|
|
|
|
# 1. Generate synthetic data
|
|
print("1. Generating synthetic data...")
|
|
synthetic_collector = DataCollector(f"{combined_path}/synthetic")
|
|
generator = SyntheticDataGenerator()
|
|
|
|
scenes = ["street_view", "building_facade", "bridge", "road", "sidewalk", "park"]
|
|
|
|
for i in range(100):
|
|
scene = scenes[i % len(scenes)]
|
|
synthetic = generator.generate_synthetic_image(scene, num_defects=3)
|
|
|
|
synthetic_collector.add_annotation(
|
|
image_id=f"syn_{i:04d}",
|
|
filename=f"syn_{i:04d}.jpg",
|
|
width=synthetic["width"],
|
|
height=synthetic["height"],
|
|
objects=synthetic["objects"],
|
|
scene_type=scene,
|
|
split="train" if i < 80 else "val" if i < 90 else "test"
|
|
)
|
|
|
|
# 2. Ingest quiXzoom data
|
|
print("2. Ingesting quiXzoom data...")
|
|
quixzoom_ingestion = QuixzoomDataIngestion(f"{combined_path}/quixzoom")
|
|
quixzoom_results = quixzoom_ingestion.run_full_pipeline()
|
|
|
|
# 3. Merge datasets
|
|
print("3. Merging datasets...")
|
|
|
|
merged_path = f"{combined_path}/merged"
|
|
os.makedirs(f"{merged_path}/images/train", exist_ok=True)
|
|
os.makedirs(f"{merged_path}/images/val", exist_ok=True)
|
|
os.makedirs(f"{merged_path}/images/test", exist_ok=True)
|
|
os.makedirs(f"{merged_path}/labels/train", exist_ok=True)
|
|
os.makedirs(f"{merged_path}/labels/val", exist_ok=True)
|
|
os.makedirs(f"{merged_path}/labels/test", exist_ok=True)
|
|
|
|
# Copy synthetic data
|
|
for split in ["train", "val", "test"]:
|
|
src_img = f"{combined_path}/synthetic/images/{split}"
|
|
src_lbl = f"{combined_path}/synthetic/labels/{split}"
|
|
dst_img = f"{merged_path}/images/{split}"
|
|
dst_lbl = f"{merged_path}/labels/{split}"
|
|
|
|
if os.path.exists(src_img):
|
|
for f in os.listdir(src_img):
|
|
shutil.copy(f"{src_img}/{f}", dst_img)
|
|
if os.path.exists(src_lbl):
|
|
for f in os.listdir(src_lbl):
|
|
shutil.copy(f"{src_lbl}/{f}", dst_lbl)
|
|
|
|
# Copy quiXzoom data
|
|
for split in ["train", "val", "test"]:
|
|
src = f"{combined_path}/quixzoom/{split}"
|
|
dst = f"{merged_path}/labels/{split}"
|
|
if os.path.exists(src):
|
|
for f in os.listdir(src):
|
|
shutil.copy(f"{src}/{f}", dst)
|
|
|
|
# Count merged data
|
|
train_count = len(os.listdir(f"{merged_path}/labels/train"))
|
|
val_count = len(os.listdir(f"{merged_path}/labels/val"))
|
|
test_count = len(os.listdir(f"{merged_path}/labels/test"))
|
|
|
|
print(f"\nMerged dataset:")
|
|
print(f" Train: {train_count}")
|
|
print(f" Val: {val_count}")
|
|
print(f" Test: {test_count}")
|
|
print(f" Total: {train_count + val_count + test_count}")
|
|
|
|
return merged_path
|
|
|
|
|
|
def train_production_model(dataset_path: str):
|
|
"""Train production-ready model"""
|
|
print("\n=== Training Production Model ===\n")
|
|
|
|
from ultralytics import YOLO
|
|
|
|
# Create data.yaml
|
|
import json
|
|
data_yaml = {
|
|
"path": dataset_path,
|
|
"train": "images/train",
|
|
"val": "images/val",
|
|
"test": "images/test",
|
|
"nc": 10,
|
|
"names": [
|
|
"street_light", "traffic_sign", "bench", "trash_can",
|
|
"sidewalk", "road", "building", "bridge", "tree", "graffiti"
|
|
]
|
|
}
|
|
|
|
with open(f"{dataset_path}/data.yaml", "w") as f:
|
|
json.dump(data_yaml, f, indent=2)
|
|
|
|
# Load model
|
|
model = YOLO("yolov8n.pt")
|
|
|
|
# Train with better settings for production
|
|
print("Training production model...")
|
|
results = model.train(
|
|
data=f"{dataset_path}/data.yaml",
|
|
epochs=50, # More epochs for production
|
|
batch=16,
|
|
imgsz=640,
|
|
device="cpu", # Change to "0" for GPU
|
|
project="/tmp/iom_production_models",
|
|
name="yolo_infrastructure_v1",
|
|
exist_ok=True,
|
|
patience=10, # Early stopping
|
|
save=True,
|
|
pretrained=True
|
|
)
|
|
|
|
print(f"Training complete!")
|
|
|
|
return model
|
|
|
|
|
|
def export_production_model(model):
|
|
"""Export model to all production formats"""
|
|
print("\n=== Exporting Production Model ===\n")
|
|
|
|
formats = ["onnx", "torchscript", "openvino", "engine"]
|
|
|
|
for fmt in formats:
|
|
try:
|
|
print(f"Exporting to {fmt}...")
|
|
model.export(format=fmt)
|
|
print(f" ✓ {fmt} export successful")
|
|
except Exception as e:
|
|
print(f" ✗ {fmt} export failed: {e}")
|
|
|
|
print("\nExport complete!")
|
|
|
|
|
|
def main():
|
|
"""Main production training pipeline"""
|
|
print("=" * 60)
|
|
print("PRODUCTION AI TRAINING PIPELINE")
|
|
print("=" * 60)
|
|
|
|
# 1. Combine datasets
|
|
dataset_path = combine_datasets()
|
|
|
|
# 2. Train model
|
|
model = train_production_model(dataset_path)
|
|
|
|
# 3. Export
|
|
export_production_model(model)
|
|
|
|
print("\n" + "=" * 60)
|
|
print("PRODUCTION TRAINING COMPLETE")
|
|
print("=" * 60)
|
|
print("\nModels saved to: /tmp/iom_production_models/")
|
|
print("\nNext steps:")
|
|
print("1. Validate model on test set")
|
|
print("2. Deploy to production API")
|
|
print("3. Monitor performance")
|
|
print("4. Collect more data and retrain")
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|