7.4. Carregando um modelo

ml.Model lê um arquivo de modelo da flash, faz o seu parsing, aloca a RAM que a rede precisa durante a inferência e retorna um objeto que carrega tudo o que o restante do script precisa saber sobre a rede carregada.

7.4.1. O construtor

O construtor recebe um caminho e um pós-processador opcional:

model = ml.Model("/rom/blazeface_front_128.tflite",
                 postprocess=BlazeFace())

Modelos em /rom/ (o sistema de arquivos residente na flash) são lidos diretamente no lugar: os pesos da rede permanecem na flash e o modelo carregado consome apenas a RAM correspondente ao tensor arena. Modelos em /sdcard/ são copiados para a RAM no momento do carregamento, portanto o custo total é o tamanho do arquivo do modelo mais o tensor arena. Qualquer um dos caminhos funciona; o trade-off é a RAM.

Se existir um arquivo .txt irmão com o mesmo nome base, seu conteúdo é carregado automaticamente em labels. A palavra-chave postprocess= registra um chamável que predict() executa após cada inferência.

7.4.2. Propriedades somente leitura

Um modelo carregado expõe um pequeno conjunto de propriedades somente leitura que descrevem a rede sem que ninguém precise executá-la.

Arquivo e memória.

  • len – tamanho do arquivo de modelo em disco, em bytes.

  • ram – tamanho do tensor arena que a rede precisa para suas ativações intermediárias durante a inferência, em bytes.

Tensores de entrada.

  • input_shape – uma lista de tuplas, uma por tensor de entrada, indicando o formato que a rede espera. Redes de visão têm uma entrada com formato (1, H, W, C).

  • input_dtype – lista de códigos de dtype de caractere único ('b' int8, 'B' uint8, 'h' int16, 'H' uint16, 'f' float32), um por entrada.

  • input_scale e input_zero_point – os parâmetros de quantização que convertem entre a entrada com valor real na qual a rede foi treinada e a representação inteira contra a qual a câmera executa.

Tensores de saída. Espelho do conjunto de entrada: output_shape, output_dtype, output_scale, output_zero_point. Redes de detecção produzem dois ou três tensores de saída (caixas, pontuações de confiança e, às vezes, probabilidades de classe); redes de classificação produzem um.

Extras. labels é a lista de nomes de classe carregada do arquivo .txt irmão, ou None. postprocess é o pós-processador registrado, ou None.

7.4.3. Inspecionando o BlazeFace

Carregar o modelo BlazeFace que acompanha o produto e imprimir cada propriedade fornece os números reais:

import ml
from ml.postprocessing.mediapipe import BlazeFace

model = ml.Model("/rom/blazeface_front_128.tflite",
                 postprocess=BlazeFace())

print("file size:    ", model.len, "bytes")
print("tensor arena: ", model.ram, "bytes")
print("input shape:  ", model.input_shape)
print("input dtype:  ", model.input_dtype)
print("input scale:  ", model.input_scale)
print("input zp:     ", model.input_zero_point)
print("output shape: ", model.output_shape)
print("output dtype: ", model.output_dtype)
print("output scale: ", model.output_scale)
print("output zp:    ", model.output_zero_point)

Os números identificam concretamente a interface da rede: um único tensor de entrada (1, 128, 128, 3) int8 e duas saídas int8 – uma para os coeficientes de regressão de caixas e outra para as pontuações de confiança por âncora. Os parâmetros de quantização descrevem como esses valores int8 mapeiam para os floats reais contra os quais a rede foi treinada; o pós-processador os utiliza para desfazer a quantização antes de decodificar as caixas.

Cada propriedade é a única fonte de verdade para aquilo que descreve. Os scripts leem input_shape para saber em que formato capturar, leem output_scale e output_zero_point para decodificar tensores manualmente e leem labels para nomes de classe legíveis por humanos – nunca codificados manualmente, nunca presumidos.