PEFT documentation

LoRA

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

and get access to the augmented documentation experience

to get started

LoRA

تُعد LoRA واحدة من أكثر طرق PEFT شيوعًا، وهي نقطة انطلاق جيدة إذا كنت تبدأ للتو في استخدام PEFT. تم تطويرها في الأصل للنماذج اللغوية الكبيرة، لكنها أصبحت طريقة تدريب شائعة للغاية لنماذج الانتشار (diffusion models) نظرًا لكفاءتها وفعاليتها.

التكيّف منخفض الرتبة (LoRA) هو أسلوب PEFT يقوم بتفكيك مصفوفة كبيرة إلى مصفوفتين أصغر منخفضتي الرتبة. وهذا يقلل بشكل كبير عدد المعلمات التي تحتاج إلى ضبط دقيق.

ملخص الورقة البحثية هو:

يتألف نموذج مهم في معالجة اللغة الطبيعية من التدريب المسبق على نطاق واسع على بيانات عامة، ثم التكيّف مع مهام أو مجالات محددة. ومع تدريب نماذج أكبر حجمًا، يصبح الضبط الدقيق الكامل، الذي يعيد تدريب جميع معاملات النموذج، أقل قابلية للتطبيق. فباستخدام GPT-3 175B كمثال، يُعد نشر نسخ مستقلة من النماذج المضبوطة بدقة، حيث تحتوي كل نسخة على 175 مليار معامل، مكلفًا بشكل غير مقبول. نقترح هنا التكيف منخفض الرتبة، أو LoRA، الذي يجمّد أوزان النموذج المدرَّب مسبقًا ويحقن مصفوفات تحليل رتبة قابلة للتدريب في كل طبقة من بنية Transformer، مما يقلل بشكل كبير عدد المعاملات القابلة للتدريب للمهام اللاحقة. مقارنةً بضبط GPT-3 175B بدقة باستخدام Adam، يمكن لـ LoRA تقليل عدد المعاملات القابلة للتدريب بمقدار 10,000 مرة، وتقليل متطلبات ذاكرة GPU بمقدار 3 مرات. يؤدي LoRA إلى جودة نموذج مماثلة أو أفضل من الضبط الدقيق على RoBERTa وDeBERTa وGPT-2 وGPT-3، على الرغم من امتلاكه عددًا أقل من المعاملات القابلة للتدريب، ومعدل إنتاجية تدريب أعلى، وبدون أي تأخير إضافي في الاستدلال، على عكس المحوِّلات (adapters). كما نقدم دراسة تجريبية حول نقص الرتبة في تكيّف نماذج اللغة، مما يسلّط الضوء على فعالية LoRA. نُصدر حزمة تسهّل دمج LoRA مع نماذج PyTorch، ونوفر تطبيقاتنا ونقاط فحص النماذج لـ RoBERTa وDeBERTa وGPT-2 في هذا الرابط.

تمثّل LoRA تحديثات الأوزان ΔW\Delta W بمصفوفتين أصغر (تُسمى مصفوفات التحديث) عبر التحليل منخفض الرتبة. يمكن تدريب هذه المصفوفات الجديدة للتكيّف مع البيانات الجديدة مع الحفاظ على العدد الإجمالي للمعاملات منخفضًا. تبقى مصفوفة الأوزان الأصلية مجمّدة ولا تتلقى أي تحديثات إضافية. لإنتاج النتائج النهائية، يتم دمج الأوزان الأصلية مع الأوزان المُكيَّفة الإضافية. كما يمكنك دمج أوزان المُكيّف مع النموذج الأساسي للقضاء على زمن استجابة الاستدلال.

تتميز هذه الطريقة بعدد من المزايا:

  • يجعل LoRA الضبط الدقيق أكثر كفاءة من خلال تقليل عدد المعاملات القابلة للتدريب بشكل كبير.
  • تُحافظ الأوزان المُسبقة التدريب الأصلية على حالة التجميد، مما يعني أنه يمكنك امتلاك عدة نماذج LoRA خفيفة الوزن وقابلة للنقل لمهام مختلفة في المراحل اللاحقة، مبنية على أساسها.
  • تُعد LoRA مستقلة عن الأساليب الأخرى الفعّالة من حيث المعاملات، ويمكن دمجها مع العديد منها.
  • أداء النماذج المُحسَّنة باستخدام LoRA مماثل لأداء النماذج المُحسَّنة بالكامل.

مبدئيًا، يمكن تطبيق LoRA على أي مجموعة فرعية من مصفوفات الأوزان في الشبكة العصبية لتقليل عدد المعلمات القابلة للتدريب. ومع ذلك، من أجل البساطة وكفاءة أكبر في المعلمات، يُطبَّق LoRA عادةً على كتل الانتباه في نماذج Transformer فقط - وقد يستهدف طبقات أخرى أيضًا. يعتمد عدد المعلمات القابلة للتدريب الناتج في نموذج LoRA على حجم مصفوفات التحديث، والذي يحدده بشكل رئيسي الرتبة r وشكل مصفوفة الأوزان الأصلية.

يمكنك تهيئة المصفوفات منخفضة الرتبة مع وضع استخدامات مختلفة في الاعتبار - مثل الوعي بالمهمة (CorDA، EVA، Astra)، والتقارب الأسرع (PiSSA)، والتخفيف من آثار التكميم (LoftQ) - وذلك على سبيل المثال لا الحصر. اقرأ عن التهيئات المختلفة فيما يلي. التهيئة الافتراضية هي أن يكون LoRA عملية لا شيء (no-op)، ليتعلم سلوكًا جديدًا تدريجيًا دون التدخل كثيرًا في النموذج الموجود.

الاستخدام

يُحدَّد حجم مصفوفات التحديث منخفضة الرتبة بواسطة الرتبة أو r. كلما زادت الرتبة، زادت عدد المعاملات التي يتعيّن تدريبها في النموذج، لكن ذلك يعني أيضًا أن النموذج يتمتع بسعة تعلّم أكبر. في المثال التالي، ستستهدف مصفوفات الاستعلام والقيمة في كتل الانتباه. من بين المعاملات المهمة الأخرى التي يجب ضبطها: lora_alpha (عامل التوسيع)، وbias (ما إذا كان ينبغي تدريب none أو all أو معاملات انحياز LoRA فقط)، وmodules_to_save (الوحدات التي يجب تدريبها وحفظها بخلاف طبقات LoRA). جميع هذه المعاملات - وغيرها - موجودة في LoraConfig.

from peft import LoraConfig, get_peft_model

config = LoraConfig(
    r=16,
    lora_alpha=16,
    target_modules=["query", "value"],
    lora_dropout=0.1,
    bias="none",
    modules_to_save=["classifier"],
)
model = get_peft_model(model, config)
model.print_healthcheck()

نظرة عامة على الاختبارات

التهيئة

يتم التحكم في تهيئة أوزان LoRA عبر المعامل init_lora_weights في LoraConfig. افتراضياً، يهيّئ PEFT أوزان LoRA باستخدام Kaiming-uniform للوزن A وقيم صفرية للوزن B، مما يؤدي إلى تحويل هوية (identity transform) (نفس التنفيذ المرجعي).

بالنسبة لطبقات transformers.Conv1D، مثل الإسقاطات في GPT-2، استخدم fan_in_fan_out=True لأن أوزانها مخزنة على شكل (in_features, out_features) بدلاً من تخطيط nn.Linear. تستخدم مبادئات التهيئة القائمة على الأوزان المدعومة تخطيط Linear للتحليل، ثم تستعيد تخطيط التخزين عند تحديث الأوزان الأساسية. كما يستخدم تحجيم "stable" في LoRA-GA بُعد الإخراج بغض النظر عن تخطيط التخزين.

كما يمكن تمرير init_lora_weights="gaussian". وكما يوحي الاسم، يقوم هذا بتبديل الأوزان A باستخدام توزيع غاوسي والأصفار للوزن B (وهو الطريقة التي يستخدم بها Diffusers تهيئة أوزان LoRA).

from peft import LoraConfig

config = LoraConfig(init_lora_weights="gaussian", ...)

يوجد أيضًا خيار لتعيين init_lora_weights=False وهو مفيد لأغراض التصحيح واختبار الأخطاء. ينبغي أن يكون هذا هو الوقت الوحيد الذي تستخدم فيه هذا الخيار. عند اختيار هذا الخيار، يتم تهيئة أوزان LoRA بحيث لا تؤدي إلى تحويل هوية.

from peft import LoraConfig

config = LoraConfig(init_lora_weights=False, ...)
NoRA
PiSSA
MiCA
CorDA
Astra
OLoRA
EVA
LoftQ
rsLoRA
LoRA-GA

التكيّف منخفض الرتبة المُطبَّع (NoRA) يُطبِّع مصفوفات الإسقاط الهابط في LoRA. يطبّق PEFT هذا التطبيع فقط عند التهيئة من خلال init_lora_weights="nora" في LoraConfig: إذ يُطبِّع أعمدة وزن LoRA A المُهيَّأ عشوائيًا ويهيّئ وزن LoRA B إلى الصفر. تبقى المصفوفتان قابلتين للتدريب، وتُترك الأوزان الأساسية دون تغيير.

لطبقة خطية، يكون تحديث وزن المُكيّف $\Delta W = sBA$، حيث AA له الشكل (r, in_features), BB له الشكل (out_features, r), و ss هو عامل تحجيم LoRA. يبدأ NoRA من وزن A العشوائي الذي أنشأته الطبقة الخطية LoRA، ويقوم بتطبيع كل عمود عبر بُعد الرتبة: A:,j←A:,jmax⁡(∥A:,j∥2,10−6),B←0. A_{:,j} \leftarrow \frac{A_{:,j}}{\max(\lVert A_{:,j} \rVert_2, 10^{-6})}, \qquad B \leftarrow 0.

بما أن B تساوي صفرًا، فإن تحديث أوزان المُكيّف يكون صفرًا قبل التدريب. مع bias="none" وlora_bias=False، يحافظ المُكيّف في البداية على مخرجات النموذج الأساسي. ولا يتطلب NoRA مجموعة بيانات معايرة أو تفكيكًا للأوزان.

في حالة NoRA، الإعداد الموصى به هو أن يكون lora_alpha مساوياً لـ r (نسبة ألفا/الرتبة 1:1)، على سبيل المثال، r=8, lora_alpha=8. مع الإعداد الافتراضي use_rslora=False، يبقى معامل التوسعة عند 1؛ أما عند تفعيل LoRA المستقر الرتبة فيتحول إلى lora_alpha / sqrt(r).

يطبّق المثال التالي NoRA على طبقتين خطيتين في نموذج PyTorch صغير:

from torch import nn

from peft import LoraConfig, get_peft_model

model = nn.Sequential(
    nn.Linear(32, 32),
    nn.ReLU(),
    nn.Linear(32, 16),
)

config = LoraConfig(
    r=8,
    lora_alpha=8,
    target_modules=["0", "2"],
    init_lora_weights="nora",
    bias="none",
    lora_bias=False,
    use_rslora=False,
)
model = get_peft_model(model, config)
model.print_healthcheck()

لنموذج Transformers، اضبط target_modules على أسماء الطبقات الخطية التي تريد تكييفها، مثل ["q_proj", "v_proj"] عندما تكون تلك الأسماء موجودة في النموذج.

يستخدم NoRA إعدادات LoRA الحالية، وواجهات برمجة التطبيقات للتدريب والحفظ والتحميل، لذا لا توجد فئة منفصلة باسم NoraConfig أو NoraModel. للاطلاع على واجهات برمجة التطبيقات المشتركة للإعداد والنموذج، راجع LoraConfig و LoraModel.

يدعم NoRA وحدات الهدف torch.nn.Linear أو معاملات nn.Parameter المُمررة مباشرةً عبر target_parameters. ولا يُدعم في طبقات التضمين أو طبقات الالتفاف وما شابه ذلك.

التدريب

تُظهر هذه القسم كيفية التعامل مع سيناريوهات تدريب أكثر تعقيدًا، بدلاً من مجرد تطبيق مُكيّف منخفض الرتبة على النموذج وإمداده بالبيانات.

التدريب بأسلوب QLoRA

تضيف إعدادات LoRA الافتراضية في PEFT أوزانًا قابلة للتدريب إلى طبقات الاستعلام والقيمة في كل كتلة انتباه. لكن QLoRA، الذي يضيف أوزانًا قابلة للتدريب إلى جميع الطبقات الخطية في نموذج الترانسفورمر، يمكن أن يوفر أداءً مساويًا لنموذج مُعاد تدريبه بالكامل. لتطبيق LoRA على جميع الطبقات الخطية، كما في QLoRA، اضبط target_modules="all-linear" (وهو أسهل من تحديد الوحدات الفردية بالاسم، والتي قد تختلف اعتمادًا على البنية).

config = LoraConfig(target_modules="all-linear", ...)

لمزيد من المعلومات حول كيفية تطبيق التكميم على محولات PEFT، يُرجى الرجوع إلى دليل التكميم.

نسخ الطبقات بكفاءة في الذاكرة باستخدام LoRA

من الأساليب المستخدمة لتحسين أداء النماذج توسيع نموذج عن طريق تكرار طبقاته لبناء نموذج أكبر انطلاقًا من نموذج مُدرَّب مسبقًا بحجم محدد. على سبيل المثال، زيادة نموذج بحجم 7B ليصبح 10B كما هو موصوف في ورقة SOLAR. يدعم PEFT LoRA هذا النوع من التوسيع بطريقة فعّالة من حيث الذاكرة، وتتيح إمكانية إجراء ضبط دقيق إضافي باستخدام محولات LoRA المربوطة بالطبقات بعد تكرارها. لا تستهلك الطبقات المكررة ذاكرة إضافية لأنها تتشارك الأوزان الأساسية، لذا فإن الذاكرة الإضافية المطلوبة هي فقط ذاكرة أوزان المحولات. لاستخدام هذه الميزة، أنشئ إعدادًا يحتوي على الحجة layer_replication.

config = LoraConfig(layer_replication=[[0,4], [2,5]], ...)

بافتراض أن النموذج الأصلي كان يحتوي على 5 طبقات [0, 1, 2 ,3, 4]، فإن هذا سيؤدي إلى إنشاء نموذج يحتوي على 7 طبقات مرتبة على النحو التالي [0, 1, 2, 3, 2, 3, 4]. يتبع هذا أسلوب الدمج المار عبر mergekit حيث تُرصّ تسلسلات الطبقات المحددة كسلاسل تبدأ من قيمة شاملة وتنتهي بقيمة حصرية لبناء النموذج النهائي. تحصل كل طبقة في النموذج النهائي على مجموعة مميزة من محولات LoRA.

Fewshot-Metamath-OrcaVicuna-Mistral-10B هو مثال على نموذج تم تدريبه باستخدام هذه الطريقة على Mistral-7B الموسّع إلى 10B. يُظهر adapter_config.json إعدادًا نموذجيًا لمُكيّف LoRA يطبّق هذه الطريقة للضبط الدقيق.

تحكم دقيق في الرتب وألفا (المقياس)

بشكل افتراضي، ستتمتع جميع الطبقات المستهدفة بواسطة LoRA بنفس الرتبة r ونفس قيمة lora_alpha (والتي تحدد مقياس LoRA)، وذلك تبعاً لما تم تحديده في LoraConfig. ومع ذلك، قد ترغب في بعض الحالات في تحديد قيم مختلفة لطبقات مختلفة. وهذا ممكن عن طريق تمرير الحججين rank_pattern وalpha_pattern إلى LoraConfig. يجب أن تكون هذه الحجج قواميس يكون المفتاح فيها اسم الطبقة والقيمة فيها قيمة الرتبة/ألفا. يمكن أن تكون المفاتيح تعبيرات منتظمة (regex). وستتخذ جميع طبقات LoRA التي لم يتم ذكرها صراحةً في rank_pattern وalpha_pattern قيم r وlora_alpha الافتراضية.

لإعطاء مثال، لنفترض أن لدينا نموذجاً له البنية التالية:

>>> print(model)
Outer(
  (foo): Linear(...)
  (module): Middle(
    (foo): Linear(...)
    (foobar): Linear(...)
    (module): Inner(
      (foo): Linear(...)
      (barfoo): Linear(...)
    )
  )
)
  • rank_pattern={"foo": 42} سيُطابق جميع طبقات foo الثلاث. ولا يُطابق أيٌّ من foobar أو barfoo.
  • rank_pattern={"^foo": 42} سيُطابق طبقة foo في النموذج فقط، لكنه لن يطابق module.foo أو module.module.foo. والسبب في ذلك أن ^ تعني “بداية السلسلة” عند استخدام التعبيرات النمطية، ولا تبدأ سوى foo بـ "foo"، بينما تحمل أسماء الطبقات الأخرى بادئات.
  • rank_pattern={"^module.foo": 42} يطابق module.foo فقط، لكنه لا يطابق module.module.foo، لنفس السبب.
  • rank_pattern={"module.foo": 42} يطابق كلًا من module.foo وmodule.module.foo، لكنه لا يطابق foo.
  • يطابق rank_pattern={"^foo": 42, "^module.module.foo": 55} foo وmodule.module.foo على التوالي، لكنه لا يطابق module.foo.
  • لا حاجة إلى تحديد $ لتمييز نهاية التطابق، حيث يضيف PEFT ذلك تلقائيًا.

تنطبق المنطقية نفسها على alpha_pattern. إذا كنت متردداً، فلا تحاول استخدام تعبيرات منتظمة معقدة — بل مرر الاسم الكامل لكل وحدة ذات رتبة/ألفا مختلفة، مع وضع بادئة ^ قبله، وستكون النتيجة جيدة.

كشف الوحدات المستهدفة القابلة للتطبيق تلقائيًا

يُنفّذ peft.helpers.KappaTuneSelector استراتيجية اختيار الأهداف القائمة على عدد الشرط (condition number) الواردة في ورقة KappaTune. يقوم بفحص كل وحدة nn.Linear، وللموديلات التي تُخزَّن فيها أوزان خبراء MoE كمُتجهات nn.Parameter ثلاثية الأبعاد مدمجة (مثل Llama-4 وQwen3-MoE)، يفحص تلك المعاملات أيضاً، ويحسب عدد شرط المصفوفة κ = σ_max / σ_min لكل منها، ثم يختار الطبقات الأكثر أيزوتروبياً (أقل قيمة لـ κ). تعمل هذه الطبقات الأيزوتروبية كمرشحات مثالية للضبط الدقيق، لأن طبيعتها عالية الإنتروبيا تتيح لها امتصاص المعلومات الجديدة بسهولة أكبر، مع إبقاء الطبقات المتخصصة غير الأيزوتروبية كما هي للتخفيف من النسيان الكارثي أثناء التعلم المستمر.

استخدم peft.helpers.find_kappa_target_modules() كسطر واحد للحصول على target_modules المثالية لـ LoraConfig:

from peft import LoraConfig, get_peft_model
from peft.helpers import find_kappa_target_modules

model = AutoModelForCausalLM.from_pretrained("mistralai/Mixtral-8x7B-Instruct-v0.1")

targets = find_kappa_target_modules(model, top_p=0.2)
config = LoraConfig(
    target_modules=targets["target_modules"],
    target_parameters=targets["target_parameters"] if stable_modules_dic["target_parameters"] else None,
    r=64,
    lora_alpha=32,
    task_type="CAUSAL_LM",
)
peft_model = get_peft_model(model, config)

راجع مثالًا كاملًا هنا.

استهداف nn.Parameter مباشرة

بشكل عام، ينبغي استخدام target_modules لاستهداف الوحدة (مثل nn.Linear). ومع ذلك، في بعض الظروف، لا يكون ذلك ممكناً. على سبيل المثال، في العديد من طبقات خليط الخبراء (MoE) في HF Transformers، يتم استخدام nn.Parameter بدلاً من nn.Linear. عادةً ما يعيد PEFT كتابة طريقة forward الخاصة بـ LoRA، لكن في حالة nn.Parameter، لا توجد طريقة من هذا النوع. لذلك، لتطبيق LoRA على ذلك المعامل، يجب استهدافه باستخدام target_parameters. كمثال، بالنسبة إلى Llama4، يمكنك تمرير: target_parameters=['feed_forward.experts.gate_up_proj', 'feed_forward.experts.down_proj].

لاحظ أنه عند استهداف معاملات الخبراء، يمكن أن يضيف PEFT عبئًا تشغيليًا كبيرًا. والسبب في ذلك أن PEFT يُنشئ دائمًا مساهمة LoRA لكل خبير حتى لو كان عدد الخبراء المطلوب صغيرًا. أثناء التدريب، يكون هذا الأمر أقل أهمية، لأن نسبة كبيرة من الخبراء تُفعَّل عادةً مرة واحدة على الأقل على مدار التسلسل. ومع ذلك، أثناء الاستدلال، يُستخدم عادةً ذاكرة KV، وبالتالي نحتاج إلى حساب الرمز الأخير فقط، مما يعني أن عددًا صغيرًا من الخبراء فقط يُفعَّل. لذلك، يمكن أن يؤدي استخدام LoRA على طبقات MoE إلى تباطؤ كبير في وقت الاستدلال. لذا، يُوصى بدمج الأوزان (model.merge_adapter() أو model = model.merge_and_unload()). وهذا يُزيل عبء PEFT.

يمكن العثور على تحقيق أكثر تفصيلاً في هذه المسألة في طلب الدمج هذا الخاص بتحسين MoE.

ملاحظات

  • حاليًا، يسمح هذا الحُجج باستهداف معاملات nn.Parameter ثنائية الأبعاد أو ثلاثية الأبعاد. ويُفترض أنه في حالة المعامل ثلاثي الأبعاد، فإن البُعد صفر هو بُعد الخبير.
  • تُؤيَّد عدة محوِّلات LoRA (المُضافة عبر model.add_adapter أو model.load_adapter) التي تستخدم target_parameters، لكن يجب أن تستهدف جميعها نفس مجموعة المعاملات.

معاملات خبراء MoE وvLLM

تخزّن بعض نماذج MoE في Transformers أوزان الخبراء كمُتجهات nn.Parameter (غالبًا ثلاثية الأبعاد)، وليس كوحَدات nn.Linear. لتطبيق LoRA على تلك الخبراء، استخدم target_parameters واضبط رتبة لكل طبقة باستخدام rank_pattern:

num_experts = getattr(model.config, "num_local_experts", None) or model.config.num_experts
effective_r = max(1, r // num_experts)
config = LoraConfig(
    r=r,
    lora_alpha=32,
    target_modules=["q_proj", "v_proj"],
    target_parameters=[
        # Mixtral / Qwen3-MoE / GPT-OSS
        "mlp.experts.gate_up_proj",
        "mlp.experts.down_proj",
        # Llama4
        # "feed_forward.experts.gate_up_proj",
        # "feed_forward.experts.down_proj",
    ],
    rank_pattern={
        "experts.gate_up_proj": effective_r,
        "experts.down_proj": effective_r,
    },
)

يُبقي هذا الميزانية الإجمالية لمعاملات LoRA مماثلة لطبقات الكثافة (انظر LoRA Without Regret من Schulman وآخرون). وتستخدم وحدات غير الخبراء الترتيب الافتراضي r.

يمكن إجراء الاستدلال المُسرَّع باستخدام النموذج المُحسَّن، على سبيل المثال، عبر vLLM الذي يدعم طبقات خبراء MoE المدمجة منذ الإصدار v0.11.2.

تدريب الرموز بكفاءة إلى جانب LoRA

تدعم محولات PEFT LoRA إضافة رموز جديدة عبر المعامل trainable_token_indices. وهذا يتيح ضبط رموز أخرى بالتوازي مع ضبط طبقات محددة. يتم تدريب الرموز المحددة فقط بينما تبقى جميع الرموز الأخرى دون تغيير. يوفر هذا الأسلوب الذاكرة ولا يتخلص من السياق المكتسب من تمثيلات الرموز الموجودة، على عكس تدريب مصفوفة التمثيل بأكملها. يستخدم هذا الأسلوب داخليًا طبقة TrainableTokensModel.

# for layer 'embed_tokens'
config = LoraConfig(trainable_token_indices=[idx_1, idx_2, ...], ...)

# specific embedding layer
config = LoraConfig(trainable_token_indices={'emb_tokens': [idx_1, idx_2, ...]}, ...)

في المقطع أدناه، نُظهر كيفية إضافة رموز جديدة إلى النموذج وكيفية تدريبه جنبًا إلى جنب مع الطبقات الأخرى في النموذج.

from transformers import AutoTokenizer, AutoModelForCausalLM
from peft import get_peft_model, LoraConfig

base_model = AutoModelForCausalLM.from_pretrained("mistralai/Mistral-7B-v0.1")
tokenizer = AutoTokenizer.from_pretrained("mistralai/Mistral-7B-v0.1")

# we define our new tokens and add them to the tokenizer as special tokens
special_tokens = ['<|start_think|>', '<|stop_think|>']
tokenizer.add_special_tokens({'additional_special_tokens': special_tokens})

# make room for new tokens in the embedding matrix if it isn't big enough already
base_model.resize_token_embeddings(max(len(tokenizer), base_model.model.embed_tokens.num_embeddings))

# typical LoRA config with `trainable_token_indices` targeting embedding layer `embed_tokens`
# and specifically our new tokens we just added
lora_config = LoraConfig(
    target_modules='all-linear',
    trainable_token_indices={'embed_tokens': tokenizer.convert_tokens_to_ids(special_tokens)},
)
peft_model = get_peft_model(base_model, lora_config)

# proceed to train the model like normal
[...]

تُحفظ أوزان الرموز كجزء من حالة القاموس (state dict) الخاص بالمُكيّف (adapter) إلى جانب أوزان LoRA. كان التدريب الكامل (Full fine-tuning) وحفظ مصفوفة التضمين (embedding matrix) سيؤديان إلى تخزين ملف أكبر بكثير.

لإعطاء فكرة تقريبية عن مقدار ذاكرة VRAM التي يمكن توفيرها، أُجري مقارنة أولية على المثال أعلاه بين تدريب مصفوفة التضمين بالكامل (modules_to_save=["embed_tokens"])، واستخدام LoRA لمصفوفة التضمين (target_modules=[..., "embed_tokens"]، رتبة 32) والرموز القابلة للتدريب (trainable_token_indices=[...]، 6 رموز):

رموز قابلة للتدريبLoRAالضبط الدقيق الكامل
VRAM15,562 ميغابايت15,581ميغابايت~16,500ميغابايت
التأثير6 رموزجميع الرموزجميع الرموز

ربط الأوزان

تستخدم العديد من نماذج اللغة السببية ربط الأوزان، حيث تتشارك وزنتان أو أكثر في نفس المعلمات الأساسية. في الحالة الأكثر شيوعاً، تتشارك أوزان التضمين المدخل (embed_tokens) وأوزان الإسقاط المخرج (lm_head) في نفس المصفوفة. والسبب في ذلك هو أنه يقلل من عدد المعلمات ويحافظ عادةً على جودة النموذج.

ليس من الواضح دائمًا كيف يتعامل PEFT مع هذه الأوزان المرتبطة عندما تكون مستهدفة للضبط الدقيق. فيما يتعلق بـ LoRA، يتحكم ensure_weight_tying في LoraConfig فيما إذا كان ينبغي لـ PEFT الحفاظ صراحةً على ارتباط تحديثات جانب المُكيّف (adapter) لتلك الطبقات. عمليًا، يمكن أن يؤثر ذلك على modules_to_save وtarget_modules وtrainable_token_indices. لاحظ أن هذه المنطقية تعتمد جزئيًا على العرف فيما يتعلق بتسمية الطبقات ("embed_tokens"، "lm_head") ولا يمكن ضمان عمل صحيح إذا لم تُستخدم تلك الأعراف.

تلخص الجداول أدناه السلوك المتوقع.

modules_to_save

أوزان النموذج الأساسي مترابطةensure_weight_tyingشكل LoraConfigالسلوك
لاFalsemodules_to_save=["embed_tokens"] أو ["lm_head"]أضف ModulesToSaveWrapper على طبقة محددة فقط
لاTruemodules_to_save=["embed_tokens"] أو ["lm_head"]تحذير، ثم أضف ModulesToSaveWrapper على الطبقة المحددة فقط
نعمFalsemodules_to_save=["embed_tokens"] أو ["lm_head"]اعتبرها منفصلة
نعمTruemodules_to_save=["embed_tokens"] أو ["lm_head"]تغليف الطبقات المرتبطة والحفاظ على ارتباط الأغلفة
لاFalsemodules_to_save=["embed_tokens", "lm_head"]اعتبرها منفصلة
لاTruemodules_to_save=["embed_tokens", "lm_head"]تحذير، ثم التعامل كعناصر منفصلة
نعمFalsemodules_to_save=["embed_tokens", "lm_head"]تحذير، ثم التعامل كعناصر منفصلة
نعمTruemodules_to_save=["embed_tokens", "lm_head"]حافظ على ارتباط ModulesToSaveWrappers

target_modules

أوزان النموذج الأساسي مترابطةensure_weight_tyingشكل LoraConfigالسلوك
لاFalsetarget_modules=["embed_tokens"] أو ["lm_head"]إضافة LoRA على طبقة محددة فقط
لاTruetarget_modules=["embed_tokens"] أو ["lm_head"]تحذير، ثم أضف LoRA على الطبقة المحددة فقط
نعمFalsetarget_modules=["embed_tokens"] أو ["lm_head"]اعتبرها منفصلة
نعمTruetarget_modules=["embed_tokens"] أو ["lm_head"]إبقاء مُكيّفات LoRA مربوطة
لاFalsetarget_modules=["embed_tokens", "lm_head"]اعتبرها منفصلة
لاTruetarget_modules=["embed_tokens", "lm_head"]تحذير، ثم التعامل كعناصر منفصلة
نعمFalsetarget_modules=["embed_tokens", "lm_head"]تحذير، ثم التعامل كعناصر منفصلة
نعمTruetarget_modules=["embed_tokens", "lm_head"]إبقاء مُكيّفات LoRA مربوطة

trainable_token_indices

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

أوزان النموذج الأساسي مترابطةensure_weight_tyingشكل LoraConfigالسلوك
لاFalsetrainable_token_indices=[1, 2, 3]الرموز القابلة للتدريب على التضمينات فقط
لاTruetrainable_token_indices=[1, 2, 3]تحذير، ثم الرموز القابلة للتدريب على التضمينات فقط
نعمFalsetrainable_token_indices=[1, 2, 3]رموز قابلة للتدريب مترابطة
نعمTruetrainable_token_indices=[1, 2, 3]رموز قابلة للتدريب مترابطة
لاFalsetrainable_token_indices={"lm_head": [1, 2], "embed_tokens": [1, 2]}اعتبرها منفصلة
لاTruetrainable_token_indices={"lm_head": [1, 2], "embed_tokens": [1, 2]}تحذير، ثم التعامل كعناصر منفصلة
نعمFalsetrainable_token_indices={"lm_head": [1, 2], "embed_tokens": [1, 2]}رموز قابلة للتدريب مترابطة
نعمTruetrainable_token_indices={"lm_head": [1, 2], "embed_tokens": [1, 2]}رموز قابلة للتدريب مترابطة
لاFalsetrainable_token_indices={"lm_head": [1, 2], "embed_tokens": [3, 4]}اعتبرها منفصلة
لاTruetrainable_token_indices={"lm_head": [1, 2], "embed_tokens": [3, 4]}تحذير، ثم التعامل كعناصر منفصلة
نعمFalsetrainable_token_indices={"lm_head": [1, 2], "embed_tokens": [3, 4]}اعتبرها منفصلة
نعمTruetrainable_token_indices={"lm_head": [1, 2], "embed_tokens": [3, 4]}خطأ

بالنسبة للمستخدمين، يعني هذا:

  • بشكل عام، إذا كنت ترغب في ضبط الأوزان المرتبطة مع الحفاظ على ارتباطها، فمرّر ensure_weight_tying=True.
  • إذا كانت أوزان النموذج الأساسي غير مترابطة، فلا يمكن لـensure_weight_tying=True فرض الترابط، بل يُصدر تحذيرًا فقط.
  • بالنسبة إلى trainable_token_indices، يجب أن تستخدم الطبقات المرتبطة نفس فهارس الرموز عندما يكون ensure_weight_tying=True.

المحسّنات

يمكن أن يتضمن تدريب LoRA اختيارياً محسّنات (Optimizers) مخصصة لأغراض خاصة. حالياً، يدعم PEFT كل من LoRA-FA وLoRA+ وLoRA المُسبَق الشرطية ريمانياً (Riemannian-preconditioned LoRA).

مُحسِّن LoRA-FA

يمكن أن يكون تدريب LoRA أكثر فعالية وكفاءة باستخدام LoRA-FA، كما هو موصوف في LoRA-FA. يقلل LoRA-FA من استهلاك ذاكرة التفعيل عن طريق تثبيت المصفوفة A وضبط المصفوفة B فقط. أثناء التدريب، يتم تحسين تدرج B لتقريب تدرج الضبط الدقيق الكامل للمعاملات. علاوة على ذلك، لا يتأثر استهلاك الذاكرة في LoRA-FA بالرتبة (بما أنه يمحو تفعيل $A$)، وبالتالي يمكنه تحسين الأداء عن طريق زيادة رتبة lora دون زيادة استهلاك الذاكرة.

from peft import LoraConfig, get_peft_model
from peft.optimizers import create_lorafa_optimizer
from transformers import Trainer, get_cosine_schedule_with_warmup

base_model = AutoModelForCausalLM.from_pretrained("meta-llama/Meta-Llama-3-8B-Instruct")

config = LoraConfig(...)
model = get_peft_model(base_model, config)

optimizer = create_lorafa_optimizer(
    model=model,
    r=128,
    lora_alpha=32,
    lr=7e-5,
)

scheduler = get_cosine_schedule_with_warmup(
    optimizer,
    num_warmup_steps=100,
    num_training_steps=1000,
)

trainer = Trainer(
    ...,
    optimizers=(optimizer, scheduler),
)

LoRA+ المحسّن لـ LoRA

يمكن تحسين تدريب LoRA باستخدام LoRA+، الذي يستخدم معدلات تعلم مختلفة لمصفوفات المحوّل A و B، وقد ثبت أنه يزيد سرعة الضبط الدقيق حتى مرتين والأداء بنسبة 1-2%.

from peft import LoraConfig, get_peft_model
from peft.optimizers import create_loraplus_optimizer
from transformers import Trainer
import bitsandbytes as bnb

base_model = ...
config = LoraConfig(...)
model = get_peft_model(base_model, config)

optimizer = create_loraplus_optimizer(
    model=model,
    optimizer_cls=bnb.optim.Adam8bit,
    lr=5e-5,
    loraplus_lr_ratio=16,
)
scheduler = None

...
trainer = Trainer(
    ...,
    optimizers=(optimizer, scheduler),
)

LoRA المُسبَق الشرط بطريقة ريمان

يمكن تحسين تدريب LoRA باستخدام مُهيِّئ ريمانّي، كما هو موصوف في LoRA المُهيَّأ ريمانّيًا. في كل خطوة مُحسِّن، تُضرب تدرّجات مصفوفات LoRA AA و BB بـ r×rr \times r مُهيِّئ يعيد مقياس التدرّج الإقليدي نحو الاتجاه الريمانّي (اتجاه التدرّج المُقيَّس) على متعدد الأشكال لمصفوفة الرتبة المنخفضة، مما يحسّن شروط التحديث ويمكن أن يحسّن التقارب. وبما أن المُهيِّئ بحجم $r \times r$، فإن تكاليفه في الذاكرة والوقت التشغيلي صغيرة بالنسبة لرتبة LoRA. create_riemannian_optimizer يغلّف أي فئة مُحسِّن أساسية (مثل torch.optim.AdamW أو torch.optim.SGD): تُحدَّث المعاملات غير LoRA بواسطة المُحسِّن الأساسي دون تغيير، ولا يُخضع للمُهيِّئة سوى nn.Linear-طبقات LoRA ذات شكلlora_A / lora_B) يُخضع للمُهيِّئة.

from peft import LoraConfig, get_peft_model
from peft.optimizers import create_riemannian_optimizer
from transformers import Trainer, get_cosine_schedule_with_warmup
import torch

base_model = AutoModelForCausalLM.from_pretrained("meta-llama/Meta-Llama-3-8B-Instruct")

config = LoraConfig(...)
model = get_peft_model(base_model, config)

optimizer = create_riemannian_optimizer(
    model=model,
    optimizer_cls=torch.optim.AdamW,
    lr=5e-5,
    reg=1e-2,
)

scheduler = get_cosine_schedule_with_warmup(
    optimizer,
    num_warmup_steps=100,
    num_training_steps=1000,
)

trainer = Trainer(
    ...,
    optimizers=(optimizer, scheduler),
)

reg هو حد تخميد يُضاف إلى r×rr \times r مصفوفة القطر قبل العكس؛ فهو يُثبّت المُسبِّق عندما يكون عامل LoRA (قريبًا من) النقص في الرتبة.

التدريب اللاحق

تُظهر هذه القسم طرق المعالجة اللاحقة المحتملة للمُكيِّفات المُدرَّبة.

دمج أوزان LoRA في النموذج الأساسي

While LoRA is significantly smaller and faster to train, you may encounter latency issues during inference due to separately loading the base model and the LoRA adapter. To eliminate latency, use the merge_and_unload() function to merge the adapter weights with the base model. This allows you to use the newly merged model as a standalone model. The merge_and_unload() function doesn’t keep the adapter weights in memory.

فيما يلي مخطط يوضح الحدس وراء دمج محوّل LoRA:

نُظهر في المقاطع أدناه كيفية تشغيل ذلك باستخدام PEFT.

from transformers import AutoModelForCausalLM
from peft import PeftModel

base_model = AutoModelForCausalLM.from_pretrained("mistralai/Mistral-7B-v0.1")
peft_model_id = "alignment-handbook/zephyr-7b-sft-lora"
model = PeftModel.from_pretrained(base_model, peft_model_id)
model = model.merge_and_unload()

من المهم تعيين النموذج المُعاد إلى متغير واستخدامه، إذ إن merge_and_unload() ليست عملية تتم في الموقع. إذا كنت بحاجة إلى الاحتفاظ بنسخة من الأوزان حتى تتمكن من إلغاء دمج المُكيّف لاحقًا أو حذفه وتحميل مُكيّفات أخرى، فيجب عليك استخدام دالة merge_adapter() بدلاً من ذلك. الآن لديك خيار استخدام unmerge_adapter() لإرجاع النموذج الأساسي.

from transformers import AutoModelForCausalLM
from peft import PeftModel

base_model = AutoModelForCausalLM.from_pretrained("mistralai/Mistral-7B-v0.1")
peft_model_id = "alignment-handbook/zephyr-7b-sft-lora"
model = PeftModel.from_pretrained(base_model, peft_model_id)
model.merge_adapter()

# unmerge the LoRA layers from the base model
model.unmerge_adapter()

في النموذج المُكمَّم، لا تكون عملية إلغاء الدمج دقيقة: فعملية الدمج تعيد تكميم الوزن الأساسي، وقد تتراكم أخطاء التقريب مع تكرار دورات الدمج وإلغاء الدمج. راجع دمج المُكيّفات في الأوزان المُكمَّمة.

إذا كانت عدة محوِّلات نشطة وتم دمج بعضها فقط، فإن المحوِّلات غير المدمجة لن تُطبَّق بصمت. سيتغير هذا السلوك في PEFT v1.0. راجع دمج بعض المحوِّلات النشطة فقط.

تُعدّ دالة add_weighted_adapter() مفيدة لدمج عدة LoRAs في مُكيّف جديد بناءً على مخطط أوزان يحدده المستخدم في معامل weights. أدناه مثال شامل من البداية إلى النهاية.

First load the base model:

from transformers import AutoModelForCausalLM
from peft import PeftModel
import torch

base_model = AutoModelForCausalLM.from_pretrained(
    "mistralai/Mistral-7B-v0.1", dtype=torch.float16, device_map="auto"
)

ثم نحمّل المُكيّف الأول:

peft_model_id = "alignment-handbook/zephyr-7b-sft-lora"
model = PeftModel.from_pretrained(base_model, peft_model_id, adapter_name="sft")

ثم حمّل مُكيّفًا مختلفًا وادمجه مع الأول:

weighted_adapter_name = "sft-dpo"
model.load_adapter("alignment-handbook/zephyr-7b-dpo-lora", adapter_name="dpo")
model.add_weighted_adapter(
    adapters=["sft", "dpo"],
    weights=[0.7, 0.3],
    adapter_name=weighted_adapter_name,
    combination_type="linear"
)
model.set_adapter(weighted_adapter_name)

توجد عدة طرق مدعومة لـcombination_type. راجع التوثيق لمزيد من التفاصيل. لاحظ أن استخدام “svd” كـcombination_type غير مدعوم عند استخدام torch.float16 أو torch.bfloat16 كنوع البيانات.

الآن، قم بتنفيذ الاستدلال:

device = torch.accelerator.current_accelerator().type if hasattr(torch, "accelerator") else "cuda"

tokenizer = AutoTokenizer.from_pretrained("mistralai/Mistral-7B-v0.1")

prompt = "Hey, are you conscious? Can you talk to me?"
inputs = tokenizer(prompt, return_tensors="pt")
inputs = {k: v.to(device) for k, v in inputs.items()}

with torch.no_grad():
    generate_ids = model.generate(**inputs, max_length=30)
outputs = tokenizer.batch_decode(generate_ids, skip_special_tokens=True, clean_up_tokenization_spaces=False)[0]
print(outputs)

استعادة أداء النموذج الأساسي عبر تقليل أبعاد المتسلل

تجادل الورقة LoRA vs Full Fine-tuning: An Illusion of Equivalence بأن تدريب LoRA يُدخل أبعادًا إضافية إلى الأوزان التي لا تشترك كثيرًا مع الأوزان المتعلمة مسبقًا، مما يؤدي إلى نسيان المعلومات المتعلمة بالفعل. تنفّذ PEFT الإجراء التخفيفي المقترح في peft.tuners.lora.intruders.reduce_intruder_dimension().

ستقوم آلية التخفيف بأخذ نموذج PEFT يحتوي على LoRA محمّل، وإنشاء مُكيّف جديد معدّل يُحمَّل إلى جانب المُكيّف الحالي ليصبح المُكيّف النشط.

مثال على الاستخدام:

from peft.tuners.lora.intruders import reduce_intruder_dimension

peft_model = AutoPeftModelForCausalLM.from_pretrained('hubnemo/llama-3.2b-metamathqa-lora64')

reduce_intruder_dimension(
    peft_model,
    mitigation_lambda=0.75,
)

peft_model.generate(...)

توجد بعض المعلمات الفائقة التي يمكن استخدامها لضبط فعالية التخفيف، ولكن، كما هو موضح في الشكل 8 من الورقة البحثية، سيكون هناك دائمًا تنازل بين دقة المهمة التي يتعلمها المُكيّف (adapter) ونسيان معرفة النموذج الأساسي. سيقوم التخفيف بإزالة المعلومات من المُكيّف لتقليل الأثر على نسيان المعرفة السابقة، لكن هذا يعني أيضًا أن بعض المعلومات المتعلقة بالمهمة التي تعلمها المُكيّف ستُفقد أيضًا.

في حين أن الإعدادات الافتراضية مُعدّة لتقديم توازن جيد بين العاملين، إلا أنه لا يُكفَل أن تبقى هذه الإعدادات مناسبة لمُكيّفك ونموذجك وبياناتك، لذا من الحكمة أن يكون لديك معيار مرجعي جاهز لقياس الأثر.

تحميل المُكيّفات

يمكن تحميل المُكيّفات (Adapters) على نموذج مُدرَّب مسبقًا باستخدام load_adapter()، وهو أمر مفيد لتجربة مُكيّفات مختلفة لم يتم دمج أوزانها. اضبط أوزان المُكيّف النشط باستخدام دالة set_adapter().

from transformers import AutoModelForCausalLM
from peft import PeftModel

base_model = AutoModelForCausalLM.from_pretrained("mistralai/Mistral-7B-v0.1")
peft_model_id = "alignment-handbook/zephyr-7b-sft-lora"
model = PeftModel.from_pretrained(base_model, peft_model_id)

# load different adapter
model.load_adapter("alignment-handbook/zephyr-7b-dpo-lora", adapter_name="dpo")

# set adapter as active
model.set_adapter("dpo")

لإرجاع النموذج الأساسي، يمكنك استخدام unload() لتفريغ جميع وحدات LoRA أو استخدام delete_adapter() لحذف المُكيّف بالكامل. لاحظ أن unload() ليست عملية تتم في الموقع (in-place)، لذا تذكّر بتعيين النموذج المُعاد إلى متغير واستخدامه.

# unload adapter
model = model.unload()

# delete adapter
model.delete_adapter("dpo")

توازي الموتر

يدعم LoRA توازي الموترات (TP) كما يوفره Transformers. عند تحميل نموذج أساسي مع tp_plan، يكتشف PEFT تلقائياً إعدادات توازي الموترات لكل وحدة مستهدفة ويضيف الخطافات المناسبة إلى أوزان محوّل LoRA حتى تشارك بشكل صحيح في حساب توازي الموترات.

يتطلب دعم التوازي في الموترات (Tensor Parallelism) لـ LoRA transformers >= 5.4.0. يتطلب واجهة برمجة التطبيقات (API) للتوازي في الموترات (Tensor Parallelism) القائمة على DTensor peft >= 0.21.1 وtransformers >= 5.17.0.

يكون الاستخدام مطابقًا تمامًا لتدفق عمل LoRA القياسي — ما عليك سوى تحميل النموذج الأساسي مع tp_plan قبل تغليفه بواسطة PEFT:

from transformers import AutoModelForCausalLM
from peft import get_peft_model, LoraConfig

model = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-3.1-8B", tp_plan="auto")
lora_config = LoraConfig(r=16, target_modules=["q_proj", "v_proj"])
model = get_peft_model(model, lora_config)

تعمل عمليات الحفظ والتحميل بشكل اعتيادي عبر save_pretrained / from_pretrained. يقوم PEFT بجمع أوزان المُكيِّف المقسَّم مرة أخرى إلى متجهات كاملة قبل الحفظ، مما يجعل نقاط التفتيش قابلة للنقل ومستقلة عن عدد الأجهزة المستخدمة أثناء التدريب.

إذا طبّقت توازي الموترات دون خطة TP، على سبيل المثال باستخدام parallelize_module الخاص بـ PyTorch، فإن PEFT يحدّد حجم أوزان LoRA لطبقة nn.Linear المقسّمة إلى حجم شحنتها المحلية إذا كان لمشبك الجهاز الخاص بالوزن بُعد باسم "tp"، وإلا فسيكون الحجم مطابقًا لشكل الطبقة الكاملة (كما هو الحال مع FSDP2). لا يضيف PEFT خطافات TP إلى هذه أوزان LoRA ولا يجمعها عند الحفظ. إذا كان بُعد مشبك TP لديك يحمل اسمًا مختلفًا، أضِفه قبل إنشاء نموذج PEFT:

from peft.utils.integrations import TpMeshDimRegistry

TpMeshDimRegistry.register("tp_dim")

الاستدلال

تُبرز هذه القسم ما يمكنك القيام به أثناء وقت الاستدلال باستخدام LoRA، مثل فك ارتباط المُكيّف.

لورا المُفعَّلة (aLoRA)

LoRA المُفعَّل (aLoRA) هو معمارية مُكيِّف منخفض الرتبة لنماذج اللغة السببية يعيد استخدام ذاكرة KV الموجودة في النموذج الأساسي لتحقيق استدلال أكثر كفاءة. يناسب هذا النهج خطوط الأنابيب التي تعتمد على النموذج الأساسي لمعظم المهام/التوليدات، لكنها تستخدم مُكيِّف aLoRA أو أكثر لأداء مهام متخصصة ضمن السلسلة. على سبيل المثال، التحقق من مخرجات النموذج الأساسي المولَّدة أو تصحيحها. في هذه الإعدادات، يمكن تسريع أوقات الاستدلال بمقدار مرتبة أو أكثر. لمزيد من المعلومات حول aLoRA والعديد من حالات الاستخدام، راجع ورقة aLoRA.

تقوم هذه التقنية بمسح آخر ظهور لسلسلة الاستدعاء (alora_invocation_tokens) في كل مدخل (ويمكن أن تكون هذه السلسلة قصيرة حتى رمز واحد). وتفعّل أوزان المحوّل (adapter) على الرموز بدءًا من بداية سلسلة الاستدعاء. كما تخضع المدخلات اللاحقة لسلسلة الاستدعاء للتكييف، وستستخدم جميع الرموز المولّدة الأوزان المُكيَّفة. وتُترك الأوزان على الرموز السابقة دون تكييف، مما يجعل ذاكرة التخزين المؤقت (cache) لتلك الرموز قابلة للاستبدال مع ذاكرة التخزين المؤقت للنموذج الأساسي بسبب قناع الانتباه السببي في النماذج اللغوية السببية. طريقة الاستخدام مشابهة جدًا لـ LoRA القياسي. والفرق الجوهري هو أنه يجب تحديد سلسلة الاستدعاء عند إنشاء المحوّل:

from peft import LoraConfig

config = LoraConfig(alora_invocation_tokens=alora_invocation_tokens, task_type="CAUSAL_LM", ...)

alora_invocation_tokens هو قائمة من معرفات الرموز الصحيحة. بالنظر إلى سلسلة استدعاء مرغوبة، يمكن الحصول عليها على النحو التالي:

invocation_string = "placeholder"
alora_invocation_tokens = tokenizer.encode(invocation_string, add_special_tokens=False).

المُرمِّز هو مُرمِّز النموذج الأساسي. استخدم add_special_tokens=False لتجنّب إضافة رموز SOS/EOS في سلسلة البحث لدينا (وهو ما سيُسبّب على الأرجح فشل عملية البحث).

ملاحظات

  • يُؤيَّد aLoRA فقط لمهام task_type=CAUSAL_LM بسبب تركيزه على إعادة استخدام ذاكرة التخزين المؤقت.
  • بما أن الأوزان تُكيَّف على عدد أقل من الرموز، فإن aLoRA يتطلب غالبًا (وليس دائمًا) رتبة (r) أعلى من LoRA. يمكن أن يكون r=32 نقطة بداية جيدة.
  • لا يمكن دمج أوزان aLoRA في النموذج الأساسي بحكم التعريف، حيث تُطبَّق أوزان المُكيِّف بشكل انتقائي على مجموعة فرعية من الرموز. ستُصدر محاولات الدمج أخطاء.
  • لا يُدعم البحث الشعاعي بعد.
  • لا يُنصح عمومًا بإضافة رموز جديدة إلى مُجزّئ الرموز (tokenizer) غير الموجودة في النموذج الأساسي. فقد يُعقّد ذلك حالة الاستخدام المستهدفة التي يعمل فيها كل من النموذج الأساسي ونموذج المُكيّف (adapter) على سياق متداخل. يمكنك تجاوز هذه المشكلة عن طريق إضافة رموز قابلة للتدريب إلى النموذج الأساسي قبل تدريب المُكيّف.

اختيار تسلسل الاستدعاء وتصميم SFT

يجب عليك إضافة تسلسل alora_invocation_tokens لأنه لا يُضاف تلقائيًا. نوصي بتفعيل أوزان المُكيّف مبكرًا (في بداية أي تلميح خاص بالمُكيّف)، ولكن بعد أي مدخلات طويلة، لتعظيم أداء النموذج دون المساس بإعادة استخدام ذاكرة التخزين المؤقت. وكما هو الحال مع أي نموذج، يجب أن يكون التنسيق متسقًا بين التدريب والاختبار.

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

  • الخيار 1: إذا لم يكن هناك موجه محدد للمهمة، أي أن المدخل هو سجل محادثة مع موجه assistant، فإن موجه assistant في قالب المحادثة (مثل <|start_of_role|>assistant<|end_of_role|>) هو خيار طبيعي لسلسلة الاستدعاء. راجع قالب المحادثة الخاص بالنموذج للعثور على الموجه الخاص بالنموذج.
  • الخيار 2: إذا كان هناك موجه محدد للمهمة للمكيّف يصف المهمة التي يتعلمها المكيّف، وتم وضع ذلك الموجه كدور user مباشرة قبل التوليد، فإن موجه user في قالب المحادثة (مثل <|start_of_role|>user<|end_of_role|>) هو خيار طبيعي لسلسلة الاستدعاء.

بعد تحديد سلسلة الاستدعاء، احصل على مُجزِّئ النموذج واحصل على alora_invocation_tokens على النحو التالي

alora_invocation_tokens = tokenizer.encode(invocation_string, add_special_tokens=False).

مثال على إعداد الاستدلال موجود في alora finetuning.

عند استخدام نصوص مخصصة لسلسلة الاستدعاء، تأكد من أن بداية ونهاية السلسلة هي رموز خاصة لتجنب المشكلات المتعلقة بالتجزئة عند الحدود.

للفهم، تخيّل أن الرموز ‘a’ و ‘b’ و ‘c’ و ‘ab’ هي توكنات في مُجزّئ النصوص الخاص بك (والأرقام 1 و 2 و 3 و 4 على التوالي). افترض أن alora_invocation_tokens = [2, 3]. الآن تخيّل أن نص الإدخال الخاص بك هو “abc”. بما أن “ab” هو توكن، فإن هذا النص سيُجزَّأ إلى [4,3]. وبالتالي، سيفشل العثور على alora_invocation_tokens على الرغم من وجود السلسلة “bc” ضمن النص. ومع ذلك، إذا كانت بداية ونهاية سلسلة الاستدعاء توكنات خاصة، فلن يحدث هذا الفشل أبدًا لأن التوكنات الخاصة لا تُدمج أبدًا مع أحرف أخرى في توكن واحد.

استخدام (وإعادة استخدام) ذاكرة التخزين المؤقت للتوليد

الغرض الرئيسي من aLoRA هو جعل ذاكرة KV قابلة للتبديل بين النموذج الأساسي ونماذج محوّل aLoRA قبل تسلسل الاستدعاء لأن قيم KV الأساسية والمحوّلة غير متوافقة. على وجه التحديد، يمكن استخدام المفاتيح والقيم المخزنة أثناء توليد نموذج واحد في عمليات التوليد اللاحقة لتجنب عمليات التعبئة المسبقة المكلفة لرموز السياق. عند مشاركة ذاكرة التخزين المؤقت بين النموذج الأساسي ومحوّلات aLoRA، هناك نمطان رئيسيان:

  1. لقد أنتج النموذج الأساسي شيئًا ما، ثم يُستدعى مُكيّف aLoRA لإجراء توليد تالٍ. على سبيل المثال، يجيب النموذج الأساسي على سؤال، ثم يفحص مُكيّف aLoRA المُدرَّب على كشف الهلوسة (الوهم) ردّ النموذج الأساسي.
  2. يكون مُكيّف aLoRA قد أنتج شيئًا ما، ثم يُستدعى النموذج الأساسي أو مُكيّف aLoRA مختلف لإجراء توليد تالٍ يتداخل جزئيًا مع سياق aLoRA الأصلي. على سبيل المثال، يقدّم المستخدم استعلامًا، فيعيد مُكيّف aLoRA صياغة الاستعلام ليكون أكثر استقلالية لتحسين الاسترجاع في نظام RAG. ثم تُسترجع المستندات وتُحمَّل في السياق، ويتحقق aLoRA من مدى صلة هذه المستندات بالسؤال، ثم يولّد النموذج الأساسي إجابة.

لإظهار السلوكيات المذكورة أعلاه عند استخدام التخزين المؤقت، نستخدم DynamicCache من transformers. انتبه إلى ضمان عدم خلط قيم التخزين المؤقت المُكيّفة بقيم التخزين المؤقت الأساسية. وبشكل خاص، يتطلب مشاركة التخزين المؤقت خطوة إضافية عندما يكون هناك تداخل جزئي في السياق (النمط 2).

النمط 1: النموذج الأساسي متبوعًا بـ aLoRA هنا، يُدخل كامل مدخلات النموذج الأساسي ومخرجاته إلى مُكيّف aLoRA، إلى جانب تسلسل الاستدعاء:

from transformers import DynamicCache
...
cache = DynamicCache()
inputs_base = tokenizer(prompt_base, return_tensors="pt")
# Generate from base model and save cache
with model_alora.disable_adapter():
    output = model_alora.generate(inputs_base["input_ids"].to(device),attention_mask=inputs_base["attention_mask"].to(device),past_key_values = cache,return_dict_in_generate=True)
output_text_base = tokenizer.decode(output.sequences[0])
cache = output.past_key_values

# Generate with aLoRA adapter from cache
prompt_alora = output_text + INVOCATION_STRING
inputs_alora = tokenizer(prompt_alora, return_tensors="pt").to(device)
output = model_alora.generate(**inputs_alora, past_key_values=cache)
output_text_alora = tokenizer.decode(output[0])

# Note: cache is now tainted with adapter values and cannot be used in base model from here on!

النمط 2: توليد aLoRA يليه النموذج الأساسي (أو aLoRA آخر) مع تداخل جزئي في السياق هنا، نملأ السياق المشترك مسبقًا باستخدام النموذج الأساسي، ثم ننتج النص.

from transformers import DynamicCache
import copy
...
cache = DynamicCache()
inputs_shared = tokenizer(prompt_shared, return_tensors="pt").to(device)

# Prefill from base model and save cache
with model_alora.disable_adapter():
    with torch.no_grad():
        model_alora(**inputs_shared, past_key_values=cache)
cache_copy = copy.deepcopy(cache)

# Generate from aLoRA using prefilled cache
prompt_alora = prompt_shared + INVOCATION_STRING
inputs_alora = tokenizer(prompt_alora, return_tensors="pt").to(device)
output = model_alora.generate(**inputs_alora, past_key_values=cache)
output_text_alora = tokenizer.decode(output[0])

# Generate from base model using saved cache not tainted by aLoRA KV values
prompt_base = prompt_shared
inputs_base = tokenizer(prompt_base, return_tensors="pt").to(device)
with model_alora.disable_adapter():
    output = model_alora.generate(**inputs_base, past_key_values=cache_copy)
output_text_base = tokenizer.decode(output[0])

الاستدلال باستخدام محولات LoRA مختلفة في نفس الدفعة

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

لحسن الحظ، يمكن خلط محولات LoRA المختلفة في نفس الدفعة باستخدام الحجة adapter_name. أدناه، نوضح مثالاً على كيفية عمل ذلك عملياً. أولاً، دعونا نحمّل النموذج الأساسي، والإنجليزية، والمحولين، الفرنسية والألمانية، على النحو التالي:

from transformers import AutoTokenizer, AutoModelForCausalLM
from peft import PeftModel

model_id = ...
tokenizer = AutoTokenizer.from_pretrained(model_id)

model = AutoModelForCausalLM.from_pretrained(model_id)
# load the LoRA adapter for French
peft_model = PeftModel.from_pretrained(model, <path>, adapter_name="adapter_fr")
# next, load the LoRA adapter for German
peft_model.load_adapter(<path>, adapter_name="adapter_de")

الآن، نريد توليد نص على عينة تحتوي على اللغات الثلاث: العيّنات الثلاث الأولى بالإنجليزية، والتالية الثلاث بالفرنسية، والأخيرة الثلاث بالألمانية. يمكننا استخدام الحجة adapter_names لتحديد المُكيّف (adapter) الذي سنستخدمه لكل عينة. بما أن النموذج الأساسي لدينا يُستخدم للإنجليزية، نستخدم السلسلة الخاصة "__base__" لهذه العيّنات. بالنسبة للعيّنات الثلاث التالية، نحدد اسم المُكيّف الخاص بالتدريب الدقيق LoRA للفرنسية، وفي هذه الحالة "adapter_fr". وبالنسبة للعيّنات الثلاث الأخيرة، نحدد اسم المُكيّف الخاص بالتدريب الدقيق LoRA للألمانية، وفي هذه الحالة "adapter_de". بهذه الطريقة، يمكننا استخدام النموذج الأساسي والمُكيّفين في دفعة واحدة.

inputs = tokenizer(
    [
        "Hello, my dog is cute",
        "Hello, my cat is awesome",
        "Hello, my fish is great",
        "Salut, mon chien est mignon",
        "Salut, mon chat est génial",
        "Salut, mon poisson est super",
        "Hallo, mein Hund ist süß",
        "Hallo, meine Katze ist toll",
        "Hallo, mein Fisch ist großartig",
    ],
    return_tensors="pt",
    padding=True,
)

adapter_names = [
    "__base__", "__base__", "__base__",
    "adapter_fr", "adapter_fr", "adapter_fr",
    "adapter_de", "adapter_de", "adapter_de",
]
output = peft_model.generate(**inputs, adapter_names=adapter_names, max_new_tokens=20)

لاحظ أن الترتيب لا يهم هنا، أي أن العينات في الدفعة لا تحتاج إلى أن تكون مجمّعة حسب المُكيّف كما في المثال أعلاه. ما نحتاجه فقط هو التأكد من أن معامل adapter_names متوافق بشكل صحيح مع العينات.

علاوة على ذلك، يعمل النهج نفسه أيضًا مع ميزة modules_to_save، التي تتيح حفظ وإعادة استخدام طبقات محددة من الشبكة العصبية، مثل رؤوس مخصصة لمهام التصنيف، عبر محولات LoRA المختلفة.

ملاحظات

يوجد بعض العيوب لاستخدام هذه الميزة، وهي:

  • يعمل للاستدلال فقط، وليس للتدريب.
  • تتفوق عملية تعطيل المُكيّفات باستخدام سياق with model.disable_adapter() على adapter_names.
  • لا يمكنك تمرير adapter_names إذا تم دمج بعض أوزان المحوّل مع الوزن الأساسي باستخدام طريقة merge_adapter. يرجى إلغاء دمج جميع المحوِّلات أولاً عن طريق استدعاء model.unmerge_adapter(). لاحظ أن دمج بعض المحوِّلات النشطة فقط يحمل تحذيراً مماثلاً خارج نطاق adapter_names.
  • لأسباب واضحة، لا يمكن استخدام هذا بعد استدعاء merge_and_unload()، حيث سيتم دمج جميع محولات LoRA في الأوزان الأساسية في هذه الحالة.
  • لا تعمل هذه الميزة حاليًا مع DoRA، لذا اضبط use_dora=False في LoraConfig الخاص بك إذا كنت ترغب في استخدامها.
  • ميزة modules_to_save مدعومة حاليًا فقط لطبقات الأنواع Linear وEmbedding وConv2d وConv1d.
  • يوجد عبء متوقع عند الاستدلال باستخدام adapter_names, خاصة إذا كان عدد المحوِّلات المختلفة في الدفعة كبيرًا. والسبب في ذلك هو أن حجم الدفعة يُقلَّص فعليًا إلى عدد العينات لكل محوِّل. إذا كانت أداء وقت التشغيل أولويتك القصوى، فحاول ما يلي:
    • زيادة حجم الدفعة.
    • حاول تجنّب تضمين عدد كبير من المحوِّلات المختلفة في الدفعة الواحدة، وفضِّل الدفعات المتجانسة. يمكن تحقيق ذلك عن طريق تخزين العينات التي تستخدم المحوِّل نفسه في منطقة مؤقتة، ثم تنفيذ الاستدلال بعدد صغير فقط من المحوِّلات المختلفة.
    • اطّلع على تطبيقات بديلة مثل LoRAX وpunica أو S-LoRA، وهي مصممة خصيصًا للعمل مع عدد كبير من المحوِّلات المختلفة.

تكوين مُكيّفات LoRA وإعادة استخدامها

Arrow

Arrow هي خوارزمية توجيه معيارية مصممة لدمج عدة محولات LoRA مسبقة التدريب ومخصصة لمهام محددة لحل مهمة معينة، على غرار Polytropon لكن دون الحاجة إلى ضبط دقيق. وبدلا من دمج جميع المحولات بشكل ساذج، يقدم آلية توجيه خالية من التدرجات على مستوى الرموز (token-wise) تعتمد على مزيج الخبراء (MoE). عند الاستدلال، يحسب أولاً نموذجًا أوليًا (prototype) لكل محول LoRA من خلال استخراج متجه القيمة المفردة اليمنى الأعلى من تحليله باستخدام SVD. ثم تُقارن تمثيلات كل رمز مع هذه النماذج الأولية عبر التشابه الجيب التمامي (cosine similarity) للحصول على معاملات التوجيه. تُسند الرموز إلى محولات LoRA الأكثر صلة (top-k)، مع تطبيع المعاملات عبر softmax، وتُدمج مخرجاتها خطيًا. وهذا يتيح إعادة استخدام وحدات LoRA الموجودة بفعالية لمهام جديدة، مما يؤدي إلى تعميم أفضل في سيناريوهات الصفرية (zero-shot).

في PEFT، يتم تفعيل Arrow من خلال andcreate_arrow_model. You can also configure parameters such astop_k(the number of LoRA adapters combined per token),router_temperature(the softmax temperature applied to the routing coefficients), andrng_seed` (for reproducibility).

from peft import create_arrow_model, ArrowConfig
from transformers import AutoModelForCausalLM

# Loading the model
base_model = AutoModelForCausalLM.from_pretrained("microsoft/Phi-3-mini-4k-instruct")

# Creating the Arrow config
arrow_config = ArrowConfig(
    top_k=3,
    router_temperature=1.0,
    rng_seed=42,
)

# The LoRA adapters below were trained on a clustered FLAN dataset.
# Task clustering was performed using the Model-Based Clustering (MBC) method,
# as described in the Arrow paper.
# While one could train a separate LoRA for each task and let Arrow route tokens among them,
# training LoRAs on clusters of tasks instead provides an indirect optimization for
# transfer across the multi-task dataset.
task_specific_adapter_paths = [
        f"TahaBa/phi3-mini-clustered-flan/ts_expert_{i}" for i in range(10)
    ]

# Creating the Arrow model
model = create_arrow_model(
        base_model=base_model,
        task_specific_adapter_paths=task_specific_adapter_paths,
        arrow_config=arrow_config,
    )

# Now the forward path could be called on this model, like a normal PeftModel.

علاوة على ذلك، يمكنك إضافة أو إزالة المُكيّفات (adapters) بعد استدعاء create_arrow_model—على سبيل المثال، لضبط مُكيّف جديد أو التخلّي عن مُكيّف غير ضروري. بمجرد وضع المُكيّفات في مكانها، يمكنك تفعيل "arrow_router" للاستدلال (inference) لاستخدام Arrow. لاحظ أنه إذا أضفت مُكيّف LoRA جديدًا بعد create_arrow_model وأردت ضبطه، فيجب عليك تعيين المُكيّف الجديد كفعّال بشكل صريح، لأن "arrow_router" يكون مفعّلًا افتراضيًا في create_arrow_model.

from trl import SFTTrainer, SFTConfig

# Adding a new adapter and activating it
model.add_adapter(adapter_name='new_adapter')
model.set_adapter('new_adapter')

# Now the model could be trained along the `new_adapter`.
trainer = SFTTrainer(
        model=model,
        args=SFTConfig(...),
        ...
    )

# Once the training is done, you can activate `arrow_router` and use it in inference
model.set_adapter('arrow_router')    # Model is ready to be used at inference time now

GenKnowSub

يعزز GenKnowSub تقنية Arrow من خلال تنقية محولات LoRA الخاصة بالمهام قبل التوجيه. الفكرة الأساسية هي طرح المعرفة العامة المُرمّزة في فضاء LoRA—بناءً على مبدأ النسيان عبر النفي—بحيث تصبح محولات المهام أكثر عزلاً وتركيزاً على الإشارات ذات الصلة بالمهمة. عملياً، يقدّر GenKnowSub فضاءً فرعيّاً منخفض الأبعاد “عامّاً” من مجموعة من محولات LoRA العامة (غير الخاصة بمهمة معينة) ثم يزيل هذا المكوّن من تحديث LoRA لكل محوّل مهام قبل التوجيه على مستوى الرموز في Arrow. وهذا يحسّن عادةً قابلية التركيب ويقلل من التداخل عند دمج العديد من محولات المهام.

في PEFT، فعّل GenKnowSub عن طريق تعيين use_gks=True في ArrowConfig، وتوفير general_adapter_paths في create_arrow_model:

from peft import create_arrow_model, ArrowConfig
from transformers import AutoModelForCausalLM

# Loading the model
base_model = AutoModelForCausalLM.from_pretrained("microsoft/Phi-3-mini-4k-instruct")

# Creating the Arrow config
arrow_config = ArrowConfig(
    top_k=3,
    router_temperature=1.0,
    use_gks=True,
    rng_seed=42,
)

# Path to task-specific, trained on flan clustered dataset (as we explained before.)
task_specific_adapter_paths = [
        f"TahaBa/phi3-mini-clustered-flan/ts_expert_{i}" for i in range(10)
    ]
# These general adapters are trained on English, German, and French Wikipedia dataset,
# with causal language modelling objective, each pair like: (507 token tsentence, 5 token completion), and the loss computed on the completion
general_adapter_paths = [
        "TahaBa/phi3-mini-general-adapters/cluster0_batch16_prop1.0_langen/checkpoint-17",
        "TahaBa/phi3-mini-general-adapters/cluster0_batch16_prop1.0_langfr/checkpoint-35",
        "TahaBa/phi3-mini-general-adapters/cluster0_batch16_prop1.0_langger/checkpoint-17"
    ]

# Creating the Arrow model
model = create_arrow_model(
        base_model=base_model,
        task_specific_adapter_paths=task_specific_adapter_paths,
        general_adapter_paths=general_adapter_paths,
        arrow_config=arrow_config,
    )

# Now the forward path could be called on this model, like a normal PeftModel.

لتشفير المعرفة العامة، يطرح GenKnowSub متوسط المُكيّفات العامة المُقدَّمة من كل مُكيّف خاص بالمهمة مرة واحدة، قبل بدء التوجيه. علاوة على ذلك، لا يزال يُدعم في هذه الحالة القدرة على إضافة أو إزالة المُكيّفات بعد استدعاء create_arrow_model (كما هو موصوف في قسم Arrow).

أشياء يجب وضعها في الاعتبار عند استخدام Arrow + GenKnowSub:

  • يجب أن تتشارك جميع محولات LoRA (المخصصة للمهمة والعامة) نفس rank وtarget_modules.

  • ستؤدي أي عدم اتساق في هذه الإعدادات إلى رفع خطأ في create_arrow_model.

  • يُؤمَن استخدام عوامل توسيع مختلفة (lora_alpha) عبر مُكيّفات المهام — يتعامل Arrow معها تلقائيًا.

  • لا يُدعم دمج "arrow_router" بسبب سلوكه الديناميكي في التوجيه.

  • في create_arrow_model، تُحمَّل مُكيّفات المهام باسم task_i ومُكيّفات الاستخدام العام باسم gks_j (حيث i وj هما فهارس). تضمن الدالة اتساق target_modules وrank، وما إذا كانت المُكيّفات مطبّقة على طبقات Linear أو Linear4bit. ثم تضيف وحدة "arrow_router" وتفعّلها. أي تخصيص لهذه العملية يتطلب تجاوز create_arrow_model.

  • يتوافق هذا التنفيذ مع التكميم بدقة 4 بت (عبر bitsandbytes):

    from transformers import AutoModelForCausalLM, BitsAndBytesConfig
    import torch
    
    # Quantisation config
    bnb_config = BitsAndBytesConfig(
            load_in_4bit=True,
            bnb_4bit_quant_type="nf4",
            bnb_4bit_compute_dtype=torch.bfloat16,
            bnb_4bit_use_double_quant=False,
        )
    
    # Loading the model
    base_model = AutoModelForCausalLM.from_pretrained(
        "microsoft/Phi-3-mini-4k-instruct",
        dtype=torch.bfloat16,
        device_map="auto",
        quantization_config=bnb_config,
    )
    
    # Now call create_arrow_model() as we explained before.

واجهة برمجة التطبيقات

LoraConfig

فئة peft.LoraConfig

< >

( task_type: Optional[Union[str, TaskType]] = Nonepeft_type: Optional[Union[str, PeftType]] = Noneauto_mapping: Optional[dict] = Nonepeft_version: Optional[str] = Nonebase_model_name_or_path: Optional[str] = Nonerevision: Optional[str] = Noneinference_mode: bool = Falser: int = 8target_modules: Optional[Union[list[str], str]] = Noneexclude_modules: Optional[Union[list[str], str]] = Nonelora_alpha: int = 8lora_dropout: float = 0.0fan_in_fan_out: bool = Falsebias: Literal['none', 'all', 'lora_only'] = 'none'use_rslora: bool = Falsemodules_to_save: Optional[list[str]] = Noneinit_lora_weights: bool | Literal['gaussian', 'eva', 'olora', 'pissa', 'pissa_niter_[number of iters]', 'corda', 'astra', 'loftq', 'orthogonal', 'mica', 'nora'] = Truelayers_to_transform: Optional[Union[list[int], int]] = Nonelayers_pattern: Optional[Union[list[str], str]] = Nonerank_pattern: Optional[dict] = <factory>alpha_pattern: Optional[dict] = <factory>megatron_config: Optional[dict] = Nonemegatron_core: Optional[str] = 'megatron.core'trainable_token_indices: Optional[Union[list[int], dict[str, list[int]]]] = Noneloftq_config: Union[LoftQConfig, dict] = <factory>eva_config: Optional[EvaConfig] = Nonecorda_config: Optional[CordaConfig] = Noneastra_config: Optional[AstraConfig] = Nonelora_ga_config: Optional[LoraGAConfig] = Noneuse_dora: bool = Falsevelora_config: Optional[Union[VeloraConfig, dict]] = Nonealora_invocation_tokens: Optional[list[int]] = Noneuse_qalora: bool = Falseqalora_group_size: int = 16monteclora_config: Optional[MontecloraConfig] = Nonelayer_replication: Optional[list[tuple[int, int]]] = Noneruntime_config: LoraRuntimeConfig = <factory>lora_bias: bool = Falsetarget_parameters: Optional[list[str]] = Noneuse_bdlora: Optional[BdLoraConfig] = Nonearrow_config: Optional[ArrowConfig] = Nonekasa_config: Optional[KasaConfig] = Noneensure_weight_tying: bool = False )

المعاملات

  • r (int) — بعدد انتباه لورا (الـ “rank”).
  • target_modules (Optional[Union[List[str], str]]) — أسماء الوحدات التي سيتم تطبيق المُكيّف عليها. إذا تم تحديد هذا، فسيتم استبدال الوحدات التي تحمل الأسماء المحددة فقط. عند تمرير نص، سيتم إجراء مطابقة باستخدام تعبير نمطي. عند تمرير قائمة من النصوص، سيتم إجراء مطابقة دقيقة أو يتم التحقق مما إذا كان اسم الوحدة ينتهي بأي من النصوص الممررة. إذا تم تحديده على أنه ‘all-linear’، فسيتم اختيار جميع وحدات linear/Conv1D (إذا كان النموذج PreTrainedModel، باستثناء طبقة الإخراج). إذا لم يتم تحديده، فسيتم اختيار الوحدات وفقًا لبنية النموذج. إذا لم تكن البنية معروفة، فسيتم رفع خطأ — في هذه الحالة، يجب عليك تحديد الوحدات المستهدفة يدويًا. لتجنب استهداف أي وحدات (لأنك تريد تطبيق target_parameters)، اضبط target_modules=[].
  • exclude_modules (Optional[Union[List[str], str]]) — أسماء الوحدات التي لا يُطبَّق عليها المُكيّف. عند تمرير نص، يتم إجراء مطابقة باستخدام تعبير نمطي. عند تمرير قائمة من النصوص، يتم إجراء مطابقة دقيقة أو يُتحقق مما إذا كان اسم الوحدة ينتهي بأي من النصوص المُمرَّرة.
  • lora_alpha (int) — معامل ألفا لتقنية Lora scaling.
  • lora_dropout (float) — احتمالية الإسقاط (dropout) لطبقات Lora.
  • fan_in_fan_out (bool) — اضبط هذا على True إذا كانت الطبقة التي سيتم استبدالها تخزن الأوزان على شكل (fan_in, fan_out). على سبيل المثال، يستخدم gpt-2 Conv1D الذي يخزن الأوزان على شكل (fan_in, fan_out) وبالتالي يجب ضبط هذا على True.
  • bias (str) — نوع الانحياز (Bias) في LoRA. يمكن أن يكون ‘none’ أو ‘all’ أو ‘lora_only’. إذا كان ‘all’ أو ‘lora_only’، فسيتم تحديث الانحيازات المقابلة أثناء التدريب. انتبه إلى أن هذا يعني أن النموذج لن ينتج نفس المخرجات التي كان سينتجها النموذج الأساسي دون تكييف، حتى عند تعطيل المحولات (adapters).
  • use_rslora (bool) — عند ضبطه على True، يستخدم Rank-Stabilized LoRA الذي يضبط معامل توسيع المحوّل على lora_alpha/math.sqrt(r)، إذ ثبت أنه يعمل بشكل أفضل. وإلا، فسيستخدم القيمة الافتراضية الأصلية lora_alpha/r.
  • modules_to_save (List[str]) — قائمة بالوحدات، بخلاف طبقات المُكيِّف (adapter)، التي يجب تعيينها قابلة للتدريب وحفظها في نقطة الفحص النهائية.
  • init_lora_weights (bool | Literal["gaussian", "eva", "olora", "pissa", "pissa_niter_[number of iters]", "corda", "astra", "loftq", "orthogonal", "mica", "nora"]) — كيفية تهيئة أوزان طبقات المُكيِّف. عند تمرير True (الافتراضي)، يتم استخدام التهيئة الافتراضية من التنفيذ المرجعي من Microsoft، حيث يتم تعيين وزن LoRA B إلى 0. هذا يعني أنه بدون تدريب إضافي، سيكون مُكيِّف LoRA عملية لا تُغيّر شيئًا (no-op). عند تعيين التهيئة إلى False، يتم تهيئة LoRA A و B بشكل عشوائي، مما يعني أن LoRA ليست عملية لا تُغيّر شيئًا قبل التدريب؛ هذا الإعداد مخصص لأغراض التصحيح. عند تمرير 'gaussian'، يتم استخدام تهيئة غاوسية مُقيَّمة حسب رتبة LoRA للطبقات الخطية. مرّر 'loftq' لاستخدام تهيئة LoftQ. عند تمرير 'eva' يتم استخدام تهيئة مبنية على البيانات لـ التكيّف مع تباين المُفسَّر. تهيّئ EVA LoRA بناءً على التحليل القيمي المفرد (SVD) لتفعيلات مدخلات الطبقة، وتحقق أداءً متقدمًا (SOTA) بسبب قدرتها على التكيّف مع بيانات الضبط الدقيق. مرّر 'olora' لاستخدام تهيئة OLoRA. عند تمرير 'pissa' يتم استخدام تهيئة التكيّف مع القيم المفردة المتجهية الرئيسية (PiSSA)، والذي يتقارب بشكل أسرع من LoRA ويحقق أداءً أفضل في النهاية. علاوة على ذلك، يقلل PiSSA من خطأ التكميم مقارنة بـ QLoRA، مما يؤدي إلى تحسينات إضافية. عند تمرير 'pissa_niter_[number of iters]'، يتم بدء تهيئة PiSSA القائمة على Fast-SVD، حيث يشير [number of iters] إلى عدد تكرارات الفضاء الجزئي لتنفيذ FSVD، ويجب أن يكون عددًا صحيحًا غير سالب. عند تعيين [number of iters] إلى 16، يمكن إكمال تهيئة نموذج 7B خلال ثوانٍ، ويكون تأثير التدريب مكافئًا تقريبًا لاستخدام SVD. عند تمرير 'corda'، يتم استخدام تهيئة التكيّف مع التحليل الموجّه نحو السياق، والذي يتقارب بشكل أسرع حتى من PiSSA في وضع المعاينة التوجيهية، ويحافظ بشكل أفضل على المعرفة العالمية في وضع الحفاظ على المعرفة. عند تمرير 'astra'، يتم استخدام تهيئة التكيّف منخفض الرتبة لمتجهات eigen في ذيل فضاء التفعيل، والذي يُسقط الوزن الأساسي على فضاء eigen لتفعيلات المخرجات المُقدَّرة من مجموعة بيانات معايرة صغيرة. عند تمرير "orthogonal"، يتم تهيئة LoRA A و B بشكل متعامد؛ يشبه هذا "olora"، لكن تُترك الأوزان الأساسية دون تغيير (يتطلب أن تكون r عددًا زوجيًا، مدعوم حاليًا فقط للطبقات الخطية). عند تمرير "mica"، يتم استخدام تهيئة التكيّف مع المكوّنات الثانوية (MiCA)، والتي تهيّئ B من متجهات singular اليسرى r للوزن الأساسي المرتبطة بأصغر قيم singular، وتعيّن A إلى صفر، وتجمّد B أثناء التدريب؛ يتم تحديث A فقط. مدعوم حاليًا للطبقات الخطية وطبقات التضمين. عند تمرير "nora"، يتم استخدام تهيئة التكيّف منخفض الرتبة المُطبَّع (NoRA)، والذي يُطبّع كل عمود من وزن LoRA A المُهيّأ عشوائيًا إلى معيار L2 وحدة، ويعيّن وزن LoRA B إلى صفر. يُطبَّق التطبيع فقط عند التهيئة؛ تبقى الأوزان الأساسية دون تغيير، ويبقى كل من A و B قابلًا للتدريب. الإعداد الموصى به هو lora_alpha يساوي r مع use_rslora=False، مما يحافظ على نسبة 1:1 ومعامل قياس 1. مدعوم حاليًا للطبقات الخطية ولـ nn.Parameters المستهدفة بواسطة target_parameters.

    التكيّف بالقيم المتفردة الرئيسية والمتجهات المتفردة (PiSSA)، الذي يتقارب بشكل أسرع من LoRA ويحقق في النهاية أداءً متفوقاً. علاوة على ذلك، يقلل PiSSA من خطأ التكميم مقارنة بـ QLoRA، مما يؤدي إلى تحسينات إضافية. عند تمرير 'pissa_niter_[number of iters]'، يبدأ تهيئة PiSSA القائمة على Fast-SVD، حيث يشير [number of iters] إلى عدد تكرارات الفضاء الجزئي لتنفيذ FSVD، ويجب أن يكون عدداً صحيحاً غير سالب. عند ضبط [number of iters] على 16، يمكن إكمال تهيئة نموذج بحجم 7B خلال ثوانٍ، ويكون تأثير التدريب مكافئاً تقريباً لاستخدام SVD. عند تمرير 'corda'، يتم تهيئة Context-Oriented Decomposition Adaptation، الذي يتقارب بشكل أسرع حتى من PiSSA في وضع معاينة التعليمات، ويحافظ بشكل أفضل على المعرفة العالمية في وضع الحفاظ على المعرفة. عند تمرير 'astra'، يتم تهيئة Activation-Space Tail-Eigenvector Low-Rank Adaptation، الذي يرمز الأوزان الأساسية إلى فضاء المتجهات الذاتية لتفعيلات المخرجات المقدّرة من مجموعة بيانات معايرة صغيرة. عند تمرير "orthogonal"، يتم تهيئة LoRA A و B بشكل متعامد؛ وفي ذلك يشبه "olora"، لكن تُترك الأوزان الأساسية دون تغيير (يتطلب أن يكون r عدداً زوجياً، مدعوماً حالياً لطبقات الخطية فقط). عند تمرير "mica"، يتم تهيئة Minor Component Adaptation (MiCA)، الذي يهيئ B من المتجهات المتفردة اليسرى r للأوزان الأساسية المرتبطة بأصغر القيم المتفردة، ويضبط A إلى الصفر، ويجمّد B أثناء التدريب؛ حيث يتم تحديث A فقط. مدعوم حالياً لطبقات الخطية وطبقات التضمين. عند تمرير "nora"، يتم تهيئة Normalized Low-Rank Adaptation (NoRA)، الذي يعيّر كل عمود من أوزان LoRA A المهيأة عشوائياً إلى معيار L2 وحدة، ويضبط وزن LoRA B إلى الصفر. يُطبَّق التعيير فقط عند التهيئة؛ وتبقى الأوزان الأساسية دون تغيير ويبقى كل من A و B قابلين للتدريب. الإعداد الموصى به هو lora_alpha يساوي r مع use_rslora=False، مما يحافظ على نسبة 1:1 ومعامل تحجيم يساوي 1. مدعوم حالياً لطبقات الخطية ولـ nn.Parameters المستهدفة بواسطة target_parameters.

  • layers_to_transform (Union[List[int], int]) — فهارس الطبقات المراد تحويلها. إذا تم تمرير قائمة من الأعداد الصحيحة، فسيتم تطبيق المُكيّف على فهارس الطبقات المحددة في هذه القائمة. أما إذا تم تمرير عدد صحيح واحد، فسيتم تطبيق التحويلات على الطبقة الموجودة عند هذا الفهرس.
  • layers_pattern (Optional[Union[List[str], str]]) — اسم نمط الطبقة، يُستخدم فقط إذا كان layers_to_transform مختلفاً عن None. يجب أن يستهدف هذا nn.ModuleList الخاص بالنموذج، والذي يُسمى غالباً 'layers' أو 'h'.
  • rank_pattern (dict) — خريطة من أسماء الطبقات أو تعبيرات نمطية إلى الترتيبات التي تختلف عن الترتيب الافتراضي المحدد بواسطة r. على سبيل المثال، {'^model.decoder.layers.0.encoder_attn.k_proj': 16}.
  • alpha_pattern (dict) — خريطة من أسماء الطبقات أو تعبيرات نمطية منتظمة إلى قيم ألفا التي تختلف عن قيمة ألفا الافتراضية المحددة بواسطة lora_alpha. على سبيل المثال، {'^model.decoder.layers.0.encoder_attn.k_proj': 16}.
  • megatron_config (Optional[dict]) — حجج TransformerConfig الخاصة بـ Megatron. تُستخدم لإنشاء طبقة الخطي المتوازي الخاصة بـ LoRA. يمكنك الحصول عليها على النحو التالي، core_transformer_config_from_args(get_args())، حيث أن هاتين الدالتين من Megatron. ستُستخدم الحجج لتبني TransformerConfig الخاص بـ Megatron. تحتاج إلى تحديد هذا المعامل عندما تريد تطبيق LoRA على طبقات ColumnParallelLinear و RowParallelLinear في megatron.
  • megatron_core (Optional[str]) — وحدة Megatron الأساسية للاستخدام، القيمة الافتراضية هي "megatron.core".
  • trainable_token_indices (Optional[Union[List[int], dict[str, List[int]]]]) — يتيح لك تحديد فهارس الرموز التي تريد ضبطها الدقيق بشكل انتقائي دون الحاجة إلى إعادة تدريب مصفوفة التضمين الكاملة باستخدام طريقة peft.TrainableTokensModel. يمكنك تحديد فهارس الرموز بطريقتين. إما أن تحدد قائمة بالفهارس التي ستستهدف طبقة تضمين الإدخال في النموذج (أو، إذا لم تُعثر عليها، embed_tokens). أو يمكنك تحديد قاموس يكون مفتاحه اسم وحدة التضمين وقيمته قائمة بفهارس الرموز، على سبيل المثال {'embed_tokens': [0, 1, ...]}. لاحظ أن التدريب باستخدام FSDP يتطلب use_orig_params=True لتجنب المشكلات المتعلقة بـ requires_grad غير المنتظم.
  • loftq_config (Optional[LoftQConfig]) — إعدادات LoftQ. إذا لم تكن هذه القيمة None، فسيتم استخدام LoftQ لكَمّية أوزان الهيكل الأساسي (backbone) وتبني طبقات Lora. كما يجب تمرير init_lora_weights='loftq'. لاحظ أنه يجب عدم تمرير نموذج مُكمَّم في هذه الحالة، لأن LoftQ سيكمّم النموذج بنفسه. يُطبَّق LoftQ على الطبقات الخطية فقط، بما في ذلك تلك المستهدفة عبر target_parameters. لا تُدعَم طبقات التضمين (Embedding) والطبقات التلافيفية (convolutional)، بل تُستخدم بدلاً من ذلك التهيئة الافتراضية لـ LoRA. لا تُدعَم طبقات nn.MultiheadAttention وتُطلق خطأً.
  • eva_config (Optional[EvaConfig]) — إعدادات EVA. على الأقل، يجب تعيين حجة dataset (استخدم نفس مجموعة البيانات المستخدمة في finetuning).
  • corda_config (Optional[CordaConfig]) — إعدادات CorDA. إذا لم تكن هذه القيمة None، فسيتم استخدام CorDA لبناء طبقات المحوّل (adapter). كما مرّر init_lora_weights='corda'.
  • astra_config (Optional[AstraConfig]) — إعدادات Astra. إذا لم تكن هذه القيمة None، فسيتم استخدام Astra لبناء طبقات المحوّل (adapter). كما يجب تمرير init_lora_weights='astra'، واستدعاء preprocess_astra قبل get_peft_model في هذه الحالة.
  • lora_ga_config (Optional[LoraGAConfig]) — إعدادات LoRA-GA. إذا تم تمرير هذا، فسيتم استخدام LoRA-GA لتبطين طبقات المحوّل. كما يجب تعيين init_lora_weights='lora_ga' في هذه الحالة.
  • use_dora (bool) — تفعيل تقنية ‘Weight-Decomposed Low-Rank Adaptation’ (DoRA). تقوم هذه التقنية بتفكيك تحديثات الأوزان إلى جزأين: الحجم والاتجاه. يُعالَج الاتجاه بواسطة LoRA العادي، بينما يُعالَج الحجم بواسطة معامل قابل للتعلم منفصل. يمكن أن يحسّن هذا أداء LoRA، لا سيما عند استخدام رتب منخفضة. في الوقت الحالي، تدعم DoRA طبقات linear وConv2D فقط. تُدخل DoRA عبئًا أكبر مقارنة بـ LoRA النقي، لذا يُوصى بدمج الأوزان عند الاستدلال. لمزيد من المعلومات، راجع https://huggingface.co/papers/2402.09353.
  • velora_config (Optional[VeloraConfig]) — تفعيل VeLoRA من خلال توفير VeloraConfig. يستبدل VeLoRA مسار التراجع المخصص لإسقاط LoRA A الذي يخزّن التفعيلات المضغوطة بدلاً من التفعيلات الكاملة للإدخال.
  • kasa_config (Optional[KasaConfig]) — تفعيل KaSA (Knowledge-aware Singular-value Adaptation) من خلال توفير KasaConfig. يقوم KaSA بقصّ أصغر r مكونات قيم مفردة من أوزان الأساس المجمّدة عبر عملية SVD لمرة واحدة، ويُدخل قطريًا قابلًا للتعلم من القيم المفردة بين عوامل LoRA A و B. حاليًا، لا يتم دعم سوى الطبقات الخطية.
  • alora_invocation_tokens (List[int]) — إذا لم تكن None، فعّل ‘Activated LoRA’ (aLoRA)، حيث تكون alora_invocation_tokens هي سلسلة الاستدعاء المُرمَّزة للمُكيِّف (يجب أن تكون موجودة في جميع نصوص مدخلات النموذج). تُفعِّل هذه التقنية أوزان المُكيِّف بشكل انتقائي فقط على الرموز أثناء وبعد alora_invocation_tokens. عند الاستخدام في CausalLM، يعني ذلك أن ذاكرة KV قبل الاستدعاء قابلة للتبديل مع ذاكرة النموذج الأساسي (ومع مُكيِّفات aLoRA الأخرى التي تعمل بهذه الطريقة). ونتيجةً لذلك، في خطوط أنابيب الاستدلال التي تتضمن التبديل بين استدلال النموذج الأساسي واستدلال المُكيِّف (مثل خطوط الأنابيب الوكيلية، راجع الورقة العلمية للحصول على أمثلة)، يتم تحقيق توفير كبير (مقارنةً بـ LoRA) من خلال حفظ عمليات التعبئة المسبقة. يمكن أن تحدث تسارعات في سرعة استدلال المُكيِّف الإجمالية بمقدار مرتبة أعدادية واحدة أو أكثر على vLLM، اعتمادًا على طول السياق المشترك. لاحظ أن الدمج غير ممكن بسبب التطبيق الانتقائي للأوزان.
  • use_qalora (bool) — لم يتم تنفيذه حاليًا إلا في GPTQ. فعّل التكيّف منخفض الرتبة الواعي بالتكميم (QALoRA). تجمع هذه التقنية بين التدريب الواعي بالتكميم وLoRA لتحسين أداء النماذج المكمّمة. يمكن أن يحسّن هذا أداء LoRA، خاصةً عند استخدام رتب منخفضة. في الوقت الحالي، يدعم QALoRA طبقات الخطية فقط.
  • qalora_group_size (int) — معامل حجم المجموعة لدمج QALoRA، يتحكم في معامل تقليل الأبعاد. يتم دمج أبعاد الإدخال في مجموعات بهذا الحجم، مما يقلل من التكلفة الحسابية. توفر القيم الأعلى ضغطًا أكبر، لكنها قد تقلل من جودة النموذج. يحدد هذا المعامل عدد الميزات الأصلية التي يتم أخذ متوسطها معًا لإنشاء ميزة واحدة مدمجة. يُستخدم فقط عندما يكون use_qalora=True.
  • monteclora_config (Optional[MontecloraConfig]) — إعدادات Monteclora (التكيّف منخفض الرتبة باستخدام مونت كارلو). إذا تم تمريرها، فسيتم استخدام Monteclora لإضافة أخذ عينات مونت كارلو التبايني فوق مُكيّفات LoRA. راجع MontecloraConfig للحصول على تفاصيل حول المعلمات الفائقة الفردية.
  • layer_replication (List[Tuple[int, int]]) — إنشاء مجموعة جديدة من الطبقات عن طريق تجميع طبقات النموذج الأصلي وفقاً للنطاقات المحددة. يتيح ذلك توسيع (أو تقليص) النموذج دون تكرار أوزان النموذج الأساسي. سيتم إرفاق محولات LoRA منفصلة بكل طبقة جديدة.
  • runtime_config (LoraRuntimeConfig) — إعدادات وقت التشغيل (التي لا يتم حفظها أو استعادتها).
  • lora_bias (bool) — القيمة الافتراضية هي False. يحدد ما إذا كان سيتم تفعيل حد الانحياز (bias) لمعامل LoRA B. عادةً، يجب تعطيل هذا الخيار. الاستخدام الرئيسي لهذا الخيار هو عندما تكون أوزان LoRA مستخرجة من معاملات تم ضبطها بالكامل (fully fine-tuned)، بحيث يمكن أخذ انحياز تلك المعاملات في الاعتبار.
  • target_parameters (List[str]، اختياري) — قائمة بأسماء المعاملات التي سيتم استبدالها بـ LoRA. يتصرف هذا الحُجج بشكل مشابه لـ target_modules، باستثناء أنه يجب تمرير اسم المعامل. بشكل عام، يجب استخدام target_modules لاستهداف الوحدة (مثل nn.Linear). ومع ذلك، في بعض الظروف، لا يكون ذلك ممكنًا. على سبيل المثال، في العديد من طبقات مزيج الخبراء (MoE) في HF Transformers، بدلاً من استخدام nn.Linear، يتم استخدام nn.Parameter. يقوم PEFT عادةً بتجاوز طريقة forward لـ LoRA، لكن في حالة nn.Parameter، لا توجد طريقة. لذلك، لتطبيق LoRA على ذلك المعامل، يجب استهدافه باستخدام target_parameters. كمثال، بالنسبة إلى Llama4، يمكنك تمرير: target_parameters=['feed_forward.experts.gate_up_proj', 'feed_forward.experts.down_proj]. تمرير نص (string) للمطابقة باستخدام التعبيرات النمطية (regex) غير مُنفَّذ بعد. لاحظ أنه عند تجميع النموذج واستخدام target_parameters، يُتوقع حدوث إعادة تجميع و/أو انقطاعات في الرسم البياني. يُنصح بعدم استخدام كليهما في الوقت نفسه.
  • use_bdlora (Optional[BdLoraConfig]) — تفعيل تقنية BD-LoRA (LoRA القطري الحزمي) من خلال تقديم كائن BdLoraConfig. تستخدم هذه التقنية مصفوفات قطرية حزمية لعوامل LoRA-A أو LoRA-B لتمكين تقديم متعدد LoRA أسرع من خلال إزالة تكاليف الاتصال في الإعدادات الموزعة.
  • arrow_config (Optional[ArrowConfig]) — الإعدادات اللازمة لتطبيق توجيه arrow على النموذج.
  • ensure_weight_tying (bool, اختياري) — ما إذا كان سيتم ربط الأوزان أم لا بعد تهيئة peft. سيضمن هذا أن المُكيّفات المضافة إلى الطبقات المرتبطة تكون مرتبطة أيضًا. ينطبق هذا فقط على الطبقات المُمررة عبر modules_to_save و target_modules.

هذه هي فئة الإعدادات لتخزين إعدادات LoraModel.

to_dict

< >

( )

يعيد إعدادات نموذج المُكيّف الخاص بك على شكل قاموس. يزيل إعدادات وقت التشغيل.

LoraModel

فئة peft.LoraModel

< >

( modelpeft_config: Union[PeftConfig, dict[str, PeftConfig]]adapter_name: strlow_cpu_mem_usage: bool = Falsestate_dict: Optional[dict[str, torch.Tensor]] = None ) → torch.nn.Module

المعاملات

  • model (torch.nn.Module) — النموذج الذي سيتم تكييفه.
  • config (LoraConfig) — إعدادات نموذج Lora.
  • adapter_name (str) — اسم المُكيّف، القيمة الافتراضية هي "default".
  • low_cpu_mem_usage (bool, optional, defaults to False) — إنشاء أوزان مُكيّف فارغة على جهاز meta. مفيد لتسريع عملية التحميل.

يعيد

torch.nn.Module

نموذج Lora.

ينشئ نموذج Low Rank Adapter (LoRA) من نموذج transformers مُدرَّب مسبقًا.

يُوصف这个方法 بالتفصيل في https://huggingface.co/papers/2106.09685.

مثال:

>>> from transformers import AutoModelForSeq2SeqLM
>>> from peft import LoraConfig, get_peft_model

>>> config = LoraConfig(
...     task_type="SEQ_2_SEQ_LM",
...     r=8,
...     lora_alpha=32,
...     target_modules=["q", "v"],
...     lora_dropout=0.01,
... )

>>> model = AutoModelForSeq2SeqLM.from_pretrained("t5-base")
>>> lora_model = get_peft_model(model, config)
>>> import torch
>>> import transformers
>>> from peft import LoraConfig, get_peft_model, prepare_model_for_kbit_training

>>> rank = ...
>>> target_modules = ["q_proj", "k_proj", "v_proj", "out_proj", "fc_in", "fc_out", "wte"]
>>> config = LoraConfig(
...     r=4, lora_alpha=16, target_modules=target_modules, lora_dropout=0.1, bias="none", task_type="CAUSAL_LM"
... )
>>> quantization_config = transformers.BitsAndBytesConfig(load_in_8bit=True)

>>> tokenizer = transformers.AutoTokenizer.from_pretrained(
...     "kakaobrain/kogpt",
...     revision="KoGPT6B-ryan1.5b-float16",  # or float32 version: revision=KoGPT6B-ryan1.5b
...     bos_token="[BOS]",
...     eos_token="[EOS]",
...     unk_token="[UNK]",
...     pad_token="[PAD]",
...     mask_token="[MASK]",
... )
>>> model = transformers.GPTJForCausalLM.from_pretrained(
...     "kakaobrain/kogpt",
...     revision="KoGPT6B-ryan1.5b-float16",  # or float32 version: revision=KoGPT6B-ryan1.5b
...     pad_token_id=tokenizer.eos_token_id,
...     use_cache=False,
...     device_map={"": rank},
...     torch_dtype=torch.float16,
...     quantization_config=quantization_config,
... )
>>> model = prepare_model_for_kbit_training(model)
>>> lora_model = get_peft_model(model, config)

الخصائص:

  • model (PreTrainedModel) — النموذج الذي سيتم تكييفه.
  • peft_config (LoraConfig): إعدادات نموذج Lora.

add_weighted_adapter

< >

( adapters: list[str]weights: list[float]adapter_name: strcombination_type: Literal['svd', 'linear', 'cat', 'ties', 'ties_svd', 'dare_ties', 'dare_linear', 'dare_ties_svd', 'dare_linear_svd', 'magnitude_prune', 'magnitude_prune_svd'] = 'svd'svd_rank: int | None = Nonesvd_clamp: int | None = Nonesvd_full_matrices: bool = Truesvd_driver: str | None = Nonedensity: float | None = Nonemajority_sign_method: Literal['total', 'frequency'] = 'total' )

المعاملات

  • adapters (list) — قائمة بأسماء المُكيِّفات التي سيتم دمجها.
  • weights (list) — قائمة بالأوزان الخاصة بكل مُكيّف. يمكن أن تكون الأوزان موجبة أو سالبة، مما يتيح الجمع بين تأثيرات المُكيّفات أو طرحها.
  • adapter_name (str) — اسم المُكيّف الجديد.
  • combination_type (str) — يمكن أن يكون نوع الدمج أحد [svd, linear, cat, ties, ties_svd, dare_ties, dare_linear, dare_ties_svd, dare_linear_svd, magnitude_prune, magnitude_prune_svd]. عند استخدام cat كـ combination_type، يكون رتبة المُكيّف الناتج مساويةً لمجموع رتب جميع المُكيّفات (قد يكون المُكيّف المختلط كبيرًا جدًا مما يؤدي إلى أخطاء نفاد الذاكرة OOM). لاحظ أن cat وsvd طريقتان دقيقتان وسوف تمنحانك دقة جيدة، بينما linear فعّالة لكنها تقريب خشن جدًا ويجب تجنبها إذا كان بإمكانك تحمّل التكلفة.
  • svd_rank (int، اختياري) — رتبة مُكيّف المخرجات الخاص بـ svd. إذا لم يُقدَّم أي قيمة، فسيتم استخدام الرتبة القصوى لمُكيّفات الدمج.
  • svd_clamp (float, اختياري) — حدّ نسبة مئوية (quantile threshold) لقصّ (clamping) ناتج تحليل SVD. إذا تم تقديم None، فلا يتم تنفيذ القصّ. القيمة الافتراضية هي None.
  • svd_full_matrices (bool, اختياري) — يتحكم في حساب SVD الكامل أو المختزل، وبالتالي في شكل الموترات U وVh المُعادَة. القيمة الافتراضية هي True.
  • svd_driver (str, اختياري) — اسم طريقة cuSOLVER التي سيتم استخدامها. يعمل هذا الحُجج المُسمّى فقط عند الدمج على CUDA. يمكن أن يكون أحد [None, gesvd, gesvdj, gesvda]. لمزيد من المعلومات، يُرجى الرجوع إلى توثيق torch.linalg.svd. القيمة الافتراضية هي None.
  • density (float, اختياري) — قيمة بين 0 و 1. تعني 0 أن جميع القيم تُحذف، وتعني 1 عدم حذف أي قيم. يجب استخدامه مع [ties, ties_svd, dare_ties, dare_linear, dare_ties_svd, dare_linear_svd, magnintude_prune, magnitude_prune_svd]
  • majority_sign_method (str) — الطريقة، يجب أن تكون واحدة من [“total”, “frequency”]، لاستخدامها في الحصول على مقدار قيم الإشارة. يجب استخدامه مع [ties, ties_svd, dare_ties, dare_ties_svd]

تضيف هذه الطريقة مُكيِّفًا جديدًا من خلال دمج المُكيِّفات المُعطاة مع الأوزان المُعطاة.

عند استخدام cat كقيمة لـ combination_type، يجب أن تكون على دراية بأن رتبة المحوّل الناتج ستكون مساوية لمجموع رتب جميع المحوّلات. لذا، من الممكن أن يصبح المحوّل المختلط كبيرًا جدًا مما يؤدي إلى أخطاء نفاد الذاكرة (OOM).

subtract_mutated_init

< >

( output_state_dict: dict[str, torch.Tensor]adapter_name: strkwargs = None )

يمكن لهذا الدالة حساب تحديثات PiSSA/CorDA/OLoRA من خلال مقارنة معاملات مُكيّف PiSSA/CorDA/OLoRA في output_state_dict مع القيم الأولية لـ PiSSA/CorDA/OLoRA في adapter_name، وبالتالي تحويل PiSSA/CorDA/OLoRA إلى LoRA.

تزيل طرق مثل PiSSA جزءًا من أوزان النموذج الأساسية للتدريب، ولذلك لا يمكن استبدالها بسهولة. ولكن إذا كنت تعرف كلًا من أوزان ما قبل التدريب الأولية وأوزان ما بعد التدريب، يمكنك حساب \Delta W واستخدامه كمُكيّف LoRA.

خطوات الحساب:

  • W=Wres+A0B0W = W_{res} + A_0 B_0 (تهيئة PiSSA
  • W+ΔW=Wres+ABW + \Delta W = W_{res} + A B (PiSSA بعد التدريب
  • ΔW=Wres+AB−W=Wres+AB−Wres−A0B0\Delta W = W_{res} + AB - W = W_{res} + AB - W_{res} - A_0 B_0 (اشتقاق dW لـ LoRA
  • ΔW=AB−A0B0\Delta W = AB - A_0 B_0

أدوات مساعدة

ArrowConfig

فئة peft.ArrowConfig

< >

( top_k: int = 3router_temperature: float = 1.0use_gks: bool = Falserng_seed: Optional[int] = None )

هذا هو فئة التهيئة الفرعية لتخزين إعدادات خوارزميتي Arrow وGenKnowSub. Arrow هي خوارزمية توجيه لدمج وحدات LoRA المدربة لحل مهام جديدة، وقد طُرحت في ’https://huggingface.co/papers/2405.11157’. أما GenKnowSub فهي تحسين على الوحدات المدربة قبل دمجها عبر Arrow، وقد عُرضت في ’https://aclanthology.org/2025.acl-short.54/’

LoftQ

replace_lora_weights_loftq

peft.replace_lora_weights_loftq

< >

( peft_modelmodel_path: Optional[str] = Noneadapter_name: str = 'default'callback: Optional[Callable[[torch.nn.Module, str], bool]] = None )

المعاملات

  • peft_model (PeftModel) — النموذج الذي سيتم استبدال أوزانه. يجب أن يكون نموذج PEFT مُكمَّمًا مع طبقات LoRA.
  • model_path (Optional[str]) — مسار ملف safetensors الخاص بالنموذج. إذا كان النموذج من نماذج Hugging Face، فسيتم استنتاجه من إعدادات النموذج. وإلا، يجب تقديمه.
  • adapter_name (str) — اسم المُكيّف الذي سيُستبدل أوزانه. اسم المُكيّف الافتراضي هو “default”.
  • callback (Optional[Callable[[PeftModel, str], bool]]) — دالة استجابة (callback) تُستدعى بعد استبدال كل وحدة. يجب أن تستقبل دالة الاستجابة النموذج واسم الوحدة الحالية كمدخلات، وتعيد قيمة منطقية (boolean) تشير إلى ما إذا كان يجب الإبقاء على الاستبدال. إذا أعادت دالة الاستجابة False، سيتم التراجع عن الاستبدال. يمكن أن يكون هذا مفيدًا جدًا للتأكد من أن تهيئة LoftQ تقلل فعليًا من خطأ التكميم (quantization error) في النموذج. كمثال، يمكن لهذه الدالة توليد قيم logits لإدخال معين ومقارنتها بقيم logits من النموذج الأصلي غير المكمم مع نفس الإدخال، وإرجاع True فقط إذا كان هناك تحسن. وبما أن هذا تحسين طمع (greedy optimization)، فمن الممكن أن يؤدي استدعاء هذه الدالة عدة مرات إلى تحسينات تدريجية.

استبدل أوزان LoRA لنموذج مُكمَّم باستخدام bitsandbytes، باستخدام تقنية LoftQ.

يتم الاستبدال على الفور عن طريق تحميل الأوزان غير المُكمّمة من ملف نموذج safetensors مخزّن محليًا، وتبديل أوزان LoRA بحيث يتم تقليل خطأ التكميم بين الأوزان الأصلية والأوزان المُكمّمة إلى أدنى حد.

بما أن التحميل الكسول غير ممكن باستخدام pickle، فلا يمكن دعم ملفات نقاط التفتيش العادية الخاصة بـ PyTorch.

قد يستغرق استدعاء هذه الدالة بعض الوقت للانتهاء، وذلك اعتمادًا على حجم النموذج.

LoftQConfig

فئة peft.LoftQConfig

< >

( loftq_bits: int = 4loftq_iter: int = 1 )

المعاملات

  • loftq_bits (int) — عدد بتات التكميم لـ LoftQ.
  • loftq_iter (int) — عدد التكرارات المتناوبة لخوارزمية LoftQ.

هذا هو فئة التهيئة الفرعية لتخزين إعدادات LoraModel.

Eva

EvaConfig

فئة peft.EvaConfig

< >

( rho: float = 2.0tau: float = 0.99use_label_mask: bool = Truelabel_mask_value: int = -100whiten: bool = Falseadjust_scaling_factors: bool = True )

المعاملات

  • rho (float) — قيمة Rho لإعادة توزيع EVA (>= 1.0). الحد الأقصى للرتبة لطبقة معينة هو lora_r * rho. القيمة الافتراضية هي 2.0، مما يعني أن الحد الأقصى للرتبة المسموح بها لطبقة معينة هو 2r. زيادة rho ستسمح بدرجة أعلى من إعادة توزيع الرتب عبر الطبقات. قد تكون بعض النماذج المُدرَّبة مسبقًا أكثر حساسية تجاه إعادة توزيع الرتب. لذلك، قد يكون من المفيد تجربة rho=1.0 (بدون إعادة توزيع) إذا كانت الأداء أقل من المتوقع.
  • tau (float) — حدّ تشابه جيب التمام للإيقاف المبكر. يقارن تشابه جيب التمام للمتجهات المفردة اليمنى بين خطوتين متتاليتين من التحليل المفرد (SVD). إذا كان تشابه جيب التمام أعلى من هذا الحدّ، يتم إيقاف تكرار التحليل المفرد. القيمة الافتراضية هي 0.99.
  • use_label_mask (bool) — استخدم قناع التسميات (label mask) لتهيئة EVA. وهذا يعني أن المواضع التي تكون فيها التسميات مساوية لـ label_mask_value تُتجاهل في حساب SVD. يُفضَّل ضبط use_label_mask=True في معظم الحالات، وقد يكون مفيدًا بشكل خاص للمحادثات متعددة الأدوار. القيمة الافتراضية هي True. قد يؤدي استبعاد العناصر بناءً على قناع التسميات أحيانًا إلى حجم دفعة صغير، مما يسبب عدم استقرار في حساب SVD. في الحالات التي يُستبعد فيها حصة كبيرة من عناصر الدفعة، اضبط use_label_mask=False.
  • label_mask_value (int) — إذا كان use_label_mask=True، فهو القيمة التي يتم البحث عنها لإخفاء الرموز المتجاهلة. القيمة الافتراضية هي -100.
  • whiten (bool) — تطبيق التبييض على المتجهات المفردة. القيمة الافتراضية هي False. لقد ثبت أن التبييض مفيد لـ EVA في مجال الرؤية.
  • adjust_scaling_factors (bool) — تعديل معاملات توسيع LoRA بعد إعادة توزيع الرتب. تعيين هذا إلى True يعني أن معاملات التوسيع ستُعدَّل بحيث تمتلك جميع تدرجات LoRA نفس المقياس بغض النظر عن رتبها. القيمة الافتراضية هي True.

هذا هو فئة التهيئة الفرعية لتخزين إعدادات التهيئة القائمة على البيانات عبر EVA. تم تقديم EVA في Explained Variance Adaptation.

initialize_lora_eva_weights

peft.initialize_lora_eva_weights

< >

( model: Moduledataloader: collections.abc.Iterable | None = Noneeva_state_dict: dict | None = Noneforward_fn: collections.abc.Callable | None = <function forward_fn_dict at 0x7f240ea44e00>prepare_model_inputs_fn: collections.abc.Callable | None = <function prepare_model_inputs_fn_language_modeling at 0x7f240ea44bf0>prepare_layer_inputs_fn: collections.abc.Callable | dict[str, collections.abc.Callable] | None = <function prepare_layer_inputs_fn_language_modeling at 0x7f240ea44d50>adapter_name: str = 'default'gather_distributed_inputs: bool = Trueshow_progress_bar: bool = True ) → model (torch.nn.Module)

المعاملات

  • model (PeftModel) — نموذج peft الذي يتم حساب SVD له.
  • dataloader (Optional[Iterable]) — محمّل البيانات (dataloader) المستخدم لتمريرة الأمامية. إذا كانت القيمة None، فيجب توفير eva_state_dict.
  • eva_state_dict (Optional[dict]) — The state_dict to load into the model. If None, a dataloader needs to be provided and the state_dict will be computed using get_eva_state_dict.
  • forward_fn (Callable) — دالة الأمامي المستخدمة في المرور الأمامي. تستقبل حجتين: model وinputs. السلوك الافتراضي هو return model(**inputs)
  • prepare_model_inputs_fn (Optional[Callable]) — تستقبل هذه الدالة مدخلات النموذج وpeft_config وتُمرر المخرجات إلى prepare_layer_inputs_fn. يمكن استخدامها لتعديل مدخلات حساب SVD بناءً على مدخلات النموذج الأصلية. على سبيل المثال، في نمذجة اللغة، يُستخدم قناع الانتباه (attention mask) لتحديد الفهارس التي تمثل رموز الحشو (padding tokens) والتي يجب ألا تُستخدم في SVD. تتوقع أي دالة معرّفة هنا حجتين: model_input وpeft_config. يُستخدم peft.tuners.lora.eva.prepare_model_inputs_fn_language_modeling افتراضيًا.
  • prepare_layer_inputs_fn (Union[Callable, Dict[str, Callable], None]) — تستقبل هذه الدالة مدخلات الطبقة، ومدخلات النموذج (التي قد تكون معدّلة بواسطة prepare_model_inputs_fn)، واسم الطبقة، وتعيد المدخلات التي يجب استخدامها لتفكيك القيم المفردة (SVD) لتلك الطبقة على وجه التحديد. تتوقع أي دالة مخصصة تُعرَّف هنا ثلاثة حُجج: layer_input، model_input، وlayer_name، ويجب أن تعيد مصفوفة ثنائية الأبعاد (2d tensor). يمكن العثور على المنطق الافتراضي في peft.tuners.lora.eva.prepare_layer_inputs_fn_language_modeling وهو يعمل لنمذجة اللغة. في هذه الحالة، تكون model_inputs هي القناع (mask) المستخدم لتحديد الفهارس التي يجب استخدامها لتفكيك القيم المفردة (SVD) (المنشأ بواسطة prepare_model_inputs_fn_language_modeling).
  • adapter_name (str) — اسم المُكيّف الذي سيتم تهيئة الأوزان له.
  • gather_distributed_inputs (bool) — ما إذا كان سيتم جمع مدخلات الطبقة من جميع الرتب. القيمة الافتراضية هي True، مما يعني أنه في الإعداد الموزّع سيتم جمع مدخلات الطبقة من جميع الرتب لحساب SVD. في الإعدادات غير الموزّعة يتم تجاهل هذا الحجة. اضبطه على False إذا كنت تستخدم مُحمِّل بيانات غير موزّع في إعداد موزّع.
  • show_progress_bar (bool) — ما إذا كان يجب عرض شريط تقدم. القيمة الافتراضية هي True.

يعيد

النموذج (torch.nn.Module)

النموذج الذي تم تهيئته بأوزان LoRA.

تهيئة أوزان طبقات LoRA باستخدام طريقة EVA.

تُهيّئ هذه الدوال أوزان طبقات LoRA باستخدام طريقة EVA. فهي تحسب التحليل القيمي المفرد (SVD) لكل طبقة مُكيّف (adapter) وتحديث الأوزان وفقاً لذلك.

get_eva_state_dict

peft.get_eva_state_dict

< >

( model: Moduledataloader: Iterablepeft_config: peft.tuners.lora.config.LoraConfig | None = Noneforward_fn: collections.abc.Callable | None = <function forward_fn_dict at 0x7f240ea44e00>prepare_model_inputs_fn: collections.abc.Callable | None = <function prepare_model_inputs_fn_language_modeling at 0x7f240ea44bf0>prepare_layer_inputs_fn: collections.abc.Callable | dict[str, collections.abc.Callable] | None = <function prepare_layer_inputs_fn_language_modeling at 0x7f240ea44d50>adapter_name: str = 'default'gather_distributed_inputs: bool = Trueshow_progress_bar: bool = True ) → eva_state_dict (dict)

المعاملات

  • model (torch.nn.Module) — النموذج الذي سيتم حساب التحليل القيمي المفرد (SVD) له. لا يشترط أن يكون من نوع PeftModel.
  • dataloader (Iterable) — مُحمِّل البيانات المستخدم في المرور الأمامي.
  • peft_config (Optional[LoraConfig]) — إعدادات طبقات LoRA. مطلوبة فقط إذا لم يكن model من نوع PeftModel.
  • forward_fn (Callable) — دالة الأمامي المستخدمة في المرور الأمامي. تستقبل حجتين: model وinputs. السلوك الافتراضي هو return model(**inputs)
  • prepare_model_inputs_fn (Optional[Callable]) — تستقبل هذه الدالة مدخلات النموذج وpeft_config وتُمرر المخرجات إلى prepare_layer_inputs_fn. يمكن استخدامها لتعديل مدخلات حساب SVD بناءً على مدخلات النموذج الأصلية. على سبيل المثال، في نمذجة اللغة، يُستخدم قناع الانتباه (attention mask) لتحديد الفهارس التي تمثل رموز الحشو (padding tokens) والتي يجب ألا تُستخدم في SVD. تتوقع أي دالة معرّفة هنا حجتين: model_input وpeft_config. يُستخدم peft.tuners.lora.eva.prepare_model_inputs_fn_language_modeling افتراضيًا.
  • prepare_layer_inputs_fn (Union[Callable, Dict[str, Callable], None]) — تستقبل هذه الدالة مدخلات الطبقة، ومدخلات النموذج (التي قد تكون معدّلة بواسطة prepare_model_inputs_fn)، واسم الطبقة، وتعيد المدخلات التي يجب استخدامها لتفكيك القيم المفردة (SVD) لتلك الطبقة على وجه التحديد. تتوقع أي دالة مخصصة تُعرَّف هنا ثلاثة حُجج: layer_input، model_input، وlayer_name، ويجب أن تعيد مصفوفة ثنائية الأبعاد (2d tensor). يمكن العثور على المنطق الافتراضي في peft.tuners.lora.eva.prepare_layer_inputs_fn_language_modeling وهو يعمل لنمذجة اللغة. في هذه الحالة، تكون model_inputs هي القناع (mask) المستخدم لتحديد الفهارس التي يجب استخدامها لتفكيك القيم المفردة (SVD) (المنشأ بواسطة prepare_model_inputs_fn_language_modeling).
  • adapter_name (str) — اسم المُكيّف الذي سيتم حساب SVD له.
  • gather_distributed_inputs (bool) — ما إذا كان سيتم جمع مدخلات الطبقة من جميع الرتب. القيمة الافتراضية هي True، مما يعني أنه في الإعداد الموزّع سيتم جمع مدخلات الطبقة من جميع الرتب لحساب SVD. في الإعدادات غير الموزّعة يتم تجاهل هذا الحجة. اضبطه على False إذا كنت تستخدم مُحمِّل بيانات غير موزّع في إعداد موزّع.
  • show_progress_bar (bool) — ما إذا كان يجب عرض شريط تقدم. القيمة الافتراضية هي True.

يعيد

eva_state_dict (dict)

قاموس الحالة الذي يحتوي على مكونات التحليل القيمي المفرد (SVD) لكل طبقة.

احسب التحليل القياسي للقيم المفردة (SVD) لكل طبقة في النموذج.

تُحسب هذه الدالة تحليل القيم المفردة (SVD) لكل طبقة في النموذج. إنها تستخدم طريقة PCA التزايدية لحساب مكونات SVD. كما تتحقق الدالة من تقارب المكونات المحسوبة باستخدام التشابه الجيبية. يتم تحديد توزيع الرتبة لكل طبقة بناءً على نسبة التباين المفسَّر.

LoraGAConfig

فئة peft.LoraGAConfig

< >

( direction: Literal['ArBr', 'A2rBr', 'ArB2r', 'random'] = 'ArB2r'scale: Literal['stable', 'weight_svd', 'gd_scale', 'unit'] = 'stable'stable_gamma: int = 16 )

المعاملات

  • direction (Literal["ArBr", "A2rBr", "ArB2r", "random"]) — استراتيجية توزيع مكوّنات SVD للتدرّجات على مصفوفتي lora_A و lora_B.
    • “ArBr”: فهارس متناوبة (يأخذ A الفهارس الفردية، ويأخذ B الفهارس الزوجية)
    • “A2rBr”: يأخذ A الفهارس [r:2r]، بينما يأخذ B الفهارس [:r]
    • “ArB2r”: يأخذ A الفهارس [:r]، ويأخذ B الفهارس [r:2r] (موصى به)
    • “random”: اختيار عشوائي للفهارس الافتراضي: “ArB2r”
  • scale (Literal["stable", "weight_svd", "gd_scale", "unit"]) — استراتيجية التوسيع (Scaling) لمُهيّئ المُكيّف (Adapter).
    • “stable”: توسيع مستقر مع معامل غاما
    • “weight_svd”: مقياس يعتمد على القيم المفردة لمصفوفة الأوزان
    • “gd_scale”: تحجيم يعتمد على هبوط التدرج
    • “unit”: لا يوجد تحجيم إضافي الافتراضي: “stable”
  • stable_gamma (int) — معامل غاما لطريقة التوسيع المستقر. الافتراضي: 16

هذا هو فئة التهيئة الفرعية لتخزين إعدادات تهيئة LoRA-GA.

يستخدم LoRA-GA (التكيّف منخفض الرتبة مع تقريب التدرّج) معلومات التدرّج أثناء التهيئة لتحقيق تقارب أسرع (تسريع بمقدار 2-4 أضعاف) من خلال محاذاة أوزان المُكيِّف الأولي مع اتجاه تدرّجات الضبط الدقيق الكامل.

مرجع: https://arxiv.org/abs/2407.05000

أدوات

peft.tuners.lora.loraga.estimate_gradients

< >

( model: Modulelora_config: LoraConfigtrain_step: Callable )

تقدير التدرجات لتهيئة LoRA-GA.

تُمكّن هذه الدالة من حساب التدرّجات على أوزان الوحدة المستهدفة فقط، وتُشغّل مستدعي train_step. وهذا أكثر كفاءة في استخدام الذاكرة من تفعيل التدرّجات على مستوى النظام بالكامل.

peft.preprocess_loraga

< >

( model: Modulelora_config: LoraConfigtrain_step: Callablecache_file: str | None = None )

المعاملات

  • model (nn.Module) — النموذج الذي سيتم معالجته مسبقًا.
  • lora_config (LoraConfig) — إعدادات Lora للنموذج. يجب تعيين lora_config.lora_ga_config.
  • train_step (Callable[[], None]) — دالة استجابة (Callback) لتنفيذ تقدير التدرجات. عادةً ما ينبغي تنفيذ تمريرَي النموذج الأمامي والخلفي (forward and backward passes) داخل هذه الدالة. سيتم تجميع التدرجات عبر جميع الاستدعاءات داخل هذه الدالة.
  • cache_file (Optional[str]) — مسار اختياري لملف التخزين المؤقت لحفظ/تحميل التدرجات. إذا تم تقديمه وكان الملف موجودًا، سيتم تحميل التدرجات من التخزين المؤقت. وإلا، سيتم تقدير التدرجات وحفظها في هذا المسار.

إنشاء الحقول اللازمة لـ LoRA-GA لنموذج من خلال تقدير التدرجات.

بالنسبة لكل طبقة خطية، سيتم تقدير التدرجات من خلال تشغيل استدعاء train_step المُقدَّم. ثم تُربط هذه التدرجات بالوحدات وتُستخدم أثناء التهيئة.

عند الانتهاء، يتم تعيين الحقول التالية لكل وحدة هدف: _peft_loraga_grad (torch.Tensor): التدرج المتراكم لمصفوفة الأوزان.

تقليل الأبعاد للغريب

peft.tuners.lora.intruders.reduce_intruder_dimension

< >

( peft_modelold_adapter_name = 'default'new_adapter_name = 'intruder_reduced'top_k = 10threshold_epsilon = 0.5mitigation_lambda = 0.75logging_sink = <built-in function print> )

المعاملات

  • peft_model — نموذج PEFT مع محوّل LoRA محمّل باسمه المُقدَّم في old_adapter_name. حاليًا، لا يتم دعم النماذج المختلطة.
  • top_k (الافتراضي — 10) يُؤخذ بعين الاعتبار الأبعاد العشرة الأولى (top-k) لكشف المتسللين. كلما زادت القيمة، زاد عدد الأبعاد التي تُدرس في تحليل كشف المتسللين (وبالتالي تزداد احتمالية وجود إيجابيات خاطئة). يعمل هذا المعامل على التشابه الجيبوي (cosine similarity) بين الأوزان الأساسية وأوزان المُكيِّف (adapter)، مرتبةً تقريبًا حسب تأثير كل بُعد (المُحدَّد عبر التحليل بالقيم المفردة)، لذا فإن قيمة top-k تساوي 10 تعني فحص الأبعاد العشرة الأكثر «أهمية».
  • threshold_epsilon (الافتراضي — 0.5) القيمة العتبة التي يُعتبر بموجبها تشابه جيب التمام بين الوزن الأساسي ووزن المُكيّف كعنصر غريب. وفقًا للورقة البحثية، تُظهر الأبعاد الغريبة تشابهًا مطلقًا لجيب التمام قريبًا من الصفر مع المتجهات المفردة المُدرَّبة مسبقًا. كلما انخفضت هذه القيمة، قلّ عدد الأبعاد المحتملة التي تُعرَّف كأبعاد غريبة. وكلما ارتفعت القيمة، زاد عدد الإيجابيات الكاذبة المحتملة التي تُعتبر عناصر غريبة.
  • mitigation_lambda (الافتراضي — 0.75) النسبة النسبية من أبعاد المتسلّل التي تُطرح من وزن دلتا المُكيّف. كلما ارتفعت القيمة، زاد مقدار بُعد المتسلّل المطروح، لكن زاد أيضاً مقدار المعلومات المفقودة. راجع الشكل 8 في الورقة البحثية لتحليل التوازن بين الخيارات.
  • logging_sink (الافتراضي — print) دالة تطبع معلومات حول عملية التخفيف. اضبطها على None إذا لم ترغب في أي مخرجات.

التخفيف من بُعد المتسلل بناءً على https://huggingface.co/papers/2410.21228 (“LoRA vs Full Fine-tuning: An Illusion of Equivalence”).

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

بعد اكتمال التخفيف، سيظهر مُكيّف جديد يحمل الاسم المحدد في new_adapter_name، وسيُعدّ هذا المُكيّف هو المُكيّف النشط حاليًا. لذلك، سيعتمد الاستدلال على النموذج المُخفَّف على المُكيّف المُعدَّل. للعودة إلى المُكيّف الأصلي، يمكنك استخدام peft_model.set_adapter(<old_adapter_name>).

حاليًا، لا يُدعم سوى LoRA، إذ لم يتضح بعد ما إذا كان بإمكان هذه الطريقة التعميم على طرق أوزان الدلتا الأخرى.

Update on GitHub