تكوين نظام مجموعة Ray ونشره على خدمة Azure Kubernetes (AKS)

في هذه المقالة، يمكنك تكوين ونشر مجموعة Ray على خدمة Azure Kubernetes (AKS) باستخدام KubeRay. كما تتعلم كيفية استخدام مجموعة Ray لتدريب نموذج تعلم آلي بسيط وعرض النتائج على لوحة معلومات Ray.

توفر هذه المقالة طريقتين لنشر نظام مجموعة Ray على AKS:

  • النشر غير التفاعلي: استخدم deploy.sh البرنامج النصي في مستودع GitHub لنشر نموذج Ray الكامل بشكل غير تفاعلي.
  • النشر اليدوي: اتبع خطوات النشر اليدوي لنشر نموذج Ray إلى AKS.

المتطلبات الأساسية

  • راجع نظرة عامة على نظام مجموعة Ray على AKS لفهم المكونات وعملية التوزيع.
  • اشتراك Azure. إذا لم يكن لديك اشتراك Microsoft Azure، فيمكنك إنشاء حساب مجاني.
  • تم تثبيت Azure CLI على جهازك المحلي. يمكنك تثبيته باستخدام الإرشادات الموجودة في كيفية تثبيت Azure CLI.
  • تم تثبيت ملحق Azure Kubernetes Service Preview.
  • Helm مثبت.
  • أدوات عميل Terraform أو OpenTofu مثبتة. تستخدم هذه المقالة Terraform ، ولكن يجب أن تكون الوحدات النمطية المستخدمة متوافقة مع OpenTofu.

نشر عينة Ray بشكل غير تفاعلي

إذا كنت ترغب في نشر نموذج Ray الكامل بشكل غير تفاعلي، يمكنك استخدام deploy.sh البرنامج النصي في مستودع GitHub (https://github.com/Azure-Samples/aks-ray-sample). يكمل هذا البرنامج النصي الخطوات الموضحة في قسم عملية نشر Ray.

  1. استنساخ مستودع GitHub محليا والتغيير إلى جذر المستودع باستخدام الأوامر التالية:

    git clone https://github.com/Azure-Samples/aks-ray-sample
    cd aks-ray-sample
    
  2. انشر النموذج الكامل باستخدام الأوامر التالية:

    chmod +x deploy.sh
    ./deploy.sh
    
  3. بمجرد اكتمال النشر، راجع إخراج السجلات ومجموعة الموارد في مدخل Microsoft Azure لمشاهدة البنية الأساسية التي تم إنشاؤها.

نشر عينة Ray يدويا

Fashion MNIST هي مجموعة بيانات من صور مقالة Zalando تتكون من مجموعة تدريب من 60,000 مثال ومجموعة اختبار من 10,000 مثال. كل مثال هو صورة تدرج رمادي 28x28 مقترنة بتسمية من عشر فئات. في هذا الدليل، يمكنك تدريب نموذج PyTorch بسيط على مجموعة البيانات هذه باستخدام مجموعة Ray.

توزيع مواصفات RayJob

لتدريب النموذج، تحتاج إلى إرسال مواصفات مهمة Ray إلى عامل تشغيل KubeRay الذي يعمل على مجموعة AKS خاصة. مواصفات مهمة Ray هي ملف YAML يصف الموارد المطلوبة لتشغيل المهمة، بما في ذلك صورة Docker والأمر المطلوب تشغيله وعدد العاملين الذين يجب استخدامهم.

بالنظر إلى وصف وظيفة Ray، قد تحتاج إلى تعديل بعض الحقول لمطابقة بيئتك:

  • replicas يحدد الحقل ضمن workerGroupSpecs القسم في rayClusterSpec عدد القرون العاملة التي يقوم KubeRay بجدولتها إلى مجموعة Kubernetes. يتطلب كل جراب عامل 3 وحدات معالجة مركزية و4 غيغابايت من الذاكرة. يتطلب جراب الرأس وحدة معالجة مركزية واحدة و4 غيغابايت من الذاكرة. replicas يتطلب تعيين الحقل إلى 2 8 وحدات vCPUs في تجمع العقدة المستخدمة لتنفيذ RayCluster للوظيفة.
  • NUM_WORKERS يحدد الحقل ضمن runtimeEnvYAML في spec عدد الجهات الفاعلة في Ray التي يجب تشغيلها. يجب أن تكون خدمة كل ممثل Ray بواسطة جراب عامل في مجموعة Kubernetes، لذلك يجب أن يكون هذا الحقل أقل من الحقل أو مساويا replicas له. في هذا المثال، قمنا بتعيين NUM_WORKERS إلى 2، والذي يطابق replicas الحقل.
  • CPUS_PER_WORKER يجب تعيين الحقل إلى أقل من أو يساوي عدد وحدات المعالجة المركزية المخصصة لكل وحدة عاملة ناقص 1. في هذا المثال، طلب مورد وحدة المعالجة المركزية لكل جراب عامل هو 3، لذلك يتم تعيين إلى CPUS_PER_WORKER.

للتلخيص، تحتاج إلى إجمالي 8 وحدات vCPUs في تجمع العقدة لتشغيل مهمة تدريب نموذج PyTorch. نظرا لأننا أضفنا تلوثا على تجمع عقدة النظام بحيث لا يمكن جدولة أي pods مستخدم عليه، يجب علينا إنشاء تجمع عقدة جديد مع ما لا يقل عن 8 وحدات معالجة مركزية ظاهرية لاستضافة نظام مجموعة Ray.

  1. قم بتنزيل ملف مواصفات مهمة Ray باستخدام الأمر التالي:

    curl -LO https://raw.githubusercontent.com/ray-project/kuberay/master/ray-operator/config/samples/pytorch-mnist/ray-job.pytorch-mnist.yaml
    
  2. قم بإجراء أي تعديلات ضرورية على ملف مواصفات مهمة Ray.

  3. قم بتشغيل مهمة تدريب نموذج PyTorch باستخدام kubectl apply الأمر .

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

تحقق من نشر RayJob

  1. تحقق من أن لديك جرابين عاملين وجراب رأس واحد يعمل في مساحة الاسم باستخدام kubectl get pods الأمر .

    kubectl get pods -n kuberay
    

    يجب أن يبدو الإخراج مشابها لإخراج المثال التالي:

    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. تحقق من حالة RayJob باستخدام kubectl get الأمر .

    kubectl get rayjob -n kuberay
    

    يجب أن يبدو الإخراج مشابها لإخراج المثال التالي:

    NAME                   JOB STATUS   DEPLOYMENT STATUS   START TIME             END TIME   AGE
    rayjob-pytorch-mnist   RUNNING      Running             2024-11-22T03:08:22Z              9m36s
    
  3. انتظر حتى يكتمل RayJob. قد تستغرق هذه العملية بضع دقائق. بمجرد أن JOB STATUS يكون SUCCEEDED، يمكنك التحقق من سجلات التدريب. يمكنك القيام بذلك عن طريق الحصول أولا على اسم الجراب الذي يقوم بتشغيل RayJob باستخدام kubectl get pods الأمر .

    kubectl get pods -n kuberay
    

    في الإخراج، يجب أن تشاهد جراب باسم يبدأ ب rayjob-pytorch-mnist، على غرار إخراج المثال التالي:

    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. عرض سجلات RayJob باستخدام kubectl logs الأمر . تأكد من استبدال rayjob-pytorch-mnist-fc959 باسم الجراب الذي يقوم بتشغيل RayJob الخاص بك.

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

    في الإخراج، يجب أن تشاهد سجلات التدريب لنموذج PyTorch، على غرار إخراج المثال التالي:

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

عرض نتائج التدريب على لوحة معلومات Ray

عند اكتمال RayJob بنجاح، يمكنك عرض نتائج التدريب على لوحة معلومات Ray. توفر لوحة معلومات Ray مراقبة وتصورات في الوقت الفعلي لمجموعات Ray. يمكنك استخدام لوحة معلومات Ray لمراقبة حالة مجموعات Ray وعرض السجلات وتصور نتائج مهام التعلم الآلي.

للوصول إلى لوحة معلومات Ray، تحتاج إلى عرض خدمة Ray head على الإنترنت العام عن طريق إنشاء تحليل الخدمة لكشف خدمة Ray head على المنفذ 80 بدلا من المنفذ 8265.

إشعار

يعرض الموضح deploy.sh في القسم السابق تلقائيا خدمة رأس Ray للإنترنت العام. يتم تضمين الخطوات التالية في deploy.sh البرنامج النصي.

  1. احصل على اسم خدمة رأس Ray واحفظها في متغير shell باستخدام الأمر التالي:

    rayclusterhead=$(kubectl get service -n $kuberay_namespace | grep 'rayjob-pytorch-mnist-raycluster' | grep 'ClusterIP' | awk '{print $1}')
    
  2. إنشاء تحليل الخدمة لعرض خدمة رأس Ray على المنفذ 80 باستخدام kubectl expose service الأمر .

    kubectl expose service $rayclusterhead \
    -n $kuberay_namespace \
    --port=80 \
    --target-port=8265 \
    --type=NodePort \
    --name=ray-dash
    
  3. قم بإنشاء الدخول لعرض تحليل الخدمة باستخدام وحدة تحكم الدخول باستخدام الأمر التالي:

    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. احصل على عنوان IP العام لوحدة تحكم الدخول باستخدام kubectl get service الأمر .

    kubectl get service -n app-routing-system
    
  5. في الإخراج، يجب أن تشاهد عنوان IP العام لموازن التحميل المرفق بوحدة تحكم الدخول. انسخ عنوان IP العام والصقه في مستعرض ويب. يجب أن تشاهد لوحة معلومات Ray.

تنظيف الموارد

لتنظيف الموارد التي تم إنشاؤها في هذا الدليل، يمكنك حذف مجموعة موارد Azure التي تحتوي على نظام مجموعة AKS.

الخطوات التالية

لمعرفة المزيد حول الذكاء الاصطناعي وأحمال عمل التعلم الآلي على AKS، راجع المقالات التالية:

المساهمون

تحتفظ Microsoft بهذه المقالة. كتبه المساهمون التاليون في الأصل:

  • راسل دي بينا | الوحدة النمطية للنظام الأساسي الموثوق به
  • كين كيلتي | الوحدة النمطية للنظام الأساسي الموثوق به
  • إيرين شيفر | مطور المحتوى 2
  • أدريان جويان | مهندس العملاء الرئيسي
  • ريان غراهام | أخصائي تقني رئيسي