Entrenamiento de modelos de scikit-learn a gran escala con Azure Machine Learning

SE APLICA A: SDK de Python azure-ai-ml v2 (actual)

En este artículo, obtendrá información sobre cómo ejecutar los scripts de entrenamiento de scikit-learn con Azure Machine Learning Python SDK v2.

Los scripts de ejemplo de este artículo se usan para clasifica imágenes de flores Iris para crear un modelo de Machine Learning basado en el conjunto de datos de Iris de scikit-learn.

Tanto si va a entrenar un modelo de scikit-learn de Machine Learning desde el principio como si va a incorporar un modelo existente a la nube, puede usar Azure Machine Learning para escalar horizontalmente trabajos de entrenamiento de código abierto mediante recursos de proceso en la nube elástica. Puede compilar, implementar y supervisar modelos de nivel de producción, así como crear versiones de dichos mismos, mediante Azure Machine Learning.

Requisitos previos

Puede ejecutar el código de este artículo en una instancia de proceso de Azure Machine Learning o en su propio Jupyter Notebook.

  • Instancia de proceso de Azure Machine Learning

    • Complete Creación de recursos para empezar para crear una instancia de proceso. Cada instancia de proceso incluye un servidor de cuadernos dedicado precargado con el SDK y el repositorio de ejemplos de cuadernos.
    • Seleccione la pestaña Cuaderno en el Estudio de Azure Machine Learning. En la carpeta de entrenamiento de muestras, encuentre un cuaderno completo y expandido navegando a este directorio: v2 > sdk > jobs > single-step > scikit-learn > train-hyperparameter-tune-deploy-with-sklearn.
    • Puede usar el código rellenado previamente en la carpeta de entrenamiento de ejemplo para completar este tutorial.
  • Su servidor de Jupyter Notebook

Configuración de la herramienta

En esta sección se configura el trabajo para el entrenamiento mediante la carga de los paquetes de Python necesarios, la conexión a un área de trabajo, la creación de un recurso de proceso para ejecutar un trabajo de comando y la creación de un entorno para ejecutar el trabajo.

Conexión a un área de trabajo

En primer lugar, debe conectarse al área de trabajo de Azure Machine Learning. El área de trabajo de Azure Machine Learning es el recurso de nivel superior para el servicio. Proporciona un lugar centralizado para trabajar con todos los artefactos que cree al usar Azure Machine Learning.

Usaremos DefaultAzureCredential para obtener acceso al área de trabajo. Esta credencial es capaz de manejar la mayoría de los escenarios de autenticación del SDK de Azure.

Si DefaultAzureCredential no funciona, consulte azure-identity reference documentation o Set up authentication para obtener más credenciales disponibles.

# Handle to the workspace
from azure.ai.ml import MLClient

# Authentication package
from azure.identity import DefaultAzureCredential

credential = DefaultAzureCredential()

Si prefiere usar un explorador para iniciar sesión y autenticarse, debe quitar los comentarios en el código siguiente y usarlo en su lugar.

# Handle to the workspace
# from azure.ai.ml import MLClient

# Authentication package
# from azure.identity import InteractiveBrowserCredential
# credential = InteractiveBrowserCredential()

A continuación, obtenga un identificador para el área de trabajo proporcionando el identificador de suscripción, el nombre del grupo de recursos y el nombre del área de trabajo. Para buscar estos parámetros:

  1. Busque en la esquina superior derecha de la barra de herramientas del estudio de Azure Machine Learning el nombre del área de trabajo.
  2. Seleccione el nombre del área de trabajo para mostrar el identificador de suscripción y el grupo de recursos.
  3. Copie los valores del grupo de recursos y el identificador de suscripción en el código.
# Get a handle to the workspace
ml_client = MLClient(
    credential=credential,
    subscription_id="<SUBSCRIPTION_ID>",
    resource_group_name="<RESOURCE_GROUP>",
    workspace_name="<AML_WORKSPACE_NAME>",
)

El resultado de la ejecución de este script es un manipulador del área de trabajo que se utiliza para administrar otros recursos y trabajos.

Nota:

La creación de MLClient no conectará al cliente con el área de trabajo. La inicialización del cliente es lenta y esperará a la primera vez que necesite hacer una llamada. En este artículo, esto ocurrirá durante la creación del proceso.

Creación de un recurso de proceso

Azure Machine Learning necesita un recurso de proceso para ejecutar un trabajo. Este recurso puede ser máquinas de un solo nodo o de varios nodos con sistema operativo Linux o Windows, o un tejido de proceso específico, como Spark.

En el siguiente script de ejemplo, aprovisionamos un Linux compute cluster. Puede ver la página Azure Machine Learning pricing para ver la lista completa de tamaños y precios de máquina virtual. Solo necesitamos un clúster básico para este ejemplo; por lo tanto, elegiremos un modelo de Standard_DS3_v2 con 2 núcleos de vCPU y 7 GB de RAM para crear un proceso de Azure Machine Learning.

from azure.ai.ml.entities import AmlCompute

# Name assigned to the compute cluster
cpu_compute_target = "cpu-cluster"

try:
    # let's see if the compute target already exists
    cpu_cluster = ml_client.compute.get(cpu_compute_target)
    print(
        f"You already have a cluster named {cpu_compute_target}, we'll reuse it as is."
    )

except Exception:
    print("Creating a new cpu compute target...")

    # Let's create the Azure ML compute object with the intended parameters
    cpu_cluster = AmlCompute(
        name=cpu_compute_target,
        # Azure ML Compute is the on-demand VM service
        type="amlcompute",
        # VM Family
        size="STANDARD_DS3_V2",
        # Minimum running nodes when there is no job running
        min_instances=0,
        # Nodes in cluster
        max_instances=4,
        # How many seconds will the node running after the job termination
        idle_time_before_scale_down=180,
        # Dedicated or LowPriority. The latter is cheaper but there is a chance of job termination
        tier="Dedicated",
    )

    # Now, we pass the object to MLClient's create_or_update method
    cpu_cluster = ml_client.compute.begin_create_or_update(cpu_cluster).result()

print(
    f"AMLCompute with name {cpu_cluster.name} is created, the compute size is {cpu_cluster.size}"
)

Creación de un entorno de trabajo

Para ejecutar un trabajo de Azure Machine Learning, necesita un entorno. Un entorno de Azure Machine Learning encapsula las dependencias (como el tiempo de ejecución de software y las bibliotecas) necesarias para ejecutar el script de entrenamiento de aprendizaje automático en el recurso de proceso. Este entorno es similar a un entorno de Python en la máquina local.

Azure Machine Learning le permite usar un entorno mantenido (o listo) o crear un entorno personalizado mediante una imagen de Docker o una configuración de Conda. En este artículo, creará un entorno personalizado para sus trabajos, mediante un archivo YAML de Conda.

Creación de un entorno personalizado

Para crear el entorno personalizado, definirá las dependencias de Conda en un archivo YAML. En primer lugar, cree un directorio para almacenar el archivo. En este ejemplo, hemos nombrado el directorio env.

import os

dependencies_dir = "./env"
os.makedirs(dependencies_dir, exist_ok=True)

Después, cree el archivo en el directorio de dependencias. En este ejemplo, hemos nombrado el archivo conda.yml.

%%writefile {dependencies_dir}/conda.yaml
name: sklearn-env
channels:
  - conda-forge
dependencies:
  - python=3.8
  - pip=21.2.4
  - scikit-learn=0.24.2
  - scipy=1.7.1
  - pip:  
    - azureml-mlflow==1.42.0
    - mlflow-skinny==2.3.2

La especificación contiene algunos paquetes habituales (como numpy y pip) que utilizará en el trabajo.

A continuación, utilice el archivo YAML para crear y registrar este entorno personalizado en su área de trabajo. El entorno se empaquetará en un contenedor de Docker en tiempo de ejecución.

from azure.ai.ml.entities import Environment

custom_env_name = "sklearn-env"

job_env = Environment(
    name=custom_env_name,
    description="Custom environment for sklearn image classification",
    conda_file=os.path.join(dependencies_dir, "conda.yaml"),
    image="mcr.microsoft.com/azureml/openmpi4.1.0-ubuntu20.04:latest",
)
job_env = ml_client.environments.create_or_update(job_env)

print(
    f"Environment with name {job_env.name} is registered to workspace, the environment version is {job_env.version}"
)

Para más información sobre la creación y el uso de los entornos, consulte Creación y uso de entornos de software en Azure Machine Learning.

[Opcional] Creación de un entorno personalizado con la Extensión Intel® para Scikit-Learn

¿Quiere acelerar sus scripts de scikit-learn en hardware Intel? Pruebe a agregar la Extensión Intel® para Scikit-Learn en su archivo yaml de conda y siga los pasos posteriores detallados anteriormente. Le mostraremos cómo habilitar estas optimizaciones más adelante en este ejemplo:

%%writefile {dependencies_dir}/conda.yaml
name: sklearn-env
channels:
  - conda-forge
dependencies:
  - python=3.8
  - pip=21.2.4
  - scikit-learn=0.24.2
  - scikit-learn-intelex
  - scipy=1.7.1
  - pip:  
    - azureml-mlflow==1.42.0
    - mlflow-skinny==2.3.2

Configuración y envío del trabajo de entrenamiento

En esta sección, vamos a explicar cómo ejecutar un trabajo de entrenamiento mediante un script de entrenamiento que hemos proporcionado. Para empezar, compilará el trabajo de entrenamiento mediante la configuración del comando para ejecutar el script de entrenamiento. Después, enviará el trabajo de entrenamiento para que se ejecute en Azure Machine Learning.

Preparar el script de entrenamiento

En este artículo, hemos proporcionado el script de entrenamiento train_iris.py. En la práctica, debería poder usar cualquier script de entrenamiento personalizado tal cual y ejecutarlo con Azure Machine Learning sin tener que modificar el código.

Nota

El script de entrenamiento proporcionado realiza lo siguiente:

  • muestra cómo registrar algunas métricas en la ejecución de Azure Machine Learning;
  • descarga y extrae los datos de entrenamiento mediante iris = datasets.load_iris(); y
  • entrena un modelo y, a continuación, lo guarda y lo registra.

Para acceder a sus propios datos y usarlos, consulte Cómo leer y escribir datos en un trabajo para que los datos estén disponibles durante el entrenamiento.

Para usar el script de entrenamiento, cree primero un directorio donde almacenará el archivo.

import os

src_dir = "./src"
os.makedirs(src_dir, exist_ok=True)

A continuación, cree el archivo de script en el directorio de origen.

%%writefile {src_dir}/train_iris.py
# Modified from https://www.geeksforgeeks.org/multiclass-classification-using-scikit-learn/

import argparse
import os

# importing necessary libraries
import numpy as np

from sklearn import datasets
from sklearn.metrics import confusion_matrix
from sklearn.model_selection import train_test_split

import joblib

import mlflow
import mlflow.sklearn

def main():
    parser = argparse.ArgumentParser()

    parser.add_argument('--kernel', type=str, default='linear',
                        help='Kernel type to be used in the algorithm')
    parser.add_argument('--penalty', type=float, default=1.0,
                        help='Penalty parameter of the error term')

    # Start Logging
    mlflow.start_run()

    # enable autologging
    mlflow.sklearn.autolog()

    args = parser.parse_args()
    mlflow.log_param('Kernel type', str(args.kernel))
    mlflow.log_metric('Penalty', float(args.penalty))

    # loading the iris dataset
    iris = datasets.load_iris()

    # X -> features, y -> label
    X = iris.data
    y = iris.target

    # dividing X, y into train and test data
    X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)

    # training a linear SVM classifier
    from sklearn.svm import SVC
    svm_model_linear = SVC(kernel=args.kernel, C=args.penalty)
    svm_model_linear = svm_model_linear.fit(X_train, y_train)
    svm_predictions = svm_model_linear.predict(X_test)

    # model accuracy for X_test
    accuracy = svm_model_linear.score(X_test, y_test)
    print('Accuracy of SVM classifier on test set: {:.2f}'.format(accuracy))
    mlflow.log_metric('Accuracy', float(accuracy))
    # creating a confusion matrix
    cm = confusion_matrix(y_test, svm_predictions)
    print(cm)

    registered_model_name="sklearn-iris-flower-classify-model"

    ##########################
    #<save and register model>
    ##########################
    # Registering the model to the workspace
    print("Registering the model via MLFlow")
    mlflow.sklearn.log_model(
        sk_model=svm_model_linear,
        registered_model_name=registered_model_name,
        artifact_path=registered_model_name
    )

    # # Saving the model to a file
    print("Saving the model via MLFlow")
    mlflow.sklearn.save_model(
        sk_model=svm_model_linear,
        path=os.path.join(registered_model_name, "trained_model"),
    )
    ###########################
    #</save and register model>
    ###########################
    mlflow.end_run()

if __name__ == '__main__':
    main()

[Opcional] Habilitación de la Extensión Intel® para optimizaciones de Scikit-Learn para obtener más rendimiento en hardware Intel

Si ha instalado la Extensión Intel® para Scikit-Learn (como se muestra en la sección anterior), puede habilitar las optimizaciones de rendimiento agregando las dos líneas de código a la parte superior del archivo de script, como se muestra a continuación.

Para obtener más información sobre la Extensión Intel® para Scikit-Learn, visite la documentación de del paquete.

%%writefile {src_dir}/train_iris.py
# Modified from https://www.geeksforgeeks.org/multiclass-classification-using-scikit-learn/

import argparse
import os

# Import and enable Intel Extension for Scikit-learn optimizations
# where possible

from sklearnex import patch_sklearn
patch_sklearn()

# importing necessary libraries
import numpy as np


from sklearn import datasets
from sklearn.metrics import confusion_matrix
from sklearn.model_selection import train_test_split

import joblib

import mlflow
import mlflow.sklearn

def main():
    parser = argparse.ArgumentParser()

    parser.add_argument('--kernel', type=str, default='linear',
                        help='Kernel type to be used in the algorithm')
    parser.add_argument('--penalty', type=float, default=1.0,
                        help='Penalty parameter of the error term')

    # Start Logging
    mlflow.start_run()

    # enable autologging
    mlflow.sklearn.autolog()

    args = parser.parse_args()
    mlflow.log_param('Kernel type', str(args.kernel))
    mlflow.log_metric('Penalty', float(args.penalty))

    # loading the iris dataset
    iris = datasets.load_iris()

    # X -> features, y -> label
    X = iris.data
    y = iris.target

    # dividing X, y into train and test data
    X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)

    # training a linear SVM classifier
    from sklearn.svm import SVC
    svm_model_linear = SVC(kernel=args.kernel, C=args.penalty)
    svm_model_linear = svm_model_linear.fit(X_train, y_train)
    svm_predictions = svm_model_linear.predict(X_test)

    # model accuracy for X_test
    accuracy = svm_model_linear.score(X_test, y_test)
    print('Accuracy of SVM classifier on test set: {:.2f}'.format(accuracy))
    mlflow.log_metric('Accuracy', float(accuracy))
    # creating a confusion matrix
    cm = confusion_matrix(y_test, svm_predictions)
    print(cm)

    registered_model_name="sklearn-iris-flower-classify-model"

    ##########################
    #<save and register model>
    ##########################
    # Registering the model to the workspace
    print("Registering the model via MLFlow")
    mlflow.sklearn.log_model(
        sk_model=svm_model_linear,
        registered_model_name=registered_model_name,
        artifact_path=registered_model_name
    )

    # # Saving the model to a file
    print("Saving the model via MLFlow")
    mlflow.sklearn.save_model(
        sk_model=svm_model_linear,
        path=os.path.join(registered_model_name, "trained_model"),
    )
    ###########################
    #</save and register model>
    ###########################
    mlflow.end_run()

if __name__ == '__main__':
    main()

Compilación del trabajo de entrenamiento

Ahora que tiene todos los recursos necesarios para ejecutar el trabajo, es el momento de compilar mediante el SDK de Python v2 de Azure Machine Learning. Para ejecutar el trabajo, creamos un command.

Un command de Azure Machine Learning es un recurso que especifica todos los detalles necesarios para ejecutar el código de entrenamiento en la nube. Estos detalles incluyen las entradas y salidas, el tipo de hardware que se va a usar, el software que se va a instalar y cómo ejecutar el código. command contiene información para ejecutar un único comando.

Configuración del comando

Usará el command de uso general para ejecutar el script de entrenamiento y realizar las tareas deseadas. Cree un objeto Command para especificar los detalles de configuración del trabajo de entrenamiento.

  • Las entradas de este comando incluyen el número de épocas, velocidad de aprendizaje, impulso y directorio de salida.
  • Para los valores de parámetro:
    • proporcione el clúster de proceso cpu_compute_target = "cpu-cluster" que creó para ejecutar este comando;
    • Proporcione el entorno sklearn-env personalizado que creó para ejecutar el trabajo de Azure Machine Learning;
    • configurar la acción de la línea de comandos en sí, en este caso, el comando es python train_iris.py. Puede acceder a las entradas y salidas en el comando a través de la notación ${{ ... }}; y
    • configure los metadatos, como el nombre para mostrar y el nombre del experimento; donde un experimento es un contenedor para todas las iteraciones que se realiza en un proyecto determinado. Todos los trabajos enviados en el mismo nombre de experimento se enumerarán de manera correlativa en Estudio de Azure Machine Learning.
from azure.ai.ml import command
from azure.ai.ml import Input

job = command(
    inputs=dict(kernel="linear", penalty=1.0),
    compute=cpu_compute_target,
    environment=f"{job_env.name}:{job_env.version}",
    code="./src/",
    command="python train_iris.py --kernel ${{inputs.kernel}} --penalty ${{inputs.penalty}}",
    experiment_name="sklearn-iris-flowers",
    display_name="sklearn-classify-iris-flower-images",
)

Enviar el archivo

Ahora es el momento de enviar el trabajo para que se ejecute en Azure Machine Learning. Esta vez se usa create_or_update en ml_client.jobs.

ml_client.jobs.create_or_update(job)

Una vez completado, el trabajo registra un modelo en el área de trabajo (como resultado del entrenamiento) y genera un vínculo para ver el trabajo en Estudio de Azure Machine Learning.

Advertencia

Azure Machine Learning ejecuta scripts de entrenamiento mediante la copia de todo el directorio de origen. Si tiene información confidencial que no quiere cargar, use un archivo .ignore o no la incluya en el directorio de origen.

¿Qué ocurre durante la ejecución del trabajo?

Durante la ejecución del trabajo, este pasa por las fases siguientes:

  • Preparando: se crea una imagen de Docker según el entorno definido. La imagen se carga en el registro de contenedor del área de trabajo y se almacena en memoria caché para ejecuciones posteriores. Los registros también se transmiten al historial de ejecución y se pueden consultar para supervisar el progreso. Si se especifica un entorno mantenido, se usa la imagen almacenada en caché que respalda el entorno mantenido.

  • Escalado: el clúster intenta escalar verticalmente si el clúster requiere más nodos para ejecutar la ejecución de los que están disponibles actualmente.

  • Ejecución: todos los scripts de la carpeta de scripts src se cargan en el objetivo de proceso, se montan o copian los almacenes de datos y se ejecuta el script. Las salidas de stdout y la carpeta ./logs se transmiten al historial de ejecución y se pueden usar para supervisar la ejecución.

Optimizar los hiperparámetros del modelo

Ahora que ha visto cómo realizar una ejecución de entrenamiento simple de Scikit-learn mediante el SDK, veamos si puede mejorar aún más la precisión del modelo. Puede ajustar y optimizar los hiperparámetros del modelo mediante las funcionalidades de sweep Azure Machine Learning.

Para ajustar los hiperparámetros del modelo, defina el espacio de parámetros en el que se va a buscar durante el entrenamiento. Para ello, reemplace algunos de los parámetros (kernel y penalty) pasados al trabajo de entrenamiento con entradas especiales del paquete azure.ml.sweep.

from azure.ai.ml.sweep import Choice

# we will reuse the command_job created before. we call it as a function so that we can apply inputs
# we do not apply the 'iris_csv' input again -- we will just use what was already defined earlier
job_for_sweep = job(
    kernel=Choice(values=["linear", "rbf", "poly", "sigmoid"]),
    penalty=Choice(values=[0.5, 1, 1.5]),
)

Después, configurará el barrido en el trabajo de comando con algunos parámetros específicos del barrido, como la métrica principal para inspeccionar y el algoritmo de muestreo que se va a usar.

En el código siguiente se usa el muestreo aleatorio para probar diferentes conjuntos de configuración de hiperparámetros en un intento de maximizar la métrica principal, Accuracy.

sweep_job = job_for_sweep.sweep(
    compute="cpu-cluster",
    sampling_algorithm="random",
    primary_metric="Accuracy",
    goal="Maximize",
    max_total_trials=12,
    max_concurrent_trials=4,
)

Ahora, puede enviar este trabajo como antes. Esta vez, va a ejecutar un trabajo de barrido que barrerá el trabajo de entrenamiento.

returned_sweep_job = ml_client.create_or_update(sweep_job)

# stream the output and wait until the job is finished
ml_client.jobs.stream(returned_sweep_job.name)

# refresh the latest status of the job after streaming
returned_sweep_job = ml_client.jobs.get(name=returned_sweep_job.name)

Puede supervisar el trabajo mediante el vínculo de la interfaz de usuario de Studio que se presenta durante la ejecución del trabajo.

Búsqueda y registro del mejor modelo

Una vez completadas todas las ejecuciones, puede encontrar la ejecución que generó el modelo con la mayor precisión.

from azure.ai.ml.entities import Model

if returned_sweep_job.status == "Completed":

    # First let us get the run which gave us the best result
    best_run = returned_sweep_job.properties["best_child_run_id"]

    # lets get the model from this run
    model = Model(
        # the script stores the model as "sklearn-iris-flower-classify-model"
        path="azureml://jobs/{}/outputs/artifacts/paths/sklearn-iris-flower-classify-model/".format(
            best_run
        ),
        name="run-model-example",
        description="Model created from run.",
        type="custom_model",
    )

else:
    print(
        "Sweep job status: {}. Please wait until it completes".format(
            returned_sweep_job.status
        )
    )

A continuación, puede registrar este modelo.

registered_model = ml_client.models.create_or_update(model=model)

Implementación del modelo

Después de registrar el modelo, puede implementarlo de la misma manera que cualquier otro modelo registrado en Azure Machine Learning. Para más información sobre la implementación, consulte Implementación y puntuación de un modelo de Machine Learning con un punto de conexión en línea administrado mediante el SDK de Python v2.

Pasos siguientes

En este artículo, ha entrenado y registrado un modelo scikit-learn, y ha aprendido sobre las opciones de implementación. Consulte estos otros artículos para más información sobre Azure Machine Learning.