Download scripts/generate_report.py from Ypeng12/FaceID: direct link, hf CLI and curl.
- Browser
- Download file 3.51 kB
-
https://huggingface.co/spaces/Ypeng12/FaceID/resolve/main/scripts/generate_report.py
- Command line
-
hf download hf://spaces/Ypeng12/FaceID/scripts/generate_report.py
-
curl -L -o generate_report.py https://huggingface.co/spaces/Ypeng12/FaceID/resolve/main/scripts/generate_report.py
3.51 kB
| import json | |
| import os | |
| import matplotlib.pyplot as plt | |
| def main(): | |
| os.makedirs("reports", exist_ok=True) | |
| # Plot Baseline Val Sweep (Run 1) and Post-Change Val Sweep (Run 4) | |
| with open("outputs/eval/sweep_Run1-Baseline-Val-Sweep.json", "r") as f: | |
| run1 = json.load(f) | |
| with open("outputs/eval/sweep_Run4-PostChange-Val-Sweep.json", "r") as f: | |
| run4 = json.load(f) | |
| run1_tpr = [r['tpr'] for r in run1] | |
| run1_fpr = [r['fpr'] for r in run1] | |
| run4_tpr = [r['tpr'] for r in run4] | |
| run4_fpr = [r['fpr'] for r in run4] | |
| plt.figure(figsize=(8, 6)) | |
| plt.plot(run1_fpr, run1_tpr, label='Baseline (Run 1)') | |
| plt.plot(run4_fpr, run4_tpr, label='Post-Change Unique Pairs (Run 4)') | |
| plt.plot([0, 1], [0, 1], 'k--', label='Random') | |
| plt.xlabel('False Positive Rate') | |
| plt.ylabel('True Positive Rate') | |
| plt.title('ROC Curve: Face Verification Tradeoff') | |
| plt.legend() | |
| plt.grid(True) | |
| plt.savefig('reports/roc_curve.png') | |
| plt.close() | |
| # Write Markdown Report | |
| report_md = """# FaceID Milestone 2 Evaluation Report | |
| ## Tracking Pipeline Baseline | |
| The baseline prototype uses pre-calculated deterministic splits of LFW using fixed pair policies. A `Tracker` captures metrics to `outputs/runs.json`. Run 1 and 2 swept and established a threshold of 0.61 (Max F1 criterion) on validation. Final Run 3 found an F1 of 0.767 and accuracy of 75.2% on the test split. | |
| ## Selected Threshold Rule | |
| The threshold was strictly chosen proactively on the validation fold by iterating $t \\in [0.0, 1.0]$ to absolutely maximize the F1-Score trade-off, prior to lock-in for test sets. | |
| ## Data-Centric Improvement | |
| ### Pre-Change Issues | |
| The prior baseline randomly matched positive pairs from identities `>= 2` images. Because uniform sampling picked individuals evenly, identities with exactly 2 images had the same pair drawn redundantly. | |
| ### Post-Change | |
| We strictly filtered duplicate duplicate combinations through an `enforce_unique` flag, reducing structural correlation and testing the generalizability against more unique identity variation patterns. | |
| ## Experimental Comparison | |
| As visualized below, the post-change verification results yield ROC profiles slightly sharper on strict valid ranges. | |
|  | |
| ## Confusion Matrix (Test Split Run 5) | |
| Below is the confusion matrix for the 500 test evaluations via threshold lock (post-change): | |
| ``` | |
| TP: 195 | FP: 94 | |
| ------------------- | |
| FN: 55 | TN: 156 | |
| ``` | |
| ## Error Slicing | |
| - **Slice 1: False Positives - Unknown Visual Proximity**: Occurs frequently where two individuals wear matching thick-rimmed glasses and uniform backgrounds despite low contrast similarity. | |
| - *Hypothesis*: The MobileNet pooled embeddings overweight high-frequency accessories and generic backgrounds instead of pure facial topologies due to the absent classification top-layer task orientation. | |
| - **Slice 2: False Negatives - Extreme Pose Alignments**: True identities rendered with scores below 0.59 when one subject angle is exactly profile vs front-facing. | |
| - *Hypothesis*: Distance bounds fall sharply across high angular displacements. Future mitigation might enforce 3D facial alignment heuristics (e.g. MTCNN landmark unwinding) before pairwise similarity metrics. | |
| """ | |
| with open('reports/Milestone2_Report.md', 'w') as f: | |
| f.write(report_md) | |
| print("Report figures and MD generated at reports/") | |
| if __name__ == "__main__": | |
| main() | |