قراية
وضع الحكايات

architecture الـ transformer (المحوّل)

~26 دقيقة قراية الدرس 2 من 3 في الوحدة 9

الـ attention هو كل اللي محتاجه

سنة 2017، فاسواني وزمايله نشروا ورقة “Attention Is All You Need”، ورقة عنوانها كان استفزاز بقد ما كان وصف. المؤلفين جادلوا إن الـ recurrent connections اللي ميّزت الـ sequence modeling تلات عقود — الـ hidden states اللي بتنقل المعلومات خطوة بخطوة — مكانتش بس مش ضرورية، دي كانت بتضر فعلًا. وكل الشغل اللي بتعمله ممكن يتعمل أحسن وأسرع وبشكل بيكبر أكتر بالـ attention لوحده.

والنتيجة كانت الـ transformer (المحوّل): model مبني كله من attention layers وfeedforward networks، من غير أي recurrence خالص. وخلال سنة، عدّى أحدث models الـ RNNs والـ CNNs على كل معيار لغوي أساسي. وخلال سنتين، النسخ المكبّرة (BERT، GPT-2) أعادت تشكيل المجال كله. والـ transformer هو الـ architecture المسيطرة دلوقتي مش للغة بس، لكن للرؤية والصوت والتنبؤ ببنية البروتين وتقريبًا كل مجال فيه بيانات تسلسلية أو مكانية.

الدرس ده بيشرّح architecture الـ transformer من الأساس: بنية الـ encoder–decoder، والـ positional encoding، والـ layer normalization مع الـ residual connections، والـ feedforward layers، والسؤال المحوري ليه الـ transformers بتكبر أحسن من الـ RNNs. وفي آخره هتفهم مش بس الـ transformer بيشتغل إزاي، لكن ليه كل قرار تصميم فيه اتاخد.

بنية الـ encoder–decoder

الـ transformer الأصلي اتصمّم لمهام الـ sequence-to-sequence (بالتحديد الترجمة الآلية)، فبيستخدم بنية encoder–decoder. الـ encoder بيقرا الـ input sequence كلها ويطلّع سلسلة من التمثيلات المستمرة. والـ decoder بيولّد الـ output sequence token واحد كل مرة، وهو منتبه لتمثيلات الـ encoder وللـ output tokens اللي اتولّدت قبل كده.

كل encoder فيه stack من N layer متطابقة (N = 6 في الورقة الأصلية). وكل layer فيها sublayerين: multi-head self-attention layer وposition-wise feedforward layer. وكل sublayer متغلّفة في residual connection وبعدها layer normalization. والأهم إن كل layer في الـ encoder بتعالج الـ sequence كلها مرة واحدة — كل الأماكن بالتوازي من غير أي اعتماد تسلسلي.

والـ decoder متنظّم بنفس الشكل بـ N layer متطابقة، بس كل layer في الـ decoder فيها تلات sublayers: masked multi-head self-attention layer (عليها mask عشان تمنع الانتباه للأماكن الجاية)، وcross-attention layer (بتنتبه لـ output الـ encoder)، وposition-wise feedforward layer. والـ mask في أول sublayer في الـ decoder بيطبّق الخاصية الـ autoregressive: أثناء التدريب، كل مكان في الـ decoder يقدر ينتبه بس للأماكن اللي قبله في الـ output sequence، لأن الـ tokens الجاية لسه مش معروفة.

الأنواع اللي فيها encoder بس وdecoder بس

مع إن الـ transformer الأصلي بيستخدم بنية encoder–decoder، التطبيقات الحديثة غالبًا بتستخدم نص واحد بس. models الـ encoder بس (زي BERT) بتعالج الـ input كله في الاتجاهين وبتلمع في مهام الفهم: الـ classification، والـ named entity recognition، والإجابة على الأسئلة. وmodels الـ decoder بس (زي GPT) بتولّد النص بشكل autoregressive وبتلمع في مهام التوليد. وبنية الـ encoder–decoder لسه مسيطرة في الترجمة والتلخيص وغيرها من المهام اللي بتحوّل sequence لتانية.

الـ positional encoding

الـ self-attention مفيهوش مفهوم أصيل للترتيب: معادلة الـ attention بتعامل كل الأماكن زي بعض مهما كان مكان ظهورها في الـ sequence. وفي اللغة، المكان مهم جدًا — “الكلب عض الراجل” و“الراجل عض الكلب” معناهم عكس بعض مع إنهم بيستخدموا نفس الكلمات. والـ transformer بيحل ده بإنه يحقن معلومات المكان على طول في embeddings الـ input قبل أول attention layer.

الورقة الأصلية بتستخدم الـ sinusoidal positional encodings (الترميزات الموضعية الجيبية): لكل مكان pos وكل بُعد i في الـ model، الترميز هو sine أو cosine لتردد بيقل هندسيًا مع البُعد. والأبعاد الزوجية بتستخدم الـ sine؛ والفردية بتستخدم الـ cosine:

الـ sinusoidal positional encoding
\begin{aligned}PE_{(pos,2i)} &= \sin\!\left(\frac{pos}{10000^{2i/d_{\text{model}}}}\right)\\ PE_{(pos,2i+1)} &= \cos\!\left(\frac{pos}{10000^{2i/d_{\text{model}}}}\right)\end{aligned}
كل مكان pos بياخد vector مميّز من dmodel قيمة. والأبعاد المختلفة بتشفّر المكان بترددات مختلفة — الأبعاد الواطية بتمسك المكان المحلي الدقيق، والأبعاد العالية بتمسك المكان العام الواسع. والشكل الجيبي بيخلّي الـ model يعمّم على أطوال sequences مشافهاش في التدريب: المكان النسبي بين أي مكانين ينفع يتعبّر عنه كـ function خطية في ترميزاتهم الفردية.

والـ positional encoding بيتجمع على embedding الـ token (مش بيتوصّل جنبه). والناتج بيعدّي على أول layer في الـ encoder أو الـ decoder. ولأن الـ embedding والـ positional encoding ليهم نفس البُعد dmodel، الـ model يقدر يتعلّم يفصل هوية الـ token عن معلومات المكان عن طريق matrices الـ weights اللي بتتعلّم.

والـ models الحديثة غالبًا بتستخدم positional embeddings بتتعلّم بدل كده — جدول بحث كل مكان فيه ليه embedding vector بيتدرّب. والـ embeddings اللي بتتعلّم بتشتغل أحسن شوية عمليًا، بس تمن ده إنها مبتعمّمش على أطوال أكبر من أقصى طول sequence الـ model شافه في التدريب. والـ relative positional encodings (الترميزات الموضعية النسبية) (زي RoPE وALiBi) بتروح أبعد: بتعدّل درجات الـ attention على طول على حسب المسافة بين الأماكن بدل ما تزوّد إشارات مكان مطلقة على الـ embeddings. والطرق النسبية دي بقت المعيار في الـ large language models.

الـ residual connections والـ layer normalization

فيه مكوّنين بيظهروا باستمرار في الـ transformer وضروريين لتدريب الشبكات العميقة: الـ residual connections (الوصلات المتبقية) والـ layer normalization (تطبيع الطبقة). كل sublayer (الـ attention أو الـ feedforward) متغلّفة بالـ pattern ده:

غلاف الـ sublayer
\text{Output} = \text{LayerNorm}\bigl(x + \text{Sublayer}(x)\bigr)
x هو الـ input للـ sublayer وSublayer(x) هو output عملية الـ attention أو الـ feedforward. والـ residual connection بتزوّد الـ input الأصلي على طول على output الـ sublayer. والـ LayerNorm بيعمل normalization للمجموع بعدها. والترتيب ده (residual وبعدين normalization) هو اصطلاح “post-norm” في الورقة الأصلية؛ والـ models الحديثة غالبًا بتستخدم “pre-norm” (الـ LayerNorm بيتطبّق قبل الـ sublayer) اللي بيدّي تدريب أثبت.

الـ residual connections بتعالج مشكلة الـ vanishing gradient في الشبكات العميقة. من غير الوصلات دي، الـ gradients لازم تعدّي على كل layer أثناء الـ backpropagation — وكل عملية ضرب بتصغّر الـ gradient ناحية الصفر. والـ residual connection بتدّي مسار مباشر للـ gradients تعدّي من الـ output للـ input من غير ما تمر على حسابات الـ sublayer. وعشان كده شبكات عميقة جدًا (100 layer وأكتر) ينفع تتدرّب باستقرار مع الـ residual connections، ومن غيرها لأ.

والـ layer normalization بتعمل normalization للـ activations على بُعد الـ feature (بُعد dmodel) لكل مكان لوحده. وعلى عكس الـ batch normalization اللي بتعمل normalization على بُعد الـ batch، الـ layer normalization بتشتغل على مثال واحد كل مرة فمبتتأثّرش بحجم الـ batch. وده حاسم لـ models الـ sequences اللي أحجام الـ batches فيها صغيرة والـ sequences أطوالها متغيّرة. والـ layer normalization كمان بتثبّت التدريب بإنها تخلّي مقياس الـ activations ثابت على الـ layers.

الـ feedforward sublayer

كل layer في الـ transformer فيها كمان position-wise feedforward network: MLP من layerين بتتطبّق على كل مكان لوحده. الشبكة بتوسّع التمثيل لبُعد وسيط أكبر dff (عادةً 4×dmodel)، وتطبّق لاخطية، وبعدين ترجّعه لـ dmodel:

الـ position-wise feedforward network
\text{FFN}(x) = \max(0,\, xW_1 + b_1)\,W_2 + b_2
نفس W1 وW2 وb1 وb2 بتتطبّق على كل مكان لوحده، بس بتختلف من layer للتانية. والورقة الأصلية بتستخدم ReLU كـ activation function؛ والـ models الحديثة غالبًا بتستخدم GeLU أو SwiGLU. ومع dmodel=512 وdff=2048، الـ feedforward network فيها حوالي 4 أضعاف parameters الـ attention layer، فبتبقى أكبر كتلة parameters في كل layer.

والـ feedforward sublayer بتخدم وظيفة مختلفة عن الـ attention sublayer. الـ attention بيجمع المعلومات على الأماكن — يعني في الأساس عملية خلط. والـ feedforward بتعالج كل مكان لوحده — يعني تحويل غير خطي لكل مكان على حدة. ومع بعض بيعملوا جوز مكمّل لبعض: الـ attention للتواصل بين الأماكن، والـ feedforward للحساب لكل مكان.

وأبحاث الـ large language models لقت إن الـ feedforward layers بتخزّن المعرفة الواقعية وبترجّعها. وينفع تحدّد neurons فردية في الـ layers دي بتشتغل لحقائق معيّنة (زي “باريس عاصمة فرنسا”)، وتعديل الـ neurons دي بيغيّر الـ model بيقول إيه عن الواقع. والنظرة دي — نظرة “الـ knowledge neurons” — بتشاور إن الـ feedforward بتشتغل كـ associative memory مبنية فوق الاستدلال البنيوي اللي آلية الـ attention بتقدّمه.

ليه الـ transformers بتكبر أحسن من الـ RNNs

سيطرة الـ transformer على الـ RNNs مش بس عن الأداء على dataset ثابتة — دي عن تصرّفه وهو بيكبر. كل ما كمية البيانات والحساب والـ parameters تزيد، الـ transformers بتكمّل تتحسّن بطرق الـ RNNs مبتقدرش عليها. وتلات خصائص في البنية بتفسّر ده:

1. التوازي أثناء التدريب. الـ RNNs بتعالج الـ sequences خطوة بخطوة: حساب ht محتاج ht−1، اللي محتاج ht−2، وهكذا. والاعتماد التسلسلي معناه إنك متقدرش تعمل توازي على بُعد الزمن — لازم تستنى كل خطوة تخلص قبل ما تبدأ اللي بعدها. ومع sequence طولها 1000، دي 1000 عملية ورا بعض مهما كان عدد أنوية الـ GPU اللي معاك. والـ transformers بتحسب كل الأماكن مرة واحدة كضرب matrices. وقدرة التدريب بتكبر مع توازي الـ hardware مش متخنوقة بطول الـ sequence.

2. طول مسار ثابت بين أي مكانين. في الـ RNN، الـ gradient لازم يعدّي على كل hidden state في النص عشان يربط المكان t بالمكان t−k — طول مسار k. ومع الـ sequences الطويلة، المسار ده بيبقى طويل جدًا لدرجة إن الـ gradients بتختفي والـ model بيفشل يتعلّم العلاقات البعيدة (والـ LSTM بتخفّف ده بس مبتلغيهوش). وفي الـ transformer، كل مكان بينتبه على طول لكل مكان تاني في layer واحدة — طول مسار 1. والعلاقات البعيدة مش أصعب في التعلّم من القريبة.

3. scaling laws ينفع تتوقّعها. كابلان وزمايله (2020) لقوا إن أداء الـ language models المبنية على الـ transformer ماشي على power law (قانون قوة) في الحساب وحجم الـ dataset وعدد الـ parameters: مضاعفة أي مورد بتدّي تحسين ثابت ومتوقّع. والانتظام ده معناه إنك تقدر تقدّر من الأول هتكسب أداء قد إيه من التكبير. والـ RNNs مبتورّيش تصرّف scaling بالوضوح ده، جزئيًا لأن طبيعتها التسلسلية بتحط سقف لفايدة الحساب الزيادة عند طول sequence معيّن. وarchitecture الـ transformer مناسبة بشكل فريد لاستراتيجية “كبّر كل حاجة” اللي طلّعت GPT-3 وGPT-4 والـ models الشبهها.

عنق زجاجة الـ O(n²)

القيد الأساسي في الـ transformer هو التكلفة التربيعية للـ attention الكامل — ودي نفس تكلفة الـ O(n²) اللي اتعرّفت لما قدّمنا الـ self-attention في الدرس اللي فات: حساب matrix الـ attention اللي مقاسها n×n محتاج وقت O(n²d) وmemory O(n²). ولأطوال sequences متوسطة (512–2048)، ده ينفع يتدار. بس للمستندات الطويلة أو الصور اللي دقتها عالية أو الـ sequences الجينومية (عشرات الآلاف من الـ tokens)، التكلفة بتبقى غالية جدًا. وأبحاث الـ sparse attention (BigBird وLongformer) والـ linear attention (Performer وRWKV) وalgorithms الكفاءة على الـ hardware (FlashAttention) بتتعامل مع القيد ده وهي محافظة على أغلب تعبيرية الـ transformer. والـ FlashAttention بالذات بيطلّع نفس outputs الـ attention الكامل بـ memory O(n) بإنه يدمج حساب الـ attention في kernel واحد، وبقى معيار في تدريب الـ large language models الحديثة.

الـ forward pass الكامل

يلا نتابع إزاي sequence بتعدّي على encoder الـ transformer كله. الـ tokens الداخلة بتتحوّل لـ embeddings بُعدها dmodel. والـ positional encodings بتتجمع عليها عنصر بعنصر. والـ matrix اللي بتطلع (شكلها: طول_الـ sequence × dmodel) بتعدّي على N encoder layers. وكل layer بتطبّق: (1) multi-head self-attention مع residual وlayer normalization، وبعدين (2) feedforward network مع residual وlayer normalization. وoutput آخر encoder layer هو تمثيل غني بالسياق لكل token داخل، لأن embedding كل token بقى شايل معلومات اتجمعت من كل الـ tokens التانية على كل الـ attention heads وكل الـ layers.

والـ decoder بيمشي في مسار شبهه مع الـ cross-attention sublayer الزيادة في كل layer، وهي اللي بتستهلك output الـ encoder. وفي كل خطوة decoding، الـ decoder بيطلّع توزيع احتمالي على الـ vocabulary، والـ token الجاي بيتختار بالسحب من التوزيع ده أو بالاختيار الـ greedy لأعلى احتمال. والـ token ده بيتزوّد على الـ output sequence والـ decoder بيشتغل تاني للخطوة اللي بعدها، ويكمّل لحد ما يتولّد token نهاية الـ sequence أو نوصل لأقصى طول.

وأثناء التدريب بنستخدم الـ teacher forcing (إجبار المعلّم): بندخّل للـ decoder في كل خطوة الـ output tokens الصح من الـ target sequence المرجعية، مش الـ predictions بتاعة الـ model نفسه. والـ causal mask بيضمن إن الـ decoder مبيشوفش الـ tokens الجاية، وبكده التدريب بيفضل صح: كل مكان بيشترط على tokens هتبقى موجودة فعلًا وقت الـ inference. والـ forward pass كله — الـ encoder والـ decoder — بيتنفّذ بالتوازي لكل الأماكن، وده اللي بيخلّي التدريب كفء جدًا.

أهم النقط
  • الـ transformer بيبدّل الـ recurrence خالص بـ layers متراصّة من الـ multi-head self-attention والـ feedforward. الـ encoder بيعالج الـ input كله بالتوازي؛ والـ decoder بيولّد الـ outputs بشكل autoregressive باستخدام الـ masked self-attention والـ cross-attention للـ encoder.
  • الـ positional encoding بيحقن معلومات الترتيب في embeddings الـ tokens قبل أول layer. والترميزات الجيبية بتسمح بالتعميم على أطوال مشافهاش؛ والـ embeddings اللي بتتعلّم غالبًا بتشتغل أحسن عمليًا؛ وترميزات المكان النسبية (RoPE وALiBi) بقت المعيار في الـ models الكبيرة.
  • كل sublayer متغلّفة في residual connection وlayer normalization. والـ residual connections بتدّي ممرات للـ gradients على الـ stacks العميقة؛ والـ layer normalization بتثبّت مقاييس الـ activations بشكل مستقل عن حجم الـ batch.
  • الـ feedforward sublayer هي MLP من layerين بتتطبّق على كل مكان لوحده، بتوسع لـ 4×dmodel وبعدين بتنكمش. بتدّي حساب غير خطي لكل مكان بيكمّل خلط الأماكن في الـ attention. وباين إن الـ feedforward layers بتخزّن المعرفة الواقعية في شكل associative memory.
  • الـ transformers بتغلب الـ RNNs لأن (1) كل الأماكن بتتدرّب بالتوازي، (2) طول المسار بين أي مكانين ثابت عند 1، (3) الأداء ماشي على power laws ينفع تتوقّعها في الحساب والبيانات. والخصائص دي بتخلّي الـ transformer فريد لنظام التدريب على نطاق واسع بتاع الـ foundation models الحديثة.
  • القيد الأساسي هو تعقيد الـ attention اللي O(n²). والـ FlashAttention والـ sparse attention والـ linear attention بيعالجوا ده وهما محافظين على أغلب التعبيرية، فبيخلّوا الـ architectures اللي شبه الـ transformer تتعامل مع sequences أطول بكتير.
اللي فات آلية الـ attention (الانتباه) نظرة عامة اللي بعده models الـ transformer (المحوّل) الحديثة