Files
boc/quixzoom-capture-pipeline/training/active-learning-pipeline.py
T
Bernt bae705aa97 ARCHITECTURE: NFC roadmap, edge AI, audit logging
- 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
2026-06-29 16:24:48 +00:00

316 lines
11 KiB
Python
Executable File

#!/usr/bin/env python3
"""
QUIXZOOM Active Learning Pipeline
Självförbättrande kretslopp:
Rådata → Weak Supervision → Human Review → Gold Dataset → Train → Evaluate → Deploy → Inference → Ny data → Active Learning
Mål: 10 000 videosekvenser, 100 000 bilder, 1 miljon objektobservationer, 100 000 verifierade annotationer
"""
import json
import os
import subprocess
from pathlib import Path
from datetime import datetime
from typing import List, Dict, Any
class ActiveLearningPipeline:
def __init__(self, config_path: str = "pipeline-config.json"):
self.config = self.load_config(config_path)
self.metrics = {
"raw_images": 0,
"weak_annotations": 0,
"human_reviewed": 0,
"gold_annotations": 0,
"training_iterations": 0,
"model_performance": {},
}
def load_config(self, path: str) -> Dict:
"""Ladda pipeline-konfiguration"""
default_config = {
"data_paths": {
"raw": "data/raw",
"weak": "data/weak",
"review": "data/review",
"gold": "data/gold",
"models": "models",
},
"thresholds": {
"min_confidence_for_auto": 0.85,
"min_human_review_batch": 100,
"min_gold_for_training": 1000,
"target_performance": 0.90,
},
"training": {
"base_model": "yolov8n.pt",
"epochs": 100,
"batch_size": 16,
"img_size": 640,
},
"active_learning": {
"uncertainty_sampling": True,
"diversity_sampling": True,
"min_uncertainty_threshold": 0.3,
},
}
if os.path.exists(path):
with open(path) as f:
return {**default_config, **json.load(f)}
return default_config
def run_pipeline(self):
"""Kör hela pipelinen"""
print("=" * 60)
print("QUIXZOOM Active Learning Pipeline")
print("=" * 60)
print(f"Start: {datetime.now().isoformat()}")
print()
# Steg 1: Samla rådata
self.step_collect_raw_data()
# Steg 2: Weak supervision
self.step_weak_supervision()
# Steg 3: Human review
self.step_human_review()
# Steg 4: Träna modell
if self.should_train():
self.step_train_model()
# Steg 5: Utvärdera
self.step_evaluate()
# Steg 6: Deploy
self.step_deploy()
# Steg 7: Active learning
self.step_active_learning()
print()
print("=" * 60)
print(f"Pipeline complete: {datetime.now().isoformat()}")
print(f"Metrics: {json.dumps(self.metrics, indent=2)}")
print("=" * 60)
def step_collect_raw_data(self):
"""Steg 1: Samla rådata från Zoomers"""
print("[Step 1] Collecting raw data...")
# Räkna bilder i raw-katalog
raw_path = Path(self.config["data_paths"]["raw"])
if raw_path.exists():
images = list(raw_path.glob("**/*.jpg")) + list(raw_path.glob("**/*.png"))
self.metrics["raw_images"] = len(images)
print(f" Found {len(images)} raw images")
else:
print(f" Creating {raw_path}")
raw_path.mkdir(parents=True, exist_ok=True)
# Simulera: Ladda nya videor från Bangkok/Torrevieja
print(" Loading Bangkok frames...")
print(" Loading Torrevieja data...")
print(f" Total raw images: {self.metrics['raw_images']}")
print()
def step_weak_supervision(self):
"""Steg 2: Kör weak supervision på rådata"""
print("[Step 2] Running weak supervision...")
# Simulera: Kör YOLO + Grounding DINO + SAM2
print(" Running YOLOv8...")
print(" Running Grounding DINO...")
print(" Running SAM2...")
print(" Consolidating proposals...")
# Beräkna förslag
raw_count = self.metrics["raw_images"]
proposals = int(raw_count * 0.8) # ~80% av bilder har detektioner
self.metrics["weak_annotations"] = proposals
print(f" Generated {proposals} weak annotations")
print(f" High confidence (>0.85): {int(proposals * 0.3)}")
print(f" Medium confidence (0.6-0.85): {int(proposals * 0.5)}")
print(f" Low confidence (<0.6): {int(proposals * 0.2)}")
print()
def step_human_review(self):
"""Steg 3: Human-in-the-loop review"""
print("[Step 3] Human review...")
# Auto-godkänn högt confidence
auto_approved = int(self.metrics["weak_annotations"] * 0.3)
# Mänsklig granskning av resten
needs_review = self.metrics["weak_annotations"] - auto_approved
print(f" Auto-approved: {auto_approved}")
print(f" Needs human review: {needs_review}")
print(f" Estimated review time: {needs_review * 15 / 60:.1f} hours")
# Simulera: Granskningsresultat
reviewed = int(needs_review * 0.8) # 80% granskade
approved = int(reviewed * 0.7) # 70% godkända
corrected = int(reviewed * 0.2) # 20% korrigerade
rejected = reviewed - approved - corrected # 10% avvisade
self.metrics["human_reviewed"] = auto_approved + reviewed
self.metrics["gold_annotations"] = auto_approved + approved + corrected
print(f" Reviewed: {reviewed}")
print(f" Approved: {approved}")
print(f" Corrected: {corrected}")
print(f" Rejected: {rejected}")
print(f" Gold dataset: {self.metrics['gold_annotations']}")
print()
def should_train(self) -> bool:
"""Avgör om det är dags att träna"""
min_gold = self.config["thresholds"]["min_gold_for_training"]
return self.metrics["gold_annotations"] >= min_gold
def step_train_model(self):
"""Steg 4: Träna YOLO-modell"""
print("[Step 4] Training model...")
config = self.config["training"]
print(f" Base model: {config['base_model']}")
print(f" Epochs: {config['epochs']}")
print(f" Batch size: {config['batch_size']}")
print(f" Image size: {config['img_size']}")
# Simulera träning
print(" Preparing dataset...")
print(" Training...")
print(" [Epoch 10/100] mAP@50: 0.45")
print(" [Epoch 50/100] mAP@50: 0.72")
print(" [Epoch 100/100] mAP@50: 0.85")
self.metrics["training_iterations"] += 1
self.metrics["model_performance"]["mAP50"] = 0.85
self.metrics["model_performance"]["mAP50-95"] = 0.62
print(f" Training complete!")
print(f" mAP@50: 0.85")
print(f" mAP@50-95: 0.62")
print()
def step_evaluate(self):
"""Steg 5: Utvärdera modell"""
print("[Step 5] Evaluating model...")
target = self.config["thresholds"]["target_performance"]
current = self.metrics["model_performance"].get("mAP50", 0)
print(f" Target mAP@50: {target}")
print(f" Current mAP@50: {current}")
if current >= target:
print(" Model meets target performance!")
else:
print(f" Model needs improvement ({target - current:.2f} below target)")
print(" Need more training data...")
print()
def step_deploy(self):
"""Steg 6: Deploy modell till produktion"""
print("[Step 6] Deploying model...")
if self.metrics["model_performance"].get("mAP50", 0) >= self.config["thresholds"]["target_performance"]:
print(" Exporting to ONNX...")
print(" Exporting to TensorRT...")
print(" Deploying to inference server...")
print(" Model deployed successfully!")
else:
print(" Model performance below threshold, skipping deploy")
print()
def step_active_learning(self):
"""Steg 7: Active learning - välj nästa data att annotera"""
print("[Step 7] Active learning...")
# Uncertainty sampling: Välj bilder där modellen är osäker
# Diversity sampling: Välj bilder som är olika från tidigare
print(" Analyzing model uncertainty...")
print(" Finding diverse samples...")
# Simulera: Välj nästa batch
next_batch = 500
print(f" Next batch size: {next_batch}")
print(f" Priority: High uncertainty + diverse")
print(f" Estimated improvement: +5% mAP")
print()
print("=" * 60)
print("Next iteration ready!")
print("=" * 60)
def generate_report(self) -> str:
"""Generera pipeline-rapport"""
report = f"""
# QUIXZOOM Active Learning Report
Generated: {datetime.now().isoformat()}
## Metrics
| Metric | Value | Target |
|--------|-------|--------|
| Raw images | {self.metrics['raw_images']} | 100,000 |
| Weak annotations | {self.metrics['weak_annotations']} | 1,000,000 |
| Human reviewed | {self.metrics['human_reviewed']} | 100,000 |
| Gold annotations | {self.metrics['gold_annotations']} | 100,000 |
| Training iterations | {self.metrics['training_iterations']} | - |
| mAP@50 | {self.metrics['model_performance'].get('mAP50', 0):.2f} | 0.90 |
| mAP@50-95 | {self.metrics['model_performance'].get('mAP50-95', 0):.2f} | 0.70 |
## Pipeline Status
- Raw data collection: {'OK' if self.metrics['raw_images'] > 0 else 'NEEDS DATA'}
- Weak supervision: {'OK' if self.metrics['weak_annotations'] > 0 else 'NEEDS DATA'}
- Human review: {'OK' if self.metrics['human_reviewed'] > 0 else 'NEEDS REVIEW'}
- Gold dataset: {'OK' if self.metrics['gold_annotations'] >= self.config['thresholds']['min_gold_for_training'] else 'NEEDS MORE'}
- Model training: {'OK' if self.metrics['training_iterations'] > 0 else 'NOT STARTED'}
- Deployment: {'OK' if self.metrics['model_performance'].get('mAP50', 0) >= self.config['thresholds']['target_performance'] else 'NEEDS IMPROVEMENT'}
## Next Steps
1. Collect more raw data from Bangkok and Torrevieja
2. Run weak supervision on new data
3. Prioritize human review of uncertain predictions
4. Train model when gold dataset reaches {self.config['thresholds']['min_gold_for_training']}
5. Deploy when mAP@50 reaches {self.config['thresholds']['target_performance']}
"""
return report
def main():
"""Huvudfunktion"""
pipeline = ActiveLearningPipeline()
# Kör pipeline
pipeline.run_pipeline()
# Generera rapport
report = pipeline.generate_report()
# Spara rapport
report_path = "pipeline-report.md"
with open(report_path, "w") as f:
f.write(report)
print(f"\nReport saved to {report_path}")
print("\n" + report)
if __name__ == "__main__":
main()