$ python export_ov.py --batch 1
exporting image encoder to OpenVINO IR (static batch=1) ...
IR: ~/photo-dedup/dedup/models/clip-vitb32-b1.xml
input : (1,3,224,224)
output: (1,512)
L’exportation unique intègre l’encodeur PyTorch dans un OpenVINO IR par lots statiques : une construction par taille de lot, chargée par les exécutions NPU qui suivent.
$ sudo ./.venv/bin/python embed.py ./scan --backend npu
backend: NPU (compiled clip-vitb32-b1.xml, hint=LATENCY, batch=1)
preprocessing: /usr/sbin/magick (parallel, 4 workers)
prepared 373 crop(s) in 0.0s
(1/373) photo0000.png 26.1 ms -> photo0000.vitb32.npy
(2/373) photo0002.png 25.6 ms -> photo0002.vitb32.npy
(3/373) photo0020.png 24.9 ms -> photo0020.vitb32.npy
…
embedded 373 in 5.7s (65.3 img/s) (backend=npu, batch=1), 0 skipped (cached), avg power 27.3 W
Une boucle NPU naïve et synchrone améliore le débit à environ 25 millisecondes par image, mais laisse l’accélérateur inactif entre les appels de répartition. La consommation électrique diminue considérablement à 27 W
Pour libérer le véritable potentiel du silicium, j’ai restructuré le script pour utiliser l’inférence par lots et appliqué l’indice de performance THROUGHPUT d’OpenVINO. En alimentant simultanément les lots NPU de 16 images, j’ai saturé ses unités d’exécution et éliminé le goulot d’étranglement de répartition. Le temps d’inférence par photo est passé d’environ 36 ms sur le processeur à environ 13 ms sur le NPU, et le débit de bout en bout est passé d’environ 28 photos par seconde (un passage en série d’une seule image) à plus de 92, soit une victoire 3x. Mais la véritable victoire n’était pas la vitesse brute, mais l’efficacité. Le NPU parcourait silencieusement des milliers d’images en arrière-plan, ne consommant que 22 W, permettant le traitement d’une archive multimédia massive sur batterie sans déclencher les ventilateurs.
