Partager via


Configurer et déployer un cluster Ray sur Azure Kubernetes Service (AKS)

Dans cet article, vous configurez et déployez un cluster Ray sur Azure Kubernetes Service (AKS) à l’aide de KubeRay. Vous allez également découvrir comment utiliser le cluster Ray pour entraîner un modèle simple d’apprentissage automatique et afficher les résultats sur le tableau de bord Ray.

Cet article décrit deux méthodes pour déployer le cluster Ray sur AKS :

  • Le déploiement non interactif : Utilisez le script deploy.sh dans le référentiel GitHub pour déployer l’échantillon complet de Ray de manière non interactive.
  • Le déploiement manuel : Suivez les étapes du déploiement manuel pour déployer l’échantillon Ray sur AKS.

Prérequis

Déployer l’échantillon Ray de manière non interactive

Si vous souhaitez déployer l’échantillon complet de Ray de manière non interactive, vous pouvez utiliser le script deploy.sh dans le référentiel GitHub (https://github.com/Azure-Samples/aks-ray-sample). Ce script complète les étapes décrites dans la Section sur le processus de déploiement de Ray.

  1. Clonez le référentiel GitHub en local et modifiez la racine du référentiel à l’aide des commandes suivantes :

    git clone https://github.com/Azure-Samples/aks-ray-sample
    cd aks-ray-sample
    
  2. Déployez l’échantillon complet à l’aide des commandes suivantes :

    chmod +x deploy.sh
    ./deploy.sh
    
  3. Une fois le déploiement terminé, passez en revue la sortie des journaux et le groupe de ressources dans le Portail Azure pour vérifier l’infrastructure qui a été créée.

Déployez manuellement l’échantillon Ray

Fashion MNIST est un ensemble de données d’images d’articles de Zalando composé d’un jeu d’apprentissage de 60 000 exemples et d’un jeu de test de 10 000 exemples. Chaque exemple est une image en nuances de gris de 28x28 associée à une étiquette de dix classes. Dans ce guide, vous entraînez un modèle PyTorch simple sur ce jeu de données à l’aide du cluster Ray.

Déployez la spécification RayJob

Pour entraîner le modèle, vous devez envoyer une spécification Ray Job à l’opérateur KubeRay qui s’exécute sur un cluster AKS privé. La spécification Ray Job est un fichier YAML qui décrit les ressources nécessaires à l’exécution du travail, notamment l’image Docker, la commande à exécuter et le nombre de Workers à utiliser.

En examinant la description du Ray Job, il se peut que vous deviez modifier certains champs pour les adapter à votre environnement :

  • Le champ replicas sous la section workerGroupSpecs dans rayClusterSpec spécifie le nombre de pods worker que KubeRay planifie pour le cluster Kubernetes. Chaque pod worker nécessite 3 processeurs et 4 Go de mémoire. Le pod principal nécessite 1 processeur et 4 Go de mémoire. La définition du champ replicas sur 2 nécessite 8 processeurs virtuels dans le pool de nœuds utilisé pour implémenter le RayCluster pour le travail.
  • Le champ NUM_WORKERS sous runtimeEnvYAML dans spec spécifie le nombre d’acteurs Ray à lancer. Chaque acteur Ray doit être desservi par un pod worker dans le cluster Kubernetes, de sorte que ce champ doit être inférieur ou égal au champ replicas. Dans cet exemple, nous avons défini NUM_WORKERS sur 2, ce qui correspond au champ replicas.
  • Le champ CPUS_PER_WORKER doit être défini comme étant inférieur ou égal au nombre de CPU alloués à chaque pod worker moins 1. Dans cet exemple, la demande de ressources processeur par pod worker est de 3. Par conséquent. CPUS_PER_WORKER est donc définie sur 2.

En résumé, vous avez besoin d’un total de 8 processeurs virtuels dans le pool de nœuds pour exécuter la tâche d’apprentissage du modèle PyTorch. Étant donné que nous avons ajouté une altération sur le pool de nœuds du système afin qu’aucun pod utilisateur ne puisse être planifié sur celui-ci, nous devons créer un nouveau pool de nœuds avec au moins 8 processeurs virtuels pour héberger le cluster Ray.

  1. Téléchargez le fichier de spécification du Ray Job à l’aide de la commande suivante :

    curl -LO https://raw.githubusercontent.com/ray-project/kuberay/master/ray-operator/config/samples/pytorch-mnist/ray-job.pytorch-mnist.yaml
    
  2. Apportez toutes les modifications nécessaires au fichier de spécification du Ray Job.

  3. Lancez le travail d’apprentissage du modèle PyTorch à l’aide de la commande kubectl apply.

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

Vérifiez le déploiement de RayJob

  1. Vérifiez que vous disposez de deux pods worker et d’un pod principal qui fonctionnent dans l’espace de noms à l’aide de la commandekubectl get pods.

    kubectl get pods -n kuberay
    

    Vous devez obtenir un résultat semblable à l’exemple de sortie qui suit :

    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. Vérifiez l’état du RayJob à l’aide de la commande kubectl get.

    kubectl get rayjob -n kuberay
    

    Vous devez obtenir un résultat semblable à l’exemple de sortie qui suit :

    NAME                   JOB STATUS   DEPLOYMENT STATUS   START TIME             END TIME   AGE
    rayjob-pytorch-mnist   RUNNING      Running             2024-11-22T03:08:22Z              9m36s
    
  3. Attendez que le RayJob soit terminé. Cette opération peut prendre quelques minutes. Une fois que le JOB STATUS est SUCCEEDED, vous pouvez vérifier les journaux d’apprentissage. Vous pouvez le faire en obtenant d’abord le nom du pod qui exécute le RayJob à l’aide de la commande kubectl get pods.

    kubectl get pods -n kuberay
    

    Dans la sortie, vous devriez voir un pod dont le nom commence par rayjob-pytorch-mnist, comme dans l’exemple de sortie suivant :

    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. Affichez les journaux du RayJob à l’aide de la commande kubectl logs. Veillez à remplacer rayjob-pytorch-mnist-fc959 par le nom du pod qui exécute votre RayJob.

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

    Dans la sortie, vous devriez voir les journaux d’apprentissage du modèle PyTorch, comme dans l’exemple de sortie suivant :

    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 -- ------------------------------------------
    

Visualiser les résultats de l’apprentissage sur le tableau de bord Ray

Lorsque le RayJob est terminé, vous pouvez consulter les résultats de l’apprentissage sur le tableau de bord Ray. Le tableau de bord Ray permet de surveiller et de visualiser les clusters Ray en temps réel. Vous pouvez utiliser le tableau de bord Ray pour surveiller l’état des clusters Ray, consulter les journaux et visualiser les résultats des travaux d’apprentissage automatique.

Pour accéder au tableau de bord Ray, vous devez exposer le service principal Ray à l’Internet public en créant un shim de service pour exposer le service principal Ray sur le port 80 au lieu du port 8265.

Remarque

La deploy.sh décrite dans la section précédente expose automatiquement le service principal Ray à l’Internet public. Les étapes suivantes sont incluses dans le script deploy.sh.

  1. Obtenez le nom du service principal Ray et enregistrez-le dans une variable d’interpréteur de commandes à l’aide de la commande suivante :

    rayclusterhead=$(kubectl get service -n $kuberay_namespace | grep 'rayjob-pytorch-mnist-raycluster' | grep 'ClusterIP' | awk '{print $1}')
    
  2. Créez le shim de service pour exposer le service principal Ray sur le port 80 à l’aide de la commande kubectl expose service.

    kubectl expose service $rayclusterhead \
    -n $kuberay_namespace \
    --port=80 \
    --target-port=8265 \
    --type=NodePort \
    --name=ray-dash
    
  3. Créez l’entrée pour exposer le shim de service à l’aide du contrôleur d’entrée à l’aide de la commande suivante :

    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. Obtenez l’adresse IP publique du contrôleur d’entrée à l’aide de la commande kubectl get service.

    kubectl get service -n app-routing-system
    
  5. Dans la sortie, vous devriez voir l’adresse IP publique de l’équilibreur de charge attaché au contrôleur d’entrée. Copiez l’adresse IP publique et collez-la dans un navigateur web. Vous devriez voir le tableau de bord Ray.

Nettoyer les ressources

Pour nettoyer les ressources créées dans ce guide, vous pouvez supprimer le groupe de ressources Azure qui contient le cluster AKS.

Étapes suivantes

Pour en savoir plus sur les charges de travail d’IA et d’apprentissage automatique sur AKS, consultez les articles suivants :

Contributeurs

Microsoft gère cet article. Les contributeurs suivants ont rédigé sa version d’origine :

  • Russell de Pina | Responsable de programme technique principal
  • Ken Kitty | Responsable de programme technique principal
  • Erin Schaffer | Développeuse de contenu 2
  • Adrian Joian | Ingénieur client principal
  • Ryan Graham | Spécialiste technique principal