Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
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.shscript 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
- Revise el Clúster de Ray en la información general de AKS para comprender los componentes y el proceso de implementación.
- Suscripción a Azure. Si no tiene una suscripción de Azure, puede crear una cuenta gratuita aquí.
- La CLI de Azure instalada en el equipo local. Puede instalarlo mediante las instrucciones de Instalación de la CLI de Azure.
- La Extensión de la versión preliminar de Azure Kubernetes Service está instalada.
- Tener Helm instalado.
- Herramientas de cliente de Terraform o OpenTofu instaladas. En este artículo se usa Terraform, pero los módulos usados deben ser compatibles con OpenTofu.
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.
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-sampleImplemente el ejemplo completo con los siguientes comandos:
chmod +x deploy.sh ./deploy.shUna 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
replicasen la secciónworkerGroupSpecsderayClusterSpecespecifica 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 camporeplicasen 2 requiere 8 vCPUs en el grupo de nodos usado para implementar RayCluster para el trabajo. - El campo
NUM_WORKERSsituadoruntimeEnvYAMLenspecespecifica 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 camporeplicas. En este ejemplo, se estableceNUM_WORKERSen 2, que coincide con el camporeplicas. - El campo
CPUS_PER_WORKERdebe 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 queCPUS_PER_WORKERse 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.
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.yamlRealice las modificaciones necesarias en el archivo de especificación del trabajo de Ray.
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
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 kuberayEl 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 6m15sCompruebe el estado de RayJob mediante el comando
kubectl get.kubectl get rayjob -n kuberayEl 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 9m36sEspere hasta que finalice RayJob. Esto puede tardar unos minutos. Una vez que
JOB STATUSesSUCCEEDED, puede comprobar los registros de entrenamiento. Para ello, obtenga primero el nombre del pod que ejecuta RayJob mediante el comandokubectl get pods.kubectl get pods -n kuberayEn 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 14mVea los registros de RayJob mediante el comando
kubectl logs. Asegúrese de reemplazarrayjob-pytorch-mnist-fc959por el nombre del pod que ejecuta RayJob.kubectl logs -n kuberay rayjob-pytorch-mnist-fc959En 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.
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}')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-dashCree 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 EOFObtenga la dirección IP pública del controlador de entrada mediante el comando
kubectl get service.kubectl get service -n app-routing-systemEn 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:
- Implementación de una aplicación que usa OpenAI en Azure Kubernetes Service (AKS)
- Creación e implementación de canalizaciones de datos y aprendizaje automático con Flyte en Azure Kubernetes Service (AKS)
- Implementación de un modelo de IA en Azure Kubernetes Service (AKS) con el operador de cadena de herramientas de IA
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