Esta entrega es la segunda parte de tres series en las que se pretende presentar una serie de escenarios que nos pretenden acercar al concepto de plataforma MLOPs. En la entrega anterior habíamos hecho una presentación de los objetivos y habíamos visto el primer escenario. En esta entrega empezaremos hablando de los problemas del escenario 1 y del diseño de una segunda solución que da un paso más hacia MLOPs, solucionando problemas del escenario 1.
A modo de recapitulación, pongo a continuación el diagrama de la solución planteada del escenario 1. Esta solución se basaba en un servidor que se ofrecía como entorno de Runtime centralizado para todos los científicos de datos:
En este escenario, una vez implantada la solución y resueltos los problemas iniciales, vemos que aparecen otros problemas nuevos:
Esto nos da paso al segundo escenario donde vamos a ver como se intentan solucionar estas problemáticas. Como en el primer caso, presento de forma resumida la problemática y objetivos principales del escenario 2.
Ante esto, la solución a implantar es una arquitectura en el Cloud de AWS. El uso de Cloud es necesario por temas de elasticidad en la infraestructura y poder trabajar con hardware especializado como lo son las GPUs. La elección del Cloud es un cambio respecto al primer escenario donde conseguir más máquinas o más hardware en unidades de tiempo podía suponer semanas.
Esta solución está basada en un Framework personalizado que integra varios componentes software para dar cobertura al desarrollo de modelos. Estos componentes aportan un repositorio de código (GIT), un servicio de aprovisionamiento de entornos de Notebooks (Jupyter Hub) y un almacén de datos compartido para estos proyectos basado en S3, servicio de almacenamiento de AWS, y que es visible desde los propios Notebooks. La integración entre estos componentes se realiza mediante un Backend que funciona a modo de orquestador durante el aprovisionamiento de entornos de desarrollo.
Este Framework, diseñado internamente, permite desplegarse en el entorno de Kubernetes de Amazon (EKS). El escalado se cubre haciendo uso de las capacidades de escalado del clúster de Kubernetes. Todas las instancias de Notebooks corren sobre un contenedor de Kubernetes y este contenedor puede llevar hardware especializado (GPUs).
Además, cada contenedor es independiente. Se le asignan unos recursos, de forma que están garantizados y no compartidos para otro tipo procesamiento. De esta forma se soluciona la competición por recursos en un único servidor que nos encontrábamos en el primer escenario.
Estos contenedores pueden servir tanto para desarrollar con Notebooks, como para lanzar entrenamientos, como para desplegar inferencias/modelos. Con esto se tiene en cuenta el consumo de modelo que no aparecía ni siquiera como planteamiento en los objetivos iniciales del escenario 1.
Funcionalmente, el Framework también permite versionar los modelos, distinguiendo qué versiones existen y en qué estado están (en desarrollo o publicados para consumirse).
Esta arquitectura cumple con las necesidades del proyecto, pero la gestión del entorno y mantenimiento tiene una serie de limitaciones. Estas limitaciones no son críticas para el número inicial de proyectos, pero sí se acentúa cuando empiezan a desarrollarse más modelos de los previstos. El motivo es que existen ciertas tareas manuales que no están automatizadas y requieren de un administrador o un rol especializado para llevarlas a cabo. Esta manualidad afecta en los siguientes puntos:
Es importante destacar aquí que ya se empieza a ver como distribuir o empaquetar un modelo para poder ser consumido o entrenado. Uno de los problemas que había hasta ahora es que el científico de datos creaba su modelo en un entorno personalizado, que no tenía que coexistir con otros procesos. Esto, a la hora de introducirlo en un entorno integrado donde existen más modelos en marcha, trae consigo temas adicionales a la competición de recursos de RAM, CPU, etc… Es el caso, por ejemplo, de las dependencias para ejecutar un modelo que puede diferir de otros modelos. Estas dependencias no sólo pueden ser el tipo de librerías usadas, sino para una misma librería en que se necesiten versiones diferentes. También para ejecuciones Batch, donde las ejecuciones son de tiempo finito, hay que resolver cómo volvemos a restaurar la máquina donde se ejecuta el entrenamiento/inferencia una vez ya haya finalizado. La solución que se plantea aquí es directamente utilizar la tecnología de contenedores para aislar ejecución y las dependencias o librerías que necesite cada modelo.
En el tercer escenario veremos cómo se afrontan estas limitaciones, partiendo de una aproximación diferente a estos dos escenarios.