feat/igpu-ov: OpenVINO iGPU detector (--gpu igpu) on Intel Level Zero

- ov_detector.OVFaceDetector: OV inference + ultralytics letterbox(1280 sq)
  + greedy NMS; model.predict()-compatible shim, process_video() unchanged
- anime_facesaver.py: --gpu igpu branch; CUDA path untouched (moved to else)
- CUDA path untouched; main() unchanged
- validate_ov.py: cross-check vs torch CPU baseline
  measured 2026-10-20 i3-N305: 59/59 matched, mean IoU 0.987,
  only_base=0 only_ov=0; 5.0s/img GPU vs 14.5s/img CPU OpenVINO-CPU vs
  torch-CPU baseline (25 real stills, yolov8x6_animeface)
This commit is contained in:
2026-10-20 13:49:57 -04:00
parent de177c8f59
commit 460ab5f73e
3 changed files with 206 additions and 9 deletions
+41
View File
@@ -0,0 +1,41 @@
"""Cross-validate OVFaceDetector vs ultralytics CPU baseline on real stills."""
import glob, sys, time
import numpy as np, cv2
imgs = sorted(glob.glob('/home/alex/Documents/ov-bench/imgs/*.png'))
sys.path.insert(0, '.')
from ov_detector import OVFaceDetector
# baseline: ultralytics torch CPU (deterministic on CPU)
from ultralytics import YOLO
base = YOLO('models/yolov8x6_animeface.pt')
ovd = OVFaceDetector('models/yolov8x6_animeface.onnx', device='GPU', imgsz=1280)
def iou(a, b):
xx1, yy1 = max(a[0], b[0]), max(a[1], b[1])
xx2, yy2 = min(a[2], b[2]), min(a[3], b[3])
inter = max(0, xx2-xx1) * max(0, yy2-yy1)
ua = (a[2]-a[0])*(a[3]-a[1]) + (b[2]-b[0])*(b[3]-b[1]) - inter
return inter / max(ua, 1e-9)
ious, n_match, n_only_base, n_only_ov = [], 0, 0, 0
t0=time.time()
for p in imgs:
fr = cv2.imread(p)
rb = base.predict(fr, conf=0.25, imgsz=1280, device='cpu', verbose=False)[0]
ro = ovd.predict(fr, conf=0.25, imgsz=1280, verbose=False)[0]
bb = rb.boxes.xyxy.cpu().numpy() if rb.boxes is not None else np.zeros((0,4))
bo = ro.boxes.xyxy.numpy()
used = set()
for box in bb:
best, bi = 0, -1
for j, ob in enumerate(bo):
v = iou(box, ob)
if v > best: best, bi = v, j
if best > 0.5:
ious.append(best); n_match += 1; used.add(bi)
else: n_only_base += 1
n_only_ov += len(bo) - len(used)
dt = time.time()-t0
print(f"imgs={len(imgs)} matched={n_match} (mean IoU {np.mean(ious):.3f}) only_base={n_only_base} only_ov={n_only_ov} [{dt:.0f}s total]")