7.12. Postprocesadores

Una red de detección no emite cuadros. Emite uno o más tensores cuya disposición depende de la arquitectura contra la que se entrenó el modelo: un tensor 2-D de predicciones candidatas para un detector de la familia YOLO, un par de tensores (boxes, scores) para un detector MediaPipe, una lista plana de coordenadas de puntos clave para una red de pose. La aplicación no puede leer ninguno de estos directamente; lo que quiere – una lista de cuadros, una lista de puntos clave, un desglose por clase – tiene que ser decodificado a partir del tensor en bruto.

Ese decodificador es un postprocesador. El módulo ml.postprocessing los agrupa por ecosistema de origen.

7.12.1. Darknet

ml.postprocessing.darknet decodifica modelos de la era original de YOLO. YOLO v2 introdujo las ideas de cuadrícula y ancla que la mayoría de los detectores posteriores heredaron de alguna forma, por lo que la disposición de v2 es el punto de partida más limpio.

YOLO v2 comienza dividiendo la imagen de entrada en una cuadrícula gruesa – una disposición de 13 por 13 para la entrada canónica de 416 píxeles, más pequeña para modelos más pequeños – y entrena la red de modo que cada celda de la cuadrícula sea responsable de detectar cualquier objeto cuyo centro caiga dentro de ella. La disposición espacial del tensor de salida refleja la disposición de la entrada: una posición en la salida por cada celda en la imagen.

En cada celda de la cuadrícula, la red no predice un cuadro de la nada. Elige entre varias formas de referencia preseleccionadas llamadas anclas – pares fijos (width, height) derivados sin conexión agrupando los tamaños de los cuadros en el conjunto de entrenamiento para que cubran los objetos típicos que se espera que el modelo vea. La tarea de la red en cada celda es predecir, para cada ancla, un pequeño desplazamiento al centro del cuadro dentro de la celda, una escala sobre el ancho y alto del ancla, una puntuación de objetividad (la probabilidad de que haya algo) y un vector de probabilidad por clase. Por tanto, una cuadrícula de 13 por 13 con las 5 anclas predeterminadas y 20 clases emite 13 * 13 * 5 * (4 + 1 + 20) = 21,125 números por inferencia.

YoloV2 decodifica esa disposición: recorre las celdas, aplica los desplazamientos y escalas de cada ancla para recuperar las coordenadas absolutas del cuadro, combina la objetividad con la probabilidad de clase para obtener una puntuación por clase, aplica el umbral y envía los supervivientes a NMS. La clase toma un argumento de constructor anchors= cuando el modelo se entrenó contra una tabla de anclas personalizada y recurre a un valor predeterminado incorporado en caso contrario. Las variantes ajustadas para conjuntos de clases específicos se incluyen en el mismo submódulo.

7.12.2. Ultralytics

ml.postprocessing.ultralytics decodifica las generaciones más nuevas de YOLO. YoloV8 lee una salida orientada a columnas donde cada columna es una predicción de ancla que contiene las coordenadas del cuadro y un vector de puntuación por clase – el canal de objetividad que llevaban las salidas anteriores de YOLO se ha eliminado en v8, y las puntuaciones de clase aparecen por sí solas. El recorrido de YOLOv8 repasa la decodificación tensor por tensor. Las versiones más antiguas de la era Ultralytics se incluyen en el mismo submódulo para modelos entrenados contra sus disposiciones.

7.12.3. MediaPipe

ml.postprocessing.mediapipe decodifica la familia ligera en dispositivo de Google. BlazeFace es el detector de caras cubierto en hello-blazeface: un detector rápido basado en anclas que emite cuadros y seis coordenadas de puntos de referencia por cara, devueltos como tuplas (box, score, keypoints) con los puntos de referencia adjuntos a cada cuadro en lugar de como una lista de salida separada. Los modelos de detección de manos, de puntos de referencia y de pose de la misma familia se incluyen junto a él y siguen la misma forma de retorno con puntos clave adjuntos.

7.12.4. Elegir uno

El postprocesador correcto está determinado por la arquitectura contra la que se entrenó el modelo, no por lo que la aplicación quiere. Un .tflite de YOLOv8 solo se decodifica correctamente a través de YoloV8; un .tflite de BlazeFace solo a través de BlazeFace. Elegir el postprocesador es parte de elegir el modelo. Cuando la arquitectura de un modelo no está representada por un postprocesador incluido, escribir el tuyo propio es sencillo.

Las redes de clasificación son la excepción. Su único tensor de salida ya es lo que la aplicación quiere – una lista de puntuaciones por clase – y no se necesita ningún postprocesador. Cargar el modelo sin postprocess= y leer el resultado de predict como un ndarray plano es el camino correcto, como cubrió E/S de tensores.