File size: 6,273 Bytes
76ec265 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 | """
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 # νΈνμ±μ μν΄ λͺ¨λ μ μ μ μ§ β main()μμ override
MODEL_SPACE = ROOT / "model_space"
YOLO_YAML = ROOT / "data" / "yolo_signs" / "dataset.yaml"
# ββββββββββββββββββββββββββββββββββββββββββββ
# ONNX val (ultralytics)
# ββββββββββββββββββββββββββββββββββββββββββββ
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", # ONNX Runtime GPU DLL μμΌλ―λ‘ νμ 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 κΈ°μ€μ
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}%)")
# ββββββββββββββββββββββββββββββββββββββββββββ
# CLI
# ββββββββββββββββββββββββββββββββββββββββββββ
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()
# κ°μ€μΉ μ μ override
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()
|