$ 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) 

A exportação única transforma o codificador PyTorch em um OpenVINO IR de lote estático – uma compilação por tamanho de lote, carregada pelas execuções de NPU a seguir.

$ 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

Um loop NPU ingênuo e síncrono melhora o rendimento para aproximadamente 25 milissegundos por imagem, mas deixa o acelerador ocioso entre as chamadas de despacho. O consumo de energia diminui significativamente para 27W

Para desbloquear o verdadeiro potencial do silício, reestruturei o script para usar inferência em lote e apliquei a dica de desempenho THROUGHPUT do OpenVINO. Ao alimentar os lotes NPU de 16 imagens simultaneamente, saturei suas unidades de execução e eliminei o gargalo de despacho. O tempo de inferência por foto caiu de aproximadamente 36 ms na CPU para cerca de 13 ms na NPU, e a taxa de transferência ponta a ponta subiu de aproximadamente 28 fotos por segundo (uma passagem serial de imagem única) para mais de 92 – uma vitória de 3x. Mas a velocidade bruta não foi a verdadeira vitória – a eficiência foi. O NPU mastigou silenciosamente milhares de imagens de fundo, consumindo apenas 22 W, permitindo o processamento de um enorme arquivo de mídia com bateria sem acionar os ventiladores.