Despliegue de Aplicaciones con Docker y FAS API en AWS
Resumen
¿Cómo poner en producción un modelo de procesamiento de lenguaje natural?
Es un momento emocionante: ¡tu modelo de procesamiento de lenguaje natural está listo para ver la luz! Implementar y desplegar aplicaciones de machine learning no solo requiere habilidades técnicas sino también una comprensión clara del entorno de producción. Aquí descubriremos cómo puedes lograr desplegar con éxito tu modelo de clasificación de tickets, asegurando que tu aplicación esté lista y funcionando eficazmente.
¿Cómo elegir el mejor modelo para producción?
Antes de cualquier implementación, asegúrate de seleccionar el modelo que haya demostrado el mejor rendimiento. Esto lo has aprendido al hacer el seguimiento de modelos con MLflow. Elegir el modelo correcto requiere evaluar cuidadosamente tanto su precisión como su robustez.
¿Cómo asegurarse de la consistencia en la transformación de datos?
La transformación de datos es fundamental para el despliegue. Asegúrate de que los datos utilizados para entrenar el modelo sufran el mismo procesamiento en producción. Esto incluye el uso de Convectorizer, que transforma datos de texto en formatos numéricos comprensibles por el modelo.
Convectorizer: Importante para vectorizar datos de texto.
Consistencia: Asegúrate de usar el mismo proceso de transformación en cada etapa.
¿Cómo construir la infraestructura de producción?
Para desplegar efectivamente tu aplicación, necesitarás construir una infraestructura robusta, lo cual implica varios pasos y herramientas claves, como Docker, Docker Compose, y FastAPI.
¿Cómo usar Docker para aplicaciones de machine learning?
Para comenzar tu viaje en producción, Docker es esencial. Aquí te mostramos cómo puedes definir tu entorno Docker:
Incorpora la API de FastAPI para manejar solicitudes y respuestas de cliente de manera eficiente. Además, utiliza Postgres para la gestión de la base de datos:
FastAPI: Ideal para APIs rápidas en entornos HTTP/HTTPS.
Postgres: Manejo avanzado de bases de datos relacionales.
¿Cómo asegurar el monitoreo y el rendimiento?
El monitoreo es un elemento crucial, añadiendo un volumen extra para Grafana te permite controlar el rendimiento y asegurar la estabilidad de tu aplicación.
¿Cómo garantizar la misma transformación de datos mediante utils.py?
Mantener la transformación de datos consistente es vital. Crea un módulo utils.py que contenga toda la lógica de procesamiento:
Esto asegura que el procesamiento se mantenga constante en todas las implementaciones.
Imagina un despliegue exitoso que aproveche tanto tus habilidades técnicas como el entendimiento de la producción. Estos pasos no solo garantizan un modelo eficiente en la práctica, sino que también te brindan flexibilidad y control sobre tu aplicación de machine learning. ¡Sigue aprendiendo y aplicando tus conocimientos para alcanzar tus metas!
Si alguien hizo como yo y al clonar el repositorio solo utilizó:
git clone <url_del_repositorio>
y solo le aparece la rama master. Puede hacer los siguientes pasos para traer la rama deploy_serving:
confirmar que solo tenga la rama master con git branch
Ejecutar git branch -a para traer las ramas ocultas
Ejecutar git checkout origin/deploy_serving para traer la rama oculta deploy_serving (En este paso git da una guia de que hacer mas adelante para guardar la rama.
Ejecutar git switch -c deploy_serving o git checkout deploy_serving para crear localmente la rama nueva y comenzar a trabajar.
Esto lo hago puesto que para los ejercicios anteriores ya se hicieron pequeños cambios en los archivos, y para no perderlos considero más comodo traer la rama individualmente, que volver a clonar todo el repositorio y comenzar de nuevo.
Espero haber podido ayudar :)
¿Y para el que está trabajando el curso en codespaces?
Para los que van empezando y buscan llevar este código a un entorno productivo real, les dejo unas observaciones técnicas sobre buenas prácticas de MLOps:
Si están usando MLflow para el tracking, cargar el vectorizador con una ruta estática hardcodeada (app/count_vectorizer.pkl) rompe por completo la trazabilidad. Al hacer esto, pierdes la forma de saber qué versión de los datos generó ese archivo, qué hiperparámetros se usaron o qué métricas obtuvo en su entrenamiento. Por buena práctica de ingeniería, las rutas jamás se hardcodean en el código; como mínimo deberían inyectarse mediante variables de entorno para que no se rompan si el contenedor cambia. Sin embargo, el estándar ideal aquí es hacer la carga consultando el Model Registry (ej. usando mlflow.sklearn.load_model(model_uri="models:/MiVectorizer/entorno")) para asegurar que siempre se consuma el artefacto correcto y versionado.
El preprocesamiento de texto y la vectorización son la lógica central de los datos, no simples utilerías. Siguiendo estándares de la industria como Cookiecutter Data Science, esta lógica debe ir estructurada en un módulo de dominio específico y no acoplada en un archivo utils.py monolítico.
Tener llamadas a nltk.download() en el entorno de producción significa que el contenedor intentará descargar paquetes desde internet cada vez que el microservicio se inicie o escale. Esto introduce una latencia severa en el arranque (Cold Start), fallará si hay restricciones de red (firewalls/proxies) y asume que los servidores de NLTK siempre estarán disponibles. Estas descargas deben ocurrir en tiempo de construcción, agregándolas como una capa directamente dentro del Dockerfile (ej. RUN python -m nltk.downloader punkt stopwords wordnet).
Declarar variables como stop_words = set(...) y cargar modelos con joblib.load(...) directamente en la raíz del script provoca que estas operaciones pesadas (y posibles bloqueos de I/O) ocurran en el instante en que alguien hace un import utils. Esto hace que el código sea muy difícil de someter a pruebas unitarias, porque no puedes mockear la carga del modelo antes de que el script intente buscar el archivo y falle. La inicialización de modelos y variables pesadas debe estar encapsulada en clases o funciones de inicialización (ej. un patrón Singleton o una función load_resources()) que se llame explícitamente en el punto de entrada de la API.