Del Notebook a Producción

Compartir

Una implementación de un modelo Machine Learning en producción usando AWS Sagemaker y MLflow
Proyecto github:
https://github.com/amarufd/MLflowAndAWSSagemaker
Todos aquellos que se inician en el mundo del Machine Learning, conocemos el famoso Notebook en sus diferentes sabores (colab de google, Jupyter en el local, Notebook en AWS SageMaker, etc), nuestro espacio de experimentación, lugar donde entrenamos y analizamos que tan eficiente se vuelven nuestros modelos, pero me surge una pregunta, ¿cómo llevamos esto a producción? que es el lugar donde todos nuestros esfuerzos cobrarán sentido ya que es el lugar.
En esta implementación se desarrolla una implementación en SageMaker de AWS y MLflow una herramienta opensource que nos permite almacenar los diferentes modelos que se van creando y asociar la estadística que está asociada a estos (MSE, Precisión (Accuracy), u otras métricas que miden la eficiencia de nuestro modelo), de modo que nos permite escoger que modelo tendremos en producción o si haremos A/B test entre algunos de estos.
AWS Sagemaker
Sagemaker es un servicio que ofrece Amazon dentro de su gran stock de soluciones en AWS, la cualidad de sagemaker es que está orientado a la explotación de los datos, donde se crean, entrenan e implementan modelos de Máquinas de Aprendizaje (ML por el inglés Machine Learning)
MLflow
Mlflow es una plataforma open source desarrollada para administrar el ciclo de vida de una Máquina de Aprendizaje, donde se encuentran: experimentación, reproducción, deployment y un registro central de modelos.
MLflow y AWS Sagemaker
A continuación vemos un diagrama de la relacion entre AWS Sagemaker y MLflow y como se llevan los modelos a producción.

Implementando el modelo
En este Artículo se implementa un modelo de regresión lineal, este es uno de los modelos más básicos de Machine Learning, la intención de usar este modelo es abrir la puerta para que personas que se están iniciando en este mundo sepan que pueden levantar soluciones básicas y desde ahí ir avanzando hasta llegar a soluciones más complejas como implementar una red neuronal (NN por el inglés Neural Networks)
Requerimientos local:
- Python 3.6 o superior con mlflow>=1.0.0
- aws cli
- Docker
Requerimientos aws:
- Acceso a guardar una imagen docker en ECR
- Acceso a AWS sagemaker
- permisos del Lambda para acceder a AWS Sagemaker
Iniciando MLflow
Para iniciar el proceso de creación de modelos es importante que primero tengamos levantado el servidor de MLflow este se realiza en la terminal con el siguiente comando:
$> mlflow ui
una vez se inicie MLflow en nuestro equipo local primero se creará una carpeta “mlruns”, esta será creada donde se ejecute el comando, yo lo ejecute en el mismo lugar en que está el proyecto y mi carpeta local quedó del siguiente modo:
Además de crear una carpeta, también se levanta por defecto un entorno web el cual transmite a través del puerto 5000, éste entorno mostrará todos aquellos elementos que se vayan almacenando dentro de MLflow, estos pueden ser bases de entrenamiento y modelos, donde estarán las diferentes versiones de los modelos y las estadísticas asociadas a este. En la imagen a continuación podemos observar los diferentes set de datos que se han almacenado y una vista general del sitio de MLflow.
Con MLflow ya corriendo en nuestra máquina local podemos comenzar a almacenar algunos datos importantes como las características principales de nuestro set de entrenamiento, esto se realiza ejecutando el script “cargando_dataset.py”, el cual contiene la preparacion de los datos que se usarán para entrenar la regresión lineal, y dentro de MLflow se almacena la ubicacion desde donde se cargaron los datos “path”, la estructura de los datos “shape”, el porcentaje de datos que se usaron para probar “test_size”, si están encodeados “True” y cual es la semilla que se uso para separar los datos “random_state”.
mlflow.log_param("dataset_path", path)
mlflow.log_param("dataset_shape", data.shape)
mlflow.log_param("test_size", test_size)
mlflow.log_param("random_state", random_state)
mlflow.log_param("one_hot_encoding", True)
Es importante destacar que para guardar cada uno de los datos mencionados anteriormente es importante que que la librería de MLflow esté inicializada.
import mlflow
Entrenamiento
Para el proceso de entrenamiento se uso la función “entrenando-lr.py”. Es importante determinar qué librería se está usando para guardar de forma correcta el modelo que se va a guardar, en el caso de la regresión lineal la llamada al modelo es:
from sklearn import linear_model
Es por esta misma razón que al momento de instanciar la librería de MLflow que determina qué modelo se va a almacenar es que se debe hacer referencia a “sklearn” como se ve a continuación:
import mlflow.sklearn
# Almacenando métricas
mlflow.log_metric("mse", mse)
mlflow.log_metric("r2", r2)
# Guardando el modelo
mlflow.sklearn.log_model(linear_regr, "covid-19-lr-model")
Como se ve esto en MLflow
Levantando ambiente local
En una primera instancia se puede levantar el modelo de manera local, pero para esto es necesarios tener las siguientes variables:
$> export MODEL_PATH=/ruta/local/mlruns/X/XXXXX/artifacts/covid-19-lr-model
$> export PUERTO=8888
Donde “RUTA_LOCAL”, corresponde a la ubicación del modelo en el computador local, este inicia con la ruta local del proyecto, en caso de windows debe iniciar con “C://” y en caso de linux y mac “/”, continuando con la carpeta creada por mlflow “mlruns” y navegar hasta llegar al modelo, también se debe establecer el puerto por el que se establecerá la comunicación, en este caso se escogió el “8888”. una vez determinado estos valores se ejecuta la línea que levanta el modelo de forma local, esta es:
$> mlflow sagemaker run-local $MODEL_PATH -m -p $PUERTO
Y después de un rato este queda levantado, listo para ser probado de manera local.
Probando Modelo levantado Localmente
Para probar el modelo local se desarrollo el script “prediccion-local-lr.py” en este se establece el puerto por donde está escuchado el modelo en nuestro equipo local:
port = 8888
Y se hace una llamada post, donde los datos a consultar van en la variable “input_data”. y los resultados se reciben en la variable “prediction”. Como se puede ver en el trozo de código a continuación:
endpoint = "http://localhost:{}/invocations".format(port)
headers = {"Content-type": "application/json; format=pandas-split"}
prediction = requests.post(
endpoint,
json=json.loads(input_data),
headers=headers
)
Deployando la imagen docker en AWS
Es importante tener Docker instalado dado que se crea una imagen local de nuestro MLflow con el siguiente comando:
$> mlflow sagemaker build-and-push-container
Este proceso cuando se realiza por primera vez es algo lento debido a que carga todas las dependencias en necesarias para compilarlas y subirlas a nuestro ECS en AWS, el ECS, del inglés Elastic Container Service, es un administrador de contenedores que se usa para almacenar modelos de Machine Learning, y poder cargarlos desde ahí también.
Deployando en AWS SageMaker
Para deployar desde el equipo local es necesario tener algunas variables básicas a considerar como: “APP_NAME” es el nombre que se le dio al modelo; “MODEL_PATH” la ubicación del modelo a deployar en mi máquina local, en caso de Windows este comienza con “C://” y en caso de Linux o MacOS con “/”, hasta llegar al nombre del modelo; “ROLE” el rol de autorización de ejecución que se tiene sobre Sagemaker; “REGION” en que región estamos trabajando dentro de nuestro ambiente de AWS.
A continuación podemos ver un ejemplo de cómo se ven estas variables:
$> export APP_NAME=covid-19-lr-demo
$> export MODEL_PATH=/ruta/local/mlruns/X/XXXXX/artifacts/covid-19-lr-model
$> export ROLE=arn:aws:iam::XXXX:role/service-role/AmazonSageMaker-ExecutionRole-XXX
$> export REGiON=us-east-X
Con las variables ya determinadas tenemos el comando a continuación que nos deployara el modelo que hayamos escogido en AWS Sagemaker.
$> mlflow sagemaker deploy -a $APP_NAME -m $MODEL_PATH -e $ROLE --region-name $REGION
Probando el modelo deployado en aws
Con el modelo ya funcionando en AWS Sagamaker a través de un script local “prediccion-aws-lr.py” usando la libreria boto3, esta corresponde al framework que proporciona AWS para establecer la comunicación con sus diferentes servicios y en este caso se usa para conectarse al servicio de AWS Sagemaker.
import boto3
Los valores que necesita el boto3 para establecer la conección con el modelo deployado previamente son el nombre de la aplicación “app_name” y la región en donde está ubicado el modelo “region”, como se puede ver a continuación:
app_name = 'covid-19-lr-demo'
region = 'us-east-X'
Con las variables creadas se inicializa el cliente que establece la conexión de nuestro script con el servicio de Sagemaker.
smrt = boto3.client('runtime.sagemaker', region_name=region)
Con la conexión establecida hacemos el llamado de al modelo, donde “input_data” es la variable que contiene los datos que se van a consultar al modelo para que éste realice una predicción, resultados que serán recibidos en la variable “prediction”.
prediction = smrt.invoke_endpoint(
EndpointName=app_name,
Body=input_data,
ContentType='application/json; format=pandas-split'
)
Exponiendo modelo a través de un lambda
Una vez que hemos determinado que nuestro modelo está funcionando en AWS Sagemaker es el momento de exponerlo, para esto se crea una función lambda “lambda_function.py” la cual también usa la librería boto3 para establecer la conección interna con el servicio de AWS Sagemaker, pero a diferencia de la llamada local al modelo, este no necesita “region” sólo “app_name” como se puede ver a continuación.
import boto3
app_name = 'covid-19-lr-demo'
sm = boto3.client('runtime.sagemaker')
En este caso se recibe un “body” con la siguiente estructura:
Request body:
{
"data": [
[
44,1936
],
[
45,2025
],
]
}
Este body se pasa directamente a la llamada del modelo para que este realice la predicción, la cantidad de dato que puede recibir son N, gracias a esto es posible generar gráficas que nos ayuden a entender el comportamiento que se está prediciendo e ir comparándolo con la realidad, una vez la llamada es hecha en la variable “prediction” se almacenan los diferentes resultados que el modelo estimó.
prediction = sm.invoke_endpoint(
EndpointName=app_name,
Body=body,
ContentType='application/json; format=pandas-split'
)
Una vez realizadas las predicciones se retornan a quien haya hecho la llamada del lambda.
return {
'statusCode': 200,
'headers' : {
'Access-Control-Allow-Origin' : '*'
},
'body': prediction
}
¿Qué viene ahora?
Ya con toda la implementación hecha sabiendo que el modelo está funcionando, es el momento de exponer el lambda a través del API Gateway para que este sea consumido por los usuarios finales o algún front que hará uso de estos datos.
Ahora esto es sólo un paso inicial para comenzar a poner nuestros modelos de forma productiva, pero no hay que olvidar que esto es algo que no para, nuestros modelos siempre debemos estar alimentadolos e ir comparándolos con la realidad de forma que sus resultados sean acordes a su entorno, no nos sirve de nada levantar un modelo si este no sigue mejorando, es importante ir robusteciendo la predicción, en este caso abordamos un modelo de regresión simple, pero este es fácilmente superable por otros modelos, y es ahí donde les dejo la invitación, a que si parten con un modelo simple, vayan probando otros que podrán fácilmente reemplazar a este creando un sistema evolutivo donde uds mismos podrán ir rompiendo sus propias barreras.
Otros comandos útiles
Antes de finalizar les dejo los últimos comandos que podrían ser de ayuda.
Listando los endpoint activos de AWS SageMaker, esto nos ayuda a ver cuantos endpoint tenemos activos listos para ser consultados.
$> aws sagemaker list-endpoints --region REGION
Eliminando endpoint de AWS SageMaker, el tener modelos activos es costoso dado que amazon nos cobra, es por lo mismo que si no se está usando el modelo correspondiente este se borre, es por lo mismo que está éste comando.
$> mlflow sagemaker delete -a APP_NAME -r REGION
Conectándose al MLflow de AWS, a veces por medio de nuestro computador local queremos saber qué cosas tiene nuestro MLflow que está en la ECS y es para esto mismo que está el siguiente comando.
$> mlflow server --default-artifact-root s3://bucket --host 0.0.0.0