# Face Recognition: dari Classifier ke Embedding Wajah yang Bisa Kenali Orang Baru

Kalau HP bisa kebuka cuma dengan lihat wajahmu, atau sistem absensi kantor langsung tahu siapa yang baru lewat pintu, jawabannya jarang sesederhana "tinggal training classifier". Tulisan ini membahas kenapa, sekaligus proses saya membangun sistem face recognition sendiri dari nol sampai jadi API yang benar-benar bisa dipanggil.

## Daftar Isi

*   Apa itu Face Recognition
    
*   Tiga Tahapan: Register, Verify, Recognize
    
*   Coba Tebak Dulu
    
*   Cara Training: dari Classifier ke Embedding
    
*   Implementasi: EfficientNet-B0, MTCNN, FastAPI, Supabase pgvector
    
*   Plot Twist: Bug yang Bikin Embedding-nya "Buta"
    
*   Hasil Terverifikasi
    
*   Keterbatasan
    
*   Quiz
    
*   Kesimpulan
    

## Apa itu Face Recognition

Face recognition adalah teknologi biometrik untuk mengidentifikasi atau memverifikasi identitas seseorang berdasarkan fitur wajahnya. Sistemnya menganalisis gambar atau video, mengekstrak fitur unik seperti jarak antar mata, bentuk hidung, dan kontur wajah, lalu membandingkannya dengan data yang sudah tersimpan sebelumnya.

Aplikasinya cukup luas. Di sisi keamanan, dipakai untuk kontrol akses dan pengawasan. Di sisi yang lebih santai, dipakai untuk unlock HP atau tag otomatis di media sosial. Deep learning adalah yang membuat akurasinya makin baik dari tahun ke tahun.

## Tiga Tahapan: Register, Verify, Recognize

Secara konsep, sistem face recognition jalan lewat tiga tahapan utama, dan ketiganya punya tujuan yang berbeda.

| Tahap | Alur | Tujuan |
| --- | --- | --- |
| Face Register | Foto → Deteksi Wajah → Cropping → Face Embedder → simpan ke Vector DB | Mendaftarkan wajah baru |
| Face Verification | Foto + klaim identitas → alur di atas → cek similarity ke satu vektor (1:1) | "Apa benar ini orang yang diklaim?" |
| Face Recognition | Foto → alur di atas → cek similarity ke semua vektor (1:N) | "Wajah siapa ini?" |

Face Verification bebannya lebih ringan karena cuma membandingkan ke satu identitas yang diklaim, jadi cocok untuk unlock device. Face Recognition lebih berat karena harus mencari di antara semua identitas terdaftar, biasa dipakai untuk pengawasan atau identifikasi massal.

## Coba Tebak Dulu

Sebelum lanjut, coba tebak dulu: kalau classifier cuma dilatih untuk mengenali 16 orang, lalu muncul wajah orang ke-17 yang belum pernah dilihat model sama sekali, apakah sistemnya masih bisa mendaftarkan dia sebagai identitas baru tanpa training ulang?

Jawabannya ada di bagian berikutnya.

## Cara Training: dari Classifier ke Embedding

Bisa, asal cara trainingnya benar. Triknya ada pada bagaimana classifier itu dipakai setelah selesai dilatih:

1.  Latih CNN sebagai classifier biasa dulu, di mana tiap kelas mewakili satu identitas orang.
    
2.  Setelah classifier-nya jadi, buang classifier head-nya (lapisan akhir yang mengeluarkan "ini si A, ini si B").
    
3.  Sisa backbone konvolusinya dipakai untuk mengekstrak fitur. Hasilnya adalah embedding, representasi numerik dari wajah.
    
4.  Dua embedding dibandingkan dengan cosine similarity, bukan lewat classifier lagi.
    

Karena perbandingannya berbasis similarity antar vektor, bukan output kelas tetap dari classifier, sistem bisa mendaftarkan wajah siapa saja kapan pun, termasuk orang yang tidak pernah ada di data training classifier awal. Inilah yang membuat pendekatan embedding jauh lebih fleksibel dibanding classifier murni untuk kasus dunia nyata, di mana daftar orang yang perlu dikenali terus bertambah.

## Implementasi: EfficientNet-B0, MTCNN, FastAPI, Supabase pgvector

Konsep di atas saya bangun jadi API yang benar-benar bisa dipanggil, bukan sekadar notebook demo.

*   **Backbone**: EfficientNet-B0 di-fine-tune sebagai classifier 16 identitas, lalu classifier head-nya dibuang dan sisanya dipakai sebagai feature extractor dengan output embedding 1280 dimensi.
    
*   **Deteksi dan alignment wajah**: MTCNN dari facenet-pytorch, mendeteksi wajah dan meluruskan orientasinya sebelum masuk ke embedder.
    
*   **Vector database**: Postgres dengan extension pgvector, di-hosting di Supabase supaya tidak perlu setup server database sendiri.
    
*   **Serving**: FastAPI dengan tiga endpoint, `/face_register/`, `/face_verification/`, dan `/face_recognition/`, di-tunnel keluar dari Google Colab lewat ngrok agar bisa diakses dari luar.
    

## Plot Twist: Bug yang Bikin Embedding-nya "Buta"

Begitu bagian training dan bagian serving disambungkan, saya iseng cek ulang cara backbone-nya dimuat. Ternyata ada bug yang cukup bikin nyesek kalau sampai kelewat.

Saat training, backbone disimpan dengan membungkusnya ulang jadi `nn.Sequential` baru. Di sisi serving, model didefinisikan lewat class custom dengan struktur atribut yang berbeda. Akibatnya, nama-nama parameter di file checkpoint tidak pernah cocok dengan nama parameter yang dicari model saat proses loading. Karena kode awalnya memakai `strict=False`, PyTorch tidak protes sama sekali. Semua parameter yang tidak cocok cuma di-skip diam-diam. Hasil akhirnya, model tetap berjalan, tapi dengan bobot acak, bukan bobot hasil training, dan tanpa satu pun error yang muncul.

Kalau ini kelewat, seluruh sistem verifikasi dan recognition tetap "jalan" secara teknis. Tidak crash, tetap mengeluarkan similarity score, tetap memberi response 200 OK. Hanya saja angkanya sama sekali tidak berarti apa-apa soal kemiripan wajah yang sesungguhnya.

Perbaikannya: muat checkpoint langsung ke submodule yang tepat, bukan ke seluruh model, lalu ganti `strict=False` menjadi `strict=True`. Dengan begitu, kalau masih ada ketidakcocokan di kemudian hari, errornya akan langsung kelihatan jelas, bukan gagal diam-diam lagi.

## Hasil Terverifikasi

**Training backbone** (EfficientNet-B0, classifier 16 identitas):

| Metrik | Nilai |
| --- | --- |
| Jumlah kelas | 16 identitas |
| Akurasi test | 95% (131 gambar held-out) |
| Dimensi embedding | 1280 |

**Tes end-to-end lewat API**, memakai foto yang tidak pernah masuk data training:

| Tes | Similarity | Hasil |
| --- | --- | --- |
| Orang sama, foto beda (verification) | 0.8664 | Terverifikasi |
| Orang sama, foto sama persis (recognition) | 1.0000 | Dikenali |
| Orang beda, belum pernah diregister (recognition) | 0.0638 | Tidak dikenali |

Jarak antara 0.0638 dan 0.8664 ini bagian yang paling penting untuk dibuktikan. Rentang yang jauh terpisah menunjukkan ruang embedding-nya benar-benar memisahkan identitas, bukan sekadar menghasilkan angka yang mirip terus-menerus siapa pun orangnya, gejala yang justru muncul kalau bug di atas tidak diperbaiki.

## Keterbatasan

*   Preprocessing training dan serving tidak identik. Training me-resize foto mentah secara langsung, sementara serving melewati deteksi dan alignment MTCNN dulu. Selama datasetnya sudah rapi dengan wajah ter-crop cukup di tengah, efeknya tidak terlalu kelihatan, tapi tetap layak dicatat.
    
*   Angka 95% berasal dari satu split train/test yang sudah diberi seed agar reproducible, bukan hasil cross-validation. Sinyalnya masuk akal, tapi bukan benchmark yang ketat.
    
*   Serving ini ditujukan untuk eksperimen lokal, bukan hosting production. Tunnel ngrok akan mati begitu runtime Colab-nya berhenti.
    
*   Belum ada rate limiting atau autentikasi di endpoint-nya.
    

## Quiz

**1\. Kenapa pendekatan embedding lebih fleksibel dibanding classifier murni untuk face recognition?** Karena identitas baru bisa didaftarkan cukup dengan menyimpan embedding barunya ke database, tanpa perlu melatih ulang classifier setiap kali ada orang baru.

**2\. Apa beda utama antara Face Verification dan Face Recognition?** Verification bersifat 1:1, mengecek similarity terhadap satu identitas yang diklaim. Recognition bersifat 1:N, mencari similarity terbaik di antara semua identitas yang terdaftar.

**3\. Kenapa** `strict=False` **pada** `load_state_dict()` **bisa berbahaya?** Karena PyTorch akan diam-diam mengabaikan parameter checkpoint yang namanya tidak cocok dengan model, tanpa melempar error. Model bisa terlihat tetap berjalan normal padahal bobot yang dimuat sebenarnya salah, bahkan bisa jadi kosong sama sekali.

## Kesimpulan

Pendekatan embedding mengubah face recognition dari sekadar "menebak salah satu dari daftar kelas tetap" menjadi sistem yang bisa terus menerima identitas baru tanpa training ulang. Tapi kemudahan itu punya jebakan tersendiri: sistemnya bisa tetap "jalan" secara teknis walau embedding yang dihasilkan sama sekali tidak berarti, kecuali dicek betul-betul sampai ke level pencocokan nama parameter.

Source code lengkap, termasuk kedua notebook dan dokumentasi hasil pengujian, ada di GitHub: [face-recognition-pgvector](https://github.com/arielshakaramiro/face-recognition-pgvector).
