MLOps وDevOps لأنظمة الذكاء الاصطناعي

بنية تدريب النماذج ووحدات معالجة الرسوميات

18 دقيقة الدرس 4 من 28

بنية تدريب النماذج ووحدات معالجة الرسوميات

تشغيل مهمة تدريب واحدة على حاسوب محمول هو تجربة علمية بحتة. أما تشغيل التدريب على نطاق واسع — مئات التجارب المتزامنة، ومهام موزعة متعددة العقد تستهلك بيتابايتات من البيانات، مع تتبع تكاليف وحدات معالجة الرسوميات بالدولار — فهو انضباط هندسي متكامل. يتناول هذا الدرس ثلاثة محاور يجب على المهندس الأول في MLOps إتقانها: جدولة أحمال عمل وحدات معالجة الرسوميات على Kubernetes، والاستفادة من طاقة الـ Spot لخفض التكاليف بنسبة 60–80%، وأسس التدريب الموزع التي تتيح لمهمة واحدة الامتداد عبر عشرات العقد. أنت تعرف Kubernetes بعمق بالفعل؛ هنا نمتد بهذه المعرفة إلى مستوى بنية ML.

جدولة وحدات معالجة الرسوميات على Kubernetes

يتعامل Kubernetes مع وحدات معالجة الرسوميات بوصفها موارد موسّعة في إطار إضافات الأجهزة (device plugin framework)، استُقرّ عليه في الإصدار 1.10. تُعلن إضافة NVIDIA الخاصة بالأجهزة — المنشورة كـ DaemonSet — عن موارد nvidia.com/gpu على كل عقدة تحتوي على وحدة رسوميات. طلب وحدة رسوميات متطابق نحويًا مع طلب CPU أو ذاكرة، مما يعني أن كل آليات RBAC وحصص مساحات الأسماء والجدولة الحالية تعمل دون تغيير.

التفصيل الإنتاجي الحاسم: موارد وحدة الرسوميات ليست كسرية بالإعداد الافتراضي. حاوية تطلب nvidia.com/gpu: 1 تحصل على وصول حصري لوحدة رسوميات فيزيائية كاملة. إذا كانت العقدة تحتوي على 8 وحدات A100 وطلبت حاوية واحدة فقط، فإن سبع وحدات تبقى خاملة ما لم يُجدوَل سبعة حاويات أخرى معها. يؤدي هذا إلى انخفاض استخدام وحدات الرسوميات — أحد أكثر أنماط الهدر تكلفةً في بنية ML. الحلول هي التقطيع الزمني (NVIDIA MIG على A100/H100) أو المشاركة الافتراضية لوحدات الرسوميات.

# 1. نشر إضافة NVIDIA الخاصة بالأجهزة عبر Helm helm repo add nvdp https://nvidia.github.io/k8s-device-plugin helm repo update helm upgrade --install nvdp nvdp/nvidia-device-plugin \ --namespace kube-system \ --set migStrategy=single \ --set failOnInitError=false # 2. وضع تسمية على مجموعات عقد وحدات الرسوميات لاستهدافها بدقة kubectl label node gpu-node-1 accelerator=nvidia-tesla-a100 node-type=gpu # 3. مهمة تدريب بوحدة رسوميات واحدة (YAML مبسّط) # apiVersion: batch/v1 # kind: Job # metadata: # name: train-resnet50-v12 # namespace: ml-training # spec: # backoffLimit: 2 # ... # resources: # limits: # nvidia.com/gpu: "1" # memory: "60Gi" # التحقق من تخصيص موارد وحدة الرسوميات على المجموعة: kubectl describe node gpu-node-1 | grep -A10 "Allocatable" kubectl get pods -n ml-training -o wide
MIG (وحدة رسوميات متعددة الأنظمة): تدعم NVIDIA A100 و H100 تقنية Multi-Instance GPU التي تُقسّم وحدة رسوميات فيزيائية واحدة إلى ما يصل إلى 7 أجزاء معزولة، كل منها بذاكرة وقدرة حسابية مخصصة. يمكن لـ A100 بسعة 40GB أن تعرض سبع أجزاء بسعة 5GB لكل منها، مما يتيح جدولة سبع مهام استدلال أو ضبط دقيق صغيرة بشكل متزامن. في Google وMeta، MIG هو الإعداد الافتراضي لخدمات الاستدلال؛ تخصيص وحدة رسوميات كاملة محجوز للتشغيلات التدريبية الكبيرة.

مكدّس جدولة وحدات معالجة الرسوميات على مجموعة حقيقية

على نطاق الشركات الكبرى، تُشغّل مجموعات وحدات الرسوميات طبقة جدولة دُفعية فوق Kubernetes. الخياران السائدان هما Volcano (CNCF) وYunikorn (Apache)، وكلاهما يضيف جدولة العصابات (gang scheduling) — الضمان بأن جميع حاويات المهمة تبدأ في وقت واحد أو لا تبدأ أي منها. هذا حاسم للتدريب الموزع: إذا بدأت 15 حاوية من 16 لكن واحدة لم تُجدوَل بسبب استنزاف العقدة، تنتظر الـ 15 الجاهزة في حاجز، محترقةً ساعات من وحدة الرسوميات دون إنجاز شيء.

GPU Scheduling Stack on Kubernetes ML Engineer kubectl / SDK Training Operator PyTorchJob / TFJob Volcano Scheduler Gang / Preemption k8s Scheduler (non-GPU pods) GPU Node Pool A100 / H100 nodes Device Plugin nvidia.com/gpu Spot GPU Nodes Preemptible / Cheap Checkpoint Store (S3 / GCS) Resume on preemption submit PodGroup spot bid on-demand
مكدّس جدولة وحدات معالجة الرسوميات: يُنشئ Training Operator مجموعة حاويات؛ يجدولها Volcano على عقد on-demand أو Spot؛ يعرض Device Plugin موارد وحدة الرسوميات؛ ونقاط التفتيش على مخزن الكائنات تتيح الاستئناف بعد الاسترداد.

التدريب على Spot: خفض التكلفة بنسبة 60–80%

أجهزة وحدات معالجة الرسوميات مكلفة. تكلّف عقدة 8xA100 عند الطلب على AWS (p4d.24xlarge) نحو 32 دولارًا في الساعة. المكافئ Spot — أو GCP Preemptible — يكلّف 10–13 دولارًا في الساعة، أي توفيرًا بنسبة 60–70%. في الشركات التي تُشغّل آلاف ساعات وحدات الرسوميات يوميًا، هذا الفارق يعادل ملايين الدولارات سنويًا. المشكلة: يمكن لمزود السحابة استعادة عقدة Spot في أقل من دقيقتين إشعارًا (EC2) أو 30 ثانية (GCP). مهمة تدريب تعمل 10 ساعات دون تحمّل للأعطاء تفقد كل شيء عند الإخلاء.

النمط الإنتاجي لجعل التدريب على Spot عمليًا هو إنشاء نقاط تفتيش دورية في مخزن الكائنات الدائم. مهمة تدريب تحفظ نقطة تفتيش كل 10 دقائق تفقد 10 دقائق على الأكثر عند الإخلاء. بالتوافق مع backoffLimit في Kubernetes Job ومنطق إعادة التشغيل الصحيح، تستأنف المهمة تلقائيًا من آخر نقطة تفتيش.

# حلقة تدريب PyTorch مع حفظ دوري إلى S3 # هذا هو النمط الذي تستخدمه Google Brain وMeta FAIR وDatabricks داخليًا. import torch, os, boto3, time CHECKPOINT_BUCKET = "ml-checkpoints-prod" CHECKPOINT_KEY = "runs/resnet50-v12/ckpt-latest.pt" CHECKPOINT_EVERY = 600 # بالثواني def save_checkpoint(model, optimizer, scheduler, epoch, step, loss): state = { "epoch": epoch, "step": step, "model_state": model.state_dict(), "optimizer_state": optimizer.state_dict(), "scheduler_state": scheduler.state_dict(), "loss": loss, } tmp = "/tmp/ckpt-latest.pt" torch.save(state, tmp) boto3.client("s3").upload_file(tmp, CHECKPOINT_BUCKET, CHECKPOINT_KEY) print(f"[ckpt] saved epoch={epoch} step={step}") # في حلقة التدريب: last_ckpt = time.time() for epoch in range(start_epoch, num_epochs): for step, batch in enumerate(dataloader, start=start_step): loss = train_step(model, optimizer, batch) if time.time() - last_ckpt >= CHECKPOINT_EVERY: save_checkpoint(model, optimizer, scheduler, epoch, step, loss) last_ckpt = time.time()
انهيار Spot المتتالي: في مهمة تدريب موزعة (مثلاً PyTorch DDP على 16 عقدة)، إذا أُخليت عقدة Spot واحدة، تتوقف جميع العقد الأخرى عند نقاط dist.barrier() وتتعطل فعليًا. يجب تهيئة معالجات SIGTERM التي تُشغّل حفظ نقطة تفتيش وإغلاق سلس للمهمة كاملة قبل انتهاء نافذة الإخلاء. على AWS، استخدم خدمة بيانات تعريف EC2 لاستطلاع إشعارات مقاطعة Spot كل 5 ثوانٍ من حاوية جانبية.

بنية مجموعات العقد: On-Demand مقابل Spot

البنية الإنتاجية القياسية تستخدم مجموعتَي عقد GPU في نفس المجموعة. مجموعة on-demand صغيرة (1–4 عقد) لمهام قصيرة وعالية الأولوية — تشغيلات التقييم النهائية، إعادة التدريب في مواعيد محددة، أي شيء أقل من 30 دقيقة. ومجموعة Spot كبيرة ذاتية التوسع (0–50 عقدة) للتجارب الاستكشافية ومسح المعاملات الفائقة (hyperparameter sweep) والتشغيلات التدريبية الطويلة القابلة للإخلاء.

# مقتطف إعداد eksctl لتكوين GPU مختلط on-demand وSpot managedNodeGroups: - name: gpu-ondemand instanceType: p4d.24xlarge capacityType: ON_DEMAND minSize: 0 maxSize: 4 labels: node-type: gpu-ondemand taints: - key: nvidia.com/gpu value: "true" effect: NoSchedule - name: gpu-spot instanceTypes: - p4d.24xlarge - p3.16xlarge - p3dn.24xlarge capacityType: SPOT minSize: 0 maxSize: 50 labels: node-type: gpu-spot taints: - key: nvidia.com/gpu value: "true" effect: NoSchedule - key: spot value: "true" effect: NoSchedule

أسس التدريب الموزع

عندما لا تكفي وحدة رسوميات واحدة لتدريب نموذج في وقت معقول، يُوزَّع التدريب عبر وحدات رسوميات وعقد متعددة. ثلاثة محاور للتوازي، والنماذج الكبيرة تستخدمها الثلاثة معًا (التوازي ثلاثي الأبعاد):

  • توازي البيانات (DDP): كل وحدة رسوميات تحتفظ بنسخة كاملة من النموذج وتعالج مجموعة بيانات صغيرة مختلفة. تُجمَّع التدرجات عبر النسخ بعملية AllReduce في نهاية كل تمرير خلفي. DistributedDataParallel في PyTorch هو المعيار. يتوسع جيدًا حتى ~32 وحدة رسوميات.
  • توازي المصفوفات (Tensor Parallelism): تُقسَّم مصفوفة الأوزان لطبقة واحدة عبر وحدات الرسوميات. التمرير للأمام يتطلب تواصلًا في منتصف الطبقة. مناسب للنماذج ذات البنية المحولة العريضة جدًا. Megatron-LM من NVIDIA هو المرجع.
  • توازي خط الأنابيب (Pipeline Parallelism): تُوزَّع طبقات مختلفة على وحدات رسوميات مختلفة. يتطلب تجزيءً دقيقًا للدُفعات الصغيرة. DeepSpeed يستخدمه لنماذج تتجاوز ذاكرة وحدة رسوميات واحدة.

لمعظم فرق ML دون نطاق LLM، DDP هو نقطة البداية والشكل الوحيد من التوازي المطلوب. تُنسّق PyTorchJob على Kubeflow DDP عبر العقد بحقن متغيرات البيئة MASTER_ADDR وMASTER_PORT وWORLD_SIZE وRANK في كل حاوية.

قاعدة الإبهام للتوسع: يتوسع DDP خطيًا حتى تتجاوز زمن تأخير مزامنة التدرجات وقت الحساب للتمرير الخلفي. على وحدات رسوميات مرتبطة بـ NVLink داخل عقدة واحدة، هذا العتبة نادرًا ما تُبلَغ. عبر عقد متعددة عبر InfiniBand، مهمة DDP على 16 عقدة مع نموذج ResNet-50 تبقى قريبة من الخطية. مع نموذج 70B، تصبح مصفوفات التدرجات عدة GB في كل خطوة — عندها يصبح التوازي الآخر ضروريًا.

قابلية الملاحظة لمهام التدريب

لمهام التدريب بوحدات الرسوميات سطح رصد مختلف عن حاويات الخدمات العادية. المقاييس الأساسية التي يجب تصديرها إلى Prometheus هي استخدام وحدة الرسوميات (DCGM_FI_DEV_GPU_UTIL)، والذاكرة المستخدمة (DCGM_FI_DEV_FB_USED)، وعرض نطاق NVLink. NVIDIA DCGM Exporter — المنشور كـ DaemonSet — يعرض كل هذه المقاييس بتنسيق Prometheus القياسي. مهمة تدريب يقل فيها استخدام وحدة الرسوميات عن 60% لفترة مستمرة تشير إلى اختناق في تحميل البيانات.

أكثر أعطال مهام التدريب شيوعًا التي ستُصحّحها: يُظهر استخدام وحدة الرسوميات 100% لبضع ثوانٍ ثم يهبط إلى 5% بشكل متكرر — هذا هو نمط تجويع DataLoader. الحل دائمًا أحد هذه الخيارات تقريبًا: زيادة num_workers في DataLoader، استخدام FSx for Lustre بدلاً من وصلات S3 FUSE، أو تحويل مجموعة البيانات وتخزينها مسبقًا.

الحكم الإنتاجي: مصفوفة قرار On-Demand مقابل Spot

ليست جميع مهام التدريب يجب أن تذهب إلى Spot. القرار يعتمد على ثلاثة عوامل: مدة المهمة، وتكلفة نقاط التفتيش، والحساسية للمواعيد النهائية. مسح hyperparameter من 200 تجربة قصيرة مدة كل منها 20 دقيقة مثالي لـ Spot. أما تشغيل التدريب النهائي قبل الإنتاج الذي يجب اكتماله في 8 ساعات لإصدار يوم الاثنين، فيجب أن يذهب إلى on-demand مع حجز ضمان للطاقة. الحكم الهندسي: إذا تجاوزت التكلفة المتوقعة للانقطاع وإعادة المحاولة (ساعات وحدات الرسوميات الضائعة بالإضافة إلى التكلفة التشغيلية) خصم Spot، استخدم on-demand.