Compartir a través de


Configuración e implementación de un clúster de Ray en Azure Kubernetes Service (AKS)

En este artículo, configurará e implementará un clúster de Ray en Azure Kubernetes Service (AKS) mediante KubeRay. También aprenderá a usar el clúster de Ray para entrenar un modelo de aprendizaje automático sencillo y mostrar los resultados en el panel de Ray.

En este artículo se proporcionan dos métodos para implementar el clúster de Ray en AKS:

  • Implementación no interactiva: use el deploy.sh script en el repositorio de GitHub para implementar el ejemplo completo de Ray de forma no interactiva.
  • Implementación manual: siga los pasos de implementación manuales para implementar el ejemplo de Ray en AKS.

Requisitos previos

Implementación del ejemplo de Ray de forma no interactiva

Si desea implementar el ejemplo completo de Ray de forma no interactiva, puede usar el script deploy.sh en el repositorio de GitHub (https://github.com/Azure-Samples/aks-ray-sample). Este script completa los pasos descritos en la Sección proceso de implementación de Ray.

  1. Clone el repositorio de GitHub localmente y cambie a la raíz del repositorio mediante los siguientes comandos:

    git clone https://github.com/Azure-Samples/aks-ray-sample
    cd aks-ray-sample
    
  2. Implemente el ejemplo completo con los siguientes comandos:

    chmod +x deploy.sh
    ./deploy.sh
    
  3. Una vez completada la implementación, revise la salida de los registros y el grupo de recursos en Azure Portal para ver la infraestructura que se creó.

Implementación manual del ejemplo de Ray

Fashion MNIST es un conjunto de datos de las imágenes de artículo de Zalando que constan de un conjunto de entrenamiento de 60 000 ejemplos y un conjunto de pruebas de 10 000 ejemplos. Cada ejemplo es una imagen de escala de grises de 28x28 asociada a una etiqueta de diez clases. En esta guía, entrenará un modelo de PyTorch simple en este conjunto de datos mediante el clúster de Ray.

Implementación de la especificación de RayJob

Para entrenar el modelo, debe enviar una especificación de trabajo de Ray al operador KubeRay que se ejecuta en un clúster de AKS privado. La especificación de trabajo de Ray es un archivo YAML que describe los recursos necesarios para ejecutar el trabajo, incluida la imagen de Docker, el comando que se va a ejecutar y el número de trabajos que se van a usar.

Al examinar la descripción del trabajo de Ray, es posible que tenga que modificar algunos campos para que coincidan con el entorno:

  • El campo replicas en la sección workerGroupSpecs de rayClusterSpec especifica el número de pods de trabajo que KubeRay programa en el clúster de Kubernetes. Cada pod de trabajo requiere 3 CPU y 4 GB de memoria. El pod principal requiere 1 CPU y 4 GB de memoria. Establecer el campo replicas en 2 requiere 8 vCPUs en el grupo de nodos usado para implementar RayCluster para el trabajo.
  • El campo NUM_WORKERS situado runtimeEnvYAML en spec especifica el número de actores de Ray que se van a iniciar. Un pod de trabajo debe atender a cada actor de Ray en el clúster de Kubernetes, por lo que este campo debe ser menor o igual que el campo replicas. En este ejemplo, se establece NUM_WORKERS en 2, que coincide con el campo replicas.
  • El campo CPUS_PER_WORKER debe establecerse en menor o igual que el número de CPU asignadas a cada pod de trabajo menos 1. En este ejemplo, la solicitud de recursos de CPU por pod de trabajo es 3, por lo que CPUS_PER_WORKER se establece en 2.

En resumen, necesita un total de 8 vCPUs en el grupo de nodos para ejecutar el trabajo de entrenamiento del modelo de PyTorch. Puesto que hemos agregado un taint en el grupo de nodos del sistema para que no se pueda programar ningún pod de usuario en él, debemos crear un nuevo grupo de nodos con al menos 8 vCPUs para hospedar el clúster de Ray.

  1. Descargue el archivo de especificación de trabajo de Ray mediante el siguiente comando:

    curl -LO https://raw.githubusercontent.com/ray-project/kuberay/master/ray-operator/config/samples/pytorch-mnist/ray-job.pytorch-mnist.yaml
    
  2. Realice las modificaciones necesarias en el archivo de especificación del trabajo de Ray.

  3. Inicie el trabajo de entrenamiento del modelo de PyTorch mediante el comando kubectl apply.

    kubectl apply -n kuberay -f ray-job.pytorch-mnist.yaml
    

Comprobación de la implementación de RayJob

  1. Compruebe que tiene dos pods de trabajo y un pod principal que se ejecuta en el espacio de nombres mediante el comando kubectl get pods.

    kubectl get pods -n kuberay
    

    El resultado debería ser similar al ejemplo siguiente:

    NAME                                                      READY   STATUS    RESTARTS   AGE
    kuberay-operator-7d7998bcdb-9h8hx                         1/1     Running   0          3d2h
    pytorch-mnist-raycluster-s7xd9-worker-small-group-knpgl   1/1     Running   0          6m15s
    pytorch-mnist-raycluster-s7xd9-worker-small-group-p74cm   1/1     Running   0          6m15s
    rayjob-pytorch-mnist-fc959                                1/1     Running   0          5m35s
    rayjob-pytorch-mnist-raycluster-s7xd9-head-l24hn          1/1     Running   0          6m15s
    
  2. Compruebe el estado de RayJob mediante el comando kubectl get.

    kubectl get rayjob -n kuberay
    

    El resultado debería ser similar al ejemplo siguiente:

    NAME                   JOB STATUS   DEPLOYMENT STATUS   START TIME             END TIME   AGE
    rayjob-pytorch-mnist   RUNNING      Running             2024-11-22T03:08:22Z              9m36s
    
  3. Espere hasta que finalice RayJob. Esto puede tardar unos minutos. Una vez que JOB STATUS es SUCCEEDED, puede comprobar los registros de entrenamiento. Para ello, obtenga primero el nombre del pod que ejecuta RayJob mediante el comando kubectl get pods.

    kubectl get pods -n kuberay
    

    En la salida, debería ver un pod con un nombre que comience por rayjob-pytorch-mnist, similar al siguiente resultado de ejemplo:

    NAME                                                      READY   STATUS      RESTARTS   AGE
    kuberay-operator-7d7998bcdb-9h8hx                         1/1     Running     0          3d2h
    pytorch-mnist-raycluster-s7xd9-worker-small-group-knpgl   1/1     Running     0          14m
    pytorch-mnist-raycluster-s7xd9-worker-small-group-p74cm   1/1     Running     0          14m
    rayjob-pytorch-mnist-fc959                                0/1     Completed   0          13m
    rayjob-pytorch-mnist-raycluster-s7xd9-head-l24hn          1/1     Running     0          14m
    
  4. Vea los registros de RayJob mediante el comando kubectl logs. Asegúrese de reemplazar rayjob-pytorch-mnist-fc959 por el nombre del pod que ejecuta RayJob.

    kubectl logs -n kuberay rayjob-pytorch-mnist-fc959
    

    En la salida, debería ver los registros de entrenamiento para el modelo de PyTorch, de forma similar a la salida del ejemplo siguiente:

    2024-11-21 19:09:04,986 INFO cli.py:39 -- Job submission server address: http://rayjob-pytorch-mnist-raycluster-s7xd9-head-svc.kuberay.svc.cluster.local:8265
    2024-11-21 19:09:05,712 SUCC cli.py:63 -- -------------------------------------------------------
    2024-11-21 19:09:05,713 SUCC cli.py:64 -- Job 'rayjob-pytorch-mnist-hndpx' submitted successfully
    2024-11-21 19:09:05,713 SUCC cli.py:65 -- -------------------------------------------------------
    2024-11-21 19:09:05,713 INFO cli.py:289 -- Next steps
    2024-11-21 19:09:05,713 INFO cli.py:290 -- Query the logs of the job:
    2024-11-21 19:09:05,713 INFO cli.py:292 -- ray job logs rayjob-pytorch-mnist-hndpx
    2024-11-21 19:09:05,713 INFO cli.py:294 -- Query the status of the job:
    ...
    
    View detailed results here: /home/ray/ray_results/TorchTrainer_2024-11-21_19-11-23
    To visualize your results with TensorBoard, run: `tensorboard --logdir /tmp/ray/session_2024-11-21_19-08-24_556164_1/artifacts/2024-11-21_19-11-24/TorchTrainer_2024-11-21_19-11-23/driver_artifacts`
    
    Training started with configuration:
    ╭─────────────────────────────────────────────────╮
    │ Training config                                 │
    ├─────────────────────────────────────────────────┤
    │ train_loop_config/batch_size_per_worker      16 │
    │ train_loop_config/epochs                     10 │
    │ train_loop_config/lr                      0.001 │
    ╰─────────────────────────────────────────────────╯
    (RayTrainWorker pid=1193, ip=10.244.4.193) Setting up process group for: env:// [rank=0, world_size=2]
    (TorchTrainer pid=1138, ip=10.244.4.193) Started distributed worker processes:
    (TorchTrainer pid=1138, ip=10.244.4.193) - (node_id=3ea81f12c0f73ebfbd5b46664e29ced00266e69355c699970e1d824b, ip=10.244.4.193, pid=1193) world_rank=0, local_rank=0, node_rank=0
    (TorchTrainer pid=1138, ip=10.244.4.193) - (node_id=2b00ea2b369c9d27de9596ce329daad1d24626b149975cf23cd10ea3, ip=10.244.1.42, pid=1341) world_rank=1, local_rank=0, node_rank=1
    (RayTrainWorker pid=1341, ip=10.244.1.42) Downloading http://fashion-mnist.s3-website.eu-central-1.amazonaws.com/train-images-idx3-ubyte.gz
    (RayTrainWorker pid=1193, ip=10.244.4.193) Downloading http://fashion-mnist.s3-website.eu-central-1.amazonaws.com/train-images-idx3-ubyte.gz to /home/ray/data/FashionMNIST/raw/train-images-idx3-ubyte.gz
    (RayTrainWorker pid=1193, ip=10.244.4.193)
      0%|          | 0.00/26.4M [00:00<?, ?B/s]
    (RayTrainWorker pid=1193, ip=10.244.4.193)
      0%|          | 65.5k/26.4M [00:00<01:13, 356kB/s]
    (RayTrainWorker pid=1193, ip=10.244.4.193)
    100%|██████████| 26.4M/26.4M [00:01<00:00, 18.9MB/s]
    (RayTrainWorker pid=1193, ip=10.244.4.193) Extracting /home/ray/data/FashionMNIST/raw/train-images-idx3-ubyte.gz to /home/ray/data/FashionMNIST/raw
    (RayTrainWorker pid=1341, ip=10.244.1.42)
    100%|██████████| 26.4M/26.4M [00:01<00:00, 18.7MB/s]
    ...
    Training finished iteration 1 at 2024-11-21 19:15:46. Total running time: 4min 22s
    ╭───────────────────────────────╮
    │ Training result               │
    ├───────────────────────────────┤
    │ checkpoint_dir_name           │
    │ time_this_iter_s        144.9 │
    │ time_total_s            144.9 │
    │ training_iteration          1 │
    │ accuracy                0.805 │
    │ loss                  0.52336 │
    ╰───────────────────────────────╯
    (RayTrainWorker pid=1193, ip=10.244.4.193)
    Test Epoch 0:  97%|█████████▋| 303/313 [00:01<00:00, 269.60it/s]
    Test Epoch 0: 100%|██████████| 313/313 [00:01<00:00, 267.14it/s]
    (RayTrainWorker pid=1193, ip=10.244.4.193)
    Train Epoch 1:   0%|          | 0/1875 [00:00<?, ?it/s]
    (RayTrainWorker pid=1341, ip=10.244.1.42)
    Test Epoch 0: 100%|██████████| 313/313 [00:01<00:00, 270.44it/s]
    (RayTrainWorker pid=1341, ip=10.244.1.42)
    Train Epoch 0: 100%|█████████▉| 1866/1875 [00:24<00:00, 82.49it/s] [repeated 35x across cluster]
    (RayTrainWorker pid=1193, ip=10.244.4.193)
    Train Epoch 0: 100%|██████████| 1875/1875 [00:24<00:00, 77.99it/s]
    Train Epoch 0: 100%|██████████| 1875/1875 [00:24<00:00, 76.19it/s]
    (RayTrainWorker pid=1193, ip=10.244.4.193)
    Test Epoch 0:   0%|          | 0/313 [00:00<?, ?it/s]
    (RayTrainWorker pid=1193, ip=10.244.4.193)
    Test Epoch 0:  88%|████████▊ | 275/313 [00:01<00:00, 265.39it/s] [repeated 19x across cluster]
    (RayTrainWorker pid=1341, ip=10.244.1.42)
    Train Epoch 1:  19%|█▉        | 354/1875 [00:04<00:18, 82.66it/s] [repeated 80x across cluster]
    (RayTrainWorker pid=1341, ip=10.244.1.42)
    Train Epoch 1:   0%|          | 0/1875 [00:00<?, ?it/s]
    (RayTrainWorker pid=1341, ip=10.244.1.42)
    Train Epoch 1:  40%|████      | 757/1875 [00:09<00:13, 83.01it/s] [repeated 90x across cluster]
    (RayTrainWorker pid=1341, ip=10.244.1.42)
    Train Epoch 1:  62%|██████▏   | 1164/1875 [00:14<00:08, 83.39it/s] [repeated 92x across cluster]
    (RayTrainWorker pid=1341, ip=10.244.1.42)
    Train Epoch 1:  82%|████████▏ | 1533/1875 [00:19<00:05, 68.09it/s] [repeated 91x across cluster]
    (RayTrainWorker pid=1341, ip=10.244.1.42)
    Train Epoch 1:  91%|█████████▏| 1713/1875 [00:22<00:02, 70.20it/s]
    (RayTrainWorker pid=1193, ip=10.244.4.193)
    Train Epoch 1:  91%|█████████ | 1707/1875 [00:22<00:02, 70.04it/s] [repeated 47x across cluster]
    (RayTrainWorker pid=1341, ip=10.244.1.42)
    Test Epoch 1:   0%|          | 0/313 [00:00<?, ?it/s]
    (RayTrainWorker pid=1341, ip=10.244.1.42)
    Test Epoch 1:   8%|▊         | 24/313 [00:00<00:01, 237.98it/s]
    (RayTrainWorker pid=1193, ip=10.244.4.193)
    Test Epoch 1:  96%|█████████▋| 302/313 [00:01<00:00, 250.76it/s]
    Test Epoch 1: 100%|██████████| 313/313 [00:01<00:00, 262.94it/s]
    (RayTrainWorker pid=1193, ip=10.244.4.193)
    Train Epoch 2:   0%|          | 0/1875 [00:00<?, ?it/s]
    (RayTrainWorker pid=1341, ip=10.244.1.42)
    Test Epoch 1:  92%|█████████▏| 289/313 [00:01<00:00, 222.57it/s]
    
    Training finished iteration 2 at 2024-11-21 19:16:12. Total running time: 4min 48s
    ╭───────────────────────────────╮
    │ Training result               │
    ├───────────────────────────────┤
    │ checkpoint_dir_name           │
    │ time_this_iter_s       25.975 │
    │ time_total_s          170.875 │
    │ training_iteration          2 │
    │ accuracy                0.828 │
    │ loss                  0.45946 │
    ╰───────────────────────────────╯
    (RayTrainWorker pid=1341, ip=10.244.1.42)
    Test Epoch 1: 100%|██████████| 313/313 [00:01<00:00, 226.04it/s]
    (RayTrainWorker pid=1193, ip=10.244.4.193)
    Train Epoch 1: 100%|██████████| 1875/1875 [00:24<00:00, 76.24it/s] [repeated 45x across cluster]
    (RayTrainWorker pid=1341, ip=10.244.1.42)
    Train Epoch 2:  13%|█▎        | 239/1875 [00:03<00:24, 67.30it/s] [repeated 64x across cluster]
    (RayTrainWorker pid=1193, ip=10.244.4.193)
    Test Epoch 1:   0%|          | 0/313 [00:00<?, ?it/s]
    (RayTrainWorker pid=1341, ip=10.244.1.42)
    Test Epoch 1:  85%|████████▍ | 266/313 [00:01<00:00, 222.54it/s] [repeated 20x across cluster]
    (RayTrainWorker pid=1341, ip=10.244.1.42)
    ..
    
    Training completed after 10 iterations at 2024-11-21 19:19:47. Total running time: 8min 23s
    2024-11-21 19:19:47,596 INFO tune.py:1009 -- Wrote the latest version of all result files and experiment state to '/home/ray/ray_results/TorchTrainer_2024-11-21_19-11-23' in 0.0029s.
    
    Training result: Result(
      metrics={'loss': 0.35892221605786073, 'accuracy': 0.872},
      path='/home/ray/ray_results/TorchTrainer_2024-11-21_19-11-23/TorchTrainer_74867_00000_0_2024-11-21_19-11-24',
      filesystem='local',
      checkpoint=None
    )
    (RayTrainWorker pid=1341, ip=10.244.1.42) Downloading http://fashion-mnist.s3-website.eu-central-1.amazonaws.com/t10k-labels-idx1-ubyte.gz [repeated 7x across cluster]
    (RayTrainWorker pid=1341, ip=10.244.1.42) Downloading http://fashion-mnist.s3-website.eu-central-1.amazonaws.com/t10k-labels-idx1-ubyte.gz to /home/ray/data/FashionMNIST/raw/t10k-labels-idx1-ubyte.gz [repeated 7x across cluster]
    (RayTrainWorker pid=1341, ip=10.244.1.42) Extracting /home/ray/data/FashionMNIST/raw/t10k-labels-idx1-ubyte.gz to /home/ray/data/FashionMNIST/raw [repeated 7x across cluster]
    (RayTrainWorker pid=1341, ip=10.244.1.42)
    Train Epoch 9:  91%|█████████ | 1708/1875 [00:21<00:01, 83.84it/s] [repeated 23x across cluster]
    (RayTrainWorker pid=1341, ip=10.244.1.42)
    Train Epoch 9: 100%|██████████| 1875/1875 [00:23<00:00, 78.52it/s] [repeated 37x across cluster]
    (RayTrainWorker pid=1341, ip=10.244.1.42)
    Test Epoch 9:   0%|          | 0/313 [00:00<?, ?it/s]
    (RayTrainWorker pid=1193, ip=10.244.4.193)
    Test Epoch 9:  89%|████████▉ | 278/313 [00:01<00:00, 266.46it/s] [repeated 19x across cluster]
    (RayTrainWorker pid=1193, ip=10.244.4.193)
    Test Epoch 9:  97%|█████████▋| 305/313 [00:01<00:00, 256.69it/s]
    Test Epoch 9: 100%|██████████| 313/313 [00:01<00:00, 267.35it/s]
    2024-11-21 19:19:51,728 SUCC cli.py:63 -- ------------------------------------------
    2024-11-21 19:19:51,728 SUCC cli.py:64 -- Job 'rayjob-pytorch-mnist-hndpx' succeeded
    2024-11-21 19:19:51,728 SUCC cli.py:65 -- ------------------------------------------
    

Visualización de los resultados del entrenamiento en el panel de Ray

Cuando RayJob se complete correctamente, puede ver los resultados del entrenamiento en el panel de Ray. El panel de Ray proporciona supervisión y visualizaciones en tiempo real de los clústeres de Ray. Puede usar el panel de Ray para supervisar el estado de los clústeres de Ray, ver los registros y visualizar los resultados de los trabajos de aprendizaje automático.

Para acceder al panel de Ray, debe exponer el servicio principal de Ray a la red pública de Internet mediante la creación de un servicio de correcciones de compatibilidad para exponer el servicio principal de Ray en el puerto 80 en lugar del puerto 8265.

Nota:

El deploy.sh descrito en la sección anterior expone automáticamente el servicio head de Ray a la red pública de Internet. Los pasos siguientes se incluyen en el script de deploy.sh.

  1. Obtenga el nombre del servicio head de Ray y guárdelo en una variable de shell mediante el siguiente comando:

    rayclusterhead=$(kubectl get service -n $kuberay_namespace | grep 'rayjob-pytorch-mnist-raycluster' | grep 'ClusterIP' | awk '{print $1}')
    
  2. Cree la corrección de compatibilidad del servicio para exponer el servicio principal de Ray en el puerto 80 mediante el comando kubectl expose service.

    kubectl expose service $rayclusterhead \
    -n $kuberay_namespace \
    --port=80 \
    --target-port=8265 \
    --type=NodePort \
    --name=ray-dash
    
  3. Cree la entrada para exponer la corrección de compatibilidad del servicio mediante el controlador de entrada mediante el comando siguiente:

    cat <<EOF | kubectl apply -f -
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: ray-dash
      namespace: kuberay
      annotations:
        nginx.ingress.kubernetes.io/rewrite-target: /
    spec:
      ingressClassName: webapprouting.kubernetes.azure.com
      rules:
      - http:
          paths:
          - backend:
              service:
                name: ray-dash
                port:
                  number: 80
            path: /
            pathType: Prefix
    EOF
    
  4. Obtenga la dirección IP pública del controlador de entrada mediante el comando kubectl get service.

    kubectl get service -n app-routing-system
    
  5. En la salida, debería ver la dirección IP pública del equilibrador de carga asociado al controlador de entrada. Copie la dirección IP pública y péguela en un explorador web. Debería ver el panel de Ray.

Limpieza de recursos

Para limpiar los recursos creados en esta guía, puede eliminar el grupo de recursos de Azure que contiene el clúster de AKS.

Pasos siguientes

Para más información sobre las cargas de trabajo de inteligencia artificial y aprendizaje automático en AKS, consulte los siguientes artículos:

Colaboradores

Microsoft se encarga del mantenimiento de este artículo. Originalmente lo escribieron los siguientes colaboradores:

  • Russell de Pina | TPM de entidad de seguridad
  • Ken Kilty | TPM de entidad de seguridad
  • Erin Schaffer | Desarrollador de contenido 2
  • Adrian Joian | Ingeniero principal de clientes
  • Ryan Graham | Especialista principal técnico