انتقل إلى المحتوى الرئيسي

الوحدة 4 — التدريب المخصّص والحاويات

الوحدة السابقة أنتجت مجموعة بيانات جاهزة على GCS. الآن نُدرِّب نموذج XGBoost لكشف الاحتيال، لكن لا على الدفتر: نُطلقه كوظيفة تدريب مُدارة تعمل في حاوية على آلة قد لا تكون آلتنا. هذا القرار يُحرِّر الدفتر (يعمل الفريق أثناء ذلك)، يُوحِّد بيئة التدريب مع الإنتاج، ويسمح بمحاسبة دقيقة على وحدات المعالجة الرسوميّة.

لماذا حاوية، ولماذا مُدارة

لثلاثة أسباب متكاملة:

  • إعادة إنتاج المطلوب: الحاوية تُثبِّت نسخ Python، xgboost، cuDNN، إلخ. تدريب مرّة بعد سنة ينتج النموذج ذاته (بفارق العشوائيّة الأوّلية).
  • عزل الفشل: تدريب على 8 ساعات على وحدة معالجة رسوميّة داخل الدفتر يُوقفه أيّ خطأ اتّصال. تدريب مُدار يعمل بعيدًا عن جلستك، ويعاود المحاولة تلقائيًّا.
  • قياسيّة الفواتير: الوظيفة المُدارة تُفوتَر لثوانِ التنفيذ الفعليّة. الآلة تُنشَأ تلقائيًّا وتُدمَّر عند الانتهاء. لا نفقد المال على آلة منسيّة.

حاويات مُسبَقة الصنع مقابل مخصّصة

Vertex يُقدِّم حاويات مُسبَقة الصنع (pre-built training containers) لأُطُر شهيرة:

  • TensorFlow (CPU / GPU)
  • PyTorch (CPU / GPU / متعدّد الأنوية)
  • XGBoost
  • scikit-learn

نُمرِّر إليها كود تدريبنا كسكريبت أو حزمة، وتُعتنى بالبقيّة. لبدايات المشروع، حاوية مُسبَقة الصنع تكفي في 90 % من الحالات.

الحاوية المخصّصة تصير ضرورةً حين:

  • تحتاج مكتبات نظام غير موجودة في المُسبَقة (libpq لPostgres، ffmpeg لصوت).
  • تشغّل إطار عمل حديثًا لم تُتاح له حاوية بعد.
  • تفرض نُسخًا محدّدة (خصوصًا CUDA وcuDNN حين تُدار بيئة CI بصرامة).

للفيل الأحمر (XGBoost)، نبدأ بحاوية مُسبَقة الصنع.

سكريبت تدريب قابل للتشغيل

يقرأ من GCS، يُدرِّب، يكتب النموذج إلى GCS. لا يفترض شيئًا عن الدفتر:

# trainer/task.py
import argparse
import os
import pandas as pd
import xgboost as xgb
import fsspec
from sklearn.metrics import roc_auc_score

def load(path: str) -> pd.DataFrame:
with fsspec.open(path, mode="rb") as f:
return pd.read_parquet(f)

def main(args):
train = load(args.train_uri)
val = load(args.val_uri)

features = [c for c in train.columns if c != "y"]
dtrain = xgb.DMatrix(train[features], label=train["y"])
dval = xgb.DMatrix(val[features], label=val["y"])

params = {
"objective": "binary:logistic",
"eval_metric": "aucpr",
"max_depth": args.max_depth,
"eta": args.learning_rate,
"tree_method": "gpu_hist" if args.use_gpu else "hist",
"scale_pos_weight": args.scale_pos_weight,
}

booster = xgb.train(
params,
dtrain,
num_boost_round=args.num_boost_round,
evals=[(dtrain, "train"), (dval, "val")],
early_stopping_rounds=20,
verbose_eval=25,
)

preds = booster.predict(dval)
print(f"val AUC-PR : {roc_auc_score(val['y'], preds):.4f}")

# AIP_MODEL_DIR يُحقن آليًّا من Vertex ⇒ مسار GCS خاصّ بهذه الوظيفة
out = os.environ.get("AIP_MODEL_DIR", args.model_dir)
with fsspec.open(f"{out}/model.bst", "wb") as f:
booster.save_model(f)
print(f"model saved to {out}/model.bst")

if __name__ == "__main__":
p = argparse.ArgumentParser()
p.add_argument("--train-uri", required=True)
p.add_argument("--val-uri", required=True)
p.add_argument("--model-dir", default="gs://fraud-models-lab/local")
p.add_argument("--max-depth", type=int, default=6)
p.add_argument("--learning-rate", type=float, default=0.1)
p.add_argument("--num-boost-round", type=int, default=400)
p.add_argument("--scale-pos-weight", type=float, default=200.0)
p.add_argument("--use-gpu", action="store_true")
main(p.parse_args())

نقطتان أساسيّتان:

  • AIP_MODEL_DIR متغيّر بيئة يُعبِّئه Vertex تلقائيًّا بمسار GCS خاصّ بهذه الوظيفة. حفظ النموذج فيه يُتيح ربطه لاحقًا في سجلّ النماذج (الوحدة 6).
  • scale_pos_weight يعكس عدم توازن التوسيم (احتيال نادر). التفاصيل مغطّاة في دورة MLOps.

إطلاق CustomTrainingJob

من الدفتر أو خطّ CI:

from google.cloud import aiplatform

aiplatform.init(project="fraud-detection-lab", location="europe-west1",
staging_bucket="gs://fraud-staging-lab")

job = aiplatform.CustomTrainingJob(
display_name="xgb-fraud-2026-09-05",
script_path="trainer/task.py",
container_uri="europe-docker.pkg.dev/vertex-ai/training/xgboost-gpu.1-6:latest",
requirements=["fsspec", "gcsfs"], # مثبَّتة داخل الحاوية
staging_bucket="gs://fraud-staging-lab",
model_serving_container_image_uri=(
"europe-docker.pkg.dev/vertex-ai/prediction/xgboost-cpu.1-6:latest"
),
)

model = job.run(
args=[
"--train-uri=gs://fraud-features-lab/features/2026-09-05/train/*.parquet",
"--val-uri=gs://fraud-features-lab/features/2026-09-05/val/*.parquet",
"--use-gpu",
],
replica_count=1,
machine_type="n1-standard-8",
accelerator_type="NVIDIA_TESLA_T4",
accelerator_count=1,
service_account="sa-training@fraud-detection-lab.iam.gserviceaccount.com",
base_output_dir="gs://fraud-models-lab/xgb-fraud-2026-09-05",
model_display_name="xgb-fraud", # ⇒ يُسجَّل في Model Registry
)

يحدث خلف الكواليس:

  1. Vertex يُنشئ الآلة، يسحب حاوية التدريب، ويشغّل السكريبت.
  2. المخرجات (السجلّات، المقاييس، النموذج) تُخزَّن تحت base_output_dir.
  3. عند نجاح التشغيل مع model_serving_container_image_uri، يُسجَّل النموذج آليًّا في سجلّ النماذج.
  4. الآلة تُدمَّر ويتوقّف الفوتُرة.

اختيار نوع الآلة والمُسرِّع

جدول الفيل الأحمر (بضعة ملايين سطر، XGBoost):

الأداةزمن التدريب التقريبيّالكلفة التقريبيّةمتى نختارها
n1-standard-8 بلا GPU55 دقيقة0.35 دولارتنقيح، اختبار
n1-standard-8 + T46 دقائق0.10 دولارتدريب دوريّ
n1-standard-16 + V1003 دقائق0.30 دولارفارق ضئيل بلا داعٍ
a2-highgpu-1g + A1002 دقيقة0.35 دولارلا مبرِّر هنا

نلاحظ أنّ T4 هي الأفضل ثمنًا لهذا الحجم: أرخص من CPU لأنّها تُنهي التدريب بسرعة عشرة أضعاف، فتُنفَق الآلة أقلّ زمنًا. النموذج الأكبر (شبكات عصبيّة عميقة) يقلب المعادلة نحو A100. القاعدة: قِس ثمّ اختر، لا تفترض أنّ الأقوى هو الأرخص لأنّه أسرع.

التدريب الموزَّع باختصار

للنماذج التي تفوق ذاكرة وحدة معالجة رسوميّة واحدة (نماذج لغة أو رؤية)، Vertex يدعم عدّة استراتيجيّات:

  • MirroredStrategy (TensorFlow): نُسخ متطابقة على عدّة وحدات معالجة رسوميّة داخل الآلة نفسها.
  • MultiWorkerMirroredStrategy و**ParameterServerStrategy**: موزَّع على عدّة آلات.
  • PyTorch DDP بمواصلات NCCL على الآلات المتّصلة بشبكة عالية السرعة.

لا نحتاجها للفيل الأحمر (XGBoost على T4 تكفي)، لكن التوسّع نحوها يتطلّب فقط ضبط replica_count، accelerator_count، وreduction_server_replica_count للحصول على شبكة تخفيض جماعيّ.

حجم القرص المؤقّت يحدّد نجاح التحميل

الآلة المفعَّلة تحمل boot_disk_size_gb بالافتراضيّ 100 غيغا. إن كان جدول التدريب Parquet 30 غيغا مضغوطة، لكنّها تنفتح إلى 90 غيغا في الذاكرة كإطار pandas، مع مؤقّتات الحاوية ولوغات، تنكسر الوظيفة قبل بدء الحلقة الأولى بخطأ «القرص ممتلئ». اضبط boot_disk_size_gb=400 للمشاريع الجدّية.

الحاوية المُسبَقة الصنع تُتيح الترقية اللاحقة إلى مخصّصة

ابدأ بالحاوية المُسبَقة الصنع؛ عندما تكتشف حاجةً غير مغطّاة (مكتبة نظام، إصدار CUDA)، بناء Dockerfile مخصّص يستنسخ سلوكها ثمّ يُضيف ما ينقصك. أفضل من محاولة بناء بيئة كاملة من الصفر.

في الخلاصة

  • التدريب المُدار يُحرِّر الدفتر، يوحّد بيئة الإنتاج، ويُحاسِب بالثانية.
  • الحاويات المُسبَقة الصنع تكفي أغلب الحالات؛ المخصّصة عند مكتبات نظام أو إصدارات دقيقة.
  • AIP_MODEL_DIR هو مسار المخرج المتوقَّع الذي يربط النموذج بسجلّ النماذج آليًّا.
  • T4 غالبًا أرخص من CPU لأنّها تنهي التدريب أسرع؛ اختيار المُسرِّع قرار قياس لا ذوق.

الوحدة التالية: ضبط المعاملات الفائقة على Vizier بتجارب متوازية وإيقاف مبكر ذكيّ.