Transformers documentation
واجهات الخلفية للانتباه
واجهات الخلفية للانتباه
تنفّذ جميع تطبيقات الانتباه (Attention) نفس العملية الحسابية. يُقارن كل رمز (Token) بكل رمز آخر. الفارق يكمن في كيف تُنفَّذ هذه العملية الحسابية. يعاني تطبيق الانتباه الأساسي من ضعف التوسع لأنه يُنشئ مصفوفة الانتباه الكاملة في الذاكرة، مما يُسبب اختناقات تُبطئ الاستدلال (Inference). تُعيد التطبيقات المُحسَّنة ترتيب العمليات الرياضية لتقليل حركة البيانات في الذاكرة، مما يؤدي إلى استدلال أسرع وأكثر ملاءمة من حيث التكلفة.
توفر AttentionInterface تطبيقات مُحسّنة للانتباه. إنها تفصل تطبيق الانتباه عن تطبيق النموذج لتبسيط التجارب مع دوال مختلفة. أضف واجهات خلفية جديدة بسهولة باستخدام هذه الواجهة المتسقة.
| واجهة الخلفية للانتباه | الوصف |
|---|---|
"flash_attention_3" | يحسّن FlashAttention-2 من خلال تداخل العمليات أيضاً ودمج مسارات الأمامي والخلفي بشكل أكثر إحكاماً |
"flash_attention_2" | يقسم عمليات الحساب إلى كتل أصغر ويستخدم ذاكرة سريعة على الشريحة |
"flex_attention" | إطار عمل لتحديد أنماط الانتباه المخصصة (المبعثرة، المحلية على مستوى الكتلة، النافذة المنزلقة) دون الحاجة إلى كتابة نواة منخفضة المستوى يدويًا |
"sdpa" | تنفيذ PyTorch المدمج لـ انتباه منتج النقطة المُقَيَّس |
"paged|flash_attention_3" | نسخة Paged من FlashAttention-3 |
"paged|flash_attention_2" | نسخة Paged من FlashAttention-2 |
"paged|sdpa" | نسخة SDPA المقسّمة إلى صفحات |
"paged|eager" | نسخة Paged من eager |
تعيين واجهة خلفية للانتباه
استخدم الحجة attn_implementation في from_pretrained() لإنشاء نموذج مع دالة انتباه محددة.
import torch
from transformers import AutoModelForCausalLM
model = AutoModelForCausalLM.from_pretrained(
"meta-llama/Llama-3.2-1B", attn_implementation="flash_attention_2"
)يمكنك التبديل بين محركات الانتباه في وقت التشغيل دون إعادة تحميل النموذج باستخدام set_attn_implementation().
model.set_attn_implementation("sdpa")النوى
قم بتنزيل نوى الحساب المُجمّعة وتحميلها مباشرةً من Hub وقت التشغيل باستخدام مكتبة Kernels. وهذا يتجنّب مشاكل التغليف الناتجة عن عدم تطابق إصدارات PyTorch أو CUDA.
تُسجَّل الأنوية تلقائيًا في AttentionInterface عند اكتشافها. لا حاجة إلى تثبيت حزمة FlashAttention صراحةً. كما أن طلب FlashAttention بالاسم يؤدي إلى الرجوع إلى نواة Hub، راجع الرجوع إلى FlashAttention.
import torch
from transformers import AutoModelForCausalLM
model = AutoModelForCausalLM.from_pretrained(
"meta-llama/Llama-3.2-1B", attn_implementation="kernels-community/flash-attn2"
)مدير سياق SDPA
يختار انتباه ضرب النقاط المُقيَّم (SDPA) في PyTorch تلقائيًا أسرع دالة انتباه لخوادم CUDA. وهو يعتمد افتراضيًا على التنفيذ بلغة C++ في PyTorch للخوادم الأخرى.
فرض استخدام SDPA لتنفيذ محدد من خلال مدير السياق torch.nn.attention.sdpa_kernel.
import torch
from torch.nn.attention import SDPBackend, sdpa_kernel
from transformers import AutoModelForCausalLM
model = AutoModelForCausalLM.from_pretrained(
"meta-llama/Llama-3.2-1B", attn_implementation="sdpa"
)
with sdpa_kernel(SDPBackend.FLASH_ATTENTION):
outputs = model.generate(**inputs)انتباه محدد لكل هيكل
تستخدم النماذج متعددة الوسائط هياكل أساسية مختلفة لكل نمط. لتحسين الأداء، قم بتخصيص دوال انتباه محددة لكل هيكل أساسي. فبعض الهياكل الأساسية للرؤية تعمل بشكل أفضل في fp32، على سبيل المثال، وهو ما لا تدعمه FlashAttention.
يمكنك تعيين هياكل الرؤية الأساسية إلى دوال انتباه مختلفة باستخدام قاموس، بينما يستمر هيكل النص الأساسي في استخدام FlashAttention. يجب أن تتطابق المفاتيح في تطبيق الانتباه مع أسماء التكوينات الفرعية.
from transformers import AutoModelForImageTextToText
attention_implementation_per_backbone = {"vision_config": "sdpa", "text_config": "flash_attention_2"}
for key in attention_implementation_per_backbone:
assert key in model.config.sub_configs, f"Invalid key in `attention_implementation`"
model = AutoModelForImageTextToText.from_pretrained(
"facebook/chameleon-7b", attn_implementation=attention_implementation_per_backbone
)احذف بعض الهياكل الأساسية من القاموس لاستخدام دالة الانتباه الافتراضية (SDPA).
model = AutoModelForImageTextToText.from_pretrained(
"facebook/chameleon-7b", attn_implementation={"text_config": "flash_attention_2"}
)اضبط دالة الانتباه نفسها لجميع الهياكل الأساسية باستخدام سلسلة واحدة.
model = AutoModelForImageTextToText.from_pretrained(
"facebook/chameleon-7b", attn_implementation="eager"
)اضبط دالة الانتباه على مستوى النظام باستخدام مفتاح فارغ.
model = AutoModelForImageTextToText.from_pretrained(
"facebook/chameleon-7b", attn_implementation={"": "eager"}
)إنشاء دالة انتباه جديدة
يمكنك تخصيص دوال الانتباه أو إنشاء دوال جديدة عن طريق إضافتها إلى سجل الانتباه باستخدام AttentionInterface.register(). تستخدم النماذج هذه الدوال عبر الحجة attn_implementation.
سجّل دالة قناع انتباه مطابقة عند تسجيل دالة انتباه مخصصة. إذا لم يكن اسم
attn_implementationالمخصص مسجلاً في AttentionMaskInterface، يتخطى Transformers إنشاء القناع ويمررattention_mask=Noneإلى طبقات الانتباه. يجب أن تتعامل دالة الانتباه الخاصة بك بنفسها مع قيود السببية، أو الحشو، أو التعبئة، أو النافذة المنزلقة، وإلا فقد تُهمل تلك القيود بصمت.
يخصص هذا المثال دالة الانتباه لطباعة عبارة لكل طبقة. كما يحافظ على القناع في التنفيذ الأصلي عن طريق تسجيل masking_utils.sdpa_mask كدالة قناع الانتباه.
import torch
from transformers import AutoModelForCausalLM, AttentionInterface, AttentionMaskInterface
from transformers.integrations.sdpa_attention import sdpa_attention_forward
from transformers.masking_utils import sdpa_mask
def my_new_sdpa(*args, **kwargs):
print("I just entered the attention computation")
return sdpa_attention_forward(*args, **kwargs)
AttentionInterface.register("my_new_sdpa", my_new_sdpa)
AttentionMaskInterface.register("my_new_sdpa", sdpa_mask) # must have the same name as the registered attention function
model = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-3.2-1B", attn_implementation="my_new_sdpa")
model(torch.ones(1, 5, dtype=int))يمكنك أيضًا إضافة حُجج جديدة إلى دالة الانتباه. النماذج التي تدعم AttentionInterface تنقل الحُجج الإضافية (kwargs) إلى طبقات الانتباه ودالة الانتباه. مرّر الحُجج كحُجج إضافية (kwargs) في دالة الأمامية (forward) للنموذج. يجب أن تتبع دوال الانتباه المخصصة هذا التوقيع (signature) وصيغة الإرجاع.
import torch
from transformers import AutoModelForCausalLM, AttentionInterface, AttentionMaskInterface
from transformers.integrations.sdpa_attention import sdpa_attention_forward
from transformers.masking_utils import sdpa_mask
def custom_attention(
module: torch.nn.Module, # required arg
query: torch.Tensor, # required arg
key: torch.Tensor, # required arg
value: torch.Tensor, # required arg
attention_mask: Optional[torch.Tensor], # required arg
a_new_kwargs = None, # You can now add as many kwargs as you need
another_new_kwargs = None, # You can now add as many kwargs as you need
**kwargs, # You need to accept **kwargs as models will pass other args
) -> tuple[torch.Tensor, Optional[torch.Tensor]]
... # do your magic!
return attn_output, attn_weights # attn_weights are optional here
AttentionInterface.register("custom", custom_attention)
AttentionMaskInterface.register("custom", sdpa_mask) # to leave the existing mask untouched
model = AutoModelForCausalLM.from_pretrained(model_id, attn_implementation="custom")
model(torch.ones(1, 5, dtype=int), a_new_kwargs=..., another_new_kwargs=...)تحقّق من كود النمذجة للنموذج للتأكد من الحجج وkwargs التي يرسلها إلى دالة الانتباه.
AttentionMaskInterface
AttentionMaskInterface هو السجل الذي تستشير منه دوال create_*_mask لتحويل القناع إلى الصيغة التي يتوقعها مُنفّذ الانتباه النشط. يحتاج FlexAttention إلى BlockMask، ويحتاج SDPA إلى متجه رباعي الأبعاد، ويحتاج FlashAttention إلى قناع الحشو الأساسي ثنائي الأبعاد. سجّل مُنفّذًا مخصصًا، أو تجاوز مُنسّق مُنفّذ قائم، باستخدام AttentionMaskInterface.register().
import torch
from transformers import AttentionMaskInterface
from transformers.masking_utils import sdpa_mask
def my_new_sdpa_mask(*args, **kwargs):
print("I just entered the attention mask computation")
return sdpa_mask(*args, **kwargs)
AttentionMaskInterface.register("my_new_sdpa_mask", my_new_sdpa_mask)في حال عدم وجود مُنسّق مسجّل لـattn_implementation النشط، يتم تجاوز إنشاء القناع، ويمرّ attention_mask=None إلى طبقات الانتباه.
يجب أن تتطابق الدوال المسجّلة مع هذا التوقيع.
def custom_attention_mask(
batch_size: int, # required arg
q_length: int, # required arg
kv_length: int, # required arg
q_offset: int = 0, # required arg
kv_offset: int = 0, # required arg
mask_function: Callable = causal_mask_function, # required arg
attention_mask: Optional[torch.Tensor] = None, # required arg
**kwargs, # a few additional args may be passed as kwargs, especially the model's config is always passed
) -> Optional[torch.Tensor]:الحجة mask_function هي Callable تحاكي دوال mask_mod في PyTorch. تستقبل 4 فهارس (batch_idx, head_idx, q_idx, kv_idx) وتعيد قيمة منطقية تشير إلى ما إذا كانت تلك الموضع تساهم في حساب الانتباه. هذا هو الشكل الأساسي نفسه المستخدم في or_mask_function وand_mask_function في بناء قناع الانتباه.
استخدم هذا الحل البديل لـ torch.export إذا فشل
mask_functionفي إنشاء قناع.
إنشاء قناع الانتباه
أنشئ أقنعة الانتباه باستخدام دوال create_*_mask في transformers.masking_utils. تقرأ كل دالة واجهة الانتباه النشطة من إعدادات النموذج، وتبحث عن مُنسّق القناع الخاص بالواجهة في AttentionMaskInterface، ثم تُرجع التنسيق الذي تتوقعه تلك الواجهة. لا تحتاج إلى عكس القناع أو توسيعه أو تحويل نوعه بنفسك.
اختر الدالة التي تتطابق مع نمط الانتباه.
| function | حالة الاستخدام |
|---|---|
create_causal_mask | نماذج فك الترميز فقط حيث يهتم كل رمز بنفسه وبالرموز السابقة |
create_bidirectional_mask | نماذج المُشفِّرات، أو الانتباه المتقاطع من المُفكِّك إلى حالات المُشفِّر |
create_sliding_window_causal_mask | نماذج فك الترميز التي تستخدم نمط انتباه بنافذة منزلقة |
create_chunked_causal_mask | نماذج فك الترميز التي تقسم التسلسل إلى كتل ذات حجم ثابت |
create_bidirectional_sliding_window_mask | نماذج المُشفِّر التي تستخدم نمط انتباه بنافذة منزلقة |
تُصدر دوال الأقنعة القابلة للاستدعاء القديمة -
get_extended_attention_mask،create_extended_attention_mask_for_decoder،invert_attention_mask- تحذيرًا بالإيقاف، وسيتم إزالتها في إصدار مستقبلي. استخدم دوالcreate_*_maskبدلاً من ذلك.
استدعِ create_causal_mask داخل مسار الترميز الأمامي (forward pass) في المُفكِّك (decoder). مرِّر الإعدادات (config)، وتضمينات الإدخال (input embeddings)، وقناع الانتباه ثنائي الأبعاد attention_mask الذي يوفّره المستخدم، والكاش (cache). تستخدم الدالة التضمينات لقراءة حجم الدفعة (batch size)، وطول الاستعلام (query length)، ونوع البيانات (dtype)، والجهاز (device)، وتستخدم الكاش لحساب طول المفتاح (key length).
from transformers.masking_utils import create_causal_mask
attention_mask = create_causal_mask(
config=self.config,
inputs_embeds=inputs_embeds,
attention_mask=attention_mask,
past_key_values=past_key_values,
)استدعِ create_bidirectional_mask للانتباه الذاتي في المُشفِّر. احذفي past_key_values لأن المُشفِّرات لا تُخزّن.
from transformers.masking_utils import create_bidirectional_mask
attention_mask = create_bidirectional_mask(
config=self.config,
inputs_embeds=embedding_output,
attention_mask=attention_mask,
)بالنسبة لانتباه التقاطع، مرّر حالات المُشفّر كـ encoder_hidden_states حتى يستخدم القناع طول المفتاح والقيمة الخاصين بالمُشفّر بدلاً من طول الاستعلام الخاص بالمُفكّك.
encoder_attention_mask = create_bidirectional_mask(
config=self.config,
inputs_embeds=embedding_output,
attention_mask=encoder_attention_mask,
encoder_hidden_states=encoder_hidden_states,
)أضِف قيودًا إضافية فوق القناع الأساسي باستخدام الحُجج or_mask_function وand_mask_function. استخدم or_mask_function للسماح لمواقع إضافية بالمشاركة، وand_mask_function لتقييد النمط الأساسي بشكل أكبر. يتبع كلاهما توقيع mask_function ذي الفهارس الأربعة الموصوف في AttentionMaskInterface. تستقبل (batch_idx, head_idx, q_idx, kv_idx) وتعيد قيمة منطقية.
يمكن للدالتين
or_mask_functionوand_mask_functionالتعبير عن أي نمط انتباه، لكنهما أبطأ من الأنماط المدمجة وغير متوافقتين مع ExecuTorch. يكون هذا العبء الإضافي أكثر وضوحًا في النماذج الأصغر حجمًا (حوالي 200 مليون معامل)، حيث يستهلك إنشاء القناع حصة أكبر من زمن المرور الأمامي. لا تلجأ إليهما إلا عندما تعجز دوالcreate_*_maskالقياسية عن التعبير عما تحتاجه.
على سبيل المثال، يمكن تراكب دالة تُرجع True في كل مكان على قناع سببي لتحويله إلى قناع ثنائي الاتجاه بالكامل. يسمح الاتحاد مع النمط السببي لكل رمز بالانتباه إلى كل رمز آخر.
mask_kwargs = {
"config": self.config,
"inputs_embeds": inputs_embeds,
"attention_mask": attention_mask,
"past_key_values": past_key_values,
"position_ids": position_ids,
"or_mask_function": lambda *args: torch.tensor(True, dtype=torch.bool),
}
attention_mask = create_causal_mask(**mask_kwargs)أثناء التوليد، يبني generate() الأقنعة عبر create_masks_for_generate، والذي يوجّه الطلب إلى create_*_mask المناسب بناءً على إعدادات النموذج. قم بتجاوز هذه الدالة في فئة النموذج لتضمين استراتيجية قناع مخصصة للتوليد.
مرر قناع انتباه مخصص بأربعة أبعاد
مرّر قناعًا رباعي الأبعاد خاصًا بك عندما تحتاج إلى نمط انتباه لا تستطيع دوال create_*_mask التعبير عنه. يكون شكل القناع الرباعي الأبعاد (batch_size, 1, query_length, kv_length)، حيث يقوم 1 ببثّ نفس القناع عبر جميع رؤوس الانتباه. يكتشف Transformers القناع ويستخدمه كما هو، متجاوزًا create_*_mask.
تستخدم قناع رباعي الأبعاد (4D) أحد نظامَي قيمتين.
| dtype | حضور | إخفاء |
|---|---|---|
| boolean | True | False |
| float | 0.0 | -inf |
تضيف اتفاقية float القناع إلى درجات الانتباه قبل softmax. تبقى الدرجة المضافة إليها 0.0 دون تغيير، وبالتالي يساهم الموقع. أما الدرجة المضافة إليها -inf فتصبح صفرًا بعد softmax، وبالتالي يُستبعد الموقع.
يعتمد الاتفاق المقبول على واجهة الانتباه الخلفية. يقبل
sdpaقناعًا منطقيًا أو قناعًا من نوع float. يضيفeagerالقناع إلى الدرجات، لذا يقبل قناعًا من نوع float فقط. تستهلكflash_attention_2وflex_attentionصيغها الخاصة (قناع حشو ثنائي الأبعاد وBlockMask) ولا تقبل قناعًا خامًا رباعي الأبعاد.
خطأ شائع هو إعادة استخدام اتفاقية 1/0 الخاصة بقناع الحشو ثنائي الأبعاد في قناع عائم رباعي الأبعاد. وبما أن القناع يُضاف إلى الدرجات، فإن 0.0 يحافظ على الموضع، بينما 1.0 يضيف انحيازًا صغيرًا فقط.
يُبيّن المثال أدناه تباينًا بين قناع خاطئ وقناع صحيح. كلاهما يبدأ من نفس النمط السببي 1/0.
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
model = AutoModelForCausalLM.from_pretrained("TinyLlama/TinyLlama-1.1B-Chat-v1.0", attn_implementation="sdpa")
tokenizer = AutoTokenizer.from_pretrained("TinyLlama/TinyLlama-1.1B-Chat-v1.0")
input_ids = tokenizer("my favorite condiment on a", return_tensors="pt").input_ids
seq_len = input_ids.shape[1]
# 1 attends, 0 masks
causal = torch.tril(torch.ones(seq_len, seq_len))
# wrong: 1.0/0.0 floats are added to the scores, so 0.0 keeps a token and 1.0 barely changes it
wrong_mask = causal[None, None]
# correct: 0.0 attends, -inf masks
correct_mask = torch.where(causal.bool(), 0.0, float("-inf"))[None, None]يُبقي القناع الخاطئ على كل المواضع لأن 0.0 هو القيمة التي تُستخدم للإخفاء، لذا لا يستثني شيئًا أبدًا.
wrong_mask correct_mask
(1 attends, 0 masks) (0 attends, -inf masks)
k0 k1 k2 k3 k4 k0 k1 k2 k3 k4
q0 1 0 0 0 0 q0 0 -inf -inf -inf -inf
q1 1 1 0 0 0 q1 0 0 -inf -inf -inf
q2 1 1 1 0 0 q2 0 0 0 -inf -inf
q3 1 1 1 1 0 q3 0 0 0 0 -inf
q4 1 1 1 1 1 q4 0 0 0 0 0انتباه ثنائي الاتجاه
تستخدم نماذج المُفكِّك فقط (Decoder-only) الانتباه السببي (أحادي الاتجاه) افتراضيًا، حيث ينتبه كل رمز إلى نفسه وإلى الرموز السابقة فقط. اضبط is_causal=False للتبديل إلى الانتباه ثنائي الاتجاه، حيث ينتبه كل رمز إلى كل رمز آخر. يتيح لك ذلك استخدام نماذج المُفكِّك فقط كمُشفِّرات للنص، على سبيل المثال، لتوليد التضمينات (embeddings).
يعمل هذا فقط مع النماذج السببية (فكّ الترميز). إنه لا يحوّل نماذج الترميز إلى نماذج فكّ ترميز.
اضبط is_causal=False في إعدادات النموذج لجعل الانتباه ثنائي الاتجاه هو الافتراضي لكل تمريرة أمامية.
from transformers import AutoModel, AutoConfig
config = AutoConfig.from_pretrained("meta-llama/Llama-3.2-1B")
config.is_causal = False
model = AutoModel.from_pretrained("meta-llama/Llama-3.2-1B", config=config)
# all forward passes now use bidirectional attention
outputs = model(**inputs)مرّر is_causal في استدعاء forward بدلاً من إعدادات النموذج للتبديل بين الانتباه السببي والانتباه ثنائي الاتجاه دون الحاجة إلى تحميل النموذج مرتين. يتجاوز هذا المعامل مؤقتًا الإعدادات ثم يُعاد ضبطها بعد انتهاء الاستدعاء.
from transformers import AutoModel
model = AutoModel.from_pretrained("meta-llama/Llama-3.2-1B")
# run with bidirectional attention
outputs = model(**inputs, is_causal=False)
# run with default causal attention
outputs = model(**inputs)