Delegados de LiteRT

Los delegados habilitan la aceleración por hardware de los modelos de LiteRT aprovechando los aceleradores integrados en el dispositivo, como la GPU y el procesador de señales digitales (DSP).

De forma predeterminada, LiteRT utiliza kernels de CPU optimizados para el conjunto de instrucciones ARM Neon. Sin embargo, la CPU es un procesador de uso múltiple que no está necesariamente optimizado para la aritmética pesada que se encuentra normalmente en los modelos de aprendizaje automático (por ejemplo, las operaciones matemáticas de matrices involucradas en las capas convolucionales y densas).

Por otro lado, la mayoría de los teléfonos celulares modernos contienen chips que son mejores para manejar estas operaciones pesadas. Su uso para operaciones de redes neuronales proporciona grandes beneficios en términos de latencia y eficiencia energética. Por ejemplo, las GPUs pueden proporcionar una aceleración de hasta 5 veces en la latencia.

Cada uno de estos aceleradores tiene APIs asociadas que permiten realizar cálculos personalizados, como OpenCL o OpenGL ES para la GPU de dispositivos móviles. Por lo general, tendrías que escribir mucho código personalizado para ejecutar una red neuronal a través de estas interfaces. Las cosas se complican aún más cuando se considera que cada acelerador tiene sus ventajas y desventajas, y no puede ejecutar todas las operaciones en una red neuronal. La API de Delegate de TensorFlow Lite resuelve este problema actuando como un puente entre el tiempo de ejecución de TFLite y estas APIs de nivel inferior.

Tiempo de ejecución con delegados

Cómo elegir un delegado

LiteRT admite varios delegados, cada uno de los cuales está optimizado para ciertas plataformas y tipos de modelos particulares. Por lo general, habrá varios delegados aplicables a tu caso de uso, según dos criterios principales: la plataforma (¿Android o iOS?) a la que te diriges y el tipo de modelo (¿de punto flotante o cuantificado?) que intentas acelerar.

Delegados por plataforma

Multiplataforma (iOS y Android)

  • Delegado de GPU: El delegado de GPU se puede usar en Android y en iOS. Está optimizado para ejecutar modelos basados en números de punto flotante de 32 y 16 bits cuando hay una GPU disponible. También admite modelos cuantizados de 8 bits y proporciona un rendimiento de GPU comparable con sus versiones de punto flotante. Para obtener detalles sobre el delegado de GPU, consulta LiteRT en GPU.

iOS

  • Delegado de Core ML para iPhones y iPads más nuevos: Para iPhones y iPads más nuevos en los que está disponible el motor neuronal, puedes usar el delegado de Core ML para acelerar la inferencia de modelos de punto flotante de 32 o 16 bits. Neural Engine está disponible en dispositivos móviles de Apple con un SoC A12 o posterior. Para obtener una descripción general del delegado de Core ML y las instrucciones paso a paso, consulta Delegado de Core ML de LiteRT.

Delegados por tipo de modelo

Cada acelerador está diseñado para una cierta cantidad de bits de datos. Si proporcionas un modelo de punto flotante a un delegado que solo admite operaciones cuantificadas de 8 bits, rechazará todas sus operaciones y el modelo se ejecutará por completo en la CPU. Para evitar este tipo de sorpresas, en la siguiente tabla, se proporciona una descripción general de la compatibilidad con delegados según el tipo de modelo:

Tipo de modelo GPU CoreML
Punto flotante (32 bits)
Cuantización de float16 posterior al entrenamiento
Cuantización de rango dinámico posterior al entrenamiento No
Cuantización de números enteros posterior al entrenamiento No
Entrenamiento con reconocimiento de la cuantización No

Cómo validar el rendimiento

La información de esta sección sirve como guía aproximada para preseleccionar los delegados que podrían mejorar tu aplicación. Sin embargo, es importante tener en cuenta que cada delegado tiene un conjunto predefinido de operaciones que admite y que puede funcionar de manera diferente según el modelo y el dispositivo. Por lo tanto, suele recomendarse que realices algunas comparativas para evaluar la utilidad de un delegado según tus necesidades. Esto también ayuda a justificar el aumento de tamaño del objeto binario asociado con la vinculación de un delegado al tiempo de ejecución de LiteRT.

LiteRT cuenta con una amplia variedad de herramientas de evaluación del rendimiento y la precisión que pueden ayudar a los desarrolladores a tener confianza en el uso de delegados en sus aplicaciones. Estas herramientas se analizan en la siguiente sección.

Herramientas de evaluación

Latencia y uso de memoria

La herramienta de comparativas de LiteRT se puede usar con parámetros adecuados para estimar el rendimiento del modelo, incluida la latencia promedio de inferencia, la sobrecarga de inicialización, la huella de memoria, etcétera. Esta herramienta admite varias marcas para determinar la mejor configuración del delegado para tu modelo. Por ejemplo, se puede especificar --gpu_backend=gl con --use_gpu para medir la ejecución de la GPU con OpenGL. La lista completa de parámetros de delegado admitidos se define en la documentación detallada.

A continuación, se muestra un ejemplo de ejecución para un modelo cuantificado con GPU a través de adb:

adb shell /data/local/tmp/benchmark_model \
  --graph=/data/local/tmp/mobilenet_v1_224_quant.tflite \
  --use_gpu=true

Puedes descargar la versión compilada previamente de esta herramienta para Android, arquitectura ARM de 64 bits aquí (más detalles).

Precisión y exactitud

Por lo general, los delegados realizan cálculos con una precisión diferente a la de sus equivalentes de CPU. Como resultado, existe una compensación de precisión (por lo general, menor) asociada con el uso de un delegado para la aceleración por hardware. Ten en cuenta que esto no siempre es cierto. Por ejemplo, dado que la GPU usa precisión de punto flotante para ejecutar modelos cuantizados, es posible que haya una ligera mejora en la precisión (por ejemplo, Mejora de menos del 1% en la precisión del Top-5 en la clasificación de imágenes de ILSVRC).

LiteRT tiene dos tipos de herramientas para medir con qué precisión se comporta un delegado para un modelo determinado: basadas en tareas y independientes de las tareas. Todas las herramientas que se describen en esta sección admiten los parámetros de delegación avanzados que utiliza la herramienta de comparativas de la sección anterior. Ten en cuenta que las subsecciones a continuación se enfocan en la evaluación del delegado (¿el delegado funciona igual que la CPU?) en lugar de la evaluación del modelo (¿el modelo en sí es bueno para la tarea?).

Evaluación basada en tareas

LiteRT tiene herramientas para evaluar la corrección en dos tareas basadas en imágenes:

Puedes encontrar los objetos binarios compilados previamente de estas herramientas (Android, arquitectura ARM de 64 bits) y la documentación aquí:

En el siguiente ejemplo, se muestra la evaluación de clasificación de imágenes con GPU en un Pixel 4:

adb shell /data/local/tmp/run_eval \
  --model_file=/data/local/tmp/mobilenet_quant_v1_224.tflite \
  --ground_truth_images_path=/data/local/tmp/ilsvrc_images \
  --ground_truth_labels=/data/local/tmp/ilsvrc_validation_labels.txt \
  --model_output_labels=/data/local/tmp/model_output_labels.txt \
  --output_file_path=/data/local/tmp/accuracy_output.txt \
  --num_images=0 # Run on all images. \
  --use_gpu=true

El resultado esperado es una lista de métricas de Top-K del 1 al 10:

Top-1 Accuracy: 0.733333
Top-2 Accuracy: 0.826667
Top-3 Accuracy: 0.856667
Top-4 Accuracy: 0.87
Top-5 Accuracy: 0.89
Top-6 Accuracy: 0.903333
Top-7 Accuracy: 0.906667
Top-8 Accuracy: 0.913333
Top-9 Accuracy: 0.92
Top-10 Accuracy: 0.923333

Evaluación independiente de la tarea

Para las tareas en las que no hay una herramienta de evaluación integrada en el dispositivo establecida o si experimentas con modelos personalizados, LiteRT tiene la herramienta Inference Diff. (Android, arquitectura binaria ARM de 64 bits aquí)

Inference Diff compara la ejecución de LiteRT (en términos de latencia y desviación del valor de salida) en dos parámetros de configuración:

  • Inferencia de CPU con un solo subproceso
  • Inferencia definida por el usuario: Se define con estos parámetros

Para ello, la herramienta genera datos gaussianos aleatorios y los pasa por dos intérpretes de TFLite: uno que ejecuta kernels de CPU de un solo subproceso y el otro parametrizado por los argumentos del usuario.

Mide la latencia de ambos, así como la diferencia absoluta entre los tensores de salida de cada intérprete, elemento por elemento.

Para un modelo con un solo tensor de salida, el resultado podría verse de la siguiente manera:

Num evaluation runs: 50
Reference run latency: avg=84364.2(us), std_dev=12525(us)
Test run latency: avg=7281.64(us), std_dev=2089(us)
OutputDiff[0]: avg_error=1.96277e-05, std_dev=6.95767e-06

Esto significa que, para el tensor de salida en el índice 0, los elementos de la salida de la CPU difieren de la salida del delegado en un promedio de 1.96e-05.

Ten en cuenta que interpretar estos números requiere un conocimiento más profundo del modelo y de lo que significa cada tensor de salida. Si se trata de una regresión simple que determina algún tipo de puntuación o incorporación, la diferencia debería ser baja (de lo contrario, se trata de un error con el delegado). Sin embargo, los resultados como el de la "clase de detección" de los modelos SSD son un poco más difíciles de interpretar. Por ejemplo, es posible que muestre una diferencia con esta herramienta, pero eso no significa que haya algo realmente mal con el delegado: considera dos clases (ficticias): "TV (ID: 10)" y "Monitor (ID:20)". Si un delegado se desvía ligeramente de la verdad fundamental y muestra un monitor en lugar de una TV, la diferencia de salida para este tensor podría ser de hasta 20 - 10 = 10.