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

الوحدة 5 — ضبط المعاملات الفائقة على نطاق واسع

في الوحدة السابقة درّبنا نموذجًا واحدًا بمعاملات مختارة يدويًّا. الآن نبحث عن أفضل توليفة معاملات بذكاء عوض التخمين. Vertex AI يُقدِّم لهذا Vizier، خدمة بحث معاملات مُدارة تُشغِّل عشرات التجارب بالتوازي، تتعلّم من النتائج الجارية، وتوقف التجارب الميؤوس منها مبكرًا. هذه الوحدة تُغطّي كيفيّة تحويل سكريبت التدريب إلى وظيفة قابلة للضبط، وكيف نُطلق حملة، وكيف نقرأ نتائجها.

لماذا لا شبكة أو عشوائيّة فقط

البحث الشبكيّ (grid search) يجرِّب كلّ توليفة على شبكة قِيَم. مكلف جدًّا: خمسة معاملات بخمس قِيَم لكلٍّ = 3125 تجربة.

البحث العشوائيّ (random search) يعيّن قيمًا عشوائيّة داخل النطاقات. أفضل من الشبكة لأنّه لا يُضيّع الوقت على أبعاد لا أثر لها، ويُغطّي الفضاء أوسع.

Vizier يُطبّق التحسين البايزي (Bayesian optimization) الذي يبني نموذجًا مستمرّ التحديث لعلاقة المعاملات بالمقياس، ثمّ يقترح التجربة التالية حيث المكاسب المتوقّعة الأكبر. عمليًّا: بعشر تجارب Vizier يبلغ ما يبلغه العشوائيّ في ثلاثين، والفارق يتّسع كلّما زاد عدد المعاملات.

كلٌّ من العشوائيّ وVizier مقبول؛ الأخير هو الافتراضيّ لأيّ حملة تفوق 15 تجربة.

تجهيز السكريبت للتقرير

Vizier يقرأ نتيجة كلّ تجربة عبر مكتبة cloudml-hypertune. نُعدِّل سكريبت الوحدة 4 لإضافة تقرير المقياس عند كلّ خطوة تحقّق:

# trainer/task.py  (إضافة)
import hypertune

hpt = hypertune.HyperTune()

# داخل حلقة boost، بعد كلّ round:
if step % 25 == 0:
val_score = booster.eval(dval).split(":")[1]
hpt.report_hyperparameter_tuning_metric(
hyperparameter_metric_tag="val_aucpr",
metric_value=float(val_score),
global_step=step,
)

نقاط بالغة الأهمّية:

  • hyperparameter_metric_tag: نصّ مطابق حرفيًّا لما نُصرّح به في تعريف الحملة. كلمة مختلفة تعني أنّ Vizier لن يرى المقياس، وستُعتبَر كلّ التجارب بلا نتيجة.
  • تقرير متكرِّر: لا يكفي إبلاغ القيمة النهائيّة. Vizier يستعمل التقارير الوسطى لتحديد ما إن كان يستحقّ متابعة التجربة أو إيقافها مبكرًا.

تعريف الحملة

from google.cloud import aiplatform
from google.cloud.aiplatform import hyperparameter_tuning as hpt

worker_pool = [{
"machine_spec": {
"machine_type": "n1-standard-8",
"accelerator_type": "NVIDIA_TESLA_T4",
"accelerator_count": 1,
},
"replica_count": 1,
"python_package_spec": {
"executor_image_uri": (
"europe-docker.pkg.dev/vertex-ai/training/xgboost-gpu.1-6:latest"
),
"package_uris": ["gs://fraud-staging-lab/trainer-0.1.tar.gz"],
"python_module": "trainer.task",
"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",
],
},
}]

job = aiplatform.CustomJob(
display_name="xgb-fraud-tuning-2026-09-05",
worker_pool_specs=worker_pool,
staging_bucket="gs://fraud-staging-lab",
)

tune_job = aiplatform.HyperparameterTuningJob(
display_name="xgb-fraud-tuning-2026-09-05",
custom_job=job,
metric_spec={"val_aucpr": "maximize"},
parameter_spec={
"max_depth": hpt.IntegerParameterSpec(min=3, max=10, scale="linear"),
"learning_rate": hpt.DoubleParameterSpec(min=0.01, max=0.3, scale="log"),
"num_boost_round": hpt.IntegerParameterSpec(min=100, max=1000, scale="linear"),
},
max_trial_count=40,
parallel_trial_count=8,
search_algorithm=None, # None ⇒ Vizier
)

tune_job.run(service_account="sa-training@fraud-detection-lab.iam.gserviceaccount.com")

القرارات المهمّة:

  • max_trial_count=40: الميزانيّة القصوى. Vizier قد يوقف مبكرًا إن استقرّت النتائج.
  • parallel_trial_count=8: ثماني تجارب تعمل بالتوازي. مكسب زمنيّ عظيم، بتنازل صغير عن جودة الاختيار (كلّ تجربة تُقرَّر قبل أن نرى نتيجة رفاقها).
  • مقياس التحسين واحد (val_aucpr تعظيمًا). ضبط متعدّد الأهداف ممكن لكنّه معقّد التفسير.
  • مقياس learning_rate بمقياس لوغاريتميّ: بين 0.01 و0.3 لوغاريتميًّا يعني توزيع القيم بين رتب المقدار (0.01، 0.03، 0.1، 0.3)، وهذا أدقّ من التوزيع الخطّيّ.

التجارب المتوازية: كم واحدة؟

كلّما زادت التجارب المتوازية:

  • ينكمش الزمن الكلّيّ: 40 تجربة على 8 متوازية ≈ 5 دفعات × مدّة تجربة.
  • تنخفض جودة اختيار Vizier قليلًا: كلّ تجربة تُقرَّر ولا نعرف نتيجة الجاريات، فالنموذج البايزيّ يقرِّر بمعلومات ناقصة.

قاعدة عملية: parallel_trial_count = max_trial_count / 5 (أي خمس دفعات في المجموع). تشغيل 40 تجربة كلّها متوازية يجعل Vizier عشوائيًّا فعليًّا لأنّه لا يتعلّم بين التجارب.

الإيقاف المبكّر داخل الحملة

Vizier يدعم إيقاف تجربة ميؤوس منها عبر إعداد enable_trial_early_stopping=True. آليّة الإيقاف تعتمد على تقرير المقاييس الوسطى: تجربة أدنى من الوسيط بعد 30 % من دورتها تُعتبَر خاسرة وتُقتَل. المكسب: الميزانيّة نفسها تُنفَق على تجارب واعدة أكثر.

فرق مع الإيقاف المبكّر داخل XGBoost (early_stopping_rounds=20): هذا الأخير يوقف حلقة التدريب داخل تجربة واحدة عند توقّف تحسّن التحقّق. لا يتضارب الاثنان: الأوّل يُنقذ الحملة من التجارب السيّئة، الثاني يُنقذ التجربة نفسها من الإفراط.

قراءة النتائج

بعد انتهاء الحملة:

trials = tune_job.trials
for t in sorted(trials, key=lambda t: -t.final_measurement.metrics[0].value)[:5]:
print(t.id, t.final_measurement.metrics[0].value, t.parameters)

نطبع الخمس تجارب الأولى وقِيَم معاملاتها. القيم القريبة من الحدود القصوى للمجال تُشير إلى مجال بحث ضيّق: توسِّعه في الحملة التالية.

للتصوير البصريّ، واجهة Vertex في وحدة التحكّم تعرض:

  • خطًّا زمنيًّا لتحسّن أفضل قيمة عبر التجارب
  • مخطّطًا متوازيًا (parallel coordinates) يربط قِيَم كلّ معامل بالمقياس النهائيّ
  • توزيع القِيَم لكلّ معامل

المخطّط المتوازي مفيد بشكل خاصّ لكشف ارتباطات غير متوقّعة: قد يكشف أنّ learning_rate < 0.05 وحده يعطي النتائج الجيّدة، بغضّ النظر عن max_depth، فتُعاد الحملة التالية على مجال أضيق حول 0.03.

ما لا يفعله Vizier

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

كلمة val_aucpr في السكريبت يجب أن تُطابق كلمة metric_spec في تعريف الحملة حرفيًّا. حرف واحد مختلف، ولن يرى Vizier أيّ نتيجة، فتبدو التجارب كأنّها فشلت جميعًا مع أنّها ناجحة. سجّل التسمية ثابتة مركزيًّا (METRIC_TAG = "val_aucpr") واستوردها في الطرفَين.

لا تُطلق حملة قبل تدريب فرديّ ناجح

اختبر أنّ سكريبت التدريب يعمل بمعاملات ثابتة ثمّ يُبلِّغ المقياس، عبر تشغيل تدريب مخصّص وحيد (الوحدة 4). حملة معاملات فاشل سكريبتها تدفع 40 تجربة قبل أن ندرك أنّ الخطأ يبعد سطرين.

في الخلاصة

  • Vizier أذكى من العشوائيّ بعد 15 تجربة، والفارق يتّسع مع تعقيد الفضاء.
  • تقرير المقياس عدّة مرّات ضروريّ لتفعيل الإيقاف المبكّر داخل الحملة.
  • التوازي يُقلّص الزمن مقابل تنازل صغير عن الجودة؛ parallel = max / 5 قاعدة سليمة.
  • المخطّط المتوازي في الواجهة يكشف الحدود الحقيقيّة للمعاملات ويوجّه الحملة التالية.

الوحدة التالية: كيف نُخزِّن النموذج الفائز في سجلّ النماذج بإصدارات وأسماء مستعارة.