| import argparse |
| import time |
| import os |
| import sys |
| import numpy as np |
| from deepface import DeepFace |
|
|
| |
| sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) |
|
|
| from src.embedding import FaceEmbedder |
| from src.similarity import numpy_vectorized_cosine |
|
|
| def run_profiling(iterations=5, batch_sizes=[1, 4, 8, 16]): |
| |
| |
| sample_img = "data/lfw/test/Alex_Ferguson/Alex_Ferguson_0000.jpg" |
| if not os.path.exists(sample_img): |
| |
| import glob |
| jpgs = glob.glob("data/lfw/**/*.jpg", recursive=True) |
| if jpgs: |
| sample_img = jpgs[0] |
| else: |
| print("Error: No sample images found in data/lfw for profiling.") |
| return |
|
|
| print(f"Starting Hardware-Aware Profiling...") |
| print(f"Sample image: {sample_img}") |
| |
| embedder = FaceEmbedder(model_name="Facenet") |
| |
| |
| print("Warming up model...") |
| _ = embedder.compute_embedding(sample_img) |
| |
| |
| print(f"Measuring latency over {iterations} iterations...") |
| pre_latencies = [] |
| emb_latencies = [] |
| sim_latencies = [] |
| |
| for _ in range(iterations): |
| |
| t0 = time.perf_counter() |
| |
| faces = DeepFace.extract_faces(img_path=sample_img, detector_backend="opencv", enforce_detection=False, align=True) |
| pre_latencies.append((time.perf_counter() - t0) * 1000) |
| |
| |
| face_img = faces[0]["face"] |
| |
| |
| t0 = time.perf_counter() |
| |
| objs = DeepFace.represent(img_path=face_img, model_name=embedder.model_name, enforce_detection=False) |
| emb_latencies.append((time.perf_counter() - t0) * 1000) |
| |
| emb1 = np.array(objs[0]["embedding"], dtype=np.float32) |
| emb2 = emb1.copy() |
| |
| |
| t0 = time.perf_counter() |
| _ = numpy_vectorized_cosine(emb1.reshape(1, -1), emb2.reshape(1, -1)) |
| sim_latencies.append((time.perf_counter() - t0) * 1000) |
|
|
| mean_pre = np.mean(pre_latencies) |
| p95_pre = np.percentile(pre_latencies, 95) |
| mean_emb = np.mean(emb_latencies) |
| p95_emb = np.percentile(emb_latencies, 95) |
| mean_sim = np.mean(sim_latencies) |
| p95_sim = np.percentile(sim_latencies, 95) |
| |
| |
| print("Measuring batch-size sensitivity...") |
| batch_results = [] |
| for bs in batch_sizes: |
| |
| paths = [sample_img] * bs |
| t0 = time.perf_counter() |
| _ = embedder.batch_compute_embeddings(paths, batch_size=bs) |
| total_time = (time.perf_counter() - t0) * 1000 |
| lat_per_img = total_time / bs |
| throughput = 1000 / lat_per_img |
| batch_results.append({ |
| "batch_size": bs, |
| "total_latency_ms": total_time, |
| "latency_per_image_ms": lat_per_img, |
| "throughput_fps": throughput |
| }) |
|
|
| |
| report = [] |
| report.append("# FaceID Hardware-Aware Profiling Summary") |
| report.append(f"Date: {time.strftime('%Y-%m-%d %H:%M:%S')}") |
| report.append("\n## Latency Breakdown (ms)") |
| report.append("| Stage | Mean | p95 |") |
| report.append("| :--- | :--- | :--- |") |
| report.append(f"| Preprocessing (Detect/Align) | {mean_pre:.2f} | {p95_pre:.2f} |") |
| report.append(f"| Embedding Generation | {mean_emb:.2f} | {p95_emb:.2f} |") |
| report.append(f"| Similarity Scoring | {mean_sim:.2f} | {p95_sim:.2f} |") |
| |
| report.append("\n## Batch Sensitivity (End-to-End)") |
| report.append("| Batch Size | Total Latency (ms) | Latency/Image (ms) | Throughput (FPS) |") |
| report.append("| :--- | :--- | :--- | :--- |") |
| for r in batch_results: |
| report.append(f"| {r['batch_size']} | {r['total_latency_ms']:.2f} | {r['latency_per_image_ms']:.2f} | {r['throughput_fps']:.2f} |") |
| |
| report_str = "\n".join(report) |
| print("\n" + report_str + "\n") |
| |
| output_path = "reports/profiling_summary.txt" |
| os.makedirs("reports", exist_ok=True) |
| with open(output_path, "w") as f: |
| f.write(report_str) |
| print(f"Report saved to {output_path}") |
|
|
| if __name__ == "__main__": |
| parser = argparse.ArgumentParser(description="Hardware-aware profiling for FaceID.") |
| parser.add_argument("--iterations", type=int, default=5, help="Number of iterations for latency measurement.") |
| args = parser.parse_args() |
| |
| run_profiling(iterations=args.iterations) |
|
|