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