<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Machine Learning on kenji.blog</title><link>http://kenji.blog/ar/categories/machine-learning/</link><description>Recent content in Machine Learning on kenji.blog</description><generator>Hugo -- gohugo.io</generator><language>ar</language><copyright>kenjinote</copyright><lastBuildDate>Fri, 11 Sep 2026 22:00:00 +0900</lastBuildDate><atom:link href="http://kenji.blog/ar/categories/machine-learning/index.xml" rel="self" type="application/rss+xml"/><item><title>【للمبتدئين】فك تشفير البنية الرياضية لنموذج Transformer</title><link>http://kenji.blog/ar/p/transformer-mathematical-structure/</link><pubDate>Fri, 11 Sep 2026 22:00:00 +0900</pubDate><guid>http://kenji.blog/ar/p/transformer-mathematical-structure/</guid><description>&lt;img src="http://kenji.blog/p/transformer-mathematical-structure/img/eyecatch.jpg" alt="Featured image of post 【للمبتدئين】فك تشفير البنية الرياضية لنموذج Transformer" />&lt;h1 id="مقدمة-لماذا-نتعلم-رياضيات-الـ-transformer">مقدمة: لماذا نتعلم رياضيات الـ Transformer؟
&lt;/h1>&lt;p>يمكن القول دون مبالغة أن &amp;ldquo;Transformer&amp;rdquo; هي البنية التي أعادت كتابة تاريخ معالجة اللغات الطبيعية (NLP) والذكاء الاصطناعي بشكل عام في العصر الحديث. تم اقتراح هذا النموذج لأول مرة في ورقة بحثية بعنوان &amp;ldquo;Attention Is All You Need&amp;rdquo; نُشرت من قبل باحثين في Google عام 2017، ويعمل كقلب نابض للنماذج اللغوية الكبيرة (LLMs) التي تجتاح العالم اليوم، مثل سلسلة GPT من OpenAI (التقنية الأساسية لـ ChatGPT)، و BERT من Google، و Claude من Anthropic.&lt;/p>
&lt;p>ومع ذلك، في حين نرى غالباً تفسيرات نوعية لآلية عمل Transformer مثل &amp;ldquo;فهم السياق باستخدام Attention (آلية الانتباه)&amp;quot;، إلا أن التفسيرات التي تتعمق في &lt;strong>البنية الرياضية&lt;/strong> الكامنة وراءها للمبتدئين قليلة بشكل مفاجئ. لفهم كيف يقوم الذكاء الاصطناعي بمعالجة &amp;ldquo;الكلمات&amp;rdquo; كـ &amp;ldquo;معادلات رياضية&amp;rdquo; وتوليد نصوص طبيعية بشكل مذهل حقاً، من الضروري فك تشفير آليته الرياضية.&lt;/p>
&lt;p>في هذا المقال، سنقوم بشرح البنية الرياضية لقلب الـ Transformer بشكل شامل ومبسط، مثل &amp;ldquo;آلية الاهتمام الذاتي (Self-Attention)&amp;quot;، ونموذج &amp;ldquo;الاستعلام والمفتاح والقيمة (Q/K/V)&amp;quot;، و&amp;quot;التسوية باستخدام دالة Softmax&amp;rdquo;، و&amp;quot;الترميز الموضعي (Positional Encoding)&amp;quot;، وذلك للأشخاص الذين لديهم معرفة أساسية بالرياضيات والبرمجة (أولئك الذين يفهمون مفاهيم المصفوفات والتفاضل على مستوى المرحلة الثانوية).&lt;/p>
&lt;p>قد تشعر بالإرهاق من سرد المعادلات الرياضية، ولكن لكل عملية حسابية &amp;ldquo;معنى&amp;rdquo; واضح. بحلول الوقت الذي تنتهي فيه من قراءة هذا المقال، يجب أن تكون قادراً على فهم أن الـ Transformer ليس مجرد صندوق أسود سحري، بل هو تبلور لرياضيات وإحصاءات مصممة بدقة.&lt;/p>
&lt;hr>
&lt;h1 id="1-حدود-الطرق-التقليدية-وابتكار-الـ-transformer">1. حدود الطرق التقليدية وابتكار الـ Transformer
&lt;/h1>&lt;p>قبل ظهور Transformer، كان الاتجاه السائد في معالجة اللغات الطبيعية هو الشبكات العصبية المتكررة (RNN) ومشتقاتها مثل LSTM (الذاكرة الطويلة قصيرة المدى). تم تصميم RNN لمعالجة بيانات السلاسل الزمنية، وتقوم بقراءة الجمل كلمة بكلمة بالترتيب من البداية.&lt;/p>
&lt;p>ومع ذلك، كان لدى RNN نقطتي ضعف قاتلتين:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>صعوبة تعلم التبعيات طويلة المدى&lt;/strong>: عندما تصبح الجملة طويلة، تتلاشى معلومات الكلمات المدخلة في البداية بحلول الوقت الذي تصل فيه إلى النهاية (مشكلة تلاشي التدرج).&lt;/li>
&lt;li>&lt;strong>استحالة الحوسبة المتوازية&lt;/strong>: نظراً لأنه يجب معالجة الكلمات بالترتيب، فإن الحوسبة المتوازية واسعة النطاق باستخدام وحدات معالجة الرسومات (GPU) تكون صعبة، ويستغرق التدريب وقتاً هائلاً.&lt;/li>
&lt;/ol>
&lt;p>تخلى الـ Transformer تماماً عن بنية الـ RNN وأحدث نقلة نوعية من خلال التقاط السياق باستخدام &amp;ldquo;الاهتمام (Attention)&amp;rdquo; فقط. بفضل هذا، لم يعد هناك فقدان للمعلومات بغض النظر عن طول السلسلة، وأصبح من الممكن موازنة العمليات الحسابية لتحقيق أقصى استفادة من أداء وحدات معالجة الرسومات.&lt;/p>
&lt;hr>
&lt;h1 id="2-البنية-العامة-لـ-transformer">2. البنية العامة لـ Transformer
&lt;/h1>&lt;p>أولاً، دعونا نلقي نظرة عامة على البنية الكلية لـ Transformer. يتكون Transformer بشكل أساسي من كتلتين: &amp;ldquo;المشفر (Encoder)&amp;rdquo; و&amp;quot;فك التشفير (Decoder)&amp;rdquo;. بأخذ مهمة الترجمة كمثال، يقوم المشفر بتحويل لغة الإدخال (مثال: الإنجليزية) إلى تمثيلات متجهة رياضية، ويقوم فك التشفير بتوليد لغة الإخراج (مثال: اليابانية) بناءً على تلك التمثيلات المتجهة.&lt;/p>
&lt;p>يوضح الشكل أدناه بنية مبسطة لكتلة المشفر من الداخل.&lt;/p>
&lt;div class="mermaid">graph TD
A["رموز الإدخال (Input Tokens)"] --> B["تضمين الإدخال (Input Embedding)"]
B --> C["الترميز الموضعي (Positional Encoding)"]
C --> D["الاهتمام الذاتي متعدد الرؤوس (Multi-Head Self-Attention)"]
D --> E["إضافة وتسوية الطبقة (Add &amp; Layer Normalization)"]
E --> F["شبكة التغذية الأمامية (Feed Forward Network)"]
F --> G["إضافة وتسوية الطبقة (Add &amp; Layer Normalization)"]
G --> H["المخرجات للطبقة التالية (Output to Next Layer)"]
C -.->|"اتصال متبقي (Residual Connection)"| E
E -.->|"اتصال متبقي (Residual Connection)"| G&lt;/div>
&lt;p>من هنا، دعونا نتبع العمليات الرياضية التي تتم في كل مكون خطوة بخطوة.&lt;/p>
&lt;hr>
&lt;h1 id="3-توجيه-الكلمات-والترميز-الموضعي-positional-encoding">3. توجيه الكلمات والترميز الموضعي (Positional Encoding)
&lt;/h1>&lt;p>لا تستطيع أجهزة الكمبيوتر فهم النصوص كما هي. يتم أولاً تقسيم النص المدخل إلى وحدات تسمى &amp;ldquo;الرموز (Tokens)&amp;quot;، ويتم تحويل كل منها إلى متجه ذي طول ثابت. هذا هو &lt;strong>تضمين الإدخال (Input Embedding)&lt;/strong>.&lt;/p>
&lt;h2 id="31-رياضيات-تضمين-الإدخال">3.1 رياضيات تضمين الإدخال
&lt;/h2>&lt;p>بفرض أن حجم المفردات هو $V$، وعدد أبعاد متجه التضمين هو $d_{model}$ (في الورقة البحثية الأصلية $d_{model} = 512$). يتم تحويل كل كلمة $w_i$ إلى متجه $x_i \in \mathbb{R}^{d_{model}}$ باستخدام مصفوفة التضمين $W_E \in \mathbb{R}^{V \times d_{model}}$.&lt;/p>
$$ x_i = W_E \cdot \text{one\_hot}(w_i) $$
&lt;p>بهذا، يتم التعبير عن الجملة بأكملها كمصفوفة $X \in \mathbb{R}^{N \times d_{model}}$ (حيث $N$ هو طول الجملة).&lt;/p>
&lt;h2 id="32-الحاجة-للترميز-الموضعي-positional-encoding-ومعادلاته">3.2 الحاجة للترميز الموضعي (Positional Encoding) ومعادلاته
&lt;/h2>&lt;p>لا يقوم Transformer بمعالجة الكلمات بشكل متسلسل مثل RNN، بل يقوم بمعالجة جميع الكلمات في وقت واحد بشكل متوازٍ. يُعد هذا ميزة كبيرة من حيث سرعة الحساب، ولكنه في الوقت نفسه يتسبب في مشكلة &lt;strong>فقدان المعلومات الهامة المتعلقة بـ &amp;ldquo;ترتيب الكلمات (سياق الكلام)&amp;rdquo;&lt;/strong>. على سبيل المثال، &amp;ldquo;الكلب يعض الرجل&amp;rdquo; و&amp;quot;الرجل يعض الكلب&amp;rdquo; لهما نفس مجموعة الكلمات المدخلة ولكن معانيهما مختلفة تماماً.&lt;/p>
&lt;p>لإعطاء النموذج معلومات ترتيب الكلمات، تم ابتكار &lt;strong>الترميز الموضعي (Positional Encoding)&lt;/strong>.
يتم حساب الترميز الموضعي $PE$ للبعد $i$ للكلمة الموجودة في الموضع $pos$ باستخدام الدوال المثلثية التالية.&lt;/p>
$$ PE_{(pos, 2i)} = \sin\left(\frac{pos}{10000^{2i/d_{model}}}\right) $$
$$ PE_{(pos, 2i+1)} = \cos\left(\frac{pos}{10000^{2i/d_{model}}}\right) $$
&lt;p>هنا، $pos$ هو موضع الكلمة ($0, 1, 2, \dots, N-1$)، و $i$ هو مؤشر أبعاد المتجه ($0, 1, \dots, d_{model}/2 - 1$).&lt;/p>
&lt;h3 id="لماذا-نستخدم-الجيب-sine-وجيب-التمام-cosine">لماذا نستخدم الجيب (Sine) وجيب التمام (Cosine)؟
&lt;/h3>&lt;p>للوهلة الأولى، تبدو معادلة معقدة وغريبة جداً، ولكن هناك أسباب رياضية عميقة لذلك. باستخدام الدوال المثلثية، يصبح من السهل على النموذج تعلم الفروق في &lt;strong>&amp;ldquo;المواضع النسبية&amp;rdquo; وليس فقط &amp;ldquo;المواضع المطلقة&amp;rdquo;&lt;/strong>.&lt;/p>
&lt;p>تذكر نظرية الجمع للدوال المثلثية التي تُدرّس في رياضيات المرحلة الثانوية.
&lt;/p>
$$ \sin(\alpha + \beta) = \sin\alpha \cos\beta + \cos\alpha \sin\beta $$
$$ \cos(\alpha + \beta) = \cos\alpha \cos\beta - \sin\alpha \sin\beta $$
&lt;p>يمكن التعبير عن الترميز الموضعي للموضع $pos + k$ الذي يبعد عن موضع معين $pos$ بمقدار $k$ كتركيبة خطية للترميز الموضعي للموضع $pos$. أي باستخدام المصفوفة $M_k$، يمكن كتابته على النحو التالي.&lt;/p>
$$ PE_{pos+k} = M_k \cdot PE_{pos} $$
&lt;p>بفضل هذا، يمكن لآلية الانتباه التعرف بسهولة على المسافة النسبية أو &amp;ldquo;مدى تباعد الكلمات عن بعضها&amp;rdquo; من خلال حساب الضرب النقطي. بالإضافة إلى ذلك، من خلال الجمع بين موجات جيب وجيب تمام متعددة ذات أطوال موجية مختلفة، هناك ميزة تتمثل في القدرة على توليد متجه موضع فريد بغض النظر عن طول الجملة.&lt;/p>
&lt;p>مصفوفة الإدخال النهائية $X_{input}$ هي مجموع متجهات تضمين الكلمات مع الترميز الموضعي.&lt;/p>
$$ X_{input} = X + PE $$
&lt;hr>
&lt;h1 id="4-الرياضيات-العميقة-لآلية-الاهتمام-الذاتي-self-attention">4. الرياضيات العميقة لآلية الاهتمام الذاتي (Self-Attention)
&lt;/h1>&lt;p>أخيراً، ندخل في أهم مكون لـ Transformer وهو &lt;strong>الاهتمام الذاتي (Self-Attention)&lt;/strong>. الهدف من الاهتمام الذاتي هو &amp;ldquo;حساب درجة الارتباط بين جميع الكلمات في الجملة، وتحديث متجه كل كلمة إلى تمثيل أكثر ثراءً يأخذ السياق في الاعتبار&amp;rdquo;.&lt;/p>
&lt;p>هنا يتم استخدام تشبيه &amp;ldquo;نظام البحث&amp;rdquo;.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>الاستعلام (Query - Q)&lt;/strong>: كلمة البحث. &amp;ldquo;ما هي المعلومات التي أبحث عنها الآن؟&amp;rdquo;&lt;/li>
&lt;li>&lt;strong>المفتاح (Key - K)&lt;/strong>: العنوان. &amp;ldquo;ما هي المعلومات التي أمتلكها؟&amp;rdquo;&lt;/li>
&lt;li>&lt;strong>القيمة (Value - V)&lt;/strong>: الكيان الفعلي. &amp;ldquo;ما هي المعلومات التي أقدمها بالفعل؟&amp;rdquo;&lt;/li>
&lt;/ul>
&lt;h2 id="41-توليد-المصفوفات-q-k-v">4.1 توليد المصفوفات $Q, K, V$
&lt;/h2>&lt;p>لمصفوفة الإدخال $X \in \mathbb{R}^{N \times d_{model}}$ (نتجاهل هنا حجم الدفعة لتبسيط الأمر)، نقوم بحساب الاستعلام $Q$ والمفتاح $K$ والقيمة $V$ عن طريق ضربها في مصفوفات الأوزان القابلة للتعلم $W^Q, W^K, W^V \in \mathbb{R}^{d_{model} \times d_k}$. (عادةً $d_k = d_v = d_{model} / h$)&lt;/p>
$$ Q = X W^Q $$
$$ K = X W^K $$
$$ V = X W^V $$
&lt;p>هنا، تكون المصفوفات $Q, K, V$ جميعها مصفوفات بأبعاد $\mathbb{R}^{N \times d_k}$.&lt;/p>
&lt;h2 id="42-حساب-درجة-الانتباه-الضرب-النقطي">4.2 حساب درجة الانتباه (الضرب النقطي)
&lt;/h2>&lt;p>لقياس مدى ارتباط الاستعلام لكل كلمة بمفاتيح جميع الكلمات الأخرى، نحسب &lt;strong>الضرب النقطي&lt;/strong> للمتجهات. يمكن كتابتها كعملية مصفوفة على النحو التالي.&lt;/p>
$$ \text{Scores} = Q K^T $$
&lt;p>كل عنصر $s_{ij}$ في المصفوفة $\text{Scores} \in \mathbb{R}^{N \times N}$ الناتجة عن هذا الحساب يمثل الضرب النقطي لاستعلام الكلمة $i$ ومفتاح الكلمة $j$، أي أنه يعبر عن &amp;ldquo;قوة الارتباط&amp;rdquo;.&lt;/p>
&lt;h2 id="43-القياس-scaling">4.3 القياس (Scaling)
&lt;/h2>&lt;p>هناك مشكلة واحدة في حساب الدرجة باستخدام الضرب النقطي. عندما يصبح بُعد المتجه $d_k$ كبيراً، تصبح قيمة الضرب النقطي كبيرة جداً أو صغيرة جداً.&lt;/p>
&lt;p>دعونا نثبت ذلك رياضياً.
لنفترض أن كل عنصر من عناصر الاستعلام $q \sim \mathcal{N}(0, 1)$، وكل عنصر من عناصر المفتاح $k \sim \mathcal{N}(0, 1)$ تتبع توزيعاً طبيعياً معيارياً مستقلاً.
نوجد المتوسط والتباين للضرب النقطي $q \cdot k = \sum_{i=1}^{d_k} q_i k_i$.
المتوسط: بما أن $\mathbb{E}[q_i k_i] = \mathbb{E}[q_i] \mathbb{E}[k_i] = 0 \times 0 = 0$، فإن متوسط المجموع هو أيضاً $0$.
التباين: تباين $q_i k_i$ يعطى من خلال الاستقلالية على أنه $\text{Var}(q_i k_i) = \mathbb{E}[(q_i k_i)^2] - (\mathbb{E}[q_i k_i])^2 = 1 \times 1 - 0 = 1$.
لذلك، فإن التباين الكلي للضرب النقطي يساوي عدد الأبعاد $d_k$.&lt;/p>
$$ \text{Var}(q \cdot k) = d_k $$
&lt;p>عندما يصبح التباين كبيراً، يحدث &amp;ldquo;تلاشي التدرج&amp;rdquo; في دالة Softmax التي سيتم تطبيقها لاحقاً، حيث تصبح التدرجات باستثناء القيمة القصوى صغيرة جداً، مما يؤدي إلى توقف التعلم.
لمنع حدوث ذلك، نقوم بقسمة (أو قياس) الدرجة على $\sqrt{d_k}$ للحفاظ على التباين دائماً عند $1$.&lt;/p>
$$ \text{Scaled Scores} = \frac{Q K^T}{\sqrt{d_k}} $$
&lt;h2 id="44-التحويل-إلى-احتمالات-باستخدام-دالة-softmax">4.4 التحويل إلى احتمالات باستخدام دالة Softmax
&lt;/h2>&lt;p>نطبق &lt;strong>دالة Softmax&lt;/strong> صفا بصف لتحويل الدرجات التي حصلنا عليها إلى توزيع احتمالي (أوزان) بحيث يكون مجموعها $1$.&lt;/p>
$$ a_{ij} = \text{softmax}(s_i)_j = \frac{\exp(s_{ij} / \sqrt{d_k})}{\sum_{m=1}^N \exp(s_{im} / \sqrt{d_k})} $$
&lt;p>تُسمى المصفوفة $A \in \mathbb{R}^{N \times N}$ مصفوفة أوزان الانتباه (Attention Weight). إذا نظرنا إلى كل صف $i$ من هذه المصفوفة، فهو يعبر بقيمة من 0 إلى 1 عن &amp;ldquo;مدى الانتباه الذي يجب إعطاؤه لأي كلمة أخرى $j$ من أجل فهم الكلمة $i$&amp;rdquo;.&lt;/p>
&lt;h2 id="45-المجموع-الموزون-للقيم-value">4.5 المجموع الموزون للقيم (Value)
&lt;/h2>&lt;p>أخيراً، باستخدام مصفوفة أوزان الانتباه $A$ التي تم الحصول عليها، نحسب المجموع الموزون لمصفوفة القيم $V$.&lt;/p>
$$ \text{Output} = A V = \text{softmax}\left(\frac{Q K^T}{\sqrt{d_k}}\right) V $$
&lt;p>المصفوفة $Z \in \mathbb{R}^{N \times d_v}$ الناتجة عن هذه العملية هي مجموعة من &amp;ldquo;التمثيلات المتجهة للكلمات المحدثة التي تأخذ السياق في الاعتبار&amp;rdquo;.
هذه هي الصورة الكاملة لـ &lt;strong>الاهتمام بالضرب النقطي المقاس (Scaled Dot-Product Attention)&lt;/strong> المعرف في الورقة البحثية.&lt;/p>
&lt;hr>
&lt;h1 id="5-الانتباه-متعدد-الرؤوس-multi-head-attention">5. الانتباه متعدد الرؤوس (Multi-Head Attention)
&lt;/h1>&lt;p>من خلال عملية حساب انتباه واحدة فقط (رأس واحد)، قد لا نتمكن من التقاط السياق إلا من وجهة نظر واحدة (على سبيل المثال &amp;ldquo;العلاقة النحوية&amp;rdquo;). لذلك، تم تقديم &lt;strong>الانتباه متعدد الرؤوس (Multi-Head Attention)&lt;/strong> من أجل التقاط العلاقات الدلالية والنحوية المتنوعة التي تمتلكها اللغة (&amp;ldquo;الفاعل والمفعول&amp;rdquo;، &amp;ldquo;الضمير ومُشار إليه&amp;rdquo;، وما إلى ذلك) في وقت واحد.&lt;/p>
&lt;p>نقوم بتوليد $Q, K, V$ وحساب الانتباه كما ذكرنا سابقاً، وذلك بشكل متوازٍ لـ $h$ من المرات (عدد الرؤوس. في الورقة الأصلية $h=8$).&lt;/p>
$$ \text{head}_i = \text{Attention}(X W_i^Q, X W_i^K, X W_i^V) $$
&lt;p>هنا، $W_i^Q, W_i^K, W_i^V \in \mathbb{R}^{d_{model} \times d_k}$ هي مصفوفات أوزان قابلة للتعلم مخصصة للرأس رقم $i$.&lt;/p>
&lt;p>يتم دمج (Concatenate) النتائج الناتجة $\text{head}_i \in \mathbb{R}^{N \times d_v}$ من كل رأس جنباً إلى جنب.&lt;/p>
$$ \text{Concat}(\text{head}_1, \dots, \text{head}_h) \in \mathbb{R}^{N \times (h \cdot d_v)} $$
&lt;p>عادةً ما يتم ضبطها بحيث تكون $h \cdot d_v = d_{model}$، لذا فإن الأبعاد بعد الدمج تعود مرة أخرى إلى $d_{model}$ كما في الإدخال. أخيراً، نضرب هذه المصفوفة في مصفوفة الأوزان $W^O \in \mathbb{R}^{d_{model} \times d_{model}}$ للحصول على المخرجات النهائية.&lt;/p>
$$ \text{MultiHead}(Q, K, V) = \text{Concat}(\text{head}_1, \dots, \text{head}_h) W^O $$
&lt;div class="mermaid">graph TD
X["الإدخال (Input X)"] --> Q1["Q1"]
X --> K1["K1"]
X --> V1["V1"]
Q1 &amp; K1 &amp; V1 --> H1["الرأس 1 (Head 1)"]
X --> Q2["Q2"]
X --> K2["K2"]
X --> V2["V2"]
Q2 &amp; K2 &amp; V2 --> H2["الرأس 2 (Head 2)"]
X --> QN["..."]
X --> KN["..."]
X --> VN["..."]
QN &amp; KN &amp; VN --> HN["الرأس h (Head h)"]
H1 &amp; H2 &amp; HN --> C["دمج (Concatenate)"]
C --> WO["الضرب في WO (Multiply by WO)"]
WO --> OUT["مخرجات متعددة الرؤوس (Multi-Head Output)"]&lt;/div>
&lt;hr>
&lt;h1 id="6-الشبكة-العصبية-ذات-التغذية-الأمامية-feed-forward-neural-network---ffn">6. الشبكة العصبية ذات التغذية الأمامية (Feed-Forward Neural Network - FFN)
&lt;/h1>&lt;p>يتم بعد ذلك إدخال مخرجات الانتباه متعدد الرؤوس في &lt;strong>الشبكة العصبية ذات التغذية الأمامية حسب الموضع (Position-wise Feed-Forward Network - FFN)&lt;/strong>.
وهي عبارة عن شبكة عصبية متصلة بالكامل من طبقتين يتم تطبيقها &amp;ldquo;بشكل مستقل لكل موضع (كلمة)&amp;rdquo; في السلسلة.&lt;/p>
&lt;p>يمكن التعبير عنها بالمعادلة التالية.&lt;/p>
$$ \text{FFN}(x) = \max(0, x W_1 + b_1) W_2 + b_2 $$
&lt;p>هنا، تشير $\max(0, z)$ إلى دالة التنشيط ReLU (وحدة خطية مقومة) (غالباً ما تُستخدم دوال مثل GELU أو SwiGLU في النماذج الحديثة).&lt;/p>
&lt;p>دور هذه الشبكة مهم جداً. فبينما تتعلم آلية الانتباه &amp;ldquo;العلاقات بين الكلمات (العلاقات المكانية والمتسلسلة)&amp;quot;، فإن شبكة FFN مسؤولة عن &amp;ldquo;التحويل غير الخطي لخصائص كل متجه كلمة بحد ذاته&amp;rdquo;.
في العادة، يتم تكبير الأبعاد مؤقتاً بشكل كبير بواسطة أوزان الطبقة الأولى $W_1$ (على سبيل المثال، تتضاعف 4 مرات من $d_{model}=512$ إلى $d_{ff}=2048$)، وبعد إجراء عمليات حسابية معقدة في فضاء الميزات، يتم إعادتها مرة أخرى إلى أبعادها الأصلية باستخدام أوزان الطبقة الثانية $W_2$. يؤدي هذا &amp;ldquo;التوسيع والتقليص للأبعاد&amp;rdquo; إلى زيادة القدرة التعبيرية للنموذج بشكل كبير.&lt;/p>
&lt;hr>
&lt;h1 id="7-الاتصال-المتبقي-residual-connection-وتسوية-الطبقة-layer-normalization">7. الاتصال المتبقي (Residual Connection) وتسوية الطبقة (Layer Normalization)
&lt;/h1>&lt;p>في التعلم العميق، عندما يتم زيادة عمق طبقات الشبكة، تحدث مشكلة تلاشي أو انفجار التدرج أثناء التدريب، مما يعيق التعلم بشكل صحيح. لمنع حدوث ذلك، يتم وضع &lt;strong>اتصال متبقي (Residual Connection)&lt;/strong> و &lt;strong>تسوية الطبقة (Layer Normalization)&lt;/strong> حول كل طبقة فرعية (الانتباه و FFN) في الـ Transformer.&lt;/p>
&lt;p>بالمعادلات، يتم معالجة مخرجات الطبقة الفرعية على النحو التالي.&lt;/p>
$$ \text{Output} = \text{LayerNorm}(x + \text{Sublayer}(x)) $$
&lt;h2 id="71-الاتصال-المتبقي-x--textsublayerx">7.1 الاتصال المتبقي ($x + \text{Sublayer}(x)$)
&lt;/h2>&lt;p>نقوم بإضافة الإدخال $x$ مباشرة إلى مخرجات الطبقة الفرعية. بفضل هذا، ينتقل التدرج مباشرة إلى الطبقات السطحية من خلال اختصار أثناء الانتشار العكسي، مما يضمن استقرار التدريب حتى مع زيادة عمق الطبقات.&lt;/p>
&lt;h2 id="72-رياضيات-تسوية-الطبقة-layer-normalization">7.2 رياضيات تسوية الطبقة (Layer Normalization)
&lt;/h2>&lt;p>تسوية الطبقة (Layer Normalization) هي تقنية تقوم بحساب المتوسط والتباين عبر اتجاه أبعاد الميزات لتسوية البيانات. في إدخال ذو حجم دفعة $B$، وطول سلسلة $N$، وعدد أبعاد $d_{model}$، يتم إجراء التسوية على متجه كلمة واحد $x \in \mathbb{R}^{d_{model}}$.&lt;/p>
&lt;p>نحسب المتوسط $\mu$ والتباين $\sigma^2$.
&lt;/p>
$$ \mu = \frac{1}{d_{model}} \sum_{i=1}^{d_{model}} x_i $$
$$ \sigma^2 = \frac{1}{d_{model}} \sum_{i=1}^{d_{model}} (x_i - \mu)^2 $$
&lt;p>ثم نحصل على المخرجات المسواة $\hat{x}$.
&lt;/p>
$$ \text{LN}(x) = \frac{x - \mu}{\sqrt{\sigma^2 + \epsilon}} \odot \gamma + \beta $$
&lt;p>
($\epsilon$ هو ثابت متناهي الصغر لمنع القسمة على صفر. $\gamma, \beta$ هما معلماتا المقياس والإزاحة القابلتان للتعلم)&lt;/p>
&lt;p>السبب في اعتماد تسوية الطبقة (Layer Normalization) بدلاً من تسوية الدفعة (Batch Normalization) هو أنه عند معالجة بيانات متسلسلة ذات أطوال غير ثابتة مثل الجمل، تميل الإحصاءات بين الدفعات إلى عدم الاستقرار. بفضل تسوية الطبقة، يصبح التدريب المستقر في Transformer ممكناً بغض النظر عن حجم الدفعة.&lt;/p>
&lt;hr>
&lt;h1 id="8-البنية-الخاصة-بفك-التشفير-decoder-الانتباه-المقنع-masked-attention-والانتباه-المتقاطع-cross-attention">8. البنية الخاصة بفك التشفير (Decoder): الانتباه المقنع (Masked Attention) والانتباه المتقاطع (Cross-Attention)
&lt;/h1>&lt;p>البنية التي تم شرحها حتى الآن تخص المشفر. في كتلة فك التشفير المسؤولة عن توليد الجمل، تختلف البنية قليلاً.&lt;/p>
&lt;h2 id="81-الانتباه-متعدد-الرؤوس-المقنع-masked-multi-head-attention">8.1 الانتباه متعدد الرؤوس المقنع (Masked Multi-Head Attention)
&lt;/h2>&lt;p>دور فك التشفير هو &amp;ldquo;التنبؤ بالكلمة التالية من الكلمات السابقة&amp;rdquo;. لذلك، إذا رأى &amp;ldquo;الكلمات المستقبلية&amp;rdquo; أثناء التدريب، فسيكون ذلك بمثابة غش. العملية الرياضية لمنع حدوث ذلك هي &lt;strong>القناع (Masking)&lt;/strong>.&lt;/p>
&lt;p>إلى مصفوفة الدرجات $Q K^T$، نقوم بإضافة مصفوفة قناع $M$ تعين قيماً صغيرة جداً تقترب من $-\infty$ في الجزء المثلثي العلوي (الذي يتوافق مع المعلومات المستقبلية).&lt;/p>
$$ M_{ij} = \begin{cases} 0 &amp; (i \le j) \\ -\infty &amp; (i > j) \end{cases} $$
$$ \text{Masked Attention}(Q, K, V) = \text{softmax}\left(\frac{Q K^T + M}{\sqrt{d_k}}\right) V $$
&lt;p>عند حساب دالة Softmax، نظراً لأن $\exp(-\infty) = 0$، فإن وزن الانتباه للكلمات المستقبلية يصبح $0$ تماماً. بفضل هذا، يصبح التوليد التلقائي الانحداري مع الحفاظ على السببية (Causality) ممكناً.&lt;/p>
&lt;h2 id="82-الانتباه-المتقاطع-بين-المشفر-وفك-التشفير-encoder-decoder-cross-attention">8.2 الانتباه المتقاطع بين المشفر وفك التشفير (Encoder-Decoder Cross-Attention)
&lt;/h2>&lt;p>الطبقة الفرعية الثانية من فك التشفير هي &lt;strong>الانتباه المتقاطع (Cross-Attention)&lt;/strong> التي تشير إلى مخرجات المشفر.
هنا، يتم توليد $Q$ من طبقة فك التشفير السابقة، بينما يتم توليد $K$ و $V$ من مخرجات الطبقة النهائية للمشفر.&lt;/p>
$$ Q_{decoder} = X_{dec} W^Q $$
$$ K_{encoder} = X_{enc} W^K $$
$$ V_{encoder} = X_{enc} W^V $$
&lt;p>من خلال هذا الحساب، يمكن للنموذج أن يتعلم في مهام الترجمة مثلاً &amp;ldquo;ما هو الجزء من الجملة الأجنبية الأصلية الذي ترتبط به بقوة الكلمة التي تُترجم الآن&amp;rdquo;.&lt;/p>
&lt;hr>
&lt;h1 id="9-تعقيد-الحساب-ورياضيات-التحسين-في-العصر-الحديث">9. تعقيد الحساب ورياضيات التحسين في العصر الحديث
&lt;/h1>&lt;p>يعد Transformer نموذجاً رائعاً، ولكنه يعاني أيضاً من &amp;ldquo;نقاط ضعف&amp;rdquo; بسبب بنيته الرياضية.
يرجى الانتباه إلى تعقيد حساب الانتباه الذاتي (Self-Attention). في حساب مصفوفة الدرجات $Q K^T$، يتم ضرب مصفوفة $(N \times d_k)$ في مصفوفة $(d_k \times N)$، وبالتالي فإن التعقيد الحسابي هو &lt;strong>$O(N^2 \cdot d_{model})$&lt;/strong>.&lt;/p>
&lt;p>بمعنى آخر، &lt;strong>يزداد التعقيد الحسابي واستهلاك الذاكرة بتربيع طول السلسلة $N$&lt;/strong>.
لا تمثل هذه مشكلة عندما تكون الجمل قصيرة، ولكن عند محاولة إدخال سياق طويل جداً مثل كتاب كامل في نماذج LLM، يصل $N$ إلى عشرات الآلاف أو مئات الآلاف، وفي الحسابات التقليدية للانتباه، ستنفد ذاكرة وحدة معالجة الرسومات (GPU) على الفور.&lt;/p>
&lt;p>لكسر هذه اللعنة المتمثلة في $O(N^2)$، تم اقتراح تحسينات مختلفة في السنوات الأخيرة من خلال المناهج الرياضية والأجهزة.
المثال الأبرز على ذلك هو &lt;strong>FlashAttention&lt;/strong>. إن FlashAttention هو خوارزمية تقوم بحساب الانتباه عن طريق تقسيمه إلى أجزاء (Tiling) لتقليل نقل البيانات (الوصول إلى الذاكرة) بين مستويات الذاكرة في وحدة معالجة الرسومات (SRAM و HBM). على الرغم من أنها تُخرج نفس النتيجة تماماً رياضياً مثل الانتباه القياسي (Exact Attention)، إلا أنها تحقق تسريعاً كبيراً وتقليلاً في استخدام الذاكرة من خلال تحسينات على مستوى الأجهزة، مما جعل من الممكن تحقيق نماذج سياق طويل مثل GPT-4.&lt;/p>
&lt;p>بالإضافة إلى ذلك، تُجرى أبحاث نشطة على الانتباه المتناثر (Sparse Attention) والانتباه الخطي (Linear Attention) التي تقرّب تعقيد الحساب إلى $O(N \log N)$ أو $O(N)$.&lt;/p>
&lt;hr>
&lt;h1 id="10-صورة-التنفيذ-كود-زائف-بأسلوب-pytorch">10. صورة التنفيذ (كود زائف بأسلوب PyTorch)
&lt;/h1>&lt;p>إذا قمنا بتحويل البنية الرياضية المذكورة حتى الآن إلى كود برمجي فعلي (Python / PyTorch)، سنلاحظ أنه يمكن كتابتها بشكل بسيط ومدهش. نعرض الكود الزائف للجزء الأساسي من الاهتمام الذاتي (Self-Attention).&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">torch&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">torch.nn.functional&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="nn">F&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">math&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">scaled_dot_product_attention&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">q&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">k&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">v&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">mask&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">None&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># أشكال q, k, v: [batch_size, num_heads, seq_length, d_k]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">d_k&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">q&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">size&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 1. حساب الدرجة بالضرب النقطي: Q * K^T&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># تبديل آخر بُعدين لحساب ضرب المصفوفات&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">scores&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">torch&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">matmul&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">q&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">k&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">transpose&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="o">-&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 2. القياس (Scaling)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">scores&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">scores&lt;/span> &lt;span class="o">/&lt;/span> &lt;span class="n">math&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">sqrt&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">d_k&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 3. القناع (في حالة Masked Attention)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">mask&lt;/span> &lt;span class="ow">is&lt;/span> &lt;span class="ow">not&lt;/span> &lt;span class="kc">None&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">scores&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">scores&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">masked_fill&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">mask&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="o">-&lt;/span>&lt;span class="mf">1e9&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 4. تحويل إلى احتمالات باستخدام Softmax&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">attention_weights&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">F&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">softmax&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">scores&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">dim&lt;/span>&lt;span class="o">=-&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 5. الضرب في مصفوفة القيم (Value)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">output&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">torch&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">matmul&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">attention_weights&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">v&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">output&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">attention_weights&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>يمكننا أن نرى أن المعادلة الرياضية $Q K^T / \sqrt{d_k}$ يتم تنفيذها بشكل حدسي كـ &lt;code>torch.matmul(q, k.transpose(-2, -1)) / math.sqrt(d_k)&lt;/code>. إن الجانب الممتع للغاية في التعلم العميق هو أن النظريات الرياضية تتحقق في بضعة أسطر من الكود بمساعدة مكتبات التحسين المتقدمة.&lt;/p>
&lt;hr>
&lt;h1 id="خاتمة-شكل-الذكاء-المرئي-من-المعادلات-الرياضية">خاتمة: شكل &amp;ldquo;الذكاء&amp;rdquo; المرئي من المعادلات الرياضية
&lt;/h1>&lt;p>في هذا المقال، قمنا بفك تشفير البنية الرياضية العميقة لنموذج Transformer.&lt;/p>
&lt;p>التضمين (Embedding) الذي يعيّن الكلمات في فضاء متجه متعدد الأبعاد، والترميز الموضعي (Positional Encoding) الذي يعبر عن معلومات الموضع بتراكب الموجات المثلثية، وآلية الاهتمام الذاتي (Self-Attention) التي هي حساب الضرب النقطي للمصفوفات المستمدة من تشبيه استرجاع المعلومات. كل واحد من هذه المكونات ما هو إلا تراكم للرياضيات الأساسية مثل الجبر الخطي، وحساب التفاضل والتكامل، والاحتمالات والإحصاء.&lt;/p>
&lt;p>ولكن عندما تتداخل هذه العمليات المصفوفية البسيطة في طبقات عديدة، وتتعلم الأنماط من مجموعات البيانات الضخمة من خلال مليارات أو مئات المليارات من المعلمات، يظهر هناك ما يشبه &amp;ldquo;شكل من أشكال الذكاء&amp;rdquo; القادر على فهم &amp;ldquo;لغتنا&amp;rdquo;، وإجراء الاستنتاجات المنطقية، وأحياناً توليد أفكار إبداعية.&lt;/p>
&lt;p>كما يوحي العنوان الاستفزازي &amp;ldquo;Attention Is All You Need&amp;rdquo; (الاهتمام هو كل ما تحتاجه)، يمكن القول إن جمال هذه البنية، التي تخلت عن المعالجات المتكررة والالتفافية المعقدة وتخصصت في حساب &amp;ldquo;الاهتمام (درجة الارتباط)&amp;rdquo; الخالص، يكمن بالتحديد في بساطتها الرياضية.&lt;/p>
&lt;p>في المستقبل، قد تظهر بنيات جديدة تتجاوز Transformer (مثل Mamba، وهو نموذج حالة الفضاء - State Space Model)، ولكن الإطار الرياضي لـ &amp;ldquo;فهم السياق بواسطة الاهتمام&amp;rdquo; الذي بناه Transformer سيُحفر بالتأكيد إلى الأبد في تاريخ الذكاء الاصطناعي.&lt;/p>
&lt;p>إذا سنحت لك الفرصة لاستخدام نماذج LLM مثل ChatGPT أو Claude في المستقبل، فحاول أن تتخيل تريليونات المرات من ضرب المصفوفات $Q K^T$ التي تُحسب كل ثانية في الخلفية، ودالة Softmax التي تستخرج الاحتمالات. سيرتفع وعيك بالتقنية، وستجد عالم الذكاء الاصطناعي أكثر إثارة للاهتمام.&lt;/p>
&lt;h3 id="المراجع">المراجع
&lt;/h3>&lt;ul>
&lt;li>Vaswani, A., et al. (2017). &amp;ldquo;Attention Is All You Need.&amp;rdquo; &lt;em>Advances in Neural Information Processing Systems&lt;/em>.&lt;/li>
&lt;li>Alammar, J. (2018). &amp;ldquo;The Illustrated Transformer.&amp;rdquo;&lt;/li>
&lt;/ul>
&lt;hr>
&lt;p>&lt;em>كُتب هذا المقال كدليل لأولئك الذين يتعلمون الأسس الرياضية لمعالجة اللغات الطبيعية والذكاء الاصطناعي. إذا كان لديك أي أسئلة أو نقاشات، فلا تتردد في مشاركتها في قسم التعليقات!&lt;/em>&lt;/p></description></item><item><title>شرح آلية تقنية التكميم (GGUF) في llama.cpp</title><link>http://kenji.blog/ar/p/llama-cpp-quantization-gguf/</link><pubDate>Fri, 11 Sep 2026 00:00:00 +0900</pubDate><guid>http://kenji.blog/ar/p/llama-cpp-quantization-gguf/</guid><description>&lt;img src="http://kenji.blog/p/llama-cpp-quantization-gguf/img/eyecatch.jpg" alt="Featured image of post شرح آلية تقنية التكميم (GGUF) في llama.cpp" />&lt;h2 id="1-مقدمة-لماذا-تحتاج-النماذج-اللغوية-الكبيرة-llm-إلى-التكميم-quantization">1. مقدمة: لماذا تحتاج النماذج اللغوية الكبيرة (LLM) إلى التكميم (Quantization)؟
&lt;/h2>&lt;p>التطور الأخير في النماذج اللغوية الكبيرة (LLMs) ملحوظ بشكل كبير، ولكن خلف الكواليس ظهرت مشاكل خطيرة تتمثل في &amp;ldquo;استنفاد الموارد الحسابية&amp;rdquo; و&amp;quot;عنق الزجاجة في النطاق الترددي للذاكرة&amp;quot;. على سبيل المثال، إذا تم تحميل نموذج يحتوي على 70 مليار (70B) معلمة مثل Llama 3 في الذاكرة باستخدام النقطة العائمة القياسية 16 بت (FP16)، فإنه يستهلك حوالي 140 جيجابايت من VRAM/RAM للمعلمات فقط. وإذا أضفنا سياق الاستدلال (ذاكرة التخزين المؤقت KV)، فلن يعمل إلا إذا تم ربط وحدات معالجة رسومات (GPU) متطورة مخصصة لمراكز البيانات (مثل NVIDIA A100 80GB أو H100 80GB) في مجموعة (Cluster).&lt;/p>
&lt;p>كمنقذ لتمكين تشغيل النماذج اللغوية الكبيرة للمطورين الأفراد وعلى الأجهزة الطرفية (مثل أجهزة MacBook وأجهزة الكمبيوتر الشخصية المخصصة للألعاب)، ظهرت &lt;strong>llama.cpp&lt;/strong> وفي صميمها &lt;strong>تقنية التكميم (Quantization)&lt;/strong>. وبشكل خاص، تعد صيغة الملفات &lt;strong>GGUF (GPT-Generated Unified Format)&lt;/strong> وخوارزمية التكميم المتقدمة القائمة على الكتل والتي تسمى &lt;strong>k-quants&lt;/strong>، نهجًا ثوريًا يضغط حجم النموذج إلى أجزاء صغيرة من حجمه الأصلي، مع الحد من تدهور دقة النموذج (Perplexity) إلى أدنى مستوى ممكن.&lt;/p>
&lt;p>في هذه المقالة، سنشرح بالتفصيل تقنية التكميم في llama.cpp بدءًا من خلفيتها الرياضية، والاختلافات عن صيغة GGML، والهيكل التفصيلي لصيغة GGUF، وصولاً إلى الآلية الداخلية لـ k-quants.&lt;/p>
&lt;hr>
&lt;h2 id="2-الأساس-الرياضي-للتكميم-quantization">2. الأساس الرياضي للتكميم (Quantization)
&lt;/h2>&lt;p>في سياق النماذج اللغوية الكبيرة، يشير التكميم إلى عملية تعيين القيم المستمرة (أو أرقام النقطة العائمة عالية الدقة) إلى قيم منفصلة بعدد بتات أقل (مثل INT8 و INT4 و INT3 وما إلى ذلك).&lt;/p>
&lt;h3 id="21-المعادلة-الأساسية-للتكميم-الخطي">2.1. المعادلة الأساسية للتكميم الخطي
&lt;/h3>&lt;p>النهج الأبسط هو التكميم الخطي (تكميم Min-Max). لنفترض أن موتر الوزن (Weight Tensor) الأصلي عالي الدقة هو $W$، وموتر الأعداد الصحيحة المكمم هو $W_q$.&lt;/p>
$$ W_q = \text{round}\left( \frac{W}{S} \right) + Z $$
&lt;p>حيث:&lt;/p>
&lt;ul>
&lt;li>$S$ هو &lt;strong>عامل المقياس (Scale Factor)&lt;/strong>، والذي يحدد حجم الخطوة (الدقة) للتكميم.&lt;/li>
&lt;li>$Z$ هي &lt;strong>نقطة الصفر (Zero-point)&lt;/strong>، وهي قيمة انحياز تستخدم لإزاحة القيمة التي سيقابلها الرقم الحقيقي $0.0$ كقيمة صحيحة بعد التكميم.&lt;/li>
&lt;li>$\text{round}(\cdot)$ هي دالة التقريب إلى أقرب عدد صحيح.&lt;/li>
&lt;/ul>
&lt;p>من خلال إلغاء التكميم (Dequantization)، نقوم باستعادة الوزن الحقيقي التقريبي $\tilde{W}$ أثناء الاستدلال.&lt;/p>
$$ \tilde{W} = S \times (W_q - Z) $$
&lt;h3 id="22-التكميم-المتماثل-مقابل-التكميم-غير-المتماثل">2.2. التكميم المتماثل مقابل التكميم غير المتماثل
&lt;/h3>&lt;p>بناءً على كيفية التعامل مع نقطة الصفر $Z$، ينقسم الأمر بشكل أساسي إلى طريقتين:&lt;/p>
&lt;ol>
&lt;li>
&lt;p>&lt;strong>التكميم غير المتماثل (Asymmetric Quantization)&lt;/strong>
يتم التعيين باستخدام الحد الأدنى $W_{\min}$ والحد الأقصى $W_{\max}$ للبيانات.
&lt;/p>
$$ S = \frac{W_{\max} - W_{\min}}{2^b - 1}, \quad Z = \text{round}\left(-\frac{W_{\min}}{S}\right) $$
&lt;p>
حيث $b$ هو عدد بتات التكميم (مثال: إذا كان 4 بت، فإن $2^4-1 = 15$). نظرًا لوجود حاجة للاحتفاظ بـ $Z$، يزداد العبء الحسابي والذاكرة قليلاً.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>التكميم المتماثل (Symmetric Quantization)&lt;/strong>
يتم التعيين حول الصفر باستخدام الحد الأقصى للقيمة المطلقة للبيانات ($Z=0$).
&lt;/p>
$$ S = \frac{\max(|W_{\max}|, |W_{\min}|)}{2^{b-1} - 1}, \quad Z = 0 $$
&lt;p>
اعتمدت عمليات التكميم المبكرة في llama.cpp (مثل Q4_0 القديم) التكميم المتماثل، ونظرًا لعدم وجود حد $Z$، فإن لها ميزة تسريع حسابات الضرب النقطي بشكل كبير باستخدام تعليمات SIMD.&lt;/p>
&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="3-التطور-من-ggml-إلى-gguf-وهيكل-الملف">3. التطور من GGML إلى GGUF وهيكل الملف
&lt;/h2>&lt;p>عند الحديث عن llama.cpp، لا يمكننا تجاهل مكتبة عمليات الموترات (Tensor) المكتوبة بلغة C++ &lt;strong>GGML&lt;/strong>، وصيغة الملفات المشتقة منها &lt;strong>GGUF&lt;/strong>.&lt;/p>
&lt;h3 id="31-تحديات-ggml">3.1. تحديات GGML
&lt;/h3>&lt;p>كانت الإصدارات الأولى من llama.cpp تستخدم صيغة &lt;code>ggml&lt;/code> (ومتغيراتها مثل &lt;code>ggjt&lt;/code>). ومع ذلك، كانت تعاني من المشاكل التالية:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>نقص قابلية التوسع:&lt;/strong> كانت الأرقام السحرية (Magic numbers) والمعلمات الفائقة مبرمجة بشكل ثابت (Hardcoded) بطول وترتيب ثابتين، مما أدى إلى تغييرات جذرية مع كل إضافة لهندسة نموذج جديدة (مثل: Llama و Falcon و Mixtral وما إلى ذلك) أو رمز مميز (Tokenizer) جديد.&lt;/li>
&lt;li>&lt;strong>فقدان التوافقية مع الإصدارات السابقة:&lt;/strong> تم تحديث الصيغة بشكل متكرر، مما أدى غالبًا إلى حالات لا يمكن فيها قراءة ملفات النماذج القديمة بواسطة أحدث إصدارات llama.cpp.&lt;/li>
&lt;/ul>
&lt;h3 id="32-ولادة-صيغة-gguf">3.2. ولادة صيغة GGUF
&lt;/h3>&lt;p>تم تقديم &lt;strong>GGUF&lt;/strong> في أغسطس 2023، وهي صيغة عالية التنوع مصممة لحل هذه المشكلات. أكبر ميزة لها هي اعتمادها على &lt;strong>هيكل بيانات وصفية (Metadata) يعتمد على المفتاح والقيمة (Key-Value)&lt;/strong>.&lt;/p>
&lt;p>يوضح مخطط Mermaid التالي الشكل المجرد لهيكل ملف GGUF.&lt;/p>
&lt;div class="mermaid">graph TD
A["ملف GGUF"] --> B["الرأس (السحر، الإصدار)"]
A --> C["البيانات الوصفية (أزواج المفتاح والقيمة)"]
A --> D["معلومات الموتر (الاسم، الشكل، الإزاحة)"]
A --> E["بيانات الموتر (حمولة ثنائية)"]
C --> C1["general.architecture: llama"]
C --> C2["llama.context_length: 4096"]
C --> C3["tokenizer.ggml.tokens: [...]"]
E --> E1["أوزان الطبقة 0"]
E --> E2["أوزان الطبقة 1"]
E --> E3["..."]&lt;/div>
&lt;p>&lt;strong>المزايا الرئيسية لـ GGUF:&lt;/strong>&lt;/p>
&lt;ol>
&lt;li>&lt;strong>المرونة:&lt;/strong> يتم تخزين جميع المعلمات الفائقة للنموذج، وإعدادات RoPE (Rotary Positional Embedding)، وبيانات مفردات الرموز (Tokenizer) كأزواج مفتاح-قيمة مسماة. يتم تجاهل المفاتيح غير المعروفة، مما يجعل إضافة ميزات جديدة أمراً سهلاً.&lt;/li>
&lt;li>&lt;strong>الاستقلالية عن ترتيب البايتات (Endianness):&lt;/strong> تعتمد GGUF على ترتيب البايتات الصغير (Little-endian) بشكل افتراضي، ولكنها تحتوي صراحة على علامة (Flag) للترتيب، مما يجعلها قابلة للنقل بأمان عبر البنى المختلفة.&lt;/li>
&lt;li>&lt;strong>التحسين لـ mmap (تخطيط الذاكرة):&lt;/strong> تتم محاذاة (Padding) بيانات الموتر عند حدود معينة، ويمكن تعيينها مباشرة من القرص إلى مساحة الذاكرة باستخدام استدعاء النظام &lt;code>mmap()&lt;/code> في نظام التشغيل. ونتيجة لذلك، يصبح وقت التهيئة لتحميل النموذج فعليًا صفراً.&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="4-أعماق-k-quants-التكميم-المتقدم-القائم-على-الكتل">4. أعماق k-quants: التكميم المتقدم القائم على الكتل
&lt;/h2>&lt;p>الجوهر الحقيقي لصيغة GGUF هو آلية &lt;strong>k-quants (K-quantization)&lt;/strong> المسؤولة عن ضغط أوزان النموذج.&lt;/p>
&lt;p>عادةً، تقترب أوزان الشبكات العصبية من التوزيع الطبيعي عند النظر إلى الطبقة ككل، ولكن توجد محلياً قيم متطرفة (Outliers). إذا قمنا بتكميم أوزان الطبقة بأكملها باستخدام عامل مقياس $S$ موحد، فإن القيم المتطرفة ستسحب المقياس، وسيتم فقدان معلومات الأوزان الصغيرة تمامًا.&lt;/p>
&lt;p>لمنع ذلك، تقوم llama.cpp بتنفيذ &lt;strong>التكميم القائم على الكتل (Block-wise Quantization)&lt;/strong>. يتم تقسيم موتر الأوزان إلى كتل صغيرة (مثلاً 32 عنصرًا أو 256 عنصرًا)، وتحصل كل كتلة على عامل مقياس (ونقطة صفر) خاص بها.&lt;/p>
&lt;h3 id="41-حدود-التكميم-القديم-q4_0-q4_1">4.1. حدود التكميم القديم (Q4_0, Q4_1)
&lt;/h3>&lt;p>كان &lt;code>Q4_0&lt;/code> الأولي يستخدم 32 وزنًا من نوع FP16 ككتلة واحدة، ويتشارك عامل مقياس FP16 واحد.&lt;/p>
&lt;ul>
&lt;li>حجم الكتلة: 32&lt;/li>
&lt;li>الذاكرة: 1 مقياس (16 بت) + 32 وزنًا بـ 4-بت (128 بت) = 144 بت&lt;/li>
&lt;li>عدد البتات الفعال لكل عنصر (bpw: bits per weight): $144 / 32 = 4.5$ bpw&lt;/li>
&lt;/ul>
&lt;p>على الرغم من أن هذا ممتاز، إلا أن حدود الدقة ونسبة الضغط أصبحت واضحة. هنا ظهرت &lt;strong>k-quants&lt;/strong> بهيكل هرمي أكثر تعقيدًا وتطوراً.&lt;/p>
&lt;h3 id="42-الهيكل-الهرمي-للكتل-الفائقة-والكتل-الفرعية-مثال-q4_k_m">4.2. الهيكل الهرمي للكتل الفائقة والكتل الفرعية (مثال Q4_K_M)
&lt;/h3>&lt;p>تمتلك k-quants هيكلاً هرمياً يتكون من &amp;ldquo;كتل فائقة (Super-block)&amp;rdquo; كبيرة، و&amp;quot;كتل فرعية (Sub-block)&amp;quot; أصغر مضمنة بداخلها. بفضل هذا، يتم تكميم البيانات الوصفية (مثل قيم المقياس) نفسها، مما يقلل bpw إلى أقصى حد مع الحفاظ على الدقة.&lt;/p>
&lt;p>لنلقِ نظرة على هيكل &lt;strong>Q4_K_M&lt;/strong>، وهو الإعداد الأكثر شيوعًا. يستخدم Q4_K_M كتلة فائقة مكونة من 256 عنصرًا.&lt;/p>
&lt;div class="mermaid">graph TD
A["كتلة فائقة (256 وزناً)"] --> B["البيانات الوصفية للمقياس (FP16/INT8)"]
A --> C["كتلة فرعية 0 (32 وزناً، 4-بت)"]
A --> D["كتلة فرعية 1 (32 وزناً، 4-بت)"]
A --> E["..."]
A --> F["كتلة فرعية 7 (32 وزناً، 4-بت)"]
B --> B1["مقياس فائق (FP16)"]
B --> B2["مقاييس فرعية (8 × 6-بت)"]
B --> B3["حدود دنيا فرعية (8 × 6-بت)"]&lt;/div>
&lt;p>يتم تعريف البنية الفعلية في C++ (GGML) بشكل مفاهيمي على النحو التالي:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;span class="lnt">8
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// الهيكل المفاهيمي لـ block_q4_K في llama.cpp
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="cp">#define QK_K 256
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">struct&lt;/span> &lt;span class="nc">block_q4_K&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">uint8_t&lt;/span> &lt;span class="n">d&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">];&lt;/span> &lt;span class="c1">// المقياس الفائق للكتلة الفائقة بأكملها (مثل FP16 x 2)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kt">uint8_t&lt;/span> &lt;span class="n">scales&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">12&lt;/span>&lt;span class="p">];&lt;/span> &lt;span class="c1">// بيانات مجمعة تحتوي على مقياس 6-بت والحد الأدنى 6-بت (نقطة الصفر) لـ 8 كتل فرعية (32 عنصرًا لكل منها)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kt">uint8_t&lt;/span> &lt;span class="n">qs&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">QK_K&lt;/span>&lt;span class="o">/&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">];&lt;/span> &lt;span class="c1">// بيانات الأوزان المكممة بـ 4-بت (256 عنصرًا / 2 = 128 بايت)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>&lt;strong>عملية إلغاء التكميم (Dequantization) الرياضية:&lt;/strong>&lt;/p>
&lt;p>يتم حساب القيمة الحقيقية التقريبية $\tilde{W}_{i, j}$ للعنصر $j$ ($0 \le j &lt; 32$) داخل الكتلة الفرعية $i$ ($0 \le i &lt; 8$) على النحو التالي:&lt;/p>
$$ \tilde{W}_{i, j} = S_{\text{super}} \times s_i \times (w_{i, j} - m_i) $$
&lt;ul>
&lt;li>$S_{\text{super}}$: مقياس النقطة العائمة للكتلة الفائقة بأكملها&lt;/li>
&lt;li>$s_i$: مقياس 6-بت المكمم للكتلة الفرعية $i$&lt;/li>
&lt;li>$m_i$: الحد الأدنى (نقطة الصفر) 6-بت المكمم للكتلة الفرعية $i$&lt;/li>
&lt;li>$w_{i, j}$: وزن التكميم 4-بت ($0 \dots 15$)&lt;/li>
&lt;/ul>
&lt;p>من خلال هذا الهيكل الهرمي، مع الحفاظ على القدرة على التكيف مع القيم المتطرفة، يتم تقليل مساحة الذاكرة التي تشغلها عوامل المقياس نفسها بشكل كبير. يحقق Q4_K_M إجماليًا يبلغ حوالي &lt;strong>4.8 bpw&lt;/strong>.&lt;/p>
&lt;h3 id="43-خيارات-k-quants-المتنوعة">4.3. خيارات k-quants المتنوعة
&lt;/h3>&lt;p>تقدم llama.cpp العديد من المتغيرات اعتمادًا على الغرض. تشير اللواحق (S, M, L) بعد &amp;ldquo;K&amp;rdquo; إلى الحجم.&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th style="text-align:left">الصيغة&lt;/th>
&lt;th style="text-align:center">BPW (بت لكل وزن)&lt;/th>
&lt;th style="text-align:left">نظرة عامة والميزات&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td style="text-align:left">&lt;strong>Q2_K&lt;/strong>&lt;/td>
&lt;td style="text-align:center">2.5～3.3&lt;/td>
&lt;td style="text-align:left">ضغط أقصى. انخفاض كبير في الدقة، لكنه مخصص للبيئات التي تحتوي على VRAM قليل جدًا.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">&lt;strong>Q3_K_M&lt;/strong>&lt;/td>
&lt;td style="text-align:center">3.3&lt;/td>
&lt;td style="text-align:left">المعيار لتكميم 3 بت. يتدهور أكثر من Q4 ولكنه غالباً ما يبقى ضمن الحدود المقبولة.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">&lt;strong>Q4_K_M&lt;/strong>&lt;/td>
&lt;td style="text-align:center">4.8&lt;/td>
&lt;td style="text-align:left">&lt;strong>النقطة المثالية الموصى بها&lt;/strong>. يوازن بين خفض حجم النموذج إلى النصف والحفاظ على الدقة.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">&lt;strong>Q5_K_M&lt;/strong>&lt;/td>
&lt;td style="text-align:center">5.5&lt;/td>
&lt;td style="text-align:left">عندما تتطلب دقة أعلى. يمثل موقعاً وسطاً بين Q4 و FP16.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">&lt;strong>Q6_K&lt;/strong>&lt;/td>
&lt;td style="text-align:center">6.6&lt;/td>
&lt;td style="text-align:left">يحافظ على Perplexity (حيرة) متطابقة تقريبًا مع FP16، لكن حجم الملف أكبر.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">&lt;strong>Q8_0&lt;/strong>&lt;/td>
&lt;td style="text-align:center">8.5&lt;/td>
&lt;td style="text-align:left">يعادل INT8. يستخدم بشكل رئيسي للموترات الوسيطة أثناء الاستدلال، أو في الطبقة الأخيرة فقط.&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>※ يتم متوسط BPW الفعلي عبر النموذج بأكمله نظرًا لأنه يتم تطبيق التكميم المختلط (Mixed Quantization) اعتمادًا على موترات النموذج (على سبيل المثال، إسقاط Q/K/V في Attention، أو أوزان FFN). داخلياً يتم إجراء تحسينات مثل تكميم الموترات المهمة بـ Q6 والباقي بـ Q4.&lt;/p>
&lt;hr>
&lt;h2 id="5-تحسين-أداء-الاستدلال-تعليمات-simd-ومعمارية-cuda">5. تحسين أداء الاستدلال: تعليمات SIMD ومعمارية CUDA
&lt;/h2>&lt;p>مجرد تحميل نموذج GGUF في الذاكرة لن يؤدي إلى تسريع الاستدلال. يمثل الجزء الأكبر من الاستدلال في النماذج اللغوية الكبيرة &amp;ldquo;ضرب المصفوفات (Matrix-Vector Multiplication، واختصاراً GEMV، أو Matrix-Matrix، GEMM)&amp;rdquo;. المفتاح هو كيفية تسريع عمليات الضرب والجمع بين الأوزان المكممة والتنشيطات (بيانات الإدخال) المحفوظة بتنسيق FP16 (أو FP32).&lt;/p>
&lt;h3 id="51-استخدام-تعليمات-simd-في-بيئة-وحدة-المعالجة-المركزية-cpu">5.1. استخدام تعليمات SIMD في بيئة وحدة المعالجة المركزية (CPU)
&lt;/h3>&lt;p>السرعة المذهلة التي تفتخر بها llama.cpp في استدلال وحدة المعالجة المركزية (CPU) ترجع إلى تحسين &lt;strong>SIMD (Single Instruction, Multiple Data)&lt;/strong> على مستوى التجميع (Assembly).
على سبيل المثال، تستفيد بشكل كامل من مجموعات تعليمات &lt;strong>AVX2&lt;/strong> أو &lt;strong>AVX-512&lt;/strong> على معالجات Intel/AMD، وتعليمات &lt;strong>ARM NEON&lt;/strong> على Apple Silicon.&lt;/p>
&lt;p>أثناء الاستدلال، لا يتم إرجاع $W_q$ إلى FP32 (إلغاء التكميم) أولاً ثم إجراء الضرب.
بل يتم تكميم جانب التنشيطات ديناميكياً (Dynamic Quantization، عادةً إلى INT8) على مستوى الكتلة، ويتم حساب العمليات الصحيحة لـ &lt;strong>INT8 $\times$ INT4&lt;/strong> دفعة واحدة باستخدام تعليمات الضرب النقطي الخاصة بـ SIMD (مثل: &lt;code>vdpaddd&lt;/code> أو &lt;code>_mm256_madd_epi16&lt;/code>). بفضل ذلك، في المتراكم النهائي (Accumulator)، يتم تحويل القيم مرة أخرى إلى FP32 وضربها في عامل المقياس، مما يحقق إنتاجية مذهلة (Throughput).&lt;/p>
&lt;h3 id="52-التفريغ-offload-في-بيئة-gpu-cublas--cuda">5.2. التفريغ (Offload) في بيئة GPU (cuBLAS / CUDA)
&lt;/h3>&lt;p>لم تعد llama.cpp تقتصر على دعم CPU فحسب، بل توفر أيضًا دعمًا قويًا لوحدات معالجة الرسومات من NVIDIA (CUBLAS / CUDA).
من الممكن تفريغ جزء من طبقات ملف GGUF أو جميعها إلى VRAM (خيار &lt;code>--n-gpu-layers&lt;/code>).&lt;/p>
&lt;div class="mermaid">sequenceDiagram
participant User
participant CPU_RAM as CPU &amp; RAM (mmap)
participant VRAM as GPU VRAM
participant Compute as أنوية Tensor
User->>CPU_RAM: تحميل GGUF (mmap)
CPU_RAM->>VRAM: تفريغ الطبقات (مثلاً 30/32 طبقة)
Note over CPU_RAM, VRAM: تبقى البيانات مكممة في VRAM
User->>Compute: التمرير الأمامي (الرموز المدخلة)
Compute->>VRAM: جلب الأوزان المكممة
Compute->>Compute: إلغاء التكميم إلى FP16 سريعاً في SRAM
Compute->>Compute: ضرب المصفوفات (cuBLAS / Custom Kernels)
Compute->>User: إخراج اللوغاريتمات (Logits)&lt;/div>
&lt;p>عند الحساب على GPU، يكون النطاق الترددي للذاكرة (Memory Bandwidth) لـ VRAM هو العائق الأكبر. وبما أن الأوزان مضغوطة بتقنية k-quants، يتم تقليل كمية نقل البيانات من VRAM إلى وحدات الحساب في GPU (SM: Streaming Multiprocessor أو أنوية Tensor) إلى 1/3 ~ 1/4. في اللحظة التي تصل فيها الأوزان إلى وحدة الحساب، يتم إلغاء تكميمها (فك ضغطها) سريعًا إلى FP16، ويتم تنفيذ ضرب المصفوفات بسرعة فائقة باستخدام Tensor Core.
بعبارة أخرى، يمكن القول إن التكميم يتم &lt;strong>&amp;ldquo;ليس لتقليل حجم العمليات الحسابية&amp;rdquo; بل &amp;ldquo;لتقليل كمية نقل البيانات من الذاكرة&amp;rdquo;&lt;/strong>.&lt;/p>
&lt;hr>
&lt;h2 id="6-أمثلة-عملية-لمقايضة-trade-off-بين-استهلاك-الذاكرة-والأداء">6. أمثلة عملية لمقايضة (Trade-off) بين استهلاك الذاكرة والأداء
&lt;/h2>&lt;p>هنا، لنأخذ نموذج Llama 3 8B كمثال لنتعرف على المواصفات المطلوبة بناءً على مستوى تكميم GGUF. (الأرقام هي قيم تقريبية)&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th style="text-align:left">النموذج/التكميم&lt;/th>
&lt;th style="text-align:left">حجم الملف&lt;/th>
&lt;th style="text-align:left">VRAM/RAM المطلوب&lt;/th>
&lt;th style="text-align:left">سرعة الاستدلال (تقريبية)&lt;/th>
&lt;th style="text-align:left">تدهور Perplexity&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td style="text-align:left">&lt;strong>Llama-3-8B (FP16)&lt;/strong>&lt;/td>
&lt;td style="text-align:left">حوالي 16 GB&lt;/td>
&lt;td style="text-align:left">18 GB أو أكثر&lt;/td>
&lt;td style="text-align:left">الأساس&lt;/td>
&lt;td style="text-align:left">لا يوجد (الأساس)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">&lt;strong>Llama-3-8B (Q8_0)&lt;/strong>&lt;/td>
&lt;td style="text-align:left">حوالي 8.5 GB&lt;/td>
&lt;td style="text-align:left">10 GB أو أكثر&lt;/td>
&lt;td style="text-align:left">سريعة&lt;/td>
&lt;td style="text-align:left">شبه معدوم&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">&lt;strong>Llama-3-8B (Q6_K)&lt;/strong>&lt;/td>
&lt;td style="text-align:left">حوالي 6.6 GB&lt;/td>
&lt;td style="text-align:left">8 GB أو أكثر&lt;/td>
&lt;td style="text-align:left">سريعة جداً&lt;/td>
&lt;td style="text-align:left">ضئيل جداً&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">&lt;strong>Llama-3-8B (Q4_K_M)&lt;/strong>&lt;/td>
&lt;td style="text-align:left">حوالي 4.9 GB&lt;/td>
&lt;td style="text-align:left">6.5 GB أو أكثر&lt;/td>
&lt;td style="text-align:left">الأسرع والأمثل&lt;/td>
&lt;td style="text-align:left">ضمن الحدود، ضئيل&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">&lt;strong>Llama-3-8B (Q3_K_M)&lt;/strong>&lt;/td>
&lt;td style="text-align:left">حوالي 3.9 GB&lt;/td>
&lt;td style="text-align:left">5.5 GB أو أكثر&lt;/td>
&lt;td style="text-align:left">الأسرع&lt;/td>
&lt;td style="text-align:left">ملحوظ قليلاً&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:left">&lt;strong>Llama-3-8B (Q2_K)&lt;/strong>&lt;/td>
&lt;td style="text-align:left">حوالي 3.0 GB&lt;/td>
&lt;td style="text-align:left">4.5 GB أو أكثر&lt;/td>
&lt;td style="text-align:left">سريعة&lt;/td>
&lt;td style="text-align:left">تدهور واضح&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>&lt;strong>ملاحظة هامة (تأثير ذاكرة التخزين المؤقت KV):&lt;/strong>
في استدلال النماذج اللغوية الكبيرة، كلما زاد طول السياق (عدد الرموز في الموجه)، لا تزيد الأوزان فحسب بل يزداد استهلاك الذاكرة بشكل انفجاري بسبب &lt;strong>ذاكرة التخزين المؤقت KV (KV Cache)&lt;/strong> التي تحفظ حالة الانتباه (Attention) السابقة.
على سبيل المثال، إذا كان طول السياق 8192 رمزاً، ستستهلك ذاكرة KV وحدها عدة جيجابايتات. ولذلك، في الاستخدام الفعلي، من الضروري الاحتفاظ بهامش إضافي (Headroom) يعادل &lt;code>حجم ملف النموذج + حوالي 1.5GB إلى 3GB&lt;/code>. السبب في التوصية بـ Q4_K_M هو أنه حتى مع تخصيص مساحة لـ KV Cache، فإنه يوفر توازناً مثالياً يسمح بتشغيل آمن على بطاقات الرسومات الشائعة المزودة بـ 8GB VRAM (مثل RTX 3060 / 4060).&lt;/p>
&lt;p>في الإصدارات الأخيرة من llama.cpp، تمت إضافة &lt;strong>ميزة تكميم ذاكرة التخزين المؤقت KV بحد ذاتها إلى Q8_0 أو Q4_0&lt;/strong>، وهناك جهود مستمرة لزيادة طول السياق بشكل أكبر.&lt;/p>
&lt;hr>
&lt;h2 id="7-الخاتمة">7. الخاتمة
&lt;/h2>&lt;p>في هذه المقالة، قمنا بالتعمق في الهيكل الداخلي لصيغة GGUF وتقنية تكميم k-quants، والتي تعد قلب llama.cpp النابض.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>مرونة GGUF:&lt;/strong> بفضل هيكل البيانات الوصفية الذي يعتمد على المفتاح والقيمة، تم بناء نظام بيئي قوي يمكنه مواكبة التطور السريع للنماذج اللغوية الكبيرة (وظهور بنيات نماذج جديدة) دون تغييرات جذرية تدمر التوافق.&lt;/li>
&lt;li>&lt;strong>ضغط أقصى مع k-quants:&lt;/strong> من خلال إدارة عامل المقياس بشكل هرمي عبر الكتل الفائقة والكتل الفرعية، أمكن تحقيق ضغط مذهل بمتوسط 4.8 بت لكل وزن (Q4_K_M) مع الحفاظ على معلومات القيم المتطرفة.&lt;/li>
&lt;li>&lt;strong>تجاوز عنق الزجاجة في النطاق الترددي للذاكرة:&lt;/strong> من خلال تنفيذ تطبيقات Kernel متقدمة في SIMD و CUDA، أتاح إجراء الحسابات مع إلغاء التكميم سريعاً (On-the-fly) تقليل كمية نقل بيانات VRAM، مما أدى إلى تحسين سرعة الاستدلال بشكل كبير.&lt;/li>
&lt;/ol>
&lt;p>إن القوة التقنية لـ llama.cpp، والتي تدفع نحو ديمقراطية الذكاء الاصطناعي، تتجاوز كونها مجرد أداة ويمكن القول إنها من أرقى قمم هندسة البرمجيات الحديثة. من خلال فهم خوارزمية التكميم وآلية صيغة GGUF، ستتمكن من اختيار النموذج الأنسب لبيئتك وإجراء ضبط الأداء بدقة أكبر.&lt;/p>
&lt;h3 id="روابط-مرجعية">روابط مرجعية
&lt;/h3>&lt;ul>
&lt;li>&lt;a class="link" href="https://github.com/ggerganov/llama.cpp" target="_blank" rel="noopener"
>مستودع llama.cpp على GitHub&lt;/a>&lt;/li>
&lt;li>&lt;a class="link" href="https://github.com/ggerganov/ggml/blob/master/docs/gguf.md" target="_blank" rel="noopener"
>مواصفات صيغة GGUF&lt;/a>&lt;/li>
&lt;li>&lt;a class="link" href="https://github.com/ggerganov/llama.cpp/pull/1684" target="_blank" rel="noopener"
>طلب السحب (PR) الخاص بتنفيذ K-quants&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>(النهاية)&lt;/p></description></item></channel></rss>