7.16. Conclusão

Este capítulo percorreu as partes do ml que uma aplicação OpenMV utiliza quando uma etapa de inferência faz parte do pipeline:

  • Conceitos – o que é uma rede neural em termos aritméticos (uma pilha de operadores treináveis que mapeia um tensor para um tensor), o que o aprendizado de máquina mudou em comparação com o processamento clássico de imagens (o algoritmo de resumo escrito por humanos desapareceu, substituído por pesos aprendidos a partir de dados rotulados) e a demonstração hello que executou um detector de rostos em algumas poucas linhas de Python.

  • O módulo ml – o objeto ml.Model e suas propriedades para inspecionar os tensores de entrada e saída, os caminhos de arquivo de modelo que ele aceita e onde esses arquivos residem: uma partição ROMFS somente leitura para execução diretamente a partir do flash, ou qualquer outro sistema de arquivos MicroPython quando o modelo pode ser copiado para a RAM no momento do carregamento.

  • O pipeline de inferência – as três etapas que predict() executa em sequência (pré-processamento, despacho ao motor, pós-processamento), o controle de Normalization na primeira etapa, o controle do pós-processador na terceira etapa e a aritmética de quantização que liga os tensores inteiros que a câmera executa de volta aos números de valor real contra os quais a rede foi treinada.

  • Motores de inferência – TFLM (o interpretador de operadores que a maioria das câmeras executa), CMSIS-NN (a biblioteca de kernels SIMD por baixo dele no Cortex-M) e as NPUs (a Ethos-U55 da Arm na AE3, em conjunto com o compilador offline Vela, e a Neural-ART da ST na N6, em conjunto com STAI e STEdgeAI). O motor é fixado pela câmera; o script não o escolhe.

  • Decodificando a saída – os pós-processadores que transformam tensores de saída brutos em caixas, pontos-chave ou listas por classe, a classe NMS que colapsa candidatos sobrepostos, o passo a passo da YOLOv8 que mostra como manter a decodificação rápida aplicando o limiar antes de dequantizar, e o protocolo para escrever um decodificador personalizado quando o catálogo não cobre um modelo.

7.16.1. O que agora está ao alcance

Três coisas para as quais o capítulo prepara:

  • Carregar um modelo treinado e executá-lo. Qualquer coisa em /rom/ funciona sem preparação adicional; qualquer coisa fornecida externamente como um .tflite compatível funciona depois que a ferramenta offline para a câmera de destino (Vela para a AE3, STEdgeAI para a N6) tiver produzido o layout correto.

  • Decodificar qualquer tensor de saída. Quando a arquitetura está no catálogo, o pós-processador correto é mecânico: YoloV8 para um modelo YOLOv8, BlazeFace para BlazeFace e assim por diante. Quando não está, o protocolo writing-your-own cobre o contrato e o passo a passo da YOLOv8 é a referência mais limpa para copiar.

  • Raciocinar sobre o desempenho. Um modelo que roda a 30 FPS em uma NPU pode rodar a 3 FPS em um Cortex-M7; a razão depende de quanto da rede a câmera consegue tirar da CPU. Quantização, posicionamento em ROMFS, compilação para NPU e a cobertura de operadores do motor de destino são as quatro alavancas, e o capítulo cobriu cada uma delas.

7.16.2. ML se combina com o resto da câmera

Uma inferência raramente é executada de forma isolada. O módulo image captura e pré-processa o quadro, o módulo ml executa a rede e ulab.numpy faz qualquer trabalho numérico para o qual nenhum dos dois tenha um recurso embutido. Um script de detecção típico combina os três: captura com csi, ajusta opcionalmente o quadro com image, executa predict(), pós-processa o resultado com o módulo correto dentre os de ml.postprocessing e recorre a ulab.numpy para qualquer cálculo personalizado que a aplicação queira sobre as caixas que o pós-processador retornou. Os três módulos compartilham o mesmo modelo de memória; as fronteiras entre eles são zero-copy sempre que possível.