ahmadarif019 Claude Sonnet 4.6 commited on
Commit
a5f0dad
Β·
1 Parent(s): 82d1c05

feat: backend-specific ArcFace thresholds (onnx cosine=0.50, deepface cosine=0.68)

Browse files

InsightFace does not publish official thresholds; 0.50 is the widely-cited
community best-practice (stricter than deepface's 0.68 because InsightFace
embeddings cluster more tightly). Update info tab with a threshold table
and per-backend sourcing notes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Files changed (3) hide show
  1. app.py +17 -5
  2. static/style.css +21 -0
  3. templates/index.html +30 -9
app.py CHANGED
@@ -29,17 +29,29 @@ UPLOAD_FOLDER = os.path.join(os.path.dirname(__file__), "uploads")
29
  ALLOWED_EXT = {"png", "jpg", "jpeg", "bmp", "webp"}
30
  MAX_CONTENT_LENGTH = 16 * 1024 * 1024 # 16 MB
31
 
32
- # ArcFace + cosine threshold (deepface default).
33
- ARCFACE_COSINE_THRESHOLD = 0.68
34
-
35
- # Per-metric thresholds for ArcFace (deepface defaults; None = no canonical threshold).
36
- ARCFACE_THRESHOLDS = {
37
  "cosine": 0.68,
38
  "euclidean": 4.15,
39
  "euclidean_l2": 1.13,
40
  "manhattan": None,
41
  "chebyshev": None,
42
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
43
 
44
  METRIC_LABELS = {
45
  "cosine": "Cosine",
 
29
  ALLOWED_EXT = {"png", "jpg", "jpeg", "bmp", "webp"}
30
  MAX_CONTENT_LENGTH = 16 * 1024 * 1024 # 16 MB
31
 
32
+ # Per-metric thresholds β€” deepface values are officially published by serengil/deepface.
33
+ # InsightFace does not publish thresholds; 0.50 is the widely-cited community value
34
+ # (stricter than deepface's 0.68 because InsightFace embeddings sit in a tighter cluster).
35
+ _ARCFACE_THRESHOLDS_DEEPFACE = {
 
36
  "cosine": 0.68,
37
  "euclidean": 4.15,
38
  "euclidean_l2": 1.13,
39
  "manhattan": None,
40
  "chebyshev": None,
41
  }
42
+ _ARCFACE_THRESHOLDS_ONNX = {
43
+ "cosine": 0.50, # InsightFace community best-practice
44
+ "euclidean": None,
45
+ "euclidean_l2": None,
46
+ "manhattan": None,
47
+ "chebyshev": None,
48
+ }
49
+
50
+ ARCFACE_THRESHOLDS = (
51
+ _ARCFACE_THRESHOLDS_DEEPFACE if FACE_BACKEND == "deepface"
52
+ else _ARCFACE_THRESHOLDS_ONNX
53
+ )
54
+ ARCFACE_COSINE_THRESHOLD = ARCFACE_THRESHOLDS["cosine"]
55
 
56
  METRIC_LABELS = {
57
  "cosine": "Cosine",
static/style.css CHANGED
@@ -835,6 +835,27 @@ body {
835
  opacity: 0.7;
836
  }
837
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
838
  /* ---------- Hi-tech Loader ---------- */
839
  .loader {
840
  display: flex; flex-direction: column;
 
835
  opacity: 0.7;
836
  }
837
 
838
+ /* ---------- Threshold table ---------- */
839
+ .threshold-table {
840
+ width: 100%;
841
+ border-collapse: collapse;
842
+ font-size: 0.83rem;
843
+ margin: 10px 0 12px;
844
+ }
845
+ .threshold-table th, .threshold-table td {
846
+ padding: 6px 12px;
847
+ border: 1px solid var(--border);
848
+ text-align: left;
849
+ }
850
+ .threshold-table thead th {
851
+ background: rgba(56, 189, 248, 0.08);
852
+ color: var(--accent);
853
+ font-family: 'JetBrains Mono', monospace;
854
+ font-weight: 600;
855
+ }
856
+ .threshold-table tbody tr:hover { background: rgba(255,255,255,0.03); }
857
+ .threshold-table code { font-size: 0.78rem; }
858
+
859
  /* ---------- Hi-tech Loader ---------- */
860
  .loader {
861
  display: flex; flex-direction: column;
templates/index.html CHANGED
@@ -319,7 +319,7 @@
319
 
320
  <p><b>Kenapa 512 angka?</b> Itu pilihan arsitektur ArcFace. Lebih sedikit dimensi β†’ kurang ekspresif, susah membedakan jutaan orang. Lebih banyak β†’ mahal komputasi tanpa banyak peningkatan akurasi. 512 dianggap sweet spot oleh para peneliti.</p>
321
 
322
- <p><b>Bagaimana cara membandingkan?</b> Kita ambil dua embedding (vektor 512 angka), lalu hitung <i>jarak</i>-nya pakai rumus seperti Cosine atau Euclidean. Kalau jaraknya kecil β†’ wajah mirip. Kalau jaraknya besar β†’ wajah beda. Threshold-nya sudah dikalibrasi DeepFace (lihat di bawah).</p>
323
 
324
  <h4>Rumus tiap algoritma</h4>
325
  <p>Untuk dua vektor embedding ArcFace 512-dimensi <code>a</code> dan <code>b</code>:</p>
@@ -382,16 +382,36 @@
382
  <p>ArcFace dilatih dengan <i>angular margin loss</i> β€” identitas wajah tersimpan di <b>arah</b> vektor, bukan panjangnya. Jadi Euclidean L2 biasanya lebih stabil untuk verifikasi wajah dibanding Euclidean biasa.</p>
383
  <p>Secara matematis, Euclidean L2 dan Cosine sebenarnya membawa informasi yang sama (sudut antar vektor), dengan hubungan:</p>
384
  <div class="formula-eq">Euclidean_L2Β² = 2 Γ— Cosine_distance</div>
385
- <p>Itu sebabnya threshold-nya konsisten: Cosine <code>0.68</code> ↔ Euclidean L2 <code>√(2 Γ— 0.68) β‰ˆ 1.166</code>, dibulatkan jadi <code>1.13</code> βœ“</p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
386
 
387
  <h4>Kenapa threshold tiap algoritma berbeda?</h4>
388
- <p>Karena tiap rumus menghasilkan skala angka yang berbeda β€” distance Manhattan untuk pasangan wajah yang sama bisa puluhan, sedangkan Chebyshev cuma di angka satuan. Threshold <code>0.68 / 4.15 / 1.13</code> bukan dipilih sembarang β€” itu nilai kalibrasi resmi DeepFace, hasil pengujian ArcFace pada dataset wajah berlabel (LFW dll) untuk cari batas optimal "orang sama" vs "orang beda" per metrik.</p>
389
 
390
  <h4>Kenapa Manhattan &amp; Chebyshev cuma "INFO"?</h4>
391
- <p>DeepFace tidak menyediakan threshold resmi untuk dua metrik ini pada ArcFace, jadi tidak ada angka kalibrasi yang valid untuk memutuskan MATCH / NO MATCH. Keduanya tetap dihitung sebagai info tambahan untuk perbandingan, tapi tidak dipakai untuk verdict.</p>
392
 
393
  <h4>Metrik mana yang paling utama?</h4>
394
- <p><b>Cosine</b>. Itu metrik default DeepFace untuk verifikasi ArcFace, dan paling stabil untuk embedding-nya. Verdict utama (MATCH / NO MATCH) di aplikasi ini selalu memakai cosine.</p>
395
 
396
  <h4>Sumber &amp; Referensi</h4>
397
  <p class="ref-group-label">Paper Model</p>
@@ -430,15 +450,16 @@
430
  </li>
431
  </ul>
432
 
433
- <p class="ref-group-label">Threshold resmi DeepFace</p>
434
  <ul class="ref-list">
435
  <li>
436
- Nilai threshold per model &amp; metrik di-hardcode di file config (ArcFace ada di baris 5 β€” <code>cosine: 0.68</code>, <code>euclidean: 4.15</code>, <code>euclidean_l2: 1.13</code>):
437
  <a href="https://github.com/serengil/deepface/blob/master/deepface/config/threshold.py#L5" target="_blank" rel="noopener">deepface/config/threshold.py</a>
 
438
  </li>
439
  <li>
440
- Lookup-nya lewat fungsi <code>find_threshold(model_name, distance_metric)</code> yang load dict di atas:
441
- <a href="https://github.com/serengil/deepface/blob/master/deepface/modules/verification.py#L477" target="_blank" rel="noopener">deepface/modules/verification.py</a>
442
  </li>
443
  </ul>
444
 
 
319
 
320
  <p><b>Kenapa 512 angka?</b> Itu pilihan arsitektur ArcFace. Lebih sedikit dimensi β†’ kurang ekspresif, susah membedakan jutaan orang. Lebih banyak β†’ mahal komputasi tanpa banyak peningkatan akurasi. 512 dianggap sweet spot oleh para peneliti.</p>
321
 
322
+ <p><b>Bagaimana cara membandingkan?</b> Kita ambil dua embedding (vektor 512 angka), lalu hitung <i>jarak</i>-nya pakai rumus seperti Cosine atau Euclidean. Kalau jaraknya kecil β†’ wajah mirip. Kalau jaraknya besar β†’ wajah beda. Threshold-nya dikalibrasi per backend β€” lihat bagian <i>"Threshold per backend"</i> di bawah.</p>
323
 
324
  <h4>Rumus tiap algoritma</h4>
325
  <p>Untuk dua vektor embedding ArcFace 512-dimensi <code>a</code> dan <code>b</code>:</p>
 
382
  <p>ArcFace dilatih dengan <i>angular margin loss</i> β€” identitas wajah tersimpan di <b>arah</b> vektor, bukan panjangnya. Jadi Euclidean L2 biasanya lebih stabil untuk verifikasi wajah dibanding Euclidean biasa.</p>
383
  <p>Secara matematis, Euclidean L2 dan Cosine sebenarnya membawa informasi yang sama (sudut antar vektor), dengan hubungan:</p>
384
  <div class="formula-eq">Euclidean_L2Β² = 2 Γ— Cosine_distance</div>
385
+ <p>Itu sebabnya threshold DeepFace konsisten: Cosine <code>0.68</code> ↔ Euclidean L2 <code>√(2 Γ— 0.68) β‰ˆ 1.166</code>, dibulatkan jadi <code>1.13</code> βœ“</p>
386
+
387
+ <h4>Threshold per backend</h4>
388
+ <p>Kedua backend menghasilkan ArcFace embedding 512-dim yang strukturnya sama, tapi threshold verifikasi-nya <b>berbeda</b> karena sumber kalibrasiya beda:</p>
389
+ <table class="threshold-table">
390
+ <thead>
391
+ <tr><th>Metrik</th><th>Backend <code>onnx</code> (InsightFace)</th><th>Backend <code>deepface</code></th></tr>
392
+ </thead>
393
+ <tbody>
394
+ <tr><td><b>Cosine</b></td><td>0.50</td><td>0.68</td></tr>
395
+ <tr><td>Euclidean</td><td>β€”</td><td>4.15</td></tr>
396
+ <tr><td>Euclidean L2</td><td>β€”</td><td>1.13</td></tr>
397
+ <tr><td>Manhattan</td><td>β€”</td><td>β€”</td></tr>
398
+ <tr><td>Chebyshev</td><td>β€”</td><td>β€”</td></tr>
399
+ </tbody>
400
+ </table>
401
+ <ul>
402
+ <li><b>Backend <code>deepface</code></b> β€” threshold dipublikasikan resmi oleh serengil/deepface (<code>deepface/config/threshold.py</code>), hasil kalibrasi di dataset LFW. <code>cosine 0.68</code> adalah nilai default untuk ArcFace.</li>
403
+ <li><b>Backend <code>onnx</code></b> β€” InsightFace tidak mempublikasikan threshold resmi. Nilai <code>cosine 0.50</code> adalah best-practice komunitas yang banyak dipakai (lebih strict dari deepface karena embedding InsightFace cenderung ter-cluster lebih ketat). Metrik lain tidak ada nilai kalibrasi yang teruji, sehingga ditampilkan sebagai info saja.</li>
404
+ </ul>
405
+ <p>Perbedaan threshold ini penting: dengan backend <code>deepface</code> cosine 0.65 dianggap MATCH, tapi dengan backend <code>onnx</code> (threshold 0.50) itu NO MATCH. Selalu perhatikan backend aktif saat menginterpretasi hasil.</p>
406
 
407
  <h4>Kenapa threshold tiap algoritma berbeda?</h4>
408
+ <p>Karena tiap rumus menghasilkan skala angka yang berbeda β€” distance Manhattan untuk pasangan wajah yang sama bisa puluhan, sedangkan Chebyshev cuma di angka satuan. Threshold bukan dipilih sembarang β€” itu nilai kalibrasi hasil pengujian ArcFace pada dataset wajah berlabel (LFW dll) untuk cari batas optimal "orang sama" vs "orang beda" per metrik.</p>
409
 
410
  <h4>Kenapa Manhattan &amp; Chebyshev cuma "INFO"?</h4>
411
+ <p>Tidak ada threshold resmi (dari DeepFace maupun InsightFace) untuk dua metrik ini pada ArcFace, jadi tidak ada angka kalibrasi yang valid untuk memutuskan MATCH / NO MATCH. Keduanya tetap dihitung sebagai info tambahan, tapi tidak dipakai untuk verdict.</p>
412
 
413
  <h4>Metrik mana yang paling utama?</h4>
414
+ <p><b>Cosine</b>. Itu metrik yang paling stabil untuk embedding ArcFace (tidak sensitif magnitudo vektor). Verdict utama (MATCH / NO MATCH) di aplikasi ini selalu memakai cosine dengan threshold sesuai backend aktif.</p>
415
 
416
  <h4>Sumber &amp; Referensi</h4>
417
  <p class="ref-group-label">Paper Model</p>
 
450
  </li>
451
  </ul>
452
 
453
+ <p class="ref-group-label">Threshold β€” sumber per backend</p>
454
  <ul class="ref-list">
455
  <li>
456
+ <b>Backend <code>deepface</code></b> β€” threshold ArcFace di-hardcode di file config (<code>cosine: 0.68</code>, <code>euclidean: 4.15</code>, <code>euclidean_l2: 1.13</code>):
457
  <a href="https://github.com/serengil/deepface/blob/master/deepface/config/threshold.py#L5" target="_blank" rel="noopener">deepface/config/threshold.py</a>
458
+ Β· lookup via <a href="https://github.com/serengil/deepface/blob/master/deepface/modules/verification.py#L477" target="_blank" rel="noopener">deepface/modules/verification.py</a>
459
  </li>
460
  <li>
461
+ <b>Backend <code>onnx</code></b> β€” InsightFace tidak mempublikasikan threshold. Nilai <code>cosine: 0.50</code> adalah best-practice komunitas yang banyak dipakai; lihat diskusi di:
462
+ <a href="https://github.com/deepinsight/insightface/issues/1071" target="_blank" rel="noopener">deepinsight/insightface #1071</a>
463
  </li>
464
  </ul>
465