Entrega modelos de AA de Spark con Vertex AI

Last reviewed 2023-07-11 UTC

Los científicos de datos y los ingenieros de aprendizaje automático (AA) suelen requerir una arquitectura de entrega que sea lo suficientemente rápida para satisfacer las necesidades de generar predicciones en línea (o en tiempo real) a partir de sus modelos de AA. Vertex AI puede satisfacer esta necesidad.

Con Vertex AI, puedes entregar modelos desde una variedad de frameworks de AA. Para frameworks como TensorFlow, PyTorch, XGBoost y scikit-learn, Vertex AI proporciona contenedores precompilados en los que ejecutar esos modelos de AA. Si aún no usas ninguno de esos frameworks de AA, deberás crear tu propio contenedor personalizado para que lo use Vertex AI.

Este documento está dirigido a los usuarios que necesitan crear un contenedor personalizado para entregar sus modelos de AA de Spark. En este documento, se incluye una descripción de la arquitectura de entrega necesaria para contenedores personalizados y una implementación de referencia que demuestra esta arquitectura para un modelo de MLlib de Spark.

Para aprovechar al máximo la parte de implementación de referencia de este documento, debes estar familiarizado con la exportación de modelos de MLlib de Spark al formato MLeap, además de comprender cómo usar Vertex AI para entregar predicciones y tener experiencia con imágenes de contenedor.

Arquitectura

Si bien los contenedores compilados previamente están disponibles para algunos frameworks de AA, los usuarios de otros frameworks de AA, como Spark, necesitan compilar contenedores personalizados en los que Vertex AI puede ejecutar predicciones. En el siguiente diagrama, se ilustra la arquitectura de entrega que necesitas para entregar modelos de Spark MLlib y otros modelos que requieren un contenedor personalizado:

La arquitectura de entrega para el modelo que se usa en el documento.

Esta arquitectura incluye los siguientes componentes:

  • Cloud Storage: proporciona almacenamiento para los artefactos del modelo necesarios a fin de ejecutar tu modelo. Para el modelo de AA de Spark que se usa en la implementación de referencia, los artefactos del modelo constan de un paquete MLeap y un esquema de modelo.
  • Cloud Build: usa la imagen del compilador para compilar una imagen de contenedor personalizada llamada imagen de contenedor de entrega. El proceso de compilación compila y empaqueta el código de entrega del modelo, compila la imagen de contenedor de entrega y, luego, la envía a Artifact Registry.
  • Artifact Registry: contiene los siguientes objetos:
    • La imagen de contenedor del compilador scala-sbt que usa Cloud Build para compilar la imagen del contenedor de entrega.
    • La imagen del contenedor de entrega que compila Cloud Build.
  • Vertex AI: contiene el modelo de AA que se subió desde Cloud Storage. El modelo importado se configura con la ubicación de los artefactos del modelo dentro de Cloud Storage y la ubicación de la imagen del contenedor de entrega dentro de Artifact Registry. Vertex AI también incluye un extremo en el que se implementó el modelo. Cuando el modelo se implementa en el extremo, Vertex AI asocia los recursos físicos con el modelo para que el modelo pueda entregar predicciones en línea.

Como parte de la implementación de esta arquitectura de entrega, deberás exportar el modelo de AA para que lo usen otras aplicaciones y definir tu propia imagen de contenedor de entrega. La implementación de referencia proporcionada en este documento proporciona el código que se usa para definir y compilar la imagen del contenedor de entrega. Este código también incluye los artefactos del modelo para un modelo de AA de Spark exportado con anterioridad. Con algunos cambios de configuración, podrías usar esta implementación de referencia para entregar tus propios modelos de AA de Spark.

Sin embargo, puedes implementar esta arquitectura de entrega por tu cuenta y no usar la implementación de referencia. Si decides implementar tu propia arquitectura, deberás hacer lo siguiente:

  • Exporta tu modelo para que otras aplicaciones puedan usarlo. Este proceso depende de los frameworks y las herramientas del AA que uses. Por ejemplo, puedes elegir exportar tus modelos de Spark MLlib si creas un paquete MLeap como se describe en la implementación de referencia. Puedes ver otros ejemplos de cómo exportar modelos en Exporta artefactos de modelo para la predicción.
  • Diseña la imagen de contenedor de entrega para que cumpla con los requisitos de contenedor personalizados que hacen que esa imagen sea compatible con Vertex AI. El código puede estar en el lenguaje de programación que elijas.
  • Empaqueta el código en un formato de archivo de paquete compatible con el lenguaje de programación que usaste. Por ejemplo, puedes usar un archivo JAR para el código de Java o una rueda de Python para el código de Python.
  • Crea una imagen de contenedor personalizada que pueda entregar el código de modo personalizado.

Implementación de referencia

En la siguiente implementación de referencia, se entrega un modelo de Spark MLlib que predice las especies de iris según la longitud y el ancho de los sépalos y pétalos de la flor.

Puedes encontrar el modelo que se usa en esta implementación en el directorio example_model en el repositorio vertex-ai-spark-ml-serving.git. El directorio contiene los artefactos del modelo que usa el contenedor de entrega para ejecutar predicciones y, además, incluye los siguientes archivos:

  • El archivo example_model/model.zip es un modelo de regresión logística que se compiló mediante Spark MLlib, se entrenó con el conjunto de datos Iris y se convirtió en un paquete MLeap. El modelo predice la especies de una flor de iris mediante el largo y el ancho de los sepales y pétalos de la flores.
  • El archivo example_model/schema.json es un archivo JSON que describe el esquema del modelo. En el esquema del modelo, se describen los campos de entrada esperados para las instancias de predicción y los campos de salida para los resultados de predicción necesarios para el esquema de MLeap.

Usa tu propio modelo de MLlib

Para usar tu propio modelo con esta implementación de referencia, primero asegúrate de que tu modelo de Spark MLlib se haya exportado a un paquete MLeap. Luego, para entregar tu modelo de Spark MLlib, debes proporcionar los artefactos del modelo adecuados: el paquete MLeap y el esquema del modelo.

Paquete MLeap

El contenedor de entrega determina la ubicación del paquete MLeap mediante la variable de entorno AIP_STORAGE_URI que se pasa de Vertex AI al contenedor durante el inicio. El valor de la variable AIP_STORAGE_URI se especifica cuando subes el modelo a Vertex AI.

Esquema del modelo

El esquema del modelo describe los atributos de entrada y el resultado de predicción de un modelo. El esquema del modelo se representa con datos JSON. El siguiente es el esquema que se usa en esta implementación de referencia para predecir las especies de iris según la longitud de la flor y el ancho de sus sépalos y pétalos:

{
  "input": [
    {
      "name": "sepal_length",
      "type": "FLOAT"
    },
    {
      "name": "sepal_width",
      "type": "FLOAT"
    },
    {
      "name": "petal_length",
      "type": "FLOAT"
    },
    {
      "name": "petal_width",
      "type": "FLOAT"
    }
  ],
  "output": [
    {
      "name": "probability",
      "type": "DOUBLE",
      "struct": "VECTOR"
    }
  ]
}

En el esquema de ejemplo, el array input contiene los campos de entrada (columnas) para el modelo, mientras que el array output contiene los campos de salida (columnas) que se mostrarán desde el modelo. En ambos arrays, cada objeto del array contiene las siguientes propiedades:

  • name: el nombre del campo (columna).
  • type: el tipo de campo (columna). Dentro de los tipos válidos, se incluyen BOOLEAN, BYTE, DOUBLE, FLOAT, INTEGER, LONG, SHORT y STRING.
  • struct: la estructura del campo, como un escalar o array (opcional). Las estructuras válidas incluyen BASIC (tipo escalar), ARRAY (Spark Array) y VECTOR (Spark DenseVector). BASIC se usa si el campo struct no está presente.

Para pasar tu esquema del modelo al contenedor de entrega, puedes usar uno de los siguientes métodos:

  • Especifica los datos JSON que definen el esquema en la variable de entorno MLEAP_SCHEMA. La variable de entorno MLEAP_SCHEMA debe contener los datos JSON en sí y no una ruta de acceso a un archivo que contiene el esquema JSON.
  • Almacena los datos JSON en un archivo llamado schema.json y haz que este archivo esté disponible para el contenedor en ${AIP_STORAGE_URI}/schema.json. Este es el método que se usa para el modelo de MLlib de ejemplo que se proporciona en esta documentación.

Si usas ambos métodos para pasar el esquema del modelo al contenedor de entrega, los datos JSON que se almacenan en la variable de entorno MLEAP_SCHEMA tienen prioridad.

Costos

En esta implementación de referencia, se usan los siguientes componentes facturables de Google Cloud:

Para generar una estimación de costos en función del uso previsto, usa la calculadora de precios.

Cuando finalices esta implementación de referencia, puedes borrar los recursos que creaste para evitar que se te siga facturando. Para obtener más información, consulta Cómo realizar una limpieza.

Antes de comenzar

  1. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Go to project selector

  2. Make sure that billing is enabled for your Google Cloud project.

  3. Enable the Vertex AI, Cloud Build, Cloud Storage, and Artifact Registry APIs.

    Enable the APIs

  4. In the Google Cloud console, activate Cloud Shell.

    Activate Cloud Shell

  5. Busca el ID del proyecto y establécelo en Cloud Shell.
    export PROJECT_ID=YOUR_PROJECT_ID
    gcloud config set project ${PROJECT_ID}
    

    Reemplaza YOUR_PROJECT_ID con el ID del proyecto.

Crea la imagen de compilador de scala-sbt

Usa Cloud Build con el constructor de la comunidad scala-sbt para compilar la imagen del contenedor de entrega. Este proceso de compilación depende de tener la imagen del compilador sbt-scala en el Container Registry de tu proyecto.

  1. En Cloud Shell, clona el repositorio cloud-builders-community.

    git clone https://github.com/GoogleCloudPlatform/cloud-builders-community.git
    
  2. Ve al directorio del proyecto:

    cd cloud-builders-community/scala-sbt
    
  3. Compila la imagen del compilador scala-sbt y envíala a Container Registry:

    gcloud builds submit .
    

Compila la imagen del contenedor de entrega

Vertex AI usa el contenedor de entrega a fin de ejecutar solicitudes de predicción para el modelo de ejemplo. El primer paso para compilar la imagen del contenedor de entrega es crear un repositorio de Docker en Artifact Registry en el que se almacenará la imagen. Luego, debes otorgar a Vertex AI permiso para extraer la imagen del contenedor de entrega del repositorio. Después de crear el repositorio y otorgar permisos, puedes compilar la imagen de contenedor de entrega y enviarla a Artifact Registry.

  1. En Cloud Shell, crea un repositorio de Docker en Artifact Registry:

    REPOSITORY="vertex-ai-prediction"
    LOCATION="us-central1"
    
    gcloud artifacts repositories create $REPOSITORY \
        --repository-format=docker \
        --location=$LOCATION
    
  2. Otorga el rol de lector de Artifact Registry al agente de servicio de Vertex AI:

    PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID \
        --format="value(projectNumber)")
    SERVICE_ACCOUNT="service-$PROJECT_NUMBER@gcp-sa-aiplatform.iam.gserviceaccount.com"
    
    gcloud projects add-iam-policy-binding $PROJECT_ID \
        --member="serviceAccount:$SERVICE_ACCOUNT" \
        --role="roles/artifactregistry.reader"
    
  3. Clona el repositorio spark-ml-serving:

    git clone https://github.com/GoogleCloudPlatform/vertex-ai-spark-ml-serving.git
    
  4. Ve al directorio del proyecto:

    cd vertex-ai-spark-ml-serving
    
  5. Compila la imagen del contenedor de entrega en tu proyecto:

    IMAGE=spark-ml-serving
    
    gcloud builds submit --config=cloudbuild.yaml \
        --substitutions="_LOCATION=$LOCATION,_REPOSITORY=$REPOSITORY,_IMAGE=$IMAGE" .
    

    El archivo cloudbuild.yaml especifica dos compiladores: el compilador scala-sbt y el compilador de imágenes docker. Cloud Build usa el compilador scala-sbt para compilar el código de entrega del modelo desde Cloud Storage y, luego, empaquetar el código compilado en un archivo JAR ejecutable. Cloud Build usa el compilador docker para compilar la imagen de contenedor de entrega que contiene el archivo JAR. Una vez que se compila la imagen del contenedor de entrega, se envía a Artifact Registry.

Importa el modelo a Vertex AI

El contenedor de entrega lee los artefactos del modelo de Cloud Storage. Debes crear una ubicación de almacenamiento para estos artefactos antes de importar el modelo a Vertex AI. Cuando importes el modelo, necesitarás la ubicación de almacenamiento del artefacto del modelo y la imagen del contenedor de entrega en Artifact Registry.

  1. En Cloud Shell, crea un bucket para los artefactos del modelo:

    REGION="us-central1"
    BUCKET="YOUR_BUCKET_NAME"
    gsutil mb -l $REGION gs://$BUCKET
    

    Reemplaza YOUR_BUCKET_NAME con el nombre de tu bucket:

  2. Copia los artefactos del modelo en el bucket:

    gsutil cp example_model/* gs://$BUCKET/example_model/
    
  3. Importa el modelo a Vertex AI:

    DISPLAY_NAME="iris-$(date +'%Y%m%d%H%M%S')"
    IMAGE_URI="${LOCATION}-docker.pkg.dev/$PROJECT_ID/${REPOSITORY}/${IMAGE}"
    ARTIFACT_URI="gs://$BUCKET/example_model/"
    
    gcloud ai models upload \
        --region=$REGION \
        --display-name=$DISPLAY_NAME \
        --container-image-uri=$IMAGE_URI \
        --artifact-uri=$ARTIFACT_URI \
        --container-health-route="/health" \
        --container-predict-route="/predict"
    

    En el comando gcloud ai models upload, el valor del parámetro --artifact-uri especifica el valor de la variable AIP_STORAGE_URI. Esta variable proporciona la ubicación del paquete MLeap que se importa a Vertex AI.

Implementa el modelo en un extremo nuevo

Para que Vertex AI ejecute predicciones, el modelo importado debe implementarse en un extremo. Necesitarás el ID del extremo y el ID del modelo cuando implementes el modelo.

  1. En Cloud Shell, crea el extremo del modelo:

    gcloud ai endpoints create \
        --region=$REGION \
        --display-name=$DISPLAY_NAME
    

    La herramienta de línea de comandos de gcloud podría tardar unos segundos en crear el extremo.

  2. Obtén el ID del extremo recién creado:

    ENDPOINT_ID=$(gcloud ai endpoints list \
        --region=$REGION \
        --filter=display_name=$DISPLAY_NAME \
        --format='value(name)')
    
    # Print ENDPOINT_ID to the console
    echo "Your endpoint ID is: $ENDPOINT_ID"
    
  3. Obtén el ID del modelo que importaste en la sección Importa el modelo a Vertex AI:

    MODEL_ID=$(gcloud ai models list \
        --region=$REGION \
        --filter=display_name=$DISPLAY_NAME \
        --format='value(name)')
    
    # Print MODEL_ID to the console
    echo "Your model ID is: $MODEL_ID"
    
  4. Implementa el modelo en el extremo:

    gcloud ai endpoints deploy-model $ENDPOINT_ID \
        --region=$REGION \
        --model=$MODEL_ID \
        --display-name=$DISPLAY_NAME \
        --traffic-split="0=100"
    

    El comando gcloud implementa el modelo en el extremo. Los valores predeterminados se usan para el tipo de recurso de máquina, la cantidad mínima y máxima de nodos y otras opciones de configuración. Si deseas obtener más información sobre las opciones de implementación para modelos, consulta la documentación de Vertex AI.

Prueba el extremo

Después de implementar el modelo en el extremo, puedes probar tu implementación. Para probar el extremo, puedes usar el cliente de ejemplo que se incluye en el código de implementación de referencia. El cliente de ejemplo genera instancias de predicción y envía solicitudes de predicción al extremo. Cada instancia de predicción contiene valores aleatorios para sepal_length, sepal_width, petal_length y petal_width. De forma predeterminada, el cliente de ejemplo combina varias instancias de predicción en una sola solicitud. La respuesta del extremo incluye una predicción para cada instancia que se envía en la solicitud. La predicción contiene las probabilidades para cada clase en el conjunto de datos Iris (setosa, versicolor y virginica).

  • En Cloud Shell, ejecuta el cliente de predicción de ejemplo:

    cd example_client
    ./run_client.sh --project $PROJECT_ID \
        --location $LOCATION \
        --endpoint $ENDPOINT_ID
    

    Cuando ejecutas la secuencia de comandos por primera vez, esta crea un entorno virtual de Python y, luego, instala las dependencias. Después de instalar las dependencias, la secuencia de comandos ejecuta el cliente de ejemplo. Para cada solicitud, el cliente imprime las instancias de predicción y las probabilidades de clase correspondientes en la terminal. A continuación, se muestra un extracto del resultado:

    Sending 10 asynchronous prediction requests with 3 instances per request ...
    
    ==> Response from request #10:
    
    Instance 1:     sepal_length:   5.925825137450266
                    sepal_width:    4.5047557888651
                    petal_length:   1.0432434310300223
                    petal_width:    0.5050397721287457
    
    Prediction 1:   setosa:         0.2036041134824573
                    versicolor:     0.6062980065549213
                    virginica:      0.1900978799626214
    
    Instance 2:     sepal_length:   6.121228622484405
                    sepal_width:    3.406317728235072
                    petal_length:   3.178583759980504
                    petal_width:    2.815141143581328
    
    Prediction 2:   setosa:         0.471811302254083
                    versicolor:     0.2063720436033448
                    virginica:      0.3218166541425723
    
    Instance 3:     sepal_length:   7.005781590327274
                    sepal_width:    2.532116893508745
                    petal_length:   2.6351337947193474
                    petal_width:    2.270855223519198
    
    Prediction 3:   setosa:         0.453579051699638
                    versicolor:     0.2132869980698818
                    virginica:      0.3331339502304803
    

Limpia

Para evitar que se apliquen cargos a tu cuenta de Google Cloud por los recursos usados en esta implementación de referencia, borra el proyecto que contiene los recursos o conserva el proyecto y borra los recursos individuales.

Borra el proyecto

  1. In the Google Cloud console, go to the Manage resources page.

    Go to Manage resources

  2. In the project list, select the project that you want to delete, and then click Delete.
  3. In the dialog, type the project ID, and then click Shut down to delete the project.

Borra los recursos individuales

  1. En Cloud Shell, anula la implementación del modelo en el extremo:

    DEPLOYED_MODEL_ID=$(gcloud ai endpoints describe $ENDPOINT_ID \
        --region=$REGION \
        --format='value(deployedModels.id)')
    
    gcloud ai endpoints undeploy-model $ENDPOINT_ID \
        --region=$REGION \
        --deployed-model-id=$DEPLOYED_MODEL_ID
    
  2. Borra el extremo:

    gcloud ai endpoints delete $ENDPOINT_ID \
        --region=$REGION \
        --quiet
    
  3. Borra el modelo:

    gcloud ai models delete $MODEL_ID \
        --region=$REGION
    
  4. Borra la imagen del contenedor de entrega:

    gcloud artifacts docker images delete \
        $LOCATION-docker.pkg.dev/$PROJECT_ID/$REPOSITORY/$IMAGE \
        --delete-tags \
        --quiet
    
  5. Borra el contenedor del compilador scala-sbt:

    gcloud container images delete gcr.io/$PROJECT_ID/scala-sbt \
        --force-delete-tags \
        --quiet
    
  6. Borra los buckets de Cloud Storage que ya no sean necesarios:

    gsutil rm -r YOUR_BUCKET_NAME
    

    Si se borra un bucket, también se borran todos los objetos almacenados en él. Los buckets y objetos borrados no se pueden recuperar después de borrarse.

¿Qué sigue?