FastAPI y Streamlit El dúo de Python que debes conocer.

FastAPI and Streamlit The Python duo you should know.

EL MARCO DE TRABAJO MLOPS DE 7 PASOS FULL STACK

Lección 6: Consuma y visualice las predicciones de su modelo utilizando FastAPI y Streamlit. Dockerize todo

Foto de Hassan Pasha en Unsplash

Este tutorial representa la lección 6 de un curso de 7 lecciones que lo guiará paso a paso sobre cómo diseñar, implementar y implementar un sistema de aprendizaje automático utilizando buenas prácticas de MLOps. Durante el curso, construirá un modelo listo para producción para pronosticar los niveles de consumo de energía para las próximas 24 horas en varios tipos de consumidores de Dinamarca.

Al final de este curso, comprenderá todos los fundamentos de cómo diseñar, codificar e implementar un sistema de aprendizaje automático utilizando una arquitectura de servicio por lotes.

Este curso está dirigido a ingenieros de aprendizaje automático intermedios / avanzados que deseen mejorar sus habilidades construyendo sus propios proyectos de extremo a extremo.

Hoy en día, los certificados están por todas partes. Construir proyectos avanzados de extremo a extremo que puedas mostrar más tarde es la mejor manera de obtener reconocimiento como ingeniero profesional.

Tabla de contenidos:

  • Introducción al curso
  • Lecciones del curso
  • Fuente de datos
  • Lección 6: Consuma y visualice las predicciones de su modelo utilizando FastAPI y Streamlit. Dockerize todo.
  • Lección 6: Código
  • Conclusión
  • Referencias

Introducción al curso

Al final de este curso de 7 lecciones, sabrá cómo:

  • diseñar una arquitectura de servicio por lotes
  • usar Hopsworks como una tienda de características
  • diseñar una canalización de ingeniería de características que lee datos de una API
  • construir una canalización de entrenamiento con ajuste de hiperparámetros
  • usar W&B como plataforma de aprendizaje automático para rastrear sus experimentos, modelos y metadatos
  • implementar una canalización de predicción por lotes
  • usar Poetry para construir sus propios paquetes de Python
  • implementar su propio servidor privado de PyPi
  • orquestar todo con Airflow
  • usar las predicciones para codificar una aplicación web utilizando FastAPI y Streamlit
  • usar Docker para contenerizar su código
  • usar Great Expectations para garantizar la validación y la integridad de los datos
  • monitorear el rendimiento de las predicciones con el tiempo
  • implementar todo en GCP
  • construir una canalización CI/CD utilizando GitHub Actions

Si suena como mucho, no se preocupe. Después de cubrir este curso, entenderá todo lo que dije antes. Lo más importante es que sabrá POR QUÉ utilicé todas estas herramientas y cómo funcionan juntas como un sistema.

Si desea aprovechar al máximo este curso, le sugiero que acceda al repositorio de GitHub que contiene todo el código de las lecciones. Este curso está diseñado para leer y replicar rápidamente el código junto con los artículos.

Al final del curso, sabrá cómo implementar el diagrama a continuación. No se preocupe si algo no tiene sentido para usted. Lo explicaré todo en detalle.

Diagrama de la arquitectura que construirá durante el curso [Imagen del autor].

Al final de la lección 6, sabrá cómo consumir las predicciones y las métricas de monitoreo del cubo GCP dentro de una aplicación web utilizando FastAPI y Streamlit.

Lecciones del curso:

  1. Servicio por lotes. Tiendas de características. Canalizaciones de ingeniería de características.
  2. Canalizaciones de entrenamiento. Plataformas de aprendizaje automático. Ajuste de hiperparámetros.
  3. Canalización de predicción por lotes. Empaquete módulos Python con Poetry.
  4. Servidor privado de PyPi. Orquestar todo con Airflow.
  5. Validación de datos para calidad e integridad utilizando GE. Monitoreo continuo del rendimiento del modelo.
  6. Consuma y visualice las predicciones de su modelo utilizando FastAPI y Streamlit. Dockerize todo.
  7. Implemente todo en GCP. Construya una canalización CI/CD utilizando GitHub Actions.

Revisa la Lección 3 para aprender cómo calculamos y almacenamos las predicciones en un bucket de GCP.

Además, en la Lección 5, puedes ver cómo calculamos las métricas de monitoreo, las cuales también se almacenan en un bucket de GCP.

Consumirás las predicciones y las métricas de monitoreo desde el bucket de GCP y las mostrarás en un dashboard amigable utilizando FastAPI y Streamlit.

Fuente de datos

Usamos una API gratuita y abierta que proporciona valores de consumo de energía por hora para todos los tipos de consumidores de energía en Dinamarca [1].

Proporcionan una interfaz intuitiva donde puedes consultar y visualizar fácilmente los datos. Puedes acceder a los datos aquí [1].

Los datos tienen 4 atributos principales:

  • Hora UTC: la fecha y hora UTC en que se observó el punto de datos.
  • Área de precios: Dinamarca se divide en dos áreas de precios: DK1 y DK2, divididas por el Gran Belt. DK1 está al oeste del Gran Belt y DK2 está al este del Gran Belt.
  • Tipo de consumidor: El tipo de consumidor es el Código de la industria DE35, propiedad y mantenida por Danish Energy.
  • Consumo total: Consumo total de electricidad en kWh

Nota: ¡Las observaciones tienen un retraso de 15 días! Pero para nuestro caso de uso de demostración, eso no es un problema, ya que podemos simular los mismos pasos que en tiempo real.

Una captura de pantalla de nuestra aplicación web que muestra cómo pronosticamos el consumo de energía para el área = 1 y el tipo de consumidor = 212 [Imagen del autor].

Los puntos de datos tienen una resolución por hora. Por ejemplo: “2023–04–15 21:00Z”, “2023–04–15 20:00Z”, “2023–04–15 19:00Z”, etc.

Modelaremos los datos como múltiples series de tiempo. Cada tupla única de área de precios y tipo de consumidor representa su serie de tiempo única.

Por lo tanto, construiremos un modelo que pronostique de manera independiente el consumo de energía para las próximas 24 horas para cada serie de tiempo.

Revisa el video a continuación para entender mejor cómo se ven los datos 👇

Resumen del curso y fuente de datos [Video del autor].

Lección 6: Consumir y visualizar las predicciones de tu modelo utilizando FastAPI y Streamlit. Dockerizar todo.

El objetivo de la Lección 6

En la Lección 6, construirás un backend de FastAPI que consumirá las predicciones y las métricas de monitoreo de GCS y las expondrá a través de una API RESTful. Más concretamente, a través de un conjunto de endpoints que expondrán los datos a través de HTTP(S).

También implementarás 2 aplicaciones frontend diferentes usando únicamente Streamlit:

  1. un dashboard que muestre los pronósticos (también conocida como tu aplicación),
  2. un dashboard que muestre las métricas de monitoreo (también conocido como tu dashboard de monitoreo).

Ambas aplicaciones frontend solicitarán datos desde la API RESTful de FastAPI a través de HTTP(s) y usarán Streamlit para renderizar los datos en algunos gráficos hermosos.

Quiero destacar que puedes usar ambos frameworks (FastAPI y Streamlit) en Python. Esto es extremadamente útil para un DS o MLE, ya que Python es su santo grial.

Diagrama de la arquitectura final con los componentes de la Lección 6 resaltados en azul [Imagen del autor].

Observa que consumir las predicciones del bucket está completamente desacoplado del diseño de las 3 pipelines. Por ejemplo, ejecutar las 3 pipelines: ingeniería de características, entrenamiento e inferencia lleva ~10 minutos. Pero leer las predicciones o las métricas de monitoreo desde el bucket es casi instantáneo.

Por lo tanto, al almacenar en caché las predicciones en GCP, se sirve el modelo de ML en línea desde el punto de vista del cliente: las predicciones se sirven en tiempo real.

Esta es la magia de la arquitectura por lotes.

Los siguientes pasos naturales son pasar de una arquitectura por lotes a una de solicitud-respuesta o de transmisión.

La buena noticia es que las canalizaciones de FE y entrenamiento serían casi las mismas, y solo tendrías que mover la canalización de predicción por lotes (también conocida como el paso de inferencia) a tu infraestructura web. Lee este artículo para aprender los conceptos básicos de cómo implementar tu modelo en una arquitectura de solicitud-respuesta utilizando Docker.

¿Por qué?

Porque la canalización de entrenamiento carga los pesos del modelo entrenado en el registro del modelo. Desde allí, puedes usar los pesos de la manera que mejor se adapte a tu caso de uso.

Conceptos y herramientas teóricos

FastAPI: Uno de los últimos y más famosos marcos web de API de Python. He probado todos los principales marcos web de API de Python: Django, Flask y FastAPI, y mi corazón va a FastAPI.

¿Por qué?

En primer lugar, es nativamente asíncrono, lo que puede mejorar el rendimiento con menos recursos informáticos.

En segundo lugar, es fácil e intuitivo de usar, lo que lo hace adecuado para aplicaciones de todos los tamaños. Incluso para los monstruos monolíticos, aún elegiría Django. Pero ese es un tema para otra ocasión.

Streamlit: Streamlit hace que la codificación de componentes de IU simples, principalmente paneles de control, sea extremadamente accesible utilizando solo Python.

El alcance de Streamlit es permitir que los científicos de datos e ingenieros de ML usen lo que mejor saben, es decir, Python, para construir rápidamente un frontend hermoso para sus modelos.

Y eso es exactamente lo que hicimos ✌️

Por lo tanto, usarás FastAPI como tu backend y Streamlit como tu frontend para construir una aplicación web únicamente en Python.

Lección 6: Código

Puedes acceder al repositorio de GitHub aquí.

Nota: Todas las instrucciones de instalación se encuentran en los archivos README del repositorio. Aquí irás directamente al código.

El código dentro de la Lección 6 se encuentra en lo siguiente:

  • carpeta app-api – backend de FastAPI
  • carpeta app-frontend – panel de predicciones
  • carpeta app-monitoring – panel de monitoreo

Usando Docker, puedes iniciar rápidamente los 3 componentes a la vez:

docker compose -f deploy/app-docker-compose.yml --project-directory . up --build

Almacenar credenciales directamente en tu repositorio de git es un gran riesgo de seguridad. Es por eso que inyectarás información confidencial usando un archivo .env.

El .env.default es un ejemplo de todas las variables que debes configurar. También es útil almacenar valores predeterminados para atributos que no son sensibles (por ejemplo, el nombre del proyecto).

Captura de pantalla del archivo .env.default [Imagen del autor].

Preparar las credenciales

Para esta lección, el único servicio al que necesitas acceder es GCS. En la sección Preparar las credenciales de la Lección 3, ya explicamos detalladamente cómo hacerlo. También tienes más información en el README de GitHub.

Para ser concisos, en esta lección, quiero destacar que la cuenta de servicio de GCP de la aplicación web solo debe tener acceso de lectura por razones de seguridad.

¿Por qué?

Porque la API de FastAPI solo leerá datos de los buckets de GCP y mantener los permisos al mínimo es una buena práctica.

Por lo tanto, si tu aplicación web es pirateada, el atacante solo puede leer los datos utilizando las credenciales de la cuenta de servicio robadas. No puede eliminar ni sobrescribir los datos, lo cual es mucho más peligroso en este caso.

Por lo tanto, repite los mismos pasos que en la sección Preparar las credenciales de la Lección 3, pero en lugar de elegir el rol de Administrador de objetos de almacenamiento, elige el rol de Visor de objetos de almacenamiento.

Recuerda que ahora debes descargar un archivo JSON diferente que contenga la clave de tu cuenta de servicio de GCP con acceso de solo lectura.

Consulta el README para aprender cómo completar el archivo .env. Quiero destacar que solo el backend de FastAPI tendrá que cargar el archivo .env. Por lo tanto, debes colocar el archivo .env solo en la carpeta app-api.

Backend de FastAPI

Descripción general del backend de FastAPI [Video del autor].

Como recordatorio, el código de FastAPI se encuentra en app-api/api.

Paso 1: Crea la aplicación FastAPI, donde configuramos la documentación, el middleware de CORS y el enrutador de la raíz de los puntos finales de la API.

Paso 2: Define la clase Settings. El alcance de esta clase es contener todas las constantes y configuraciones que necesitas en todo tu código de API, como:

  • configuraciones genéricas: el puerto, el nivel de registro o la versión,
  • credenciales de GCP: nombre del bucket o ruta a las claves de la cuenta de servicio JSON.

Usarás el objeto Settings en todo el proyecto utilizando la función get_settings().

Además, dentro de la clase Config, programamos FastAPI para buscar un archivo .env en el directorio actual y cargar todas las variables con el prefijo APP_API_.

Como puedes ver en el archivo .env.default, todas las variables comienzan con APP_API_.

Captura de pantalla del archivo .env.default [Imagen del autor].

Paso 3: Define los esquemas de los datos de la API utilizando Pydantic. Estos esquemas codifican o decodifican datos de JSON a un objeto Python o viceversa. Además, validan el tipo y la estructura de tu objeto JSON basándose en tu modelo de datos definido.

Cuando defines un Pydantic BaseModel, es esencial agregar un tipo a cada variable, que se utilizará en la validación.

Paso 4: Define tus puntos finales, en la jerga web, conocidos como vistas. Por lo general, una vista tiene acceso a algún almacenamiento de datos y, en función de una consulta, devuelve un subconjunto de la fuente de datos al solicitante.

Por lo tanto, un flujo estándar para recuperar (también conocido como solicitud GET) datos se ve así:

“cliente → solicita datos → punto final → accede al almacenamiento de datos → codifica a un esquema Pydantic → decodifica a JSON → responde con los datos solicitados”

Veamos cómo definimos un punto final para OBTENER todos los tipos de consumidor:

Usamos ” gcsfs.GCSFileSystem” para acceder al bucket de GCS como un sistema de archivos estándar.

Adjuntamos el punto final al api_router.

Usando el decorador Python api_router.get(), adjuntamos una función básica al punto final /consumer_type_values.

En el ejemplo anterior, al llamar ” https://<some_ip>:8001/api/v1/consumer_type_values”, se activará la función consumer_type_values(), y la respuesta del punto final será estrictamente en función de lo que la función devuelva.

Otra cosa importante a destacar es que al definir el response_model (también conocido como el esquema) en el decorador de Python, no tienes que crear explícitamente el esquema Pydantic.

Si devuelves un diccionario que es 1:1, respetando la estructura del esquema, FastAPI creará automáticamente el objeto Pydantic por ti.

eso es todo. Ahora repetiremos la misma lógica para definir el resto de los puntos finales. FastAPI lo hace todo fácil e intuitivo para ti.

Ahora, echemos un vistazo al archivo completo views.py, donde definimos puntos finales para lo siguiente:

  • /health → chequeo de salud
  • /consumer_type_values → OBTENER todos los posibles tipos de consumidor
  • /area_values → OBTENER todos los posibles tipos de área
  • /predictions/{area}/{consumer_type} → OBTENER las predicciones para un área y tipo de consumidor dados. Note que usando la sintaxis {<some_variable>}, puedes agregar parámetros a tu punto final — FastAPI docs [2].
  • /monitoring/metrics → OBTENER las métricas de monitoreo agregadas
  • /monitoring/values/{area}/{consumer_type} → OBTENER los valores de monitoreo para un área y tipo de consumidor dado

Quiero destacar de nuevo que el backend de FastAPI solo lee las predicciones del bucket de GCS. El paso de inferencia se realiza únicamente en la canalización de predicción por lotes.

También puedes acceder a la documentación de Swagger de la API y probar todos tus puntos finales en ” http://<tu-ip>:8001/api/v1/docs :

Captura de pantalla de la documentación de la API de Swapper [Imagen del autor].

¡Eso es todo! Ahora sabes cómo construir un backend de FastAPI. Las cosas pueden complicarse al agregar una capa de base de datos y sesiones de usuario, pero aprendiste todos los conceptos principales que te ayudarán a comenzar.

Panel de predicciones de Streamlit

Resumen del panel de predicciones de Streamlit [Vídeo del autor].

Accede al código en app-frontend/frontend.

Usar Streamlit es bastante simple. Toda la interfaz de usuario se define utilizando el siguiente código que realiza lo siguiente:

  • define el título,
  • hace una solicitud al backend para todos los posibles tipos de área y crea un menú desplegable basado en eso,
  • hace una solicitud al backend para todos los posibles tipos de consumidor y crea un menú desplegable basado en eso,
  • basándose en los tipos de área y consumidor elegidos, construye y representa un gráfico de Plotly.

Sencillo, ¿verdad?

Tenga en cuenta que podríamos haber realizado comprobaciones adicionales para el código de estado de las solicitudes HTTP. Por ejemplo, si el código de estado de la solicitud es diferente de 200, mostrar un texto con “El servidor está caído”. Pero queríamos mantener las cosas simples y enfatizar solo el código de Streamlit ✌️

Movimos todas las constantes a un archivo diferente para que sean fácilmente accesibles en todo el código. Como siguiente paso, podría hacerlos configurables a través de un archivo .env, similar a la configuración de FastAPI.

Ahora, veamos cómo construimos el gráfico 🔥

Esta parte no contiene código de Streamlit, solo algo de código de Pandas y Plotly.

La función build_data_plot() realiza 3 pasos principales:

  1. Solicita los datos de predicción para un tipo de área y consumidor del backend de FastAPI.
  2. Si la respuesta es válida (status_code == 200), extrae los datos de la respuesta y construye un DataFrame a partir de ellos. De lo contrario, crea un DataFrame vacío para pasar la misma estructura más adelante.
  3. Construye un gráfico de líneas — gráfico de Plotly usando el DataFrame calculado anteriormente.

La función de build_dataframe() tiene como objetivo tomar 2 listas:

  1. una lista de datetimes que se utilizará como eje X del gráfico de líneas;
  2. una lista de valores que se utilizarán como eje Y del gráfico de líneas;

…y convertirlos en un DataFrame. Si faltan algunos puntos de datos, volvemos a muestrear los datetimes a una frecuencia de 1H para tener los datos continuos y destacar los puntos de datos faltantes.

Bastante simple, ¿no? Por eso a la gente le encanta Streamlit.

Panel de monitoreo de Streamlit

Resumen del panel de monitoreo de Streamlit [Vídeo del autor].

El código de monitoreo se puede acceder en app-monitoring/monitoring .

Verás que el código es casi idéntico al del panel de predicciones.

Cuando se define la estructura de la interfaz de usuario de Streamlit, implementamos adicionalmente un gráfico que contiene las métricas agregadas y un divisor.

Lo bueno de desacoplar la definición de los componentes de la interfaz de usuario con el acceso a los datos es que se puede inyectar cualquier dato en la interfaz de usuario sin modificarlo siempre que se respete la interfaz de los datos esperados.

La función build_metrics_plot() es casi idéntica a la función build_data_plot() del panel de predicciones, excepto por los datos que solicitamos de la API.

La misma historia para la función build_data_plot() del panel de monitoreo:

Como puede ver, todo el acceso y manipulación de datos son manejados en el backend de FastAPI. El trabajo de la interfaz de usuario de Streamlit es solicitar y mostrar los datos.

Es bueno que reutilizamos el 90% del código del panel de predicciones para construir un panel de monitoreo amigable.

Envolver todo con Docker

El último paso es Dockerizar las 3 aplicaciones web y envolverlas en un archivo docker-compose.

Así, podemos iniciar toda la aplicación web con un solo comando:

docker compose -f deploy/app-docker-compose.yml --project-directory . up --build

Aquí está el Dockerfile de FastAPI :

Una cosa interesante a destacar es que inicialmente copiamos e instalamos solo las dependencias de Poetry. Por lo tanto, cuando modifica el código, la imagen de Docker se reconstruirá solo a partir de la línea 19, es decir, copiando su código.

Esta es una estrategia común para aprovechar las características de almacenamiento en caché de Docker al construir una imagen para acelerar su proceso de desarrollo, ya que rara vez agrega nuevas dependencias y su instalación es el paso más largo.

También, dentro de run.sh llamamos:

/usr/local/bin/python -m api

Pero espera, no hay un archivo Python en el comando 😟

Bueno, en realidad puede definir un archivo __main__.py dentro de un módulo, lo que hace que su módulo sea ejecutable.

Así, al llamar al módulo api, llama al archivo __main__.py:

En nuestro caso, en el archivo __main__.py, usamos el servidor web uvicorn para iniciar el backend de FastAPI y configurarlo con la IP correcta, puerto, nivel de registro, etc.

Aquí está el Dockerfile del panel de predicciones de Streamlit :

Como puede ver, este Dockerfile es casi idéntico al utilizado para el backend de FastAPI, excepto por el último comando CMD, que es un comando CLI estándar para iniciar su aplicación de Streamlit.

El Dockerfile del panel de monitoreo de Streamlit es idéntico al Dockerfile del panel de predicciones. Por lo tanto, es redundante copiarlo aquí.

La buena noticia es que puede aprovechar la plantilla de Dockerfile que le mostré anteriormente para Dockerizar la mayoría de sus aplicaciones de Python ✌️

Finalmente, veamos cómo envolver todo con docker-compose. Puede acceder al archivo en deploy/app-docker-compose.yml:

Como puede ver, los servicios de frontend y monitoreo deben esperar a que la API se encienda antes de comenzar.

Además, solo la API necesita cargar las credenciales desde un archivo .env.

Ahora, puede ejecutar toda la aplicación web usando solo el siguiente comando, y Docker se encargará de construir las imágenes y ejecutar los contenedores:

docker compose -f deploy/app-docker-compose.yml --project-directory . up --build

Conclusión

¡Felicidades! Terminaste la sexta lección del curso Framework MLOps de 7 pasos Full Stack. Significa que ahora comprende cómo consumir las predicciones de su sistema de ML para construir su aplicación impresionante.

En esta lección, aprendió cómo:

  • consumir las predicciones y métricas de monitoreo de GCS,
  • construir un backend de FastAPI para cargar y servir los datos de GCS,
  • implementar un panel en Streamlit para mostrar las predicciones,
  • crear un panel de monitoreo en Streamlit para visualizar el rendimiento del modelo.

Ahora que comprende la flexibilidad de construir una aplicación sobre un sistema de ML que utiliza una arquitectura de predicción por lotes, puede diseñar fácilmente aplicaciones de aprendizaje automático de pila completa.

Consulte la Lección 7 para el paso final del Framework MLOps de 7 pasos Full Stack, que es implementar todo en GCP y construir un pipeline CI/CD usando GitHub Actions.

También, puede acceder al repositorio de GitHub aquí .

💡 Mi objetivo es ayudar a los ingenieros de aprendizaje automático a mejorar en el diseño y producción de sistemas de ML. ¡Sígueme en LinkedIn o suscríbete a mi boletín semanal para obtener más información!

🔥 Si disfrutas leyendo artículos como este y deseas apoyar mi escritura, considera convertirte en miembro de Zepes. Usando mi enlace de referencia, puedes apoyarme sin costo adicional mientras disfrutas de un acceso ilimitado a la rica colección de historias de Zepes.

🤖 Únete para obtener contenido exclusivo sobre el diseño y la construcción de sistemas de aprendizaje automático listos para producción 🚀 Desbloquea acceso completo a…

pauliusztin.medium.com

¡Gracias ✌🏼!

Referencias

[1] Consumo de energía por código de industria DE35 de Dinamarca desde la API de Dinamarca, Servicio de datos de energía de Dinamarca

[2] Parámetros de ruta, Documentación de FastAPI

We will continue to update Zepes; if you have any questions or suggestions, please contact us!

Share:

Was this article helpful?

93 out of 132 found this helpful

Discover more

Inteligencia Artificial

Investigadores de Stanford presentan Spellburst un entorno de codificación creativa impulsado por un modelo de lenguaje grande (LLM).

Mientras crean impresionantes obras de arte digitales, los artistas generativos a menudo se enfrentan a las complejid...

Investigación

NYU y NVIDIA colaboran en un gran modelo de lenguaje para predecir la readmisión de pacientes.

Darse de alta en el hospital es un hito importante para los pacientes, pero a veces no es el final de su camino hacia...

Inteligencia Artificial

Conoce a CityDreamer Un modelo generativo compositivo para ciudades 3D ilimitadas

La creación de entornos naturales en 3D ha sido objeto de mucha investigación en los últimos años. Se han realizado a...

Inteligencia Artificial

Explorando la Inteligencia Artificial Generativa Avanzada | VAEs Condicionales

Introducción Bienvenido a este artículo, donde exploraremos el emocionante mundo de la IA Generativa. Nos centraremos...