Introducción
Tulip Vision es una solución de visión por ordenador sin código paraoperaciones en el taller. Permite crear Tulip Apps que utiliza la visión por ordenador para dirigir y supervisar las operaciones. Tulip La visión puede utilizarse para detectar la actividad en el puesto de trabajo, rastrear objetos y personas. Las señales de visión pueden construirse para supervisar la seguridad, las operaciones de montaje manual, el kitting y el picking, y muchas otras aplicaciones que aumentan la fiabilidad y reducen los errores. En el centro de Vision for the shop-floor se encuentran los algoritmos de visión por ordenador basados en redes neuronales profundas. Los algoritmos están diseñados para ejecutarse en el hardware existente en los talleres, que a menudo es un modesto PC que ejecuta Windows. Para llevar lo último en IA a los ordenadores poco potentes de los talleres, utilizamos el Intel Neural Compute Stick versión 2 (NCS v2), también conocido como Unidad de Procesamiento de Visión (VPU) de Movidius. Se trata de un dispositivo USB con hardware de computación diseñado para ejecutar redes neuronales profundas, que quita el trabajo aritmético a la CPU o GPU del PC. La NCS es una solución de bajo coste y bajo consumo para la IA en el borde, que además es plug-and-play.
¿Por qué es necesaria la optimización?
El Intel NCS nos pareció un procesador muy capaz para nuestras necesidades en Tulip Vision. Nos centramos en la detección de humanos y sus operaciones en la línea, por lo que poder detectar manos y personas en un flujo de cámara entrante es importante. Los últimos modelos de detección humana emplean redes neuronales profundas y modelos pesados, que suponen un reto para el NCS en términos de rendimiento.
Con la ejecución en vainilla de un modelo de detección de manos pudimos alcanzar una velocidad de 14 fotogramas por segundo (FPS) para la inferencia. Se requiere cierta optimización para que podamos alcanzar nuestros objetivos de detección de operaciones humanas en tiempo real (coloquialmente considerado a partir de 30 FPS, la velocidad de ejecución habitual de la mayoría de las cámaras). También queríamos sacar el máximo partido del hardware NCS, cuyo coste se paga por adelantado. Las especificaciones del NCS especifican una tasa de procesamiento teórica de 100 GFLOP/s (giga operaciones en coma flotante por segundo), mientras que inicialmente pudimos sacar apenas 20-25 GFLOP/s (con una red de 1,5 GFLOP a 14 FPS) con una latencia considerable.
En este artículo analizamos las técnicas de optimización que exploramos, y la que realmente marcó la diferencia para nosotros y nos situó bien en el rango de la inferencia en tiempo real. Intel ya proporcionó una guía útil sobre la optimización de redes para la NCSv2, que utilizamos en nuestro trabajo.
Convertir un modelo para ejecutarlo en el NCS
Para empezar, obtuvimos el grafo y los pesos para una red de detección de manos. Entrenamos nuestros propios modelos para la detección de manos, ajustados para su rendimiento en escenas de taller, pero hay modelos disponibles gratuitamente en línea que funcionan sorprendentemente bien. He aquí un modelo de ejemplo en GitHub que utilizamos para las pruebas y las comparaciones de referencia. Con un modelo preentrenado, uno puede querer afinarlo para su propósito y sus datos. Utilizamos un conjunto de herramientas de TensorFlow de Google para probar el ajuste fino y las técnicas de aprendizaje por transferencia.
Para que un modelo determinado pueda funcionar en el NCS debe convertirse al formato adecuado. Intel NCS utiliza OpenVINO para desarrollar para el NCS. Se trata de un conjunto de herramientas muy completo que permite ejecutar modelos en entornos heterogéneos (por ejemplo, CPU, GPU, VPU), convertir desde muchas arquitecturas de origen como TensorFlow, ONYX, PyTorch, etc. y optimizar los modelos de diversas formas.
Para convertir un modelo, primero debe estar en un estado de grafo congelado. Eso significa que sólo se conservan las partes de la red neuronal necesarias para la inferencia, mientras que todo lo demás se descarta, así como asegurarse de que todos los pesos del grafo están finalizados. Hay varios datos que acompañan a los gráficos de ejecución de la red neuronal que tienen que ver con su entrenamiento, que no son necesarios para la inferencia y que, de hecho, pueden causar problemas en la conversión. Para llevar nuestro modelo de ejemplo de detección de manos a un estado de grafo congelado utilizamos el siguiente script:
python3 /content/models/research/object_detection/export_inference_graph.py \ --input_type=tensor_de_imagen \ --pipeline_config_path=ruta/a/pipeline.config \ --output_directory=ruta/a/directorio_salida \ --trained_checkpoint_prefix=/ruta/a/modelo.ckpt-xyz # Sustituya xyz por el valor del paso del punto de control.
Figura 1. Script de exportación del gráfico de inferencia para modelos entrenados con la API de detección de objetos de Tensorflow
Para la conversión utilizamos el DL (Deep Learning) Workbench, de OpenVINO. Se instala fácilmente en cualquier sistema operativo importante y funciona como una aplicación gráfica (GUI) independiente, o manejable desde la línea de comandos. Aquí nos centraremos en utilizar la GUI para visualizar nuestras operaciones. OpenVINO proporciona una magnífica guía de "introducción" al banco de trabajo DL. En el banco de trabajo DL cargamos el modelo y especificamos las formas del tensor de entrada y de salida.
Figura 2. Intel Configuración del modelo de Deep Learning Workbench
El banco de trabajo también dispone de herramientas muy útiles para la evaluación comparativa de la ejecución y el rendimiento del modelo, así como de pruebas para asegurarse de que el modelo es operable en el NCS en términos de capas NN implementadas.
Figura 3. Comparación del modelo con datos de prueba (no anotados) utilizando la CPU Intel i7-8700T
Por último, el banco de trabajo facilita enormemente la conversión del modelo al formato requerido por el NCS:
Figura 4. Descarga del modelo OpenVINO convertido
Optimización del modelo para una inferencia rápida
Para empezar, utilizamos el código de ejemplo de OpenVINO para la detección de objetos. Utiliza una API sincrónica simple que realiza una solicitud de inferencia (IR) para el NCS y espera (bloquea el hilo) a que se complete, suponiendo que la ejecución del modelo simplemente tarda un tiempo en terminar. Esto nos dio nuestro decepcionante punto de rendimiento original de unos 14 FPS. Haciendo números, nos dimos cuenta de que esto es un rendimiento muy por debajo de lo que el NCS es capaz de hacer.
Teorizamos que el modelo es demasiado grande y que ésa es la razón del bajo rendimiento. Así que primero probamos a reducir el tamaño de la imagen de entrada al modelo. La teoría en marcha era que las grandes capas convolucionales iniciales en tamaños de entrada grandes antes de la agrupación soportan gran parte del peso computacional. Cambiamos la forma de entrada a 64x64 y 128x128, por debajo de los 224x224 originales. Pero esto también redujo la precisión en un gran margen, algo que no podemos aceptar.
Figura 5. Gráfico de barras que representa los FPS frente al tamaño de entrada del modelo. Todos los modelos son modelos SSDLite basados en Mobilenetv2.Para mobilenetv2 xy-abc, xy=Multiplicador de profundidad, abc=Tamaño de entrada.
También probamos diferentes redes troncales y arquitecturas de detectores, por ejemplo MobileNet V3, EfficientDet, que están disponibles como parte del zoo de modelos OpenVINO. Pero llegamos a la conclusión de que la compensación entre velocidad y precisión al inferir sobre NCS no es favorable para nuestro caso de uso.
Figura 6. Modelo de red troncal y arquitectura frente a FPS. Todas las redes troncales de Mobilenet utilizan SSDLite como detectores de cajas.
Perplejos ante estos resultados, probamos a podar el modelo. Al podar eliminamos partes del modelo que no contribuyen mucho a su rendimiento, sacrificando velocidad por precisión. Probamos la poda inteligente de modelos de Tensorflow, basada en la búsqueda de "capas ligeras". Actualmente, Tensorflow sólo admite la poda de modelos para modelos secuenciales basados en Keras y no admite modelos entrenados mediante la API de detección de objetos de Tensorflow. Esto frustró aún más nuestros esfuerzos por crear un modelo podado ligero.
Otro ángulo para la optimización es la cuantización. En la cuantización cambiamos la precisión numérica de algunas capas de la red a un tipo más ligero y rápido. Esto supone que el hardware de ejecución más débil, como los teléfonos móviles, es más lento a la hora de ejecutar operaciones aritméticas de coma flotante (por ejemplo, coma flotante de 32 bits, FLOAT32) que operaciones de enteros (por ejemplo, enteros de 8 bits, INT8). Este es uno de los mejores trucos para la optimización de la NN. Sin embargo, de nuevo, el NCS no admite operaciones INT8 y volvemos al principio.
Ejecución asíncrona
Por último, tras muchos ensayos de técnicas de optimización, descubrimos que podemos simplemente no esperar a que se complete la solicitud de inferencia y ejecutar otra en paralelo utilizando la API asíncrona de OpenVINO (como se describe en la guía). Podemos obtener otra solicitud de inferencia mientras las otras siguen ejecutándose, y pasarle otra imagen para su detección. Como tenemos captura de fotogramas en tiempo real de la cámara, esto introduce un pequeño retraso en la salida pero una ganancia muy grande en velocidad. El siguiente diagrama muestra la ventaja del flujo IR asíncrono:
En la práctica, ejecutamos un pool de 4 solicitudes de inferencia concurrentes. El tamaño del pool viene determinado por el dispositivo de inferencia, es decir, el NCS. Una CPU tendrá más IR que el NCS, y una GPU potente puede tener muchas más aún. En cualquier caso, si un modelo es grande y por lo tanto lento, tardando mucho tiempo en completar la solicitud, podemos agotar el pool de IRs y aún así tener una reducción en la velocidad de fotogramas.
Evaluación y resultados
Nuestras métricas clave para la evaluación del rendimiento son los FPS y la latencia. Queremos una mayor tasa de FPS y una menor latencia, sin embargo, con el enfoque de la API asíncrona estos dos están en un compromiso. Ejecutar más IR concurrentes implica un periodo de calentamiento y una latencia mayores, pero proporciona un tiempo de respuesta global más rápido.
Para medir el rendimiento disponemos de herramientas internas, pero también utilizamos la herramienta de evaluación comparativa de C++ disponible en OpenVINO. Es capaz de ejecutar los modelos en el NCS y proporciona estadísticas muy útiles. Aunque no es una verdadera simulación de la inferencia de modelos en Tulip Vision, nos proporcionó datos muy buenos sin necesidad de ejecutar realmente el modelo en nuestro marco.
Figura 7. Rendimiento del modelo para SSDLite MobilenetV2 utilizando la API asíncrona y síncrona.
Conclusión
Encontramos que la Intel NCSv2 y el conjunto de herramientas OpenVINO son muy útiles para nuestras necesidades. Más allá de ser una plataforma heterogénea para ejecutar modelos, que funciona sin problemas con la VPU NCS, también tiene un soporte bastante amplio para la conversión y la evaluación comparativa y herramientas útiles para la optimización. Probamos muchas cosas antes de encontrar la opción de inferencia asíncrona, y aprendimos mucho en el proceso. Así es como ofrecemos un rendimiento de primera a nuestros clientes utilizando Tulip Vision a muy bajo coste. La API asíncrona de OpenVINO proporcionó el mejor aumento de rendimiento en relación con muchos otros enfoques tradicionales en los trucos de optimización de la inferencia de modelos, pero éstos pueden seguir siendo útiles a medida que introduzcamos más modelos profundos en la producción de Vision.