Transformers documentation

التوازي الخبير

You are viewing main version, which requires installation from source. If you'd like regular pip install, checkout the latest stable version (v5.22.1).
Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

التوازي الخبير

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

DistributedConfig

فعّل توازي الخبراء باستخدام فئة DistributedConfig والحجة ep_size. تعتمد معظم نماذج MoE افتراضيًا على token dispatch، لذا يمكن تعيين ep_size بشكل مستقل عن tp_size. لا تزال بعض النماذج، مثل Llama 4 و Gemma 4، تعتمد افتراضيًا على الأقنعة و all-reduce ("ep_router" و "moe_tp_experts" في model.ep_plan). كما يتوفر استخدام الأقنعة على أي نموذج مع تجاوز ep_plan، ويتطلب ذلك ep_size=tp_size حتى يتلقى كل رتبة في مجموعة الخبراء الرموز نفسها.

import os

import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
from transformers.distributed.configuration_utils import DistributedConfig

distributed_config = DistributedConfig(
    tp_size=int(os.environ["WORLD_SIZE"]),
    ep_size=int(os.environ["WORLD_SIZE"]),
)

model = AutoModelForCausalLM.from_pretrained(
    "openai/gpt-oss-120b",
    distributed_config=distributed_config,
)

يحدد كل نموذج MoE خطتين في ملفه الإعدادي: base_model_tp_plan للوحدات الكثيفة وbase_model_ep_plan للخبراء. وتُعرض هاتان الخطتان على النموذج المحمّل على شكل model.tp_plan وmodel.ep_plan. عند استخدام tp_size > 1 وep_size > 1، تُطبَّق الخطتان معًا: حيث يقوم خط التوازي على مستوى المصفوفات بتقسيم وحدات الانتباه ووحدات MLP الكثيفة، بينما يقوم خط التوازي على مستوى الخبراء بتقسيم الخبراء. ولأن قواعد EP لها الأولوية على قواعد TP بالنسبة لنفس الوحدات، فإن أوزان الخبراء تُقسَّم مرة واحدة فقط، وذلك وفق خط EP. وفي خط EP، يقوم نمط GroupedGemmParallel بتقسيم أوزان الخبراء على طول بُعد الخبراء بحيث يحمّل كل rank الخبراء المحليين لديه فقط، بينما يقوم ep_router بإخفاء الخبراء الموجودة على ranks أخرى قبل أن يجمع all-reduce مخرجات الخبراء.

يُطبَّق tp_plan فقط عندما يكون tp_size > 1، وep_plan فقط عندما يكون ep_size > 1. عند تفعيل TP وتعطيل EP، يُطبَّق خطة TP الكاملة، بما في ذلك قواعد الخبراء.

تختص قاعدة الأمامي الخبير في ep_plan بكيفية وصول الرموز إلى الخبراء:

قاعدةآليةتخطيط
"moe_tp_experts" مع "ep_router" على الموجّهالتخفي والجمع الشامل: يقوم كل رتبة بتشغيل خبرائها المحليين على الدفعة الكاملة، ويقوم الموجّه بتخفي الآخرين، ثم يجمع الجمع الشامل المخرجاتep_size=tp_size
"ep_dispatch_experts"توزيع الرموز: يحتفظ كل رتبة برموزها الخاصة ولا يتبادل إلا أزواج (الرمز، الخبير) الموجَّهة عبر مجموعتين من عمليات all-to-allep_size مضاعف لـ tp_size يقسم fsdp_size * tp_size

استخدام enable_expert_parallel=True دون تحديد ep_size أصبح غير مدعوم، ويُصدر تحذيرًا من نوع FutureWarning. يقوم هذا الإعداد بتقسيم الخبراء فقط، تمامًا كما في ep_size=tp_size, tp_plan={}.

شغّل سكربت الاستدلال الخاص بك باستخدام torchrun. يجب أن يساوي عدد العمليات tp_size * fsdp_size * pp_size، وأن يقسم ep_size عدد الخبراء قسمة تامة.

torchrun --nproc-per-node 8 your_script.py

التجاوز على الخطط

مرّر tp_plan={...} أو ep_plan={...} إلى DistributedConfig لتجاوز قواعد محددة في الخطط المحددة مسبقًا. تُحفظ القواعد غير المحددة، وتُخزَّن الخطط المدمجة على النموذج. يجب أن يطابق كل مفتاح وحدةً أو معاملًا أو عنصرًا موجودًا في الخطة؛ وإلا فسيُطلق التحميل ValueError قبل تقسيم أي شيء. استخدم المسار الكامل كما يظهر من النموذج المحمّل، لذا model.layers.* لنموذج LM السببي وlayers.* لنموذه الأساسي.

distributed_config = DistributedConfig(
    tp_size=4,
    ep_size=4,
    tp_plan={"model.layers.*.self_attn.q_proj": "colwise_rep"},
    ep_plan={"model.layers.*.mlp.experts.down_proj": "grouped_gemm"},
)

تقديم خطة لا يستنتج أحجام التوازي: اضبط tp_size وep_size بشكل صريح.

تعتمد معظم نماذج MoE افتراضيًا على "ep_dispatch_experts". لاستخدام الأقنعة (masking) و all-reduce بدلاً من ذلك، اضبط ep_size=tp_size وأعد كتابة كلٍّ من قواعد التوجيه (router) وقواعد الأمامية (forward) للخبراء (يعتمد اسم وحدة التوجيه على النموذج، مثل mlp.router في gpt-oss):

distributed_config = DistributedConfig(
    tp_size=4,
    ep_size=4,
    ep_plan={
        "model.layers.*.mlp.gate": "ep_router",
        "model.layers.*.mlp.experts": "moe_tp_experts",
    },
)

وعلى العكس من ذلك، تجاوز قاعدة الأمامية للخبراء في نموذج يستخدم الخطة التي تعتمد على الأقنعة باستخدام "ep_dispatch_experts" لتوزيع الرموز. يتم تجاهل قاعدة الموجّه في هذه الحالة، لأن التوزيع يحتاج إلى معرفات الخبراء العالمية لإيجاد مالك كل خبير.

توزيع الرموز

With token dispatch, each rank trains on its own part of the batch. At every MoE layer, a rank routes its tokens, sends each (token, expert) pair to the rank that owns the expert with an all-to-all, runs its local experts on what it receives, gets the results back with a second all-to-all and combines them with the routing weights. Only the routed activations and expert outputs travel, and no rank computes experts for tokens it does not own.

from transformers import AutoModelForCausalLM
from transformers.distributed import DistributedConfig

distributed_config = DistributedConfig(
    tp_size=1,
    fsdp_size=8,
    ep_size=4,
)
model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen3-30B-A3B", distributed_config=distributed_config)

عند tp_size=1، يجب أن يكون ep_size قاسماً لـ fsdp_size وعدد الخبراء، ولا يكون الانتباه مقيداً بـ num_key_value_heads. أما بالنسبة لباقي النموذج:

  • تُقسَّم المعاملات خارج الخبراء باستخدام FSDP2 عبر fsdp، مما يقلل من تدرجاتها.
  • تُقسَّم الخبراء عبر ep، وعندما يكون efsdp_size = fsdp_size * tp_size // ep_size أكبر من واحد، تُقسَّم أيضًا عبر efsdp باستخدام تقسيم FSDP. وهي دائمًا مُغلَّفة بـ FSDP، لذا فإن fsdp_mixed_precision وfsdp_cpu_offload تنطبق عليها أيضًا، وsave_pretrained() تجمعها مثل أي معامل آخر.
  • يحتوي مجموعة التوازي الخبير على ep_size / tp_size دفعات، لذا فإن تدرج الخبير هو مجموع على ذلك العدد من الدفعات. تقسيم efsdp يقسم على fsdp_size بدلاً من حجم مجموعته، مما يعطي متوسط FSDP2 لكل دفعة الذي تتخذه للوحدات الكثيفة.
  • يعالج كل خبير محلي أيضًا صفًا واحدًا من الحشو الصفري في كل طبقة. أما المرتبة التي لم تتلقِ خبراؤها أي رموز، فإنها تشارك لا تزال في عملية all-to-all العكسية وتقليل تدرجات الخبراء.

كيف يتم دمج الأحجام

  • tp_size * fsdp_size هو عدد العمليات. ep_size لا يضيف شيئًا: فهو يعيد تجميع نفس الرتب لأوزان الخبراء فقط.
  • يقسم ep_size قائمة الخبراء إلى ep_size كتل. يحسب كل رتبة num_experts / ep_size من الخبراء، وتحتفظ ep_size رتب متتالية بمجموعة كاملة واحدة. تلك المجموعة من الرتب هي المجموعة التي يعمل فيها all-to-all.
  • efsdp_size = fsdp_size * tp_size / ep_size هو عدد النسخ الكاملة الموجودة من مجموعة الخبراء. تقوم الرتب الموجودة في نفس الموقع في النسخ المختلفة بتجزئة هؤلاء الخبراء من أجل الذاكرة، ثم تُوسط تدرجاتهم، تماماً كما تفعل FSDP مع الوحدات الكثيفة.
  • يعتمد الدفعة التي يحتفظ بها كل رتبة على fsdp فقط. تتكوّن الرتب المتتالية من مجموعة TP وتحصل على نفس الدفعة؛ بينما تحصل مجموعات fsdp_size على دفعات مختلفة.

ثماني عمليات، tp_size=2, fsdp_size=4، ثمانية خبراء:

rank         0      1       2      3       4      5       6      7
batch       [====B0====]   [====B1====]   [====B2====]   [====B3====]     one batch per TP pair
tp           0      1       0      1       0      1       0      1

ep_size=2   E0-3   E4-7    E0-3   E4-7    E0-3   E4-7    E0-3   E4-7     group = a TP pair,   efsdp_size=4
ep_size=4   E0E1   E2E3    E4E5   E6E7    E0E1   E2E3    E4E5   E6E7     group = two pairs,   efsdp_size=2
ep_size=8   E0     E1      E2     E3      E4     E5      E6     E7       group = all ranks,   efsdp_size=1

ينجم عن الصورة عددان:

  • داخل مجموعة EP، يوجد كل رمز tp_size مرات، مرة واحدة لكل رتبة من الزوج الذي يحمل دفعته. ولا يعتمد هذا على ep_size.
  • تحتوي مجموعة EP على ep_size / tp_size دفعات مختلفة. وهذا هو العدد الذي تُجمَّع عليه تدرّجات الخبير.

مع توازي الموترات

اضبط tp_size > 1 لتقسيم الوحدات الكثيفة وفق خطة TP بينما تستخدم الخبراء الإرسال. على ثمانية عمليات:

distributed_config = DistributedConfig(
    tp_size=2,
    fsdp_size=4,
    ep_size=4,
)

تستقبل كل زوج من رتب TP الدفعة (batch) نفسها، لأن توازي الموترات (tensor parallelism) يكرر التفعيلات (activations) داخل الزوج. إذا أرسلت كلتا الرتب جميع رموزها (tokens)، فإن الرتبة التي تمتلك خبيرًا (expert) ستتلقى كل رمز مرتين، وتحسبه مرتين، وستتضاعف تدرج أوزانه (weight gradient). نظرًا لأن الخبراء كاملون على رتبة واحدة، فلا يمكن تقسيم النسخة المكررة عبر الأوزان، وغالبًا ما تكون الرتبة المالكة رتبة أخرى، فلا يمكن حل المشكلة عبر الملكية كما تفعل عملية الإخفاء (masking). لذلك يقسم الزوج الصفوف: ترسل كل رتبة TP جزءًا منفصلًا 1 / tp_size من الرموز، وتعود النتائج إلى الرتبة التي أرسلتها، ثم تعيد عملية all-reduce على الزوج للنصفين المملوءين بالصفر استعادة المخرجات المكررة التي تتوقعها الطبقة التالية. يتم التقسيم حسب tp_size وليس ep_size، لأن الرتب التي تحمل دفعة فقط هي التي يمكنها إرسالها. تمتد مجموعات الخبراء عبر أربع رتب، وكل خبير مقسّم عبر FSDP على efsdp_size = 2 رتبة، بينما تمتد مجموعة FSDP للجذع (trunk) عبر أربع رتب. لا تزال قيود TP المعتادة للنموذج، مثل قابلية رؤوس الانتباه (attention-heads) للقسمة، تنطبق على الوحدات الكثيفة (dense modules). قد تكون شرائح الرموز غير متساوية أو فارغة، بما في ذلك أثناء فك ترميز رمز واحد.

لا يمكن دمج توزيع الرموز (Token dispatch) مع توازي الخطوط (pipeline parallelism) بعد؛ استخدم pp_size=1 (لم يتم الاختبار بعد) تستخدم كل من هذه الإعدادات ثمانية وحدات معالجة رسومية (GPU):

الإعدادالنتيجة
DistributedConfig(tp_size=4, fsdp_size=2, ep_size=4)التوزيع عبر مجموعات TP من أربعة، حيث تقطع كل مجموعة دفعتها إلى أربعة (الخطة الافتراضية)؛ ما لم تحدد ep_plan لاستخدام EP المقنّع القديم
DistributedConfig(tp_size=1, fsdp_size=8, ep_size=4)Dispatch مع دفعة مستقلة على كل رتبة، دون تقطيع، وخبراء مُقسَّمين عبر أزواج من الرتب باستخدام FSDP.
DistributedConfig(tp_size=2, fsdp_size=4, ep_size=4)أرسل باستخدام زوج TP لكل دفعة، حيث يقسم كل زوج دفعته إلى نصفين؛ دفعتان لكل مجموعة خبراء.
DistributedConfig(tp_size=8, ep_size=8)أرسل مع مشاركة كل رتبة دفعة واحدة، مقسّمة إلى ثمانية، أو استخدم الإخفاء (masking) وجميع الاختزال (all-reduce) لخطة مخفية.

لا يأخذ Trainer بعد في الحسبان إرسال الرموز: فعدّ الدفعات والرموز يفترض تخطيط all-reduce، حيث تتشارك رتب مجموعة TP دفعة واحدة وتوجد fsdp_size شظايا موازية للبيانات. تأتي دعم Trainer للإرسال في متابعة لاحقة.

الدمج مع FSDP2

يقوم توازي الموترات وتوازي الخبراء بتقسيم الأوزان عبر tp، لكن حالة المُحسِّن (optimizer) والوحدات التي لا تخضع لقاعدة ما تبقى مكررة على كل رتبة ضمن المجموعة، مما يحد من حجم النموذج الذي يمكن تدريبه. أضف FSDP2 على بُعد شبكة ثانٍ باستخدام fsdp_size. مع استخدام الأقنعة (masking) و all-reduce، حافظ على ep_size=tp_size ومرر `ep_plan={“layers..mlp.gate”: “ep_router”, “layers..mlp.experts”: “moe_tp_experts”}“.

from transformers import AutoModelForCausalLM
from transformers.distributed import DistributedConfig

distributed_config = DistributedConfig(
    tp_size=4,
    ep_size=4,  # expert parallel size, must match tp_size with masking and all-reduce
    fsdp_size=2,  # data parallel shards
    ep_plan={
        "model.layers.*.mlp.gate": "ep_router",
        "model.layers.*.mlp.experts": "moe_tp_experts",
    },
)
model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen3-30B-A3B", distributed_config=distributed_config)

حمّل النموذج كما هو معتاد، ثم درّبه باستخدام Trainer. يقوم هذا بإيجاد معيار التدرج عبر كلا الشبكتين ومنح كل شبكة مجموعة معلمات خاصة بها في المُحسِّن. تجمع save_model() الأوزان المجزأة في نقطة تحقق عادية. يتطلب هذا accelerate>=1.12 حتى يتمكن Trainer من عكس tp_size وfsdp_size إلى ~Accelerate.ParallelismConfig.

يقارن الجدول أدناه التدريب باستخدام EP فقط مع التدريب ثنائي الأبعاد EP+FSDP2 على 8 وحدات GPU من نوع H100. يتكون عبء العمل من الضبط الكامل لنموذج Qwen3-30B-A3 بدقة bf16 عند طول تسلسل يبلغ 2048. تقلل شظايا FSDP الإضافية من ذروة الذاكرة، وتنخفض سرعة المعالجة (رموز/ثانية) قليلاً لأن FSDP2 يقوم بجمع (all-gathers) وتشتيت (reduce-scatters) الخبراء عبر fsdp.

الإعدادرموز/ثانية/وحدة معالجة رسوميةذروة الذاكرة/وحدة معالجة الرسوميات
tp_size=8348538.6 GB
tp_size=4, fsdp_size=2290034.2 GB
tp_size=2, fsdp_size=4283032.3 GB

لا يُدعَم استئناف التدريب من نقطة تحقق بعد للنماذج التي تُقسَّم عند التحميل، لذا يقبل Trainer فقط save_only_model=True أو save_strategy="no" لها.

مرجع الواجهة البرمجية

فئة transformers.DistributedConfig

< >

( tp_size: int | None = Nonetp_plan: typing.Union[dict[str, str], typing.Literal['auto'], NoneType] = Noneenable_sequence_parallel: bool = Falseenable_expert_parallel: bool = Falsefsdp_size: int | None = Nonefsdp_plan: dict[str, str] | None = Nonefsdp_cpu_offload: bool = Falsefsdp_mixed_precision: bool = Falsepp_size: int | None = Noneep_size: int | None = Noneep_plan: dict[str, str] | None = None )

المعاملات

  • tp_size (int، اختياري) — عدد الأجهزة للتوازي على مستوى الموترات. إذا كان None وتم تعيين tp_plan، فإن القيمة الافتراضية هي WORLD_SIZE // (other_parallel_size). إذا كان None ولم يتم تعيين tp_plan، فإن القيمة الافتراضية هي 1.
  • tp_plan (dict[str, str] أو "auto"، اختياري) — خطة تقسيم التوازي على مستوى المصفوفات. مرّر "auto"، أو اتركه None عند ضبط tp_size، لاستخدام base_model_tp_plan المُعرّف مسبقًا للنموذج. مرّر قاموسًا لتجاوز قواعد محددة في تلك الخطة؛ تُحفظ القواعد غير المحددة. تطبيق قاموس فارغ يعني عدم تطبيق أي قاعدة لتوازي المصفوفات.
  • enable_sequence_parallel (bool، اختياري، القيمة الافتراضية False) — مخصص للتوازي التسلسلي. لم يتم ربطه بعد.
  • enable_expert_parallel (bool، اختياري، القيمة الافتراضية False) — مُتقادم، أُزيل في الإصدار v5.21. بدون ep_size، يكون مطابقًا لـep_size=tp_size, tp_plan={}: خطة التوازي بين الخبراء وحدها عبر tp_size من الرتب. القيمة الصريحة لـep_size لها الأولوية. لا يغيّر هذا العلم قيمة tp_size أو fsdp_size.
  • fsdp_size (int، اختياري) — عدد الأجهزة الخاصة بـ FSDP (التوازي في البيانات). إذا كانت None وتم تعيين tp_size، فإن القيمة الافتراضية هي 1.
  • fsdp_plan (dict[str, str], اختياري) — خطة تجزئة FSDP2. اتركه None لاستخدام base_model_fsdp_plan المحدد مسبقًا في النموذج و_fsdp_plan على مستوى الفئة. مرر قاموسًا لتجاوز قواعد فردية؛ وتُحفظ القواعد غير المحددة. يُطبَّق فقط عندما fsdp_size > 1.
  • fsdp_cpu_offload (bool، اختياري، القيمة الافتراضية False) — ما إذا كان سيتم تفعيل نقل المعالجة إلى وحدة المعالجة المركزية (CPU) لـ FSDP2.
  • fsdp_mixed_precision (bool، اختياري، القيمة الافتراضية False) — ما إذا كان سيتم تفعيل الدقة المختلطة لـ FSDP2.
  • pp_size (int، اختياري) — عدد الأجهزة للتوازي في خط الأنابيب. إذا كان None وتم ضبط وضع توازي آخر، يكون الافتراضي 1.
  • ep_size (int، اختياري) — عدد الأجهزة التي تمتلك شرائح خبراء مميزة. القيمة الافتراضية هي 1. اضبطه صراحةً لتفعيل EP. يجب أن يكون مضاعفًا لـtp_size وقاسمًا لـfsdp_size * tp_size. تتطلب خطط تقليل الخبراء الكلّية ep_size=tp_size؛ كما يسمح توزيع الرموز ("ep_dispatch_experts") أيضًا بـep_size > tp_size.
  • ep_plan (dict[str, str]، اختياري) — خطة تجزئة التوازي بين الخبراء. اتركه None لاستخدام base_model_ep_plan المُعرَّفة مسبقًا في النموذج. مرِّر قاموسًا لتجاوز قواعد فردية في تلك الخطة؛ وتُحفظ القواعد غير المحددة. تُطبَّق فقط عندما يكون ep_size > 1، وتأخذ قواعدها الأولوية على قواعد tp_plan لنفس الوحدات. قاعدة "ep_dispatch_experts" تختار إرسال الرموز من الكل إلى الكل بدلاً من إخفاء الموجِّه والجمع الشامل.

إعدادات الاستدلال والتدريب الموزعين الأصليين باستخدام التوازي على مستوى الموترات أو خط الأنابيب أو FSDP2.

Update on GitHub