En el anterior artículo comentábamos qué era exactamente Machine Learning Operations, y el porqué de su reciente aparición. Es momento de ponerse manos a la obra con un pequeño laboratorio que hemos preparado.
¿Y por dónde puedo empezar?
Pues obviamente por este artículo (risas y aplausos). En los siguientes puntos te explicaremos como puedes empezar a montar tu primer proceso de MLOps, de manera sencilla. El código con el laboratorio, puedes obtenerlo aquí
Para ello necesitaremos el siguiente “material” necesario:
- Una cuenta de Azure Devops. Puedes obtener una cuenta gratuita aquí
- Una suscripción de Azure. Puedes obtener una cuenta gratuita de 30 días, con 170€ de consumo, aquí. Necesitaremos esta suscripción para alojar los siguientes servicios:
- Azure Key Vault: contendrá las variables/secretos que deberemos leer desde nuestro proceso de MLOps
- Azure ML Service: Lo utilizaremos como plataforma para el entrenamiento, el versionado y el despliegue del modelo de ML
- Azure Storage: Lo utilizaremos para almacenar y leer desde aquí el dataset de origen
El laboratorio es sencillo y consta de los siguientes pasos:
- Crearemos un modelo de ML basado en una regresión logística, utilizando IRIS como dataset de origen
- Crearemos un pipeline de Azure Devops, que nos permitirá la automatización del proceso de Integración Continua (CI) y Despliegue Continuo (CD), en los siguientes pasos:
- Versionado del código
- Creación del entorno de entrenamiento
- Entrenamiento del modelo
- Despliegue del modelo
Configuración del entorno
En primer lugar, crearemos el workspace de Azure ML Service y una cuenta de almacenamiento de Azure Storage, a través del portal de Azure
Una vez hecho esto, crearemos también un Azure Key Vault en nuestra suscripción con los siguientes secretos:
- Tenant-id: Id del directorio activo de Azure AD de nuestra suscripción
- Aml-client-id: Service principal asociado al workspace de Azure ML Service
- Aml-client-secret: Password del service principal asociado al workspace de Azure ML Service
- Aml-workspace-name: Nombre del workspace de Azure ML Service
- Aml-resource-group: Nombre del grupo de recursos de Azure que contiene el workspace de Azure ML Service
- Aml-subscription-id: Id de la suscripción de Azure
- Storage-account-name: Nombre de la cuenta de Azure Storage donde almacenaremos el dataset que vamos a leer
- Storage-account-key: Clave de la cuenta de Azure Storage donde almacenaremos el dataset que vamos a leer
Versionado del Código
Una vez que hayamos descargado el código de ejemplo de aquí, crearemos un proyecto en Azure Devops para subir nuestro código y crear los pipelines de entrenamiento y despliegue del modelo:
A modo de resumen, la estructura de carpetas del proyecto es muy sencilla y contiene los siguientes elementos:
- Data: contiene el dataset de iris, que subiremos a nuestro blob storage de Azure
- Pipelines: Contiene los pipelines de Azure Devops, con los que automatizaremos para este modelo la creación de un entorno de entrenamiento, el entrenamiento, versionado y despliegue del modelo. La estructura de los pipelines es la siguiente:
- Es decir, tenemos un pipeline principal (main_mlops_pipeline) desde el que se lanzan 3 pipelines en este orden:
- create_environment
- train_model
- deploy_pipeline
- Src: contiene scripts de código Python hace uso del api de Azure ML Services, para interactuar con el workspace de Azure ML Services que habremos provisionado previamente en nuestra suscripción de Azure
Seguidamente crearemos un Service Connection, de tipo Azure Resource Manager, para conectar con nuestra suscripción de Azure:
Una vez rellenado los parámetros de la conexión, podremos acceder a nuestros recursos de la suscripción de Azure, desde Azure Devops. Esto nos va a resultar muy útil, para crear un grupo de variables de Azure Devops, desde el KeyVault que creamos en el primer paso, para que asi todos los secretos que hayamos creado estén disponibles al ejecutar los pipelines, y no tengamos que “hardcodear” ningún parámetro
Crearemos por tanto un grupo de variables de Azure Devops, y conectaremos nuestro KeyVault a estre grupo de variables y lo llamaremos “AMLVariables”
A continuación, crearemos un pipeline de Azure Devops, a partir del fichero main_mlops_pipeline.yml, que deberemos haber versionado ya en un repositorio de Azure Devops
Una vez terminada la creación del pipeline, lo lanzaremos pulsando el botón “Run”:
Se lanzará entonces todo el proceso de entrenamiento y despliegue, que diseccionaremos a continuación:
Creación del entorno de entrenamiento
El script en la ruta src/mbs/create_aml_env.py se usa para crear y registrar el entorno de entrenamiento en Azure ML Service
def create_aml_environment(aml_interface): aml_env = Environment(name=AML_ENVIRONMENT_NAME) conda_dep = CondaDependencies() conda_dep.add_pip_package("numpy==1.18.2") conda_dep.add_pip_package("pandas==1.0.3") conda_dep.add_pip_package("scikit-learn==0.22.2.post1") conda_dep.add_pip_package("joblib==0.14.1") conda_dep.add_pip_package("azure-storage-blob==12.3.0") aml_env.environment_variables[AZURE_STORAGE_ACCOUNT_NAME] = os.getenv(AZURE_STORAGE_ACCOUNT_NAME) aml_env.environment_variables[AZURE_STORAGE_ACCOUNT_KEY] = os.getenv(AZURE_STORAGE_ACCOUNT_KEY) aml_env.environment_variables[MODEL_NAME_VARIABLE] = MODEL_NAME logger.info(f"set environment variables on compute environment: {aml_env.environment_variables}") whl_filepath = retrieve_whl_filepath() whl_url = Environment.add_private_pip_wheel( workspace=aml_interface.workspace, file_path=whl_filepath, exist_ok=True ) conda_dep.add_pip_package(whl_url) aml_env.python.conda_dependencies = conda_dep aml_env.docker.enabled = True return aml_env
En este paso, se crea un entorno de entrenamiento al que se le van a instalar las dependencias necesarias, siendo las típicas, numpy, scikit-learn, etc…
También se podría haber instalado desde un fichero requirements.txt, pero por simplificar se han añadido al entorno de manera manual
Adicionalmente, también se registra un Datastore de Azure ML, apuntando a la cuenta de Azure Blob Storage donde tengamos almacenado nuestro fichero
Una vez terminada la ejecución de este script el entorno quedará correctamente configurado y registrado en Azure ML Service, con las dependencias que hemos asignado
Entrenamiento del modelo
Ahora que tenemos configurados nuestros datos y nuestro entorno, podemos comenzar a entrenar nuestro modelo.
Para hacer esto, se invoca el script en la ruta src/mbs/create_aml_experiment.py:
def submit_run(aml_interface): experiment = Experiment(aml_interface.workspace, AML_EXPERIMENT_NAME) src_dir = __here__ run_config = ScriptRunConfig( source_directory=src_dir, script='train.py', ) run_config.run_config.target = aml_interface.get_compute_target( AML_COMPUTE_NAME, 'STANDARD_D1_V2' ) aml_run_env = Environment.get( aml_interface.workspace, AML_ENVIRONMENT_NAME ) run_config.run_config.environment = aml_run_env logger.info(f"Submitting Run to {AML_COMPUTE_NAME}@{AML_EXPERIMENT_NAME}") run = experiment.submit(config=run_config) run.wait_for_completion(show_output=True) logger.info(run.get_metrics()) logger.info(f"Finished Run on {AML_COMPUTE_NAME}@{AML_EXPERIMENT_NAME}")
Aquí, configuramos el nodo de computación que usaremos para el entrenamiento y, le agregamos el entorno que configuramos en el paso anterior junto con el datastore que configuramos, que recordemos que apunta hacia la cuenta de Azure Storage donde residen los datos para el entrenamiento del modelo.
Por simplicidad, como se comentaba anteriormente, entrenaremos un modelo de regresión logística. Después de entrenar el modelo, lo registraremos en Azure ML Service
Aunque nuestros datos no cambian en este caso, en un escenario real, es probable que recibamos nuevos datos que podamos usar para volver a entrenar el modelo y garantizar que el modelo se mantenga al día con cualquier cambio en los datos subyacentes.
Para este asunto, se puede programar que este pipeline completo se lance con una programación temporal (una vez por semana, una vez al día, etc…)
El entrenamiento se lanza como un Experimento dentro de Azure ML Service
Si accedemos al detalle del experimento, podremos ver las métricas asociadas a esta ejecución en concreto:
Además, también seremos capaces de ver qué datos generaron este entrenamiento, así como el código que generó el modelo
Gracias a este nivel de detalle, tenemos un linaje completo de los artefactos que han producido el modelo, así como trazabilidad y reproducibilidad absoluta.
Despliegue del modelo
En este último paso, desplegamos el modelo que hemos entrenado previamente. Lo desplegaremos como un web service en Azure Container Instances
En este caso, utilizaremos el script de la ruta src/mbs/deploy_aml_model.py
def deploy_service(aml_interface): inference_config = get_inference_config(aml_interface) deployment_config = AciWebservice.deploy_configuration( cpu_cores=1, memory_gb=1 ) model = aml_interface.workspace.models.get(MODEL_NAME) service = Model.deploy( aml_interface.workspace, DEPLOYMENT_SERVICE_NAME, [model], inference_config, deployment_config) service.wait_for_deployment(show_output=True) print(service.scoring_uri)
Al definir la configuración de inferencia, la ruta del script de puntuación es score.py en el mismo directorio que deploy_aml_model.py y el entorno Azure ML que creamos en el pipeline de creación del entorno.
def init(): global model model_path = Model.get_model_path(os.getenv("MODEL_NAME_VARIABLE")) model = joblib.load(model_path) def run(data): try: data = json.loads(data) data = data['data'] result = model.predict(np.array(data)) return result.tolist() except Exception as e: error = str(e) return error
Este script es muy sencillo. Recoge y carga el último modelo registrado en el entrenamiento, y se utiliza para hacer la inferencia con los datos entrantes
A continuación, definimos una configuración de AciWebservice del servicio web Azure Container Instances con requisitos mínimos de un solo núcleo de CPU, con 1 GB de memoria.
El modelo de regresión logística que entrenamos y registramos en el proceso de capacitación del modelo se recupera de nuestro espacio de trabajo.
Usamos este modelo, la configuración de inferencia, la configuración de implementación y el espacio de trabajo para implementar el servicio web que desplegaremos en ACI.
Podemos acceder a la instancia de ACI creada desde el portal de Azure ML Service
Para testear este modelo, en el proyecto se incluye un notebook, en la ruta notebooks/testing_web_service.ipynb, que podremos ejecutar para consumir el servicio desplegado.
Es importante que cuando hayamos terminado de hacer las pruebas, eliminemos tanto el target de computación creado en el entrenamiento, como la instancia de ACI creada en este último paso, dado que generan un consumo diario en la suscripción de Azure