Implementación rentable de modelos de visión y lenguaje para la detección del comportamiento de mascotas en AWS Inferentia2

Tomofun, la startup de tecnología para mascotas con sede en Taiwán detrás de Furbo Pet Camera, está redefiniendo la forma en que los dueños de mascotas interactúan con sus mascotas de forma remota. Furbo combina cámaras inteligentes con IA para detectar comportamientos como ladridos, carreras o actividades inusuales, y alerta a los propietarios en tiempo real. En el centro de esta capacidad se encuentran la visión por computadora y los modelos de lenguaje de visión que interpretan las acciones de las mascotas a partir de las transmisiones de video.

Originalmente, las cargas de trabajo de inferencia de Furbo estaban alojadas en instancias de Amazon Elastic Compute Cloud (Amazon EC2) basadas en GPU. Si bien las GPU proporcionaban un alto rendimiento, también eran costosas porque la inferencia siempre activa era necesaria para admitir alertas de actividad de mascotas en tiempo real a escala. Para reducir costos y mantener la precisión, Tomofun recurrió a instancias EC2 Inf2 impulsadas por AWS Inferentia2, los chips de inteligencia artificial especialmente diseñados por Amazon. En esta publicación, analizamos las siguientes secciones en detalle.

Desafío: Reducir el costo de inferencia de GPU para modelos de lenguaje de visión en tiempo real a escala

La ejecución de modelos avanzados de visión y lenguaje como Bootstrapping Language-image Pre-Training (BLIP), que se detalla en el documento original, se alojó en instancias de GPU y resultó menos rentable para cargas de trabajo de inferencia a escala y en tiempo real siempre activas. El desafío era doble: Tomofun necesitaba mantener la rentabilidad para un monitoreo casi continuo del comportamiento de las mascotas en cientos de miles de dispositivos, manteniendo al mismo tiempo la fidelidad y el rendimiento del modelo. Tomofun necesitaba hacer esto sin reescribir grandes porciones del código base BLIP ya optimizado para PyTorch.

Descripción general de la solución

Antes de profundizar en la arquitectura, el siguiente diagrama proporciona una vista de alto nivel de cómo el sistema procesa la detección del comportamiento de las mascotas a escala en todos los servicios de AWS.

Interacción con cámara web: la API de Furbo se encuentra en el centro del servicio de detección de comportamiento de mascotas de Tomofun, orquestando flujos de imágenes desde las cámaras de mascotas del cliente hasta puntos finales de inferencia en AWS. El diagrama muestra la arquitectura de Elastic Load Balancing (ELB) y el grupo Amazon EC2 Auto Scaling implementado utilizando instancias EC2 Inf2 que proporcionan escalamiento a medida que el volumen de inferencia crece en tiempo real. Cuando una cámara captura un fotograma, los datos se enrutan a través de Amazon CloudFront y un ELB a la primera capa del grupo EC2 Auto Scaling que aloja los servidores API de detección de comportamiento de mascotas. Después de que la capa API procesa cada solicitud, reenvía la imagen a un grupo de Auto Scaling de segunda capa dedicado a ejecutar la inferencia del modelo. Inferencia del modelo: después del procesamiento, las imágenes se reenvían a un grupo de EC2 Auto Scaling de segunda capa que contiene instancias de inferencia. Dentro de este grupo, los contenedores albergan el modelo BLIP, que puede ejecutarse en instancias EC2 Inf2 basadas en Inferentia2. Los componentes del modelo BLIP compilados con Neuron SDK se cargan en contenedores en instancias de Inf2. En la implementación inicial, la API de Furbo enrutaba llamadas de inferencia exclusivamente a contenedores de GPU, pero ahora también puede dirigir solicitudes a contenedores basados ​​en Inf2 sin cambiar la API ascendente o la lógica de alerta descendente. Esta arquitectura permite a Tomofun dirigir solicitudes de inferencia y cambiar entre los backends de GPU e Inferentia2 en tiempo real. Esto mantiene una alta disponibilidad y les brinda la flexibilidad de escalar la inferencia rentable mientras preserva la misma superficie API para los usuarios de Furbo. Recopilación de métricas: Amazon CloudWatch monitorea métricas operativas clave en toda la flota de inferencia, incluida la latencia, el rendimiento y las tasas de error. Estas señales proporcionan la observabilidad necesaria para detectar tempranamente la degradación del rendimiento y garantizar que se cumplan los objetivos de nivel de servicio a medida que los patrones de tráfico cambian a lo largo del día. Escalado con demanda: ELB envía solicitudes a las instancias disponibles dentro del grupo de Auto Scaling, que administra el tamaño del grupo de instancias en función del recuento de solicitudes entrantes como métrica de CloudWatch. Este enfoque basado en métricas se adopta porque los puntos de referencia de rendimiento para cada tipo de instancia ya se han establecido mediante pruebas de estrés, por lo que las decisiones de escalado pueden depender directamente del volumen de solicitudes de imágenes. El resultado es una arquitectura que escala la capacidad de inferencia rentable en tiempo real, manteniendo una alta disponibilidad a medida que crece la demanda.

Mejorando BLIP en Inferentia2

Antes de profundizar en los detalles del modelo, el siguiente diagrama proporciona una descripción general de alto nivel de la arquitectura BLIP y cómo interactúan sus componentes principales.

Arquitectura modelo

Fuente: BLIP: Bootstrapping Language-Image Pre-training for Unified Vision-Language Understanding and Generation, 2022 https://arxiv.org/pdf/2201.12086

BLIP se compone de tres componentes: codificador de imágenes, codificador de texto y decodificador de texto, como se muestra en la imagen. Para ser compatibles con Inferentia2, los modelos se pueden dividir en componentes y ajustar para ajustarse a las formas de entrada y salida. Tomofun aplicó este método a BLIP, creando contenedores livianos para cada uno de los tres componentes del modelo BLIP para que la arquitectura original permaneciera sin cambios. Cada componente se compiló de forma independiente con torch_neuronx y luego se combinó en el proceso de inferencia, lo que permitió que las entradas fluyeran de forma secuencial. Este enfoque modular mantuvo la compatibilidad con Inferentia2 sin alterar la lógica previamente entrenada de BLIP.

Código de modelo original

El primer paso es aislar el codificador de texto BLIP original para que pueda compilarse sin modificar su lógica interna. La clase TextEncoder es una envoltura delgada alrededor del submódulo original (model.text_encoder.model) que estandariza la salida directa al devolver solo el tensor primario. Esto hace que el componente sea fácil de rastrear y compilar con Neuron y al mismo tiempo preservar la arquitectura original.

clase TextEncoder(torch.nn.Module): def __init__(self, modelo): super().__init__() self.model = modelo def forward(self, input_ids, máscara_atención, encoder_hidden_states, encoder_attention_mask): salida = self.model( input_ids=input_ids, atención_mask=attention_mask, encoder_hidden_states=encoder_hidden_states, encoder_attention_mask=encoder_attention_mask, return_dict=False,) devuelve salida[0]

Durante la fase de compilación, el modelo original (model.text_encoder.model) se pasa directamente a torch_neuronx.trace() y se compila en un artefacto TorchScript optimizado para Neuron, sin modificar la lógica BLIP previamente entrenada.

código contenedor

Se necesita un contenedor porque la API torch_neuronx.trace() espera una tupla tensorial de tensores como entrada y salida. Para evitar reescribir el modelo, los contenedores livianos actúan como una capa adaptadora que reformatea las entradas y salidas manteniendo la arquitectura original sin cambios. Este enfoque minimiza los cambios de código y permite que los componentes compilados se integren perfectamente en el proceso de inferencia existente.

clase TextEncoderWrapper(torch.nn.Module): def __init__(self, modelo): super().__init__() self.model = TextEncoder(modelo) @classmethod def from_model(cls, modelo): wrapper = cls(modelo) wrapper.model = modelo return wrapper def forward(self, input_ids, atención_mask, encoder_hidden_states, encoder_attention_mask, return_dict): salida = self.model(input_ids, atención_mask, encoder_hidden_states, encoder_attention_mask) retorno (salida,)

El contenedor se usa solo en la implementación para cargar el modelo compilado y formatear las E/S, de modo que se ajuste a la canalización BLIP existente.

Compilar: use el modelo original (model.text_encoder.model) Implementar: use TextEncoderWrapper para ejecutar el modelo compilado

Esto mantiene el código original sin cambios y al mismo tiempo hace que el modelo compilado sea fácil de conectar a producción.

Compilación de modelos para Inferentia2

En el siguiente fragmento de código, model.text_encoder.model representa el submódulo Text Encoder no modificado, que está compilado en un formato TorchScript optimizado para Neuron.

def trace_model(modelo, directorio, compiler_args=f"–auto-cast-type fp16 –logfile {LOG_DIR}/log-neuron-cc.txt"): if os.path.isfile(directorio): print(f"La ruta proporcionada ({directorio}) debe ser un directorio, no un archivo") return os.makedirs(directorio, exist_ok=True) os.makedirs(LOG_DIR, exist_ok=True) # Omitir el rastreo si el modelo ya está rastreado, en caso contrario os.path.isfile(os.path.join(directory, 'text_encoder.pt')): print("Tracing text_encoder") # Paso 1: Proporcionar pseudodatos de entrada con las formas y tipos d esperados inputs = ( torch.ones((1, 8), dtype=torch.int64), torch.ones((1, 8), dtype=torch.int64), torch.ones((1, 577, 768), dtype=torch.float32), torch.ones((1, 577), dtype=torch.int64), ) # Paso 2: Utilice torch_neuronx.trace() para compilar el modelo para el codificador Inferentia = torch_neuronx.trace(model.text_encoder.model, inputs, compiler_args=compiler_args) # Paso 3: Guarde el modelo compilado como artefacto TorchScript torch.jit.save(encoder, os.path.join(directory, 'text_encoder.pt')) else: print('Skipping text_encoder.pt')

Para compilar componentes BLIP para Inferentia2, Tomofun definió una función de seguimiento que automatiza la conversión de modelos PyTorch entrenados por GPU en artefactos optimizados para Inferentia. El proceso comienza con la preparación de pseudotensores de entrada que representan las formas y tipos de datos esperados de las entradas del modelo, lo que guía el proceso de rastreo. Una vez definidas las entradas, la función llama a torch_neuronx.trace() para compilar el submodelo BLIP para la ejecución de Inferentia, produciendo una versión optimizada para Neuron del código original. Finalmente, el artefacto compilado se guarda con torch.jit.save, dejándolo listo para su implementación en instancias Inf2. Este flujo de tres pasos (cargar el contenedor, proporcionar pseudodatos de entrada y compilar con Neuron) garantiza que Tomofun pueda migrar TextDecoder de BLIP y otros componentes sin cambiar el código del modelo original.

Implementación del modelo en Inferentia2

En la fase de implementación, los submódulos compilados se cargan a través de clases contenedoras para ensamblar el canal de inferencia BLIP final. Esta separación crea un flujo de trabajo claro donde los componentes del modelo original se usan directamente para mejorar Neuron durante la compilación, mientras que las clases contenedoras manejan el formato de entrada y salida durante la inferencia para garantizar la compatibilidad con Inferentia2. El código de la fase de implementación es el siguiente:

modelos.text_encoder = TextEncoderWrapper.from_model(
torch.jit.load(os.path.join(directorio, 'text_encoder.pt')))

Este diseño conservó la arquitectura BLIP original sin modificaciones y al mismo tiempo cumplió con los requisitos de la interfaz de E/S del SDK de Neuron a través de clases contenedoras livianas. También permitió un flujo de trabajo modular a nivel de componentes tanto para la compilación como para la implementación, lo que permitió compilar y administrar cada submódulo BLIP de forma independiente. Como resultado, el uso de model.text_encoder.model es esencial durante la fase de compilación para la optimización directa de Neuron, mientras que las clases contenedoras manejan el formato de entrada y salida durante la inferencia para garantizar una ejecución fluida en Inferentia2.

Pruebas de estrés

Para validar el rendimiento a escala, Tomofun realizó pruebas de estrés simulando cargas de trabajo de cámaras Furbo del mundo real. Cada transmisión de video generó consultas de detección de acciones como "¿Está ladrando el perro?", "¿Está jugando el perro?" o "¿Está el perro masticando muebles?". Estas pruebas confirmaron que las instancias Inf2 (un chip Inferentia2, 32 GB de memoria) podían mantener el rendimiento requerido manteniendo una baja latencia. Además de la precisión, las pruebas resaltaron que la implementación de Inf2 podría manejar solicitudes simultáneas en cientos de miles de dispositivos, lo que la hace muy adecuada para la base global de clientes siempre activa de Furbo. Es importante destacar que la base de comparación fue la ejecución de instancias basadas en GPU con un modelo de precios bajo demanda, que reflejaba el costo que pagaba Tomofun antes de la migración a Inf2. Al migrar de esas implementaciones bajo demanda de GPU a instancias Inf2.xlarge con Inferentia2, Tomofun logró una reducción de costos del 83 % sin comprometer el rendimiento.

El gráfico ilustra cómo cambia la latencia de inferencia a medida que aumenta la simultaneidad del servidor y del cliente. El eje X representa combinaciones de etiquetas que representan #subprocesos del servidor – #subprocesos del cliente para simular el rendimiento en diferentes escenarios de carga. Cuando solo hay unos pocos subprocesos del servidor disponibles, agregar más subprocesos del cliente hace que la latencia aumente rápidamente. Aumentar la cantidad de subprocesos del servidor ayuda a absorber esta carga y mantiene la latencia más baja. En niveles de concurrencia más altos, la latencia aumenta y las ganancias se estabilizan, lo que indica saturación. Este experimento muestra que los equipos deben utilizar pruebas de carga para identificar el equilibrio adecuado entre la simultaneidad del cliente y la capacidad del servidor, y luego limitar la simultaneidad a ese rango para lograr la compensación adecuada entre latencia y costo en producción.

Conclusión

Al migrar la inferencia BLIP en instancias EC2 Inf2 basadas en AWS Inferentia, Tomofun redujo los costos de implementación de aplicaciones Furbo en un 83 %. La transición de GPU a Inferentia2 fue perfecta, ya que la migración solo requirió clases contenedoras livianas y dejó intacta la lógica central de BLIP. Las pruebas confirmaron que el uso de Inferentia2 no solo redujo los costos de implementación, sino que también mantuvo un alto rendimiento para la inferencia en tiempo real a escala. Tomofun planea migrar más cargas de trabajo a Inferentia2, ya que admite cargas de trabajo más allá de los modelos de visión y lenguaje, como la detección de eventos de audio para el reconocimiento de ladridos y una posible integración futura con grandes modelos de lenguaje para mejorar las interacciones entre los dueños de mascotas. Además, la adopción de contenedores de aprendizaje profundo (DLC) de AWS se ha programado en la hoja de ruta como el siguiente paso, utilizando imágenes de contenedores mejoradas y prediseñadas para simplificar la gestión de dependencias y agilizar los flujos de trabajo de inferencia.

Para saber cómo implementar mejoras similares, explore la documentación y los ejemplos de AWS Neuron a los que puede consultar el documento de AWS Neuron. También puedes visitar el sitio web de Furbo para explorar las funciones impulsadas por IA de Furbo y ver cómo el ecosistema Furbo mantiene seguras a tus mascotas.

Sobre los autores

Chen-Hsin

Chen-Hsin Ding es ingeniero de aprendizaje automático en Tomofun, con más de 10 años de experiencia en desarrollo de software. Lidera proyectos de IA generativa y trabaja en estrecha colaboración con equipos de backend para diseñar arquitecturas prácticas de sistemas de IA, centrándose en incorporar las mejores prácticas de MLOps al equipo de IA y ofrecer aplicaciones LLM y RAG listas para producción. Fuera del trabajo, Chen-Hsin disfruta preparar café y escuchar bandas sonoras de películas y jazz en su sistema de audio de alta fidelidad.

Rayo

Ray Wang es arquitecto senior de soluciones en AWS. Con 15 años de experiencia en la industria de TI, Ray se dedica a crear soluciones modernas en la nube, especialmente en NoSQL, big data, aprendizaje automático e IA generativa. Como un emprendedor hambriento, aprobó los 12 certificados de AWS para hacer que su campo técnico no solo sea profundo sino amplio. Le encanta leer y ver películas de ciencia ficción en su tiempo libre.

Howard

Howard Su es arquitecto de soluciones en AWS. Con amplia experiencia en desarrollo de software y operaciones de sistemas, ha desempeñado diversos roles, incluidos RD, QA y SRE. Howard ha sido responsable del diseño arquitectónico de numerosos sistemas a gran escala y ha liderado varias migraciones a la nube. Después de años de profunda acumulación técnica, ahora se dedica a defender DevOps aprovechando la IA generativa para construir infraestructuras "nativas de IA" autorreparables, haciendo la transición del SDLC de la orquestación tradicional a un ecosistema predictivo verdaderamente inteligente.