Accelerate documentation
استخدام عدة نماذج مع DeepSpeed
استخدام عدة نماذج مع DeepSpeed
يفترض هذا الدليل أنك قد قرأت وفهمت دليل استخدام DeepSpeed.
يُفيد تشغيل عدة نماذج باستخدام Accelerate وDeepSpeed في:
- التقطير المعرفي
- تقنيات ما بعد التدريب مثل RLHF (انظر مكتبة TRL لمزيد من الأمثلة)
- تدريب عدة نماذج في وقت واحد
حاليًا، يحتوي Accelerate على واجهة برمجة تجريبية للغاية لمساعدتك في استخدام عدة نماذج.
ستركّز هذه الشرحية على حالتَي استخدام شائعتين:
- التقطير المعرفي، حيث يُدرَّب نموذج طالب أصغر لمحاكاة أداء معلم أكبر وأفضل. إذا كان نموذج الطالب يتسع على وحدة معالجة رسومية واحدة، يمكننا استخدام ZeRO-2 للتدريب وZeRO-3 لتقسيم المعلم للاستدلال. وهذا أسرع بكثير من استخدام ZeRO-3 لكلا النموذجين.
- تدريب عدة نماذج غير مترابطة في وقت واحد.
التقطير المعرفي
يُعدّ تقطير المعرفة مثالاً جيدًا على استخدام عدة نماذج مع تدريب أحدها فقط.
عادةً، كنتَ ستستخدم utils.DeepSpeedPlugin واحدًا لكلا النموذجين. ومع ذلك، في هذه الحالة، هناك إعدادان منفصلان. يتيح لك Accelerate إنشاء واستخدام عدة إضافات فقط إذا كانت ضمن dict حتى تتمكن من الإشارة إلى الإضافة المناسبة وتفعيلها عند الحاجة.
from accelerate.utils import DeepSpeedPlugin
zero2_plugin = DeepSpeedPlugin(hf_ds_config="zero2_config.json")
zero3_plugin = DeepSpeedPlugin(hf_ds_config="zero3_config.json")
deepspeed_plugins = {"student": zero2_plugin, "teacher": zero3_plugin}يجب أن يُهيّأ zero2_config.json للتدريب الكامل (لذلك حدد scheduler وoptimizer إذا لم تكن تستخدم خاصيتك الخاصة)، بينما يجب أن يُهيّأ zero3_config.json لنموذج الاستدلال فقط، كما هو موضح في المثال أدناه.
{
"bf16": {
"enabled": "auto"
},
"zero_optimization": {
"stage": 3,
"overlap_comm": true,
"reduce_bucket_size": "auto",
"stage3_prefetch_bucket_size": "auto",
"stage3_param_persistence_threshold": "auto",
"stage3_max_live_parameters": "auto",
"stage3_max_reuse_distance": "auto",
},
"train_micro_batch_size_per_gpu": 1
}يُظهر ما يلي مثالاً على تكوين zero2_config.json.
{
"bf16": {
"enabled": "auto"
},
"optimizer": {
"type": "AdamW",
"params": {
"lr": "auto",
"weight_decay": "auto",
"torch_adam": true,
"adam_w_mode": true
}
},
"scheduler": {
"type": "WarmupLR",
"params": {
"warmup_min_lr": "auto",
"warmup_max_lr": "auto",
"warmup_num_steps": "auto"
}
},
"zero_optimization": {
"stage": 2,
"offload_optimizer": {
"device": "cpu",
"pin_memory": true
},
},
"gradient_accumulation_steps": 1,
"gradient_clipping": "auto",
"train_batch_size": "auto",
"train_micro_batch_size_per_gpu": "auto",
}سيُطلق DeepSpeed خطأً إذا لم يتم تحديد
train_micro_batch_size_per_gpu، حتى لو لم يكن هذا النموذج المحدد قيد التدريب.
من هنا، أنشئ كائن Accelerator واحدًا ومرر كلا التكوينين إليه.
from accelerate import Accelerator
accelerator = Accelerator(deepspeed_plugins=deepspeed_plugins)دعونا الآن نرى كيفية استخدامها.
نموذج الطالب
بشكل افتراضي، يحدد Accelerate العنصر الأول في dict كإضافة افتراضية أو مفعّلة (إضافة "student"). تحقق من ذلك باستخدام دالة utils.deepspeed.get_active_deepspeed_plugin() لمعرفة الإضافة المفعّلة.
active_plugin = get_active_deepspeed_plugin(accelerator.state)
assert active_plugin is deepspeed_plugins["student"]يحفظ AcceleratorState أيضًا إضافة DeepSpeed النشطة في state.deepspeed_plugin.
assert active_plugin is accelerator.deepspeed_pluginبما أن student هو الإضافة النشطة حاليًا، فلنقم بالتحضير للنموذج والمُحسِّن والمُجدوِل.
student_model, optimizer, scheduler = ... student_model, optimizer, scheduler, train_dataloader = accelerator.prepare(student_model, optimizer, scheduler, train_dataloader)
حان الوقت الآن للتعامل مع نموذج المعلم.
نموذج المعلم
أولاً، عليك تحديد في Accelerator أنه يجب استخدام تكوين zero3_config.json.
accelerator.state.select_deepspeed_plugin("teacher")يعطّل هذا الأمر إضافة "student" ويمكّن إضافة "teacher" بدلاً منها. يتم تحديث إعداد DeepSpeed ذي الحالة داخل Transformers، مما يغيّر إعداد الإضافة الذي يُستدعى عند استخدام deepspeed.initialize(). ويتيح لك ذلك استخدام تكامل مدير السياق التلقائي deepspeed.zero.Init الذي يوفره Transformers.
teacher_model = AutoModel.from_pretrained(...) teacher_model = accelerator.prepare(teacher_model)
وإلا، يجب عليك تهيئة النموذج يدويًا باستخدام deepspeed.zero.Init.
with deepspeed.zero.Init(accelerator.deepspeed_plugin.config):
model = MyModel(...)التدريب
من هنا، يمكن أن يكون حلقة التدريب الخاصة بك أي شيء تريده، طالما أن teacher_model لا يُدرَّب عليه أبدًا.
teacher_model.eval()
student_model.train()
for batch in train_dataloader:
with torch.no_grad():
output_teacher = teacher_model(**batch)
output_student = student_model(**batch)
# Combine the losses or modify it in some way
loss = output_teacher.loss + output_student.loss
accelerator.backward(loss)
optimizer.step()
scheduler.step()
optimizer.zero_grad()تدريب نماذج متعددة غير مترابطة
تدريب عدة نماذج هو سيناريو أكثر تعقيداً. في حالته الحالية، نفترض أن كل نموذج منفصل تماماً عن غيره أثناء التدريب.
لا يزال هذا السيناريو يتطلب إنشاء وحدتين من utils.DeepSpeedPlugin. ومع ذلك، تحتاج أيضاً إلى وحدة Accelerator ثانية، نظراً لأن محركات deepspeed مختلفة تُستدعى في أوقات مختلفة. لا يمكن لوحدة Accelerator واحدة أن تحمل سوى نسخة واحدة في كل مرة.
بما أن state.AcceleratorState كائن ذو حالة، فهو على دراية بالفعل بكل utils.DeepSpeedPlugin المتاحة. يمكنك ببساطة إنشاء كائن Accelerator ثانٍ دون أي حجة إضافية.
first_accelerator = Accelerator(deepspeed_plugins=deepspeed_plugins) second_accelerator = Accelerator()
يمكنك استدعاء first_accelerator.state.select_deepspeed_plugin() لتفعيل أو تعطيل إضافة معينة، ثم استدعاء prepare.
# can be `accelerator_0`, `accelerator_1`, or by calling `AcceleratorState().select_deepspeed_plugin(...)`
first_accelerator.state.select_deepspeed_plugin("first_model")
first_model = AutoModel.from_pretrained(...)
# For this example, `get_training_items` is a nonexistent function that gets the setup we need for training
first_optimizer, first_scheduler, train_dl, eval_dl = get_training_items(model1)
first_model, first_optimizer, first_scheduler, train_dl, eval_dl = accelerator.prepare(
first_model, first_optimizer, first_scheduler, train_dl, eval_dl
)
second_accelerator.state.select_deepspeed_plugin("second_model")
second_model = AutoModel.from_pretrained(...)
# For this example, `get_training_items` is a nonexistent function that gets the setup we need for training
second_optimizer, second_scheduler, _, _ = get_training_items(model2)
second_model, second_optimizer, second_scheduler = accelerator.prepare(
second_model, second_optimizer, second_scheduler
)والآن يمكنك التدريب:
for batch in dl:
outputs1 = first_model(**batch)
first_accelerator.backward(outputs1.loss)
first_optimizer.step()
first_scheduler.step()
first_optimizer.zero_grad()
outputs2 = model2(**batch)
second_accelerator.backward(outputs2.loss)
second_optimizer.step()
second_scheduler.step()
second_optimizer.zero_grad()الموارد
لمشاهدة المزيد من الأمثلة، يرجى الاطلاع على الاختبارات ذات الصلة الموجودة حاليًا في [Accelerate].
Update on GitHub