| """
|
| E1~E5 μμν μ€ν μλ μ€ν μ€ν¬λ¦½νΈ.
|
|
|
| κ° μ€νλ³λ‘:
|
| 1. μμν μ μ© β ONNX λ΄λ³΄λ΄κΈ°
|
| 2. ultralytics valλ‘ mAP μΈ‘μ
|
| 3. κ²°κ³Ό μΆλ ₯ (EXPERIMENTS.mdμ μλμΌλ‘ κΈ°μ
)
|
|
|
| μ¬μ©λ²:
|
| python src/quant/run_experiments.py # E1~E5 μ 체
|
| python src/quant/run_experiments.py --exp E1 # νΉμ μ€νλ§
|
| """
|
|
|
| import argparse
|
| import sys
|
| from pathlib import Path
|
|
|
| ROOT = Path(__file__).parent.parent.parent
|
| sys.path.insert(0, str(ROOT))
|
|
|
| DEFAULT_WEIGHTS = ROOT / "runs" / "detect" / "edge_sign_v2_e0_full3" / "weights" / "best.pt"
|
| WEIGHTS = DEFAULT_WEIGHTS
|
| MODEL_SPACE = ROOT / "model_space"
|
| YOLO_YAML = ROOT / "data" / "yolo_signs" / "dataset.yaml"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| def val_onnx(onnx_path: Path, batch: int = 16, device: str = "cpu") -> dict:
|
| """ONNX λͺ¨λΈ νκ° β ONNX Runtimeμ CPU μ€ν (GPU DLL μμ‘΄μ± μμ)."""
|
| from ultralytics import YOLO
|
|
|
| model = YOLO(str(onnx_path))
|
| results = model.val(
|
| data=str(YOLO_YAML),
|
| imgsz=640,
|
| batch=batch,
|
| device="cpu",
|
| verbose=False,
|
| plots=False,
|
| )
|
| return {
|
| "map50": round(results.box.map50, 4),
|
| "map": round(results.box.map, 4),
|
| "precision": round(results.box.mp, 4),
|
| "recall": round(results.box.mr, 4),
|
| }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| def run_e1(device="0"):
|
| """E1: W8A8 YOLOv8s (κ²μΆκΈ°λ§)."""
|
| from src.quant.quantize_yolo import run_w8a8
|
|
|
| print("\n" + "=" * 50)
|
| print("E1: W8A8 PTQ κ²μΆκΈ°")
|
| print("=" * 50)
|
| onnx_path = run_w8a8(WEIGHTS)
|
| metrics = val_onnx(onnx_path, device=device)
|
| return "E1", onnx_path, metrics
|
|
|
|
|
| def run_e4(device="0"):
|
| """E4: W4A16 μ 체 (κ²μΆκΈ° κΈ°μ€)."""
|
| from src.quant.quantize_yolo import run_w4a16
|
|
|
| print("\n" + "=" * 50)
|
| print("E4: W4A16 PTQ κ²μΆκΈ°")
|
| print("=" * 50)
|
| onnx_path = run_w4a16(WEIGHTS)
|
| metrics = val_onnx(onnx_path, device=device)
|
| return "E4", onnx_path, metrics
|
|
|
|
|
| def run_e5(device="0", calib_batches=10):
|
| """E5: SmoothQuant μ 체 (κ²μΆκΈ° κΈ°μ€)."""
|
| from src.quant.quantize_yolo import run_smoothquant
|
|
|
| print("\n" + "=" * 50)
|
| print("E5: SmoothQuant + W8A8 κ²μΆκΈ°")
|
| print("=" * 50)
|
| onnx_path = run_smoothquant(WEIGHTS, calib_batches=calib_batches)
|
| metrics = val_onnx(onnx_path, device=device)
|
| return "E5", onnx_path, metrics
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| def print_results(results: list):
|
| print("\n" + "=" * 60)
|
| print("κ²μΆ μ€ν κ²°κ³Ό μμ½")
|
| print("=" * 60)
|
| print(f"{'ID':<6} {'mAP@0.5':<10} {'mAP@0.5:0.95':<14} {'P':<8} {'R':<8} {'ν¬κΈ°(MB)':<10}")
|
| print("-" * 60)
|
|
|
|
|
| e0_onnx = MODEL_SPACE / "yolov8s_signs_fp32.onnx"
|
| e0_size = e0_onnx.stat().st_size / 1024 / 1024 if e0_onnx.exists() else 42.67
|
| print(
|
| f"{'E0':<6} {'0.6275':<10} {'0.4371':<14} {'0.722':<8} {'0.543':<8} {e0_size:<10.2f} β FP32 κΈ°μ€μ "
|
| )
|
|
|
| for exp_id, onnx_path, m in results:
|
| size_mb = onnx_path.stat().st_size / 1024 / 1024
|
| print(
|
| f"{exp_id:<6} {m['map50']:<10} {m['map']:<14} {m['precision']:<8} {m['recall']:<8} {size_mb:<10.2f}"
|
| )
|
|
|
| print("\n[λ―Όκ°λ λΆμ]")
|
| if results:
|
| e0_map = 0.6275
|
| for exp_id, _, m in results:
|
| delta = m["map50"] - e0_map
|
| pct = delta / e0_map * 100
|
| print(f" {exp_id}: mAP50 {e0_map:.4f} β {m['map50']:.4f} ({delta:+.4f}, {pct:+.1f}%)")
|
|
|
|
|
|
|
|
|
|
|
|
|
| EXPERIMENT_MAP = {
|
| "E1": run_e1,
|
| "E4": run_e4,
|
| "E5": run_e5,
|
| }
|
|
|
|
|
| def main():
|
| parser = argparse.ArgumentParser(description="μμν μ€ν E1/E4/E5 μ€ν")
|
| parser.add_argument(
|
| "--exp", choices=list(EXPERIMENT_MAP.keys()) + ["all"], default="all", help="μ€νν μ€ν ID"
|
| )
|
| parser.add_argument("--device", type=str, default="0", help="GPU λλ°μ΄μ€")
|
| parser.add_argument(
|
| "--calib_batches", type=int, default=10, help="SmoothQuant μΊλ¦¬λΈλ μ΄μ
λ°°μΉ μ"
|
| )
|
| parser.add_argument(
|
| "--weights",
|
| type=str,
|
| default=None,
|
| help="κ²μΆκΈ° κ°μ€μΉ (.pt) β λ―Έμ§μ μ κΈ°λ³Έ v1 κ²½λ‘ μ¬μ©",
|
| )
|
| args = parser.parse_args()
|
|
|
|
|
| if args.weights:
|
| global WEIGHTS
|
| WEIGHTS = Path(args.weights)
|
| print(f"[INFO] κ°μ€μΉ override: {WEIGHTS}")
|
|
|
| targets = list(EXPERIMENT_MAP.keys()) if args.exp == "all" else [args.exp]
|
| results = []
|
|
|
| for exp_id in targets:
|
| fn = EXPERIMENT_MAP[exp_id]
|
| if exp_id == "E5":
|
| result = fn(device=args.device, calib_batches=args.calib_batches)
|
| else:
|
| result = fn(device=args.device)
|
| results.append(result)
|
|
|
| print_results(results)
|
| print("\nμ κ²°κ³Όλ₯Ό docs/EXPERIMENTS.md κ²μΆ κ²°κ³Ό νμ κΈ°μ
νμΈμ.")
|
|
|
|
|
| if __name__ == "__main__":
|
| main()
|
|
|