COE 592Lecture 5.2المحاضرة 5.2Part 03الجزء 03
Linear Quantized Matrix Multiplicationضرب المصفوفات المكمّم خطيًا
Substitutes r = S(q - Z) into Y = WX and expands the result. The terms then sort into runtime N-bit integer MACs, offline precomputation, a single rescale by S_W S_X / S_Y (done as a fixed-point multiply plus a bit shift) and an N-bit addition of Z_Y. The section ends by asking whether Z_W can be 0.يعوّض r = S(q - Z) في Y = WX ويفك الناتج. ثم تنقسم الحدود إلى عمليات MAC بأعداد صحيحة من N بت وقت التشغيل، وحسابات مسبقة خارج التشغيل (offline)، وإعادة قياس واحدة بـS_W S_X / S_Y (تُنفَّذ بضرب بالفاصلة الثابتة مع إزاحة بت)، وجمع Z_Y بـN بت. ويختتم القسم بالسؤال عما إذا كان Z_W يمكن أن يساوي 0.
- Conceptsالمفاهيم
- 4
- Slidesالشرائح
- 11-14
- Readingمدة القراءة
- 24 min24 دقيقة
Why this part mattersلماذا يهمّ هذا الجزء
Parts 01 and 02 told you how to store a tensor as integers: pick a scale and a zero point, and every real value becomes r = S(q - Z). Storage is only half the win. The other half, the half that makes a microcontroller or a phone DSP fast, is doing the arithmetic on those integers directly, without ever turning them back into floats. This part answers one question: if the inputs and weights of a layer are integers, what exactly does the chip have to compute to get the integer output?
The answer is a single equation with four inner terms and two outer operations, and the exam will almost certainly ask you to derive it, label which terms are precomputed, and explain how the one floating-point factor is applied with integer hardware. Everything in the next two parts (symmetric weights, bias folding, integer-only layers) is a consequence of the cost map you build here.
أخبرك الجزآن 01 و02 كيف تخزّن مصفوفة (tensor) على شكل أعداد صحيحة: اختر scale وzero point، فتصبح كل قيمة حقيقية r = S(q - Z). لكن التخزين نصف المكسب فقط. النصف الآخر، وهو الذي يجعل المتحكم الدقيق (microcontroller) أو معالج DSP في الهاتف سريعاً، هو إجراء الحساب على هذه الأعداد الصحيحة مباشرة دون إعادتها إلى أعداد عشرية أبداً. يجيب هذا الجزء عن سؤال واحد: إذا كانت مدخلات الطبقة وأوزانها أعداداً صحيحة، فما الذي يجب على الشريحة أن تحسبه بالضبط لتحصل على المخرج على شكل عدد صحيح؟
الجواب معادلة واحدة فيها أربعة حدود داخلية وعمليتان خارجيتان، والامتحان سيطلب منك على الأرجح أن تشتقها، وأن تحدد الحدود التي تُحسب مسبقاً، وأن تشرح كيف يُطبَّق المعامل العشري الوحيد باستخدام عتاد الأعداد الصحيحة. كل ما في الجزأين التاليين (الأوزان المتماثلة، ودمج الانحياز bias، والطبقات التي تعمل بالأعداد الصحيحة فقط) نتيجة لخريطة التكلفة التي تبنيها هنا.
By the end you canفي نهاية هذا الجزء ستستطيع
- Derive q_Y = (S_W S_X / S_Y)(q_W - Z_W)(q_X - Z_X) + Z_Y from Y = WX and r = S(q - Z), one line at a time.اشتق q_Y = (S_W S_X / S_Y)(q_W - Z_W)(q_X - Z_X) + Z_Y من Y = WX ومن r = S(q - Z)، سطراً بسطر.
- Expand the product into its four terms and say, for each, whether it runs at inference time or offline, and why.افتح حاصل الضرب إلى حدوده الأربعة، وحدّد لكل حد هل يُحسب وقت الاستدلال (inference) أم مسبقاً (offline)، ولماذا.
- Translate the slide's scalar shorthand into real matrix terms: column sums of q_X, row sums of q_W, and the factor K.حوّل الاختصار العددي المفرد في الشريحة إلى حدود مصفوفية حقيقية: مجاميع أعمدة q_X، ومجاميع صفوف q_W، والعامل K.
- Convert any rescale factor M in (0, 1) into M0 in [0.5, 1) and a right shift n, and apply it to an int32 accumulator.حوّل أي معامل إعادة قياس M في (0, 1) إلى M0 في [0.5, 1) وإزاحة يمينية n، وطبّقه على مراكم int32.
- Justify the 32-bit accumulator with a bit count, and explain why weights are quantized with Z_W = 0.برّر المراكم ذا 32 بت بعدّ البتات، واشرح لماذا تُكمَّم الأوزان مع Z_W = 0.
Start with something tiny: one weight and one input. Say the real weight is w = 0.5 and the real input is x = 1.5, so the real output is y = 0.75. In a quantized network none of these floats exist on the chip. What exists is three integer codes and, written next to each tensor, a scale and a zero point. The question is: given the codes q_w and q_x, which integer q_y should the chip write out, so that S_y(q_y - Z_y) is as close as possible to 0.75?
ابدأ بشيء صغير جداً: وزن واحد ومدخل واحد. لنقل إن الوزن الحقيقي w = 0.5 والمدخل الحقيقي x = 1.5، فيكون المخرج الحقيقي y = 0.75. في الشبكة المكمّمة لا يوجد أي من هذه الأعداد العشرية على الشريحة. الموجود هو ثلاثة رموز صحيحة (integer codes)، ومع كل مصفوفة scale وzero point مكتوبان بجانبها. والسؤال: بمعرفة الرمزين q_w وq_x، ما العدد الصحيح q_y الذي يجب أن تكتبه الشريحة كي تكون S_y(q_y - Z_y) أقرب ما يمكن إلى 0.75؟
The trick is to stop thinking about the codes and think about what they mean. Under Linear quantization, every tensor obeys the same Affine mapping: the real value equals its Scale (S) times the code minus its Zero point (Z). So wherever the real equation has a real number, you may substitute S(q - Z). The layer is Y = WX, and it is the source of the whole derivation.
الحيلة أن تتوقف عن التفكير في الرموز وتفكر في معناها. في Linear quantization تخضع كل مصفوفة للتحويل نفسه، Affine mapping: القيمة الحقيقية تساوي scale مضروباً في الرمز بعد طرح zero point منه. لذلك أينما ظهر عدد حقيقي في المعادلة الحقيقية يمكنك أن تعوّض مكانه S(q - Z). الطبقة هي Y = WX، وهي منطلق الاشتقاق كله.
Symbols used in this partالرموز المستخدمة في هذا الجزء
- Y = WX
- The real layer: weights W (M x K) times input X (K x N)الطبقة الحقيقية: الأوزان W (M x K) مضروبة في المدخل X (K x N)
- S_W, S_X, S_Y
- Float scales of the three tensors, fixed after calibrationمعاملات scale العشرية (float) للمصفوفات الثلاث، وتُثبَّت بعد المعايرة
- Z_W, Z_X, Z_Y
- Integer zero points of the three tensors, also fixed after calibrationنقاط الصفر (zero points) الصحيحة للمصفوفات الثلاث، وتُثبَّت هي أيضاً بعد المعايرة
- q_W, q_X, q_Y
- The stored N-bit integer codes (typically INT8)الرموز الصحيحة المخزّنة بـ N بت (عادةً INT8)
- M
- Shorthand for the combined factor S_W S_X / S_Yاختصار للمعامل المركّب S_W S_X / S_Y
Three lines of algebraثلاثة أسطر من الجبر
Substitute the affine map for all three tensors. The left side is the output, the right side the product of the two inputs:
عوّض التحويل affine للمصفوفات الثلاث. الطرف الأيسر هو المخرج، والطرف الأيمن حاصل ضرب المدخلين:
The scales are scalars, so they slide out of the product. Divide both sides by S_Y and move Z_Y to the right. This is the form to remember; it says the output code is a rescaled product of zero-shifted input codes, shifted by the output's zero point:
معاملات scale أعداد مفردة (scalars)، لذا تخرج من حاصل الضرب. اقسم الطرفين على S_Y وانقل Z_Y إلى الطرف الأيمن. هذه هي الصيغة التي يجب أن تحفظها؛ فهي تقول إن رمز المخرج هو حاصل ضرب رموز المدخلات بعد طرح نقاط الصفر منها، مُعاداً قياسه، ثم مُزاحاً بنقطة الصفر الخاصة بالمخرج:
Finally, multiply out the brackets. Nothing new happens mathematically, but this expanded form is the one that exposes the cost of each piece, which is what slides 12 to 14 are about:
أخيراً، افتح الأقواس. لا يحدث شيء جديد رياضياً، لكن هذه الصيغة المفكوكة هي التي تكشف تكلفة كل جزء، وهذا موضوع الشرائح 12 إلى 14:
That is the Quantized matrix multiplication. Notice what it buys. Every quantity inside the big bracket is an integer: codes and zero points. The only non-integer in the whole equation is the single factor S_W S_X / S_Y, a constant for the layer that you know before inference begins. So the expensive part, the inner products with millions of multiply-accumulates, can run on integer hardware, and the float only shows up once per output element at the very end. The construction comes from Jacob et al. (CVPR 2018), which is the source cited on every slide in this part.
هذا هو Quantized matrix multiplication. لاحظ ما يمنحك إياه. كل كمية داخل القوس الكبير عدد صحيح: رموز ونقاط صفر. والعدد غير الصحيح الوحيد في المعادلة كلها هو المعامل المفرد S_W S_X / S_Y، وهو ثابت للطبقة تعرفه قبل أن يبدأ الاستدلال. لذلك يمكن تنفيذ الجزء المكلف، أي الضرب الداخلي بملايين عمليات الضرب والجمع التراكمي (multiply-accumulate)، على عتاد الأعداد الصحيحة، ولا يظهر العدد العشري إلا مرة واحدة لكل عنصر من المخرج في النهاية تماماً. هذا البناء مأخوذ من Jacob et al. (CVPR 2018)، وهو المصدر المذكور في كل شريحة من هذا الجزء.
Worked exampleمثال محلول
One output element, end to endعنصر واحد من المخرج، من البداية إلى النهاية
Choose parametersاختر المعاملات
Let S_W = 0.5, Z_W = 1, S_X = 0.25, Z_X = 2, S_Y = 0.3125, Z_Y = -3. The real weight 0.5 is code q_W = 2 (since 0.5(2 - 1) = 0.5) and the real input 1.5 is code q_X = 8 (since 0.25(8 - 2) = 1.5).لتكن S_W = 0.5 وZ_W = 1 وS_X = 0.25 وZ_X = 2 وS_Y = 0.3125 وZ_Y = -3. الوزن الحقيقي 0.5 رمزه q_W = 2 (لأن 0.5(2 - 1) = 0.5)، والمدخل الحقيقي 1.5 رمزه q_X = 8 (لأن 0.25(8 - 2) = 1.5).Integer coreاللب الصحيح العددي
(q_W - Z_W)(q_X - Z_X) = (2 - 1)(8 - 2) = 6. Expanded, the same number is q_W q_X - Z_W q_X - Z_X q_W + Z_W Z_X = 16 - 8 - 4 + 2 = 6. Pure integer arithmetic.(q_W - Z_W)(q_X - Z_X) = (2 - 1)(8 - 2) = 6. وبعد فك الأقواس نحصل على العدد نفسه: q_W q_X - Z_W q_X - Z_X q_W + Z_W Z_X = 16 - 8 - 4 + 2 = 6. حساب بالأعداد الصحيحة فقط.Rescaleإعادة القياس
M = S_W S_X / S_Y = 0.125 / 0.3125 = 0.4, so M x 6 = 2.4, which rounds to 2.M = S_W S_X / S_Y = 0.125 / 0.3125 = 0.4، إذن M x 6 = 2.4، ويُقرَّب إلى 2.Add the output zero pointأضف نقطة الصفر للمخرج
q_Y = 2 + (-3) = -1.q_Y = 2 + (-3) = -1.Resultالنتيجة
Decoding gives S_Y(q_Y - Z_Y) = 0.3125 x 2 = 0.625 against the true 0.75. The error, 0.125, is below half an output step (S_Y / 2 = 0.156), exactly the rounding error part 01 promised.فك الترميز يعطي S_Y(q_Y - Z_Y) = 0.3125 x 2 = 0.625 مقابل القيمة الحقيقية 0.75. الخطأ، 0.125، أقل من نصف خطوة في المخرج (S_Y / 2 = 0.156)، وهو بالضبط خطأ التقريب الذي وعد به الجزء 01.
Recall
Starting from Y = WX and r = S(q - Z), derive q_Y. What are the two key moves?انطلاقاً من Y = WX و r = S(q - Z)، اشتق q_Y. ما الخطوتان الأساسيتان؟
Look at the four terms inside the bracket and ask one question of each: does it change when the input image changes? q_W q_X obviously does: it is the matrix product itself. Z_W q_X does too, because it contains q_X. But Z_X q_W involves only the weights and the input zero point, both frozen after calibration, and Z_W Z_X is two constants. Those last two are the same for every image the model will ever see, so there is no reason to compute them more than once.
انظر إلى الحدود الأربعة داخل القوس واسأل كل حد سؤالاً واحداً: هل يتغير عندما تتغير صورة المدخل؟ q_W q_X يتغير بالطبع، فهو ضرب المصفوفات نفسه. وZ_W q_X يتغير أيضاً لأنه يحتوي على q_X. لكن Z_X q_W يتضمن الأوزان ونقطة الصفر للمدخل فقط، وكلاهما مُثبَّت بعد المعايرة، وZ_W Z_X عبارة عن ثابتين. هذان الحدان الأخيران متطابقان لكل صورة سيراها النموذج، لذلك لا داعي لحسابهما أكثر من مرة.
That is the logic of slide 12. The amber box marks -Z_X q_W + Z_W Z_X as precomputed: it is evaluated offline, when the model is converted, and stored as a constant per output. The big red box marks the whole bracket as N-bit integer multiplications with 32-bit integer additions and subtractions. The blue box on the left is the rescale, and the small box on the right is +Z_Y, an integer addition. Slide 14 adds the last label: the rescale converts back to an N-bit integer.
هذا منطق الشريحة 12. الصندوق الكهرماني (amber) يحدد -Z_X q_W + Z_W Z_X على أنه precomputed (محسوب مسبقاً): يُقيَّم offline عند تحويل النموذج، ويُخزَّن ثابتاً لكل مخرج. والصندوق الأحمر الكبير يحدد القوس كله على أنه عمليات ضرب صحيحة بـ N بت مع عمليات جمع وطرح صحيحة بـ 32 بت. الصندوق الأزرق على اليسار هو إعادة القياس، والصندوق الصغير على اليمين هو +Z_Y، وهو جمع صحيح. وتضيف الشريحة 14 التسمية الأخيرة: إعادة القياس تُرجع القيمة إلى عدد صحيح بـ N بت.
| Termالحد | Depends onيعتمد على | Whenمتى | Costالتكلفة |
|---|---|---|---|
| q_W q_Xq_W q_X | Weights and inputالأوزان والمدخل | Every inferenceفي كل استدلال | N-bit multiplies, int32 adds: the main MAC loopعمليات ضرب بـ N بت وعمليات جمع بـ int32: حلقة MAC الرئيسية |
| -Z_W q_X-Z_W q_X | Input (and Z_W)المدخل (وZ_W) | Every inferenceفي كل استدلال | Column sums of q_X, one extra pass over the inputمجاميع أعمدة q_X، أي مرور إضافي واحد على المدخل |
| -Z_X q_W-Z_X q_W | Weights (and Z_X)الأوزان (وZ_X) | Offlineمسبقاً (offline) | Row sums of q_W, computed once at conversion timeمجاميع صفوف q_W، تُحسب مرة واحدة وقت تحويل النموذج |
| +Z_W Z_X+Z_W Z_X | Constants onlyثوابت فقط | Offlineمسبقاً (offline) | One constant, K Z_W Z_X, added to every outputثابت واحد، K Z_W Z_X، يُضاف إلى كل مخرج |
| x S_W S_X / S_Yx S_W S_X / S_Y | Constants onlyثوابت فقط | Every inferenceفي كل استدلال | One fixed-point multiply and a shift per outputعملية ضرب واحدة بفاصلة ثابتة وإزاحة واحدة لكل مخرج |
| +Z_Y+Z_Y | Constantثابت | Every inferenceفي كل استدلال | One integer add per output, then clamp to the N-bit rangeعملية جمع صحيحة واحدة لكل مخرج، ثم قص إلى مدى N بت |
What the scalar notation hidesما تخفيه الكتابة بالأعداد المفردة
The slides write the terms as if q_W and q_X were single numbers. In a real layer they are matrices, and each output entry is a sum over the inner dimension K:
تكتب الشرائح الحدود كأن q_W وq_X عددان مفردان. في الطبقة الحقيقية هما مصفوفتان، وكل عنصر في المخرج مجموع على البعد الداخلي K:
Read it term by term. Z_W q_X is really Z_W times the column sum of q_X (one number per output column). Z_X q_W is really Z_X times the row sum of q_W (one number per output row). And Z_W Z_X is added once per k, so it appears multiplied by K. This is exactly how production kernels such as gemmlowp organize the computation: they compute the row and column sums during packing and add them as a correction afterwards.
اقرأها حداً حداً. Z_W q_X هو في الحقيقة Z_W مضروباً في مجموع عمود q_X (عدد واحد لكل عمود في المخرج). وZ_X q_W هو في الحقيقة Z_X مضروباً في مجموع صف q_W (عدد واحد لكل صف في المخرج). أما Z_W Z_X فيُضاف مرة لكل k، لذلك يظهر مضروباً في K. وهذا بالضبط ما تفعله النوى (kernels) المستخدمة في الإنتاج مثل gemmlowp: تحسب مجاميع الصفوف والأعمدة أثناء التعبئة (packing) ثم تضيفها تصحيحاً بعد ذلك.
Worked exampleمثال محلول
A 2x2 example that makes the notation honestمثال 2x2 يكشف المعنى الحقيقي للترميز
Set upالإعداد
q_W = [[3, 1], [4, 2]], q_X = [[5, 1], [3, 6]], Z_W = 1, Z_X = 2, so K = 2.q_W = [[3, 1], [4, 2]] وq_X = [[5, 1], [3, 6]] وZ_W = 1 وZ_X = 2، إذن K = 2.Ground truthالقيمة المرجعية الصحيحة
q_W - Z_W = [[2, 0], [3, 1]] and q_X - Z_X = [[3, -1], [1, 4]]. Their product is [[6, -2], [10, 1]].q_W - Z_W = [[2, 0], [3, 1]] وq_X - Z_X = [[3, -1], [1, 4]]. حاصل ضربهما [[6, -2], [10, 1]].The four termsالحدود الأربعة
q_W q_X = [[18, 9], [26, 16]]. Column sums of q_X are 8 and 7, so Z_W times them gives 8 in column 0 and 7 in column 1. Row sums of q_W are 4 and 6, so Z_X times them gives 8 in row 0 and 12 in row 1. The constant is K Z_W Z_X = 2 x 1 x 2 = 4.q_W q_X = [[18, 9], [26, 16]]. مجاميع أعمدة q_X هي 8 و7، فضربها في Z_W يعطي 8 في العمود 0 و7 في العمود 1. مجاميع صفوف q_W هي 4 و6، فضربها في Z_X يعطي 8 في الصف 0 و12 في الصف 1. والثابت هو K Z_W Z_X = 2 x 1 x 2 = 4.Assembleالتجميع
Entry (0,0) is 18 - 8 - 8 + 4 = 6. All four entries match the ground truth (table below).العنصر (0,0) هو 18 - 8 - 8 + 4 = 6. والعناصر الأربعة كلها تطابق القيمة المرجعية (الجدول أدناه).Resultالنتيجة
The correct correction is a column vector, a row vector and the constant K Z_W Z_X. Dropping the K and adding Z_W Z_X = 2 instead makes every entry wrong by 2.التصحيح الصحيح هو متجه عمودي ومتجه صفي والثابت K Z_W Z_X. إسقاط K وإضافة Z_W Z_X = 2 بدلاً منه يجعل كل عنصر خاطئاً بمقدار 2.
| Outputالمخرج | With K Z_W Z_X = 4مع K Z_W Z_X = 4 | Resultالنتيجة | Forgetting Kعند نسيان K |
|---|---|---|---|
| Entry (0,0)العنصر (0,0) | 18 - 8 - 8 + 418 - 8 - 8 + 4 | 66 | 18 - 8 - 8 + 2 = 418 - 8 - 8 + 2 = 4 |
| Entry (0,1)العنصر (0,1) | 9 - 7 - 8 + 49 - 7 - 8 + 4 | -2-2 | 9 - 7 - 8 + 2 = -49 - 7 - 8 + 2 = -4 |
| Entry (1,0)العنصر (1,0) | 26 - 8 - 12 + 426 - 8 - 12 + 4 | 1010 | 26 - 8 - 12 + 2 = 826 - 8 - 12 + 2 = 8 |
| Entry (1,1)العنصر (1,1) | 16 - 7 - 12 + 416 - 7 - 12 + 4 | 11 | 16 - 7 - 12 + 2 = -116 - 7 - 12 + 2 = -1 |
Why the accumulator is 32 bitsلماذا المراكم 32 بت
The red box's label pairs N-bit multiplies with 32-bit additions, and the reason is a bit count. Two INT8 codes multiply to at most (-128) x (-128) = 16,384, which needs 16 signed bits. A dot product adds K of these, and each doubling of K can add one more bit, so the sum needs about 16 + log2(K) bits. That is why products go into an 32-bit accumulator: the width has room for the worst case of more than a hundred thousand terms, far more than any real layer has.
تسمية الصندوق الأحمر تقرن عمليات ضرب بـ N بت مع عمليات جمع بـ 32 بت، والسبب عدٌّ للبتات. حاصل ضرب رمزين من نوع INT8 لا يتجاوز (-128) x (-128) = 16,384، ويحتاج 16 بت بإشارة. الضرب النقطي (dot product) يجمع K من هذه النواتج، وكل مضاعفة لـ K قد تضيف بتاً واحداً، لذلك يحتاج المجموع نحو 16 + log2(K) بت. ولهذا تذهب النواتج إلى 32-bit accumulator: فعرضه يتسع لأسوأ حالة تزيد على مئة ألف حد، وهذا أكثر بكثير مما تملكه أي طبقة حقيقية.
Counting accumulator bitsعدّ بتات المراكم
- One int8 x int8 productحاصل ضرب واحد int8 x int8
- at most (-128) x (-128) = 16,384 = 2^14, so 16 signed bitsلا يتجاوز (-128) x (-128) = 16,384 = 2^14، إذن 16 بت بإشارة
- Sum of K productsمجموع K من النواتج
- at most K x 2^14, so about 16 + log2(K) bitsلا يتجاوز K x 2^14، إذن نحو 16 + log2(K) بت
- K = 4,608 (a 3 x 3 conv over 512 channels)K = 4,608 (التفاف 3 x 3 على 512 قناة)
- at most 4,608 x 2^14, about 2^26.2, so 28 signed bits: fits int32, overflows int16 after two termsلا يتجاوز 4,608 x 2^14، أي نحو 2^26.2، إذن 28 بت بإشارة: يتسع في int32، ويفيض في int16 بعد حدّين فقط
- Worst-case K for int32أسوأ حالة لـ K مع int32
- (2^31 - 1) / 2^14, about 131,071 terms(2^31 - 1) / 2^14، أي نحو 131,071 حداً
Recall
For W of size M x K and X of size K x N, what does Z_X q_W really mean, and how many distinct numbers does it produce?إذا كانت W بحجم M x K و X بحجم K x N، فما المعنى الحقيقي لـ Z_X q_W، وكم عدداً مختلفاً ينتج؟
Quick checkاختبار سريع
Which term of the expanded product must be recomputed for every new input?أي حد من حدود حاصل الضرب المفكوك يجب إعادة حسابه مع كل مدخل جديد؟
Quick checkاختبار سريع
An int8 dot product sums K = 4096 terms. Roughly how many bits can its worst-case sum need?ضرب نقطي بـ int8 يجمع K = 4096 حداً. كم بتاً تقريباً قد يحتاج مجموعه في أسوأ حالة؟
Suppose the accumulator for one output holds 5,000 and the layer's rescale factor is M = S_W S_X / S_Y = 0.0072. The output code before adding Z_Y is 5,000 x 0.0072 = 36. Easy on a laptop. On a microcontroller with no floating-point unit, that multiply by 0.0072 is the one operation left in the equation that is not an integer operation. If it stays a float multiply, the promise of Integer-only inference breaks at the last step.
افترض أن المراكم لمخرج واحد يحمل 5,000 وأن معامل إعادة القياس للطبقة هو M = S_W S_X / S_Y = 0.0072. رمز المخرج قبل إضافة Z_Y هو 5,000 x 0.0072 = 36. أمر سهل على حاسوب محمول. لكن على متحكم دقيق بلا وحدة فاصلة عائمة (floating-point unit)، يكون الضرب في 0.0072 هو العملية الوحيدة المتبقية في المعادلة التي ليست عملية أعداد صحيحة. وإذا بقي ضرباً عشرياً، ينكسر وعد Integer-only inference في الخطوة الأخيرة.
The fix is to rewrite M so that it uses only things integer hardware does cheaply. Keep doubling 0.0072 until it lands in [0.5, 1): 0.0144, 0.0288, 0.0576, 0.1152, 0.2304, 0.4608, 0.9216. Seven doublings. So 0.0072 = 2^(-7) x 0.9216. Multiplying by 0.9216 is a Fixed-point multiplication, and multiplying by 2^(-7) is a right shift by seven bits. That is the M0 and bit shift decomposition of slide 13:
الحل أن نعيد كتابة M بحيث لا تستخدم إلا ما ينفذه عتاد الأعداد الصحيحة بتكلفة رخيصة. استمر في مضاعفة 0.0072 حتى تقع في [0.5, 1): 0.0144، 0.0288، 0.0576، 0.1152، 0.2304، 0.4608، 0.9216. سبع مضاعفات. إذن 0.0072 = 2^(-7) x 0.9216. الضرب في 0.9216 هو Fixed-point multiplication (ضرب بفاصلة ثابتة)، والضرب في 2^(-7) هو إزاحة يمينية بسبع بتات. هذا هو تفكيك M0 and bit shift في الشريحة 13:
How M0 becomes an integerكيف يصبح M0 عدداً صحيحاً
M0 is still a real number, so it is stored as a fixed-point integer. With a 32-bit word, Jacob et al. store the int32 nearest to 2^31 M0, which is the Q31 format: the integer represents the fraction value / 2^31. For M0 = 0.9216 that integer is 1,979,120,930. The chip multiplies the accumulator by this integer into a 64-bit product and keeps the top bits (a right shift by 31 with rounding), then shifts right by n with rounding. Because M0 >= 0.5, the stored integer is at least 2^30, so it always uses about 30 significant bits. That is the point of normalizing: a tiny M stored directly in Q31 would waste most of its bits on leading zeros.
M0 ما زال عدداً حقيقياً، لذلك يُخزَّن عدداً صحيحاً بفاصلة ثابتة. مع كلمة من 32 بت، يخزّن Jacob et al. أقرب عدد int32 إلى 2^31 M0، وهذه صيغة Q31: العدد الصحيح يمثل الكسر value / 2^31. بالنسبة لـ M0 = 0.9216 يكون هذا العدد 1,979,120,930. تضرب الشريحة المراكم في هذا العدد لتحصل على حاصل ضرب من 64 بت وتحتفظ بالبتات العليا (إزاحة يمينية بمقدار 31 مع تقريب)، ثم تزيح يميناً بمقدار n مع تقريب. ولأن M0 >= 0.5، يكون العدد المخزّن 2^30 على الأقل، فيستخدم دائماً نحو 30 بتاً ذات دلالة. هذا هو الهدف من التطبيع (normalizing): لو خُزّن M صغير مباشرة بصيغة Q31 لأهدر معظم بتاته على أصفار بادئة.
| MM | Doubling to [0.5, 1)المضاعفة حتى [0.5, 1) | nn | M0M0 | M0 as Q31 int32M0 بصيغة Q31 في int32 |
|---|---|---|---|---|
| 0.30.3 | 0.3 x 2 = 0.60.3 x 2 = 0.6 | 11 | 0.60.6 | 1,288,490,1891,288,490,189 |
| 0.0450.045 | 0.045 x 16 = 0.720.045 x 16 = 0.72 | 44 | 0.720.72 | 1,546,188,2271,546,188,227 |
| 0.00720.0072 | 0.0072 x 128 = 0.92160.0072 x 128 = 0.9216 | 77 | 0.92160.9216 | 1,979,120,9301,979,120,930 |
Worked exampleمثال محلول
Rescale 5,000 by M = 0.0072 with integers onlyأعد قياس 5,000 بـ M = 0.0072 باستخدام الأعداد الصحيحة فقط
Normalize offlineطبِّع مسبقاً (offline)
n = 7, M0 = 0.9216, stored as M0_q31 = 1,979,120,930.n = 7 وM0 = 0.9216، ويُخزَّن على صورة M0_q31 = 1,979,120,930.Fixed-point multiplyضرب بفاصلة ثابتة
5,000 x 1,979,120,930 gives a 64-bit product; a rounding right shift by 31 leaves 4,608, which is 5,000 x 0.9216.5,000 x 1,979,120,930 يعطي حاصل ضرب من 64 بت؛ وإزاحة يمينية مع تقريب بمقدار 31 تترك 4,608، وهو 5,000 x 0.9216.Bit shiftإزاحة البتات
4,608 >> 7 with rounding is 36.4,608 >> 7 مع التقريب يساوي 36.Resultالنتيجة
36, the same as the float computation, with no floating-point instruction. Adding Z_Y and clamping to the N-bit range finishes the Requantization (rescale).36، النتيجة نفسها التي يعطيها الحساب العشري، دون أي تعليمة فاصلة عائمة. وإضافة Z_Y ثم القص إلى مدى N بت تُكمل requantization (إعادة التكميم).
5000 x 0.0072 = 5000 x 2^-7 x 0.9216
Try M = 0.3 in the calculator: one doubling gives 0.6, so n = 1 and M0 = 0.6. Try M = 0.5: it is already in range, so n = 0 and M0 = 0.5. The rule is mechanical: n is the number of doublings needed to reach 0.5, and M0 = M x 2^n.
جرّب M = 0.3 في الحاسبة: مضاعفة واحدة تعطي 0.6، إذن n = 1 وM0 = 0.6. جرّب M = 0.5: هي أصلاً داخل المدى، إذن n = 0 وM0 = 0.5. القاعدة آلية: n هو عدد المضاعفات اللازمة للوصول إلى 0.5، وM0 = M x 2^n.
Why M is below 1, and why that is only an observationلماذا M أقل من 1، ولماذا هذه مجرد ملاحظة
S_W S_X is the value of one unit in the accumulator, and the accumulator sums many products, so it spans a far wider range than one output code. S_Y must cover that whole output range in only 2^N levels, so it is usually much larger than S_W S_X, which makes M small. Jacob et al. report that they empirically find it to always be in (0, 1). That is a finding about trained networks, not a theorem: nothing in the algebra forbids S_Y < S_W S_X. The gemmlowp documentation is more careful and says the multiplier is typically less than one.
S_W S_X هو قيمة الوحدة الواحدة في المراكم، والمراكم يجمع نواتج كثيرة، لذلك يمتد على مدى أوسع بكثير من رمز مخرج واحد. يجب أن يغطي S_Y مدى المخرج كله في 2^N مستوى فقط، لذلك يكون عادة أكبر بكثير من S_W S_X، وهذا يجعل M صغيراً. ويذكر Jacob et al. أنهم وجدوه تجريبياً دائماً في (0, 1). هذه نتيجة عن الشبكات المدرّبة، لا نظرية رياضية: لا شيء في الجبر يمنع S_Y < S_W S_X. ووثائق gemmlowp أكثر حذراً، إذ تقول إن المضاعِف يكون عادةً أقل من واحد.
Recall
Why is M0 restricted to [0.5, 1) rather than stored as M directly?لماذا يُقيَّد M0 بالمدى [0.5, 1) بدلاً من تخزين M مباشرة؟
Quick checkاختبار سريع
A layer has M = 0.045. What are n and M0 in M = 2^(-n) M0?طبقة فيها M = 0.045. ما قيمتا n و M0 في M = 2^(-n) M0؟
Go back to the cost map and look at the one term that is neither the core product nor precomputable: Z_W q_X. Slide 14 shades it light blue for that reason. Every inference, before or alongside the main multiply, the kernel has to sum each column of the input codes, multiply by Z_W and subtract. That is an extra pass over X, every inference, for every layer. The extra work is smaller than the matrix product itself (Jacob et al. count it as order N^2 additions against 2N^3 for the product), but it costs memory traffic, kernel complexity and energy, and on a tiny device none of that is free.
عد إلى خريطة التكلفة وانظر إلى الحد الوحيد الذي ليس هو حاصل الضرب الأساسي ولا يمكن حسابه مسبقاً: Z_W q_X. لهذا السبب تظلله الشريحة 14 باللون الأزرق الفاتح. في كل استدلال، قبل الضرب الرئيسي أو بالتوازي معه، يجب على النواة (kernel) أن تجمع كل عمود من رموز المدخل، وتضربه في Z_W، ثم تطرحه. هذا مرور إضافي على X، في كل استدلال، ولكل طبقة. العمل الإضافي أصغر من ضرب المصفوفات نفسه (يحسبه Jacob et al. بعدد عمليات جمع من رتبة N^2 مقابل 2N^3 لحاصل الضرب)، لكنه يكلّف حركة ذاكرة وتعقيداً في النواة وطاقة، وعلى جهاز صغير لا شيء من ذلك مجاني.
The slide's question, Z_W = 0?, is the obvious way out. If the weight zero point is zero, the term Z_W q_X vanishes, and so does Z_W Z_X. What remains is
سؤال الشريحة، Z_W = 0?، هو المخرج الواضح. إذا كانت نقطة الصفر للأوزان صفراً، يختفي الحد Z_W q_X، ويختفي معه Z_W Z_X. والمتبقي هو
Now the only runtime work inside the bracket is the integer matrix product, and the only correction is precomputed. This choice is Z_W = 0, and in practice it means quantizing weights with Symmetric quantization, the topic of the next part.
الآن العمل الوحيد وقت التشغيل داخل القوس هو ضرب المصفوفات الصحيح، والتصحيح الوحيد محسوب مسبقاً. هذا الاختيار هو Z_W = 0، ويعني عملياً تكميم الأوزان بـ Symmetric quantization (التكميم المتماثل)، وهو موضوع الجزء التالي.
Why weights can afford itلماذا تستطيع الأوزان تحمّل ذلك
Forcing Z = 0 means real 0 sits in the middle of the integer range, so the scheme is only efficient when the data is spread roughly evenly on both sides of zero. The histogram on slide 14 shows that weights are: the Weight distribution of a trained layer is a narrow bell, peaked at 0, falling off almost symmetrically by about -0.05 and +0.05. Centering the grid at zero wastes almost no levels. Activations after a ReLU are the opposite case, all non-negative, so a symmetric grid would waste half its codes on values that never occur. That is why activations keep a free zero point and weights do not.
فرض Z = 0 يعني أن الصفر الحقيقي 0 يقع في منتصف مدى الأعداد الصحيحة، لذلك لا يكون هذا الأسلوب فعالاً إلا عندما تنتشر البيانات بشكل متوازن تقريباً على جانبي الصفر. ويُظهر المدرج التكراري (histogram) في الشريحة 14 أن الأوزان كذلك: Weight distribution لطبقة مدرّبة جرس ضيق قمته عند 0، ويتلاشى بشكل شبه متماثل عند نحو -0.05 و+0.05. توسيط الشبكة عند الصفر لا يكاد يهدر أي مستوى. أما التنشيطات (activations) بعد ReLU فهي الحالة المعاكسة، كلها غير سالبة، فالشبكة المتماثلة ستهدر نصف رموزها على قيم لا تظهر أبداً. لهذا تحتفظ التنشيطات بنقطة صفر حرة ولا تحتفظ الأوزان بها.
Recall
Why does Z_W = 0 help more than Z_X = 0 would?لماذا يفيد Z_W = 0 أكثر مما قد يفيده Z_X = 0؟
Quick checkاختبار سريع
After setting Z_W = 0, which zero-point correction term is still left inside the bracket?بعد جعل Z_W = 0، أي حد تصحيح لنقطة الصفر يبقى داخل القوس؟
Recapالخلاصة
If you remember nothing elseإن لم تتذكر شيئاً آخر فتذكّر هذا
- Substitute r = S(q - Z) into Y = WX for all three tensors, divide by S_Y, add Z_Y: q_Y = (S_W S_X / S_Y)(q_W - Z_W)(q_X - Z_X) + Z_Y.عوّض r = S(q - Z) في Y = WX للمصفوفات الثلاث، ثم اقسم على S_Y وأضف Z_Y: q_Y = (S_W S_X / S_Y)(q_W - Z_W)(q_X - Z_X) + Z_Y.
- Expanded: q_Y = M(q_W q_X - Z_W q_X - Z_X q_W + Z_W Z_X) + Z_Y with M = S_W S_X / S_Y.بعد فك الأقواس: q_Y = M(q_W q_X - Z_W q_X - Z_X q_W + Z_W Z_X) + Z_Y حيث M = S_W S_X / S_Y.
- q_W q_X and Z_W q_X run every inference (they touch the input). -Z_X q_W + Z_W Z_X depends only on weights and fixed parameters, so it is precomputed offline.الحدّان q_W q_X و Z_W q_X يُحسبان في كل استدلال (لأنهما يتعاملان مع المدخل). أما -Z_X q_W + Z_W Z_X فيعتمد فقط على الأوزان والمعاملات الثابتة، لذلك يُحسب مسبقاً offline.
- In a real matrix product, Z_W q_X means Z_W times the column sums of q_X, Z_X q_W means Z_X times the row sums of q_W, and Z_W Z_X is multiplied by the inner dimension K.في ضرب المصفوفات الحقيقي، Z_W q_X تعني Z_W مضروباً في مجاميع أعمدة q_X، و Z_X q_W تعني Z_X مضروباً في مجاميع صفوف q_W، و Z_W Z_X يُضرب في البعد الداخلي K.
- An int8 x int8 product needs 16 bits and a sum of K products needs about 16 + log2(K) bits, so products are summed in an int32 accumulator.حاصل ضرب int8 x int8 يحتاج 16 بت، ومجموع K من هذه النواتج يحتاج نحو 16 + log2(K) بت، لذلك تُجمع النواتج في مراكم int32.
- M is a float, empirically in (0, 1). Write M = 2^(-n) M0 with M0 in [0.5, 1): M0 becomes an int32 fixed-point multiplier (Q31) and 2^(-n) a rounding right shift. Example: M = 0.0072 gives n = 7, M0 = 0.9216.M عدد عشري (float)، ويقع تجريبياً في (0, 1). اكتب M = 2^(-n) M0 حيث M0 في [0.5, 1): يصبح M0 مضاعِفاً بفاصلة ثابتة من نوع int32 (بصيغة Q31)، ويصبح 2^(-n) إزاحة يمينية مع تقريب. مثال: M = 0.0072 يعطي n = 7 و M0 = 0.9216.
- Z_W q_X cannot be precomputed and costs an extra pass over X. Weights are bell-shaped around 0, so symmetric quantization with Z_W = 0 removes that term for free.لا يمكن حساب Z_W q_X مسبقاً، وهو يكلّف مروراً إضافياً على X. الأوزان على شكل جرس حول 0، لذلك يزيل التكميم المتماثل مع Z_W = 0 هذا الحد مجاناً.
Sourcesالمصادر
- Quantization and Training of Neural Networks for Efficient Integer-Arithmetic-Only InferencePaperJacob et al., CVPR 2018Section 2.2: M empirically in (0, 1), M = 2^(-n) M0 with M0 in [0.5, 1), int32 nearest 2^31 M0. Section 2.3: the N Z1 Z2 term and row and column sums. Section 2.4: 32-bit accumulatorالقسم 2.2: M يقع تجريبياً في (0, 1)، و M = 2^(-n) M0 حيث M0 في [0.5, 1)، و int32 الأقرب إلى 2^31 M0. القسم 2.3: الحد N Z1 Z2 ومجاميع الصفوف والأعمدة. القسم 2.4: مراكم 32 بت(opens in a new tab)(يفتح في تبويب جديد)
- gemmlowp: the low-precision paradigmDocsGoogleFour-term expansion with offsets: row sums, column sums, and the constant offset product times depthفك الحدود الأربعة مع الإزاحات (offsets): مجاميع الصفوف، ومجاميع الأعمدة، وحاصل ضرب الإزاحتين الثابت مضروباً في العمق (depth)(opens in a new tab)(يفتح في تبويب جديد)
- gemmlowp: quantizationDocsGoogleMultiplier typically less than one, applied as a fixed-point multiply in [1/2, 1) and a right shiftالمضاعِف عادةً أقل من واحد، ويُطبَّق على شكل ضرب بفاصلة ثابتة في [1/2, 1) ثم إزاحة يمينية(opens in a new tab)(يفتح في تبويب جديد)
- LiteRT 8-bit quantization specificationDocsGoogleSymmetric weights with zero point 0, asymmetric activations, and why the activation cross term runs every inferenceأوزان متماثلة بنقطة صفر 0، وتنشيطات غير متماثلة، ولماذا يُحسب الحد المتقاطع مع التنشيط في كل استدلال(opens in a new tab)(يفتح في تبويب جديد)