face-recognition-rk3588-opencl/README.md

8.9 KiB

Face Recognition RK3588 OpenCL

Motore C++ per rilevamento facciale, generazione di embedding e riconoscimento kNN accelerato su Rockchip RK3588.

Il progetto usa:

  • NPU tramite RKNN per SCRFD e SFace;
  • GPU Mali-G610 tramite OpenCL per kNN;
  • CPU C++ come riferimento numerico e fallback.

Funzionalità

  • rilevamento volti con SCRFD;
  • confidence, bounding box e cinque landmark;
  • non-maximum suppression;
  • allineamento volto 112 x 112;
  • embedding SFace float32 a 128 dimensioni;
  • normalizzazione L2;
  • cosine similarity tramite prodotto scalare;
  • kNN CPU e OpenCL;
  • conteggi dinamici, TOPK configurabile e chunking;
  • leave-one-out tramite self-map;
  • JSON su stdout e diagnostica su stderr.

Architettura

Immagine
   |
   v
SCRFD tramite RKNN / NPU
   |
   v
Bounding box e landmark
   |
   v
Allineamento volto 112 x 112
   |
   v
SFace tramite RKNN / NPU
   |
   v
Embedding float32[128] normalizzato L2
   |
   +-----------------------------+
   |                             |
   v                             v
kNN CPU C++              kNN OpenCL / Mali-G610
   |                             |
   +-------------+---------------+
                 |
                 v
          TOPK prototype
                 |
                 v
      Leave-one-out opzionale
                 |
                 v
       Soglia di riconoscimento

Formato degli embedding

Dimensione: 128
Tipo: float32
Dimensione binaria: 512 byte
Ordine byte: little-endian
Normalizzazione: L2
Norma attesa: circa 1.0

Poiché gli embedding sono normalizzati:

cosine_similarity(a, b) = dot(a, b)

Componenti

Face engine RKNN

include/face_config.h
include/face_engine.h
include/rknn_api.h
src/face_engine.cc
src/face_recognition.cc
src/face_scan.cc

Motore kNN

include/knn_opencl.h
src/knn_opencl.cc
src/knn_opencl_backend.cc
src/face_knn.cc
kernels/knn_float4_topk.cl
kernels/knn_reference.cl

Il kernel produttivo viene compilato a runtime, ad esempio con:

-cl-fast-relaxed-math
-D DIM=128
-D TOPK=5
-D QUERY_COUNT=21
-D LANES_PER_QUERY=8

Requisiti

  • Linux AArch64;
  • Rockchip RK3588 o piattaforma compatibile;
  • compilatore C++17 e GNU Make;
  • runtime RKNN;
  • OpenCL ICD loader e driver Mali;
  • modelli SCRFD e SFace in formato RKNN.

Su Debian:

sudo apt-get install \
  build-essential \
  opencl-headers \
  ocl-icd-opencl-dev

Verifica OpenCL:

clinfo 2>/dev/null \
  | grep -E 'Platform Name|Device Name|Device Type|Device Version'

File locali richiesti

Non sono versionati:

models/SCRFD_500M_KPS_640.rknn
models/face_recognition_sface_2021dec.rknn
lib/librknnrt.so

Compilazione

Dalla root del repository:

make clean
make -j"$(nproc)"

Binari previsti:

bin/face_recognition
bin/face_scan
bin/face_knn

Verifica del binario OpenCL:

file bin/face_knn
ldd bin/face_knn | grep -Ei 'opencl|stdc|not found'

Utilizzo dei binari

face_recognition

Programma dimostrativo con output destinato alla lettura umana.

Analisi di una singola fotografia:

./bin/face_recognition test/test.jpg

Confronto tra due fotografie:

./bin/face_recognition \
  test/test.jpg \
  test/test3f.jpg

Usarlo per verificare modelli e runtime RKNN, detection, landmark, embedding e similarità. Non è il binario consigliato per integrazioni applicative.

face_scan

Elabora una fotografia e produce JSON con immagine, volti, confidence, bounding box, landmark ed embedding.

./bin/face_scan test/test3f.jpg

Separazione di risultato e diagnostica:

./bin/face_scan test/test3f.jpg \
  > /tmp/face-scan.json \
  2> /tmp/face-scan.stderr

Validazione:

python3 -m json.tool /tmp/face-scan.json > /dev/null \
  && echo "OK: JSON valido"

Exit code:

0  scansione completata
2  argomenti non validi
3  inizializzazione FaceEngine fallita
4  caricamento o elaborazione immagine fallita
5  risultato facciale o embedding non valido

Usarlo per integrare il face engine con Node.js, Python o altri linguaggi e per costruire query destinate a face_knn.

face_knn

Confronta embedding query con un database di prototype. Backend disponibili:

cpu
opencl

Il programma va normalmente eseguito dalla root del repository, perché il kernel viene caricato da:

kernels/knn_float4_topk.cl

Help:

./bin/face_knn --help

Backend CPU:

./bin/face_knn \
  --queries queries.bin \
  --database prototypes.bin \
  --query-count 21 \
  --database-count 5 \
  --dimension 128 \
  --top-k 5 \
  --threshold 0.50 \
  --backend cpu

Backend OpenCL:

./bin/face_knn \
  --queries queries.bin \
  --database prototypes.bin \
  --query-count 21 \
  --database-count 5 \
  --dimension 128 \
  --top-k 5 \
  --threshold 0.50 \
  --backend opencl

Argomenti:

--queries          file binario degli embedding query
--database         file binario degli embedding prototype
--query-count      numero di query
--database-count   numero di prototype
--dimension        componenti per embedding, 128 per SFace
--top-k            numero massimo di vicini
--threshold        soglia minima di riconoscimento
--self-map         esclusioni leave-one-out opzionali
--backend          cpu oppure opencl

Il TOPK effettivo è:

effective_top_k = min(top_k, database_count)

Leave-one-out

Quando una query è anche un prototype, il confronto con sé stessa va escluso. La self-map contiene una riga per query:

-1
1
3
0
4
-1

-1 indica nessuna esclusione; un valore da zero in su indica l'indice del prototype da escludere.

./bin/face_knn \
  --queries queries.bin \
  --database prototypes.bin \
  --query-count 21 \
  --database-count 5 \
  --dimension 128 \
  --top-k 5 \
  --threshold 0.50 \
  --self-map self-map.txt \
  --backend opencl

Output e diagnostica

./bin/face_knn \
  --queries queries.bin \
  --database prototypes.bin \
  --query-count 21 \
  --database-count 5 \
  --dimension 128 \
  --top-k 5 \
  --threshold 0.50 \
  --self-map self-map.txt \
  --backend opencl \
  > /tmp/face-knn.json \
  2> /tmp/face-knn.stderr
stdout → JSON valido
stderr → diagnostica OpenCL e driver Mali

Validazione:

python3 -m json.tool /tmp/face-knn.json > /dev/null \
  && echo "OK: JSON valido"

Campi principali del JSON:

backend, device_name, query_count, database_count, dimension, top_k,
threshold, leave_one_out, elapsed_ms, results, recognized_count,
below_threshold_count, coverage_percent

Per ogni query:

query_index, excluded_index, recognized, best_index, best_score, neighbors

test_knn_cpu

Sorgente:

test/knn/test_knn_cpu.cc

Esecuzione, se compilato:

./bin/test_knn_cpu

Output atteso:

OK: backend CPU dinamico
query_count=2
database_count=3
top_k=2

Scelta del backend

Usare CPU per database piccoli, riferimento numerico o fallback. Usare OpenCL per database grandi o molte query. Con cinque prototype l'overhead OpenCL può superare il costo del calcolo; con 350000 prototype e 256 query è stato misurato uno speedup di circa 7 volte.

Flusso completo

face_scan
→ estrae gli embedding
→ applicazione seleziona i prototype
→ face_knn calcola TOPK
→ applicazione associa gli indici alle identità
→ applicazione applica soglia e margine
→ applicazione salva il risultato

Prestazioni sintetiche validate

Database: 350000
Query: 256
Dimensione: 128
TOPK: 32
Chunk: 50000
GPU: Mali-G610 r0p0
CPU: 9663.226 ms
OpenCL: 1373.797 ms
Speedup: 7.034x
TOPK identico: 8192 / 8192

Variante float4 min-replace:

Kernel: 1244.576 ms
Throughput: 71.992 M vector/s
Dot rate: 18.430 GFLOP/s
Traffico effettivo: 36.860 GB/s

Validazione reale

Query: 21
Prototype: 5
Dimensione: 128
Soglia: 0.50
Leave-one-out: attivo
Riconosciuti: 20 / 21
Copertura: 95.2%
Caso sotto soglia: IMG_0183.JPG
Score: 0.466428
Miglior prototype: IMG_0143.JPG

Confronti:

Python vs C++ CPU: 21 / 21 query coerenti
CPU vs OpenCL dopo leave-one-out: 100 / 100 posizioni
CPU vs OpenCL TOPK grezzo: 105 / 105 posizioni
Errore massimo CPU/OpenCL: 3.58e-7

Dettagli:

VALIDATION_JESSICA.md
README1.md
modules/knn-opencl/reference/VALIDATION.md

Integrazione applicativa

Un'applicazione deve leggere e validare i prototype, generare i file binari e i metadati, invocare face_knn, associare gli indici alle identità, applicare soglia e margine e salvare il risultato. La prima integrazione dovrebbe funzionare in modalità shadow, confrontando il risultato corrente con OpenCL prima dell'attivazione definitiva.

Stato

Face engine RKNN: validato
Backend CPU: validato
Backend OpenCL: validato
Mali-G610: validata
TOPK dinamico: validato
Chunking: validato
Leave-one-out: validato
Output JSON puro: validato
Dataset reale: validato
Integrazione applicativa: da completare