COE 592Lecture 5.3المحاضرة 5.3Part 01الجزء 01
Quantization granularity: per-tensor vs per-channel scalesدقة التكميم (Granularity): مقاييس لكل موتر مقابل لكل قناة
Post-training quantization asks how to choose S and Z. The first knob is granularity: one scale for the whole weight tensor fails when output channels have wildly different ranges, so per-channel quantization gives each output channel its own scale and cuts reconstruction error, shown on a full 2-bit worked example.التكميم بعد التدريب (PTQ) يسأل كيف نختار S وZ. أول خيار هو الدقة (granularity): مقياس واحد لموتر الأوزان كله يفشل عندما تكون لقنوات المخرج مديات مختلفة جدًا، لذا يعطي التكميم لكل قناة (per-channel) كل قناة مخرج مقياسها الخاص ويقلل خطأ إعادة البناء، كما يظهر في مثال محلول كامل بـ2 بت.
- Conceptsالمفاهيم
- 5
- Slidesالشرائح
- 1-13
- Readingمدة القراءة
- 30 min30 دقيقة
Why this part mattersلماذا يهمّ هذا الجزء
The last two lectures gave you the machinery of linear quantization: a real number is stored as an integer with . What they did not settle is how to choose and for a real network that has already been trained. This part starts that story with the first and most exam-visible decision: how many weights should share one scale.
The ideas come in a chain. First, the framing: post-training quantization and its three questions. Second, the menu of granularities. Third, why the simplest choice, one scale per tensor, breaks on small models. Fourth and fifth, the lecture’s 2-bit example computed by hand under both schemes, ending with the reason per-channel scales live on output channels. Expect the midterm to hand you a small matrix and ask for , and the error under both schemes, so the worked examples are written to be copied step by step.
أعطتك المحاضرتان السابقتان أدوات التكميم الخطي: يُخزَّن العدد الحقيقي كعدد صحيح بحيث . لكنهما لم تحسما كيف نختار و لشبكة حقيقية دُرِّبت بالفعل. يبدأ هذا الجزء تلك القصة بالقرار الأول والأكثر ظهورًا في الامتحان: كم وزنًا يجب أن يتشارك scale واحدًا؟
تأتي الأفكار في سلسلة. أولًا الإطار العام: التكميم بعد التدريب (post-training quantization) وأسئلته الثلاثة. ثانيًا قائمة مستويات الدقة (granularity). ثالثًا لماذا ينهار أبسط خيار، أي scale واحد لكل tensor، في النماذج الصغيرة. رابعًا وخامسًا مثال المحاضرة ذو 2 bit محسوبًا باليد بالطريقتين، وننتهي بسبب وضع مقاييس per-channel على قنوات الخرج (output channels). توقّع أن يعطيك الامتحان النصفي مصفوفة صغيرة ويطلب و والخطأ بالطريقتين، لذلك كُتبت الأمثلة المحلولة بحيث تنسخها خطوة بخطوة.
By the end you canفي نهاية هذا الجزء ستستطيع
- State what post-training quantization does and name the three questions it answers about S and Z.أن تذكر ما يفعله التكميم بعد التدريب (PTQ) وتسمّي الأسئلة الثلاثة التي يجيب عنها بشأن S وZ.
- Distinguish per-tensor, per-channel and group granularity by how many weights share one scale.أن تميّز بين granularity من نوع per-tensor وper-channel وgroup بحسب عدد الأوزان التي تتشارك scale واحدًا.
- Compute S, q and the reconstruction error for a small weight matrix under symmetric per-tensor and per-channel quantization.أن تحسب S وq وخطأ إعادة البناء لمصفوفة أوزان صغيرة في التكميم المتماثل per-tensor وper-channel.
- Explain why one outlier output channel ruins per-tensor quantization, citing the MobileNetV2 evidence.أن تشرح لماذا تُفسد قناة خرج شاذة واحدة تكميم per-tensor، مستشهدًا بدليل MobileNetV2.
- Explain why per-channel scales are taken over output channels and not input channels.أن تشرح لماذا تؤخذ مقاييس per-channel على قنوات الخرج (output channels) وليس على قنوات الدخل.
Suppose a colleague hands you a ResNet trained in FP32 and says: make it run in INT8 on our microcontroller by Friday, and no, you cannot retrain it. You have the weights, perhaps a few hundred unlabeled images, and that is all.
لنفترض أن زميلًا أعطاك شبكة ResNet مدرّبة بدقة FP32 وقال: اجعلها تعمل بـ INT8 على المتحكم الدقيق (microcontroller) لدينا قبل يوم الجمعة، ولا، لا يمكنك إعادة تدريبها. لديك الأوزان، وربما بضع مئات من الصور غير الموسومة، وهذا كل شيء.
That job is Post-training quantization (PTQ). The network’s weights are frozen; the only things you get to choose are the quantization parameters, the scale and the zero point , for every tensor you quantize. Its opposite, which the lecture covers later, is Quantization-aware training (QAT), where quantization is simulated during training so the weights can adapt to it. PTQ is cheap and needs no labels; QAT costs a training run but recovers more accuracy at low bit widths.
هذه المهمة هي post-training quantization (التكميم بعد التدريب). أوزان الشبكة مجمّدة، والشيء الوحيد الذي تختاره هو معاملات التكميم: الـ scale ونقطة الصفر (zero point) ، لكل tensor تكمّمه. ونقيضه، الذي تغطيه المحاضرة لاحقًا، هو quantization-aware training (التدريب الواعي بالتكميم)، حيث يُحاكى التكميم أثناء التدريب كي تتكيّف الأوزان معه. الـ PTQ رخيص ولا يحتاج إلى تسميات (labels)، أما QAT فيكلّف عملية تدريب كاملة لكنه يستعيد دقة أكبر عند عدد بتات منخفض.
The lecture breaks the PTQ question “what are the best ?” into three independent sub-questions, and the rest of the lecture’s first half answers them in order.
تقسّم المحاضرة سؤال الـ PTQ «ما أفضل ؟» إلى ثلاثة أسئلة فرعية مستقلة، ويجيب باقي النصف الأول من المحاضرة عنها بالترتيب.
How many weights share one S? The whole tensor, one channel, or a small group.
كم وزنًا يتشارك S واحدًا؟ الـ tensor بأكمله، أو قناة واحدة، أو مجموعة صغيرة.
Which |r|_max to map onto q_max? The observed max, or a smaller clipped value.
أي قيمة |r|_max نربطها بـ q_max؟ القيمة العظمى المرصودة، أو قيمة أصغر بعد القص.
Round each value to the nearest level, or choose up or down to cut layer error.
قرّب كل قيمة إلى أقرب مستوى، أو اختر التقريب للأعلى أو للأسفل لتقليل خطأ الطبقة.
Keep the three apart in your head. Granularity decides who shares a scale. Dynamic range clipping decides how large that scale is, given the values that share it. Rounding decides which level each value lands on once the grid is fixed; the default, Rounding to nearest, turns out not to be optimal. Every one of the three changes the same final number, the error between the original and the dequantized weights, so they interact, but each can be studied with the other two held fixed.
أبقِ الثلاثة منفصلة في ذهنك. الـ granularity تحدد من يتشارك الـ scale. وdynamic range clipping (قصّ المدى الديناميكي) يحدد كم يكون كبيرًا هذا الـ scale، بالنظر إلى القيم التي تتشاركه. والتقريب (rounding) يحدد أي مستوى تقع عليه كل قيمة بعد تثبيت الشبكة؛ والخيار الافتراضي، rounding to nearest (التقريب إلى الأقرب)، يتبيّن أنه ليس الأمثل. كل واحد من الثلاثة يغيّر الرقم النهائي نفسه، أي الخطأ بين الأوزان الأصلية والأوزان بعد إزالة التكميم (dequantized)، لذا فهي تتفاعل فيما بينها، لكن يمكن دراسة كل واحد منها مع تثبيت الاثنين الآخرين.
Recall
Name the three PTQ sub-questions and say in one phrase what each one decides.سمِّ الأسئلة الفرعية الثلاثة في PTQ وقل بعبارة واحدة ماذا يحدد كل منها.
Granularity: which weights share one scale. Dynamic range clipping: what range is mapped onto the integer grid, which sets the size of S. Rounding: which grid level each value is assigned to once S is fixed.
الـ granularity: أي الأوزان تتشارك scale واحدًا. الـ dynamic range clipping: أي مدى يُسقَط على الشبكة الصحيحة، وهذا يحدد حجم S. الـ rounding: أي مستوى في الشبكة تُسنَد إليه كل قيمة بعد تثبيت S.
Take two filters in the same layer. One has weights in [-128, 128], the other in (-0.5, 0.5). Quantize both to INT8 with one shared scale: S = 128 / 127 ≈ 1.01. Every weight of the second filter divided by 1.01 is below 0.5 in magnitude, so all of them round to 0. That filter is erased, even with 8 bits.
خذ مرشحين في الطبقة نفسها. أحدهما أوزانه في [-128, 128]، والآخر في (-0.5, 0.5). كمّم الاثنين إلى INT8 بـ scale مشترك واحد: S = 128 / 127 ≈ 1.01. كل وزن من المرشح الثاني بعد قسمته على 1.01 تكون قيمته المطلقة أقل من 0.5، فتُقرَّب كلها إلى 0. هذا المرشح يُمحى تمامًا، حتى مع 8 bits.
This is the example Nagel et al. (ICCV 2019) use, and it is the whole reason this part exists. Before going further, fix the recipe the lecture uses for weights. Weights are roughly centred on zero, so the lecture uses Symmetric quantization: the zero point is and the range is set by the largest magnitude.
هذا هو المثال الذي يستخدمه Nagel et al. (ICCV 2019)، وهو السبب الذي يوجد هذا الجزء من أجله أصلًا. قبل المتابعة، ثبّت الوصفة التي تستخدمها المحاضرة للأوزان. الأوزان متمركزة تقريبًا حول الصفر، لذا تستخدم المحاضرة symmetric quantization (التكميم المتماثل): نقطة الصفر والمدى تحدده أكبر قيمة مطلقة.
Notice what does to the integer range. An N-bit two’s complement integer can hold -2^(N-1) up to 2^(N-1) - 1, but a symmetric grid uses only -q_max to +q_max, so the most negative code is never produced. For N = 8 that is [-127, 127], exactly the range the TensorFlow Lite (LiteRT) specification mandates for weights. For N = 2 it is dramatic: q_max = 2^1 - 1 = 1, so only the three codes -1, 0, 1 are used, and the fourth code, -2, is wasted.
لاحظ ما تفعله بمدى الأعداد الصحيحة. العدد الصحيح ذو N bit بتمثيل المتمم الثنائي (two’s complement) يمكن أن يحمل القيم من -2^(N-1) حتى 2^(N-1) - 1، لكن الشبكة المتماثلة لا تستخدم إلا من -q_max إلى +q_max، فلا يُنتَج الرمز الأكثر سالبية أبدًا. عند N = 8 يكون ذلك [-127, 127]، وهو بالضبط المدى الذي تفرضه مواصفة TensorFlow Lite (LiteRT) للأوزان. وعند N = 2 يكون الأثر كبيرًا: q_max = 2^1 - 1 = 1، فلا تُستخدم إلا الرموز الثلاثة -1, 0, 1، ويضيع الرمز الرابع -2.
One scale, many channels: the outlier problemscale واحد وقنوات كثيرة: مشكلة القيم الشاذة (outliers)
With one scale per tensor, is the largest weight in the entire layer. If one output channel holds that outlier, its range dictates the step size for every channel. Channels whose weights are much smaller collapse onto a handful of levels, often just zero.
مع scale واحد لكل tensor، تكون أكبر وزن في الطبقة كلها. إذا كانت قناة خرج واحدة تحمل هذه القيمة الشاذة، فإن مداها يفرض حجم الخطوة على كل القنوات. القنوات ذات الأوزان الأصغر بكثير تنهار إلى عدد قليل من المستويات، وغالبًا إلى الصفر وحده.
The lecture’s evidence is the box plot from Nagel et al.: the per-output-channel weight ranges of the first depthwise-separable layer in MobileNetV2. Most of the 32 channels sit within a few units of zero, while a few stretch to around ±50 to ±100. The lecture’s summary:
دليل المحاضرة هو مخطط الصندوق (box plot) من Nagel et al.: مديات الأوزان لكل قناة خرج في أول طبقة depthwise-separable في MobileNetV2. معظم القنوات الـ 32 تقع في حدود وحدات قليلة حول الصفر، بينما يمتد بعضها إلى نحو ±50 حتى ±100. خلاصة المحاضرة:
- Per-tensor quantization works well for large models but accuracy drops for small models.تكميم per-tensor يعمل جيدًا للنماذج الكبيرة لكن الدقة تنخفض في النماذج الصغيرة.
- The common failure is a large difference, more than 100×, in weight ranges across output channels, caused by outlier weights.الفشل الشائع هو فرق كبير، أكثر من 100×، في مديات الأوزان بين قنوات الخرج، تسببه الأوزان الشاذة.
- The solution is per-channel quantization.الحل هو تكميم per-channel.
The numbers in the paper are stark. MobileNetV2 reaches 71.72% top-1 on ImageNet in FP32. With plain per-tensor INT8 it drops to 0.12%, essentially random guessing; with per-channel INT8 it keeps 70.65%. Depthwise layers are the worst offenders because each output channel has only a few weights (3 × 3 = 9), so one channel can drift far from the others, and folding batch normalization into the weights amplifies the imbalance (Nagel et al., 2021). Large models like ResNets have many weights per channel and smoother ranges, which is why per-tensor survives there.
الأرقام في الورقة صارخة. يصل MobileNetV2 إلى دقة top-1 قدرها 71.72% على ImageNet بدقة FP32. ومع تكميم INT8 عادي من نوع per-tensor تهبط إلى 0.12%، أي ما يعادل التخمين العشوائي؛ ومع INT8 من نوع per-channel تحافظ على 70.65%. طبقات الـ depthwise هي أسوأ المتسببين لأن كل قناة خرج فيها لا تملك إلا أوزانًا قليلة (3 × 3 = 9)، فيمكن لقناة واحدة أن تبتعد كثيرًا عن الأخرى، كما أن دمج الـ batch normalization في الأوزان يضخّم هذا التفاوت (Nagel et al., 2021). أما النماذج الكبيرة مثل ResNets فلديها أوزان كثيرة في كل قناة ومديات أكثر انتظامًا، ولهذا ينجو الـ per-tensor هناك.
Quick checkاختبار سريع
In the lecture's 2-bit symmetric scheme, which integer codes can a quantized weight take?في طريقة المحاضرة المتماثلة بـ 2 bit، ما الرموز الصحيحة التي يمكن أن يأخذها وزن مكمَّم؟
Now the lecture’s example, done by hand. Rows are output channels (oc), columns are input channels (ic), and we quantize to N = 2 bits with one scale.
الآن مثال المحاضرة، محلولًا باليد. الصفوف هي قنوات الخرج (oc)، والأعمدة هي قنوات الدخل (ic)، ونكمّم إلى N = 2 bits بـ scale واحد.
Worked exampleمثال محلول
Per-tensor, 2-bit symmetricPer-tensor، تكميم متماثل بـ 2 bit
Find the rangeأوجد المدى
The largest magnitude anywhere in W is 2.12 (row oc1, last column), so |r|_max = 2.12.أكبر قيمة مطلقة في أي مكان من W هي 2.12 (الصف oc1، العمود الأخير)، إذن |r|_max = 2.12.Compute the scaleاحسب الـ scale
Divide and roundاقسم وقرّب
Divide every weight by 2.12 and round to the nearest integer in [-1, 1]. Anything with |W| < 1.06 (half a step) becomes 0. So 2.09 / 2.12 = 0.986 → 1, 1.48 / 2.12 = 0.698 → 1, -0.98 / 2.12 = -0.462 → 0, -1.08 / 2.12 = -0.509 → -1 (just past half a step), and -1.03 / 2.12 = -0.486 → 0 (just short of it).اقسم كل وزن على 2.12 وقرّبه إلى أقرب عدد صحيح في [-1, 1]. أي وزن فيه |W| < 1.06 (نصف خطوة) يصبح 0. لذلك 2.09 / 2.12 = 0.986 → 1، و1.48 / 2.12 = 0.698 → 1، و-0.98 / 2.12 = -0.462 → 0، و-1.08 / 2.12 = -0.509 → -1 (تجاوز نصف الخطوة بقليل)، و-1.03 / 2.12 = -0.486 → 0 (قصُر عنها بقليل).Reconstructأعد البناء
Multiply back by S: every nonzero code becomes ±2.12.اضرب مرة أخرى في S: كل رمز غير صفري يصبح ±2.12.Measure the errorقِس الخطأ
Sum the squared differences over all 16 entries, then take the square root (the Frobenius norm). The biggest contributors are the weights zeroed out (-0.98, -0.91, -1.03) and the small positives pushed up to 2.12 (1.48, 1.53, 1.49).اجمع مربعات الفروق على المدخلات الـ 16 كلها، ثم خذ الجذر التربيعي (معيار فروبينيوس، Frobenius norm). أكبر المساهمين هم الأوزان التي صُفّرت (-0.98 و-0.91 و-1.03) والقيم الموجبة الصغيرة التي دُفعت إلى 2.12 (1.48 و1.53 و1.49).Resultالنتيجة
S = 2.12, codes only in {-1, 0, 1}, error ‖W - Sq‖_F = 2.28.S = 2.12، والرموز فقط في {-1, 0, 1}، والخطأ ‖W - Sq‖_F = 2.28.
Recall
Without looking back: what is S for this matrix under 2-bit per-tensor quantization, and why is it equal to |r|_max?دون النظر إلى ما سبق: ما قيمة S لهذه المصفوفة في تكميم per-tensor بـ 2 bit، ولماذا تساوي |r|_max؟
S = 2.12. Because q_max = 2^(2-1) - 1 = 1, dividing |r|_max by 1 leaves it unchanged. At 8 bits the same matrix would give S = 2.12 / 127 ≈ 0.0167.
S = 2.12. لأن q_max = 2^(2-1) - 1 = 1، فقسمة |r|_max على 1 تتركها كما هي. وعند 8 bits تعطي المصفوفة نفسها S = 2.12 / 127 ≈ 0.0167.
Quick checkاختبار سريع
Under 2-bit per-tensor quantization with S = 2.12, which code does the weight -1.03 receive?في تكميم per-tensor بـ 2 bit مع S = 2.12، ما الرمز الذي يأخذه الوزن -1.03؟
Same matrix, same 2 bits, but now each output channel (each row) gets its own scale. With q_max = 1, each scale is simply that row’s largest magnitude.
المصفوفة نفسها، و2 bits نفسها، لكن الآن تحصل كل قناة خرج (كل صف) على scale خاص بها. ومع q_max = 1، يكون كل scale ببساطة أكبر قيمة مطلقة في ذلك الصف.
Worked exampleمثال محلول
Per-channel, 2-bit symmetricPer-channel، تكميم متماثل بـ 2 bit
One range per rowمدى واحد لكل صف
oc0: |r|_max = 2.09, so S_0 = 2.09. oc1: 2.12, so S_1 = 2.12. oc2: 1.92, so S_2 = 1.92. oc3: 1.87, so S_3 = 1.87. Only oc1 keeps the per-tensor scale, because it is the row that holds the global maximum.oc0: |r|_max = 2.09، إذن S_0 = 2.09. oc1: 2.12، إذن S_1 = 2.12. oc2: 1.92، إذن S_2 = 1.92. oc3: 1.87، إذن S_3 = 1.87. وحده oc1 يحتفظ بالـ scale نفسه الذي في per-tensor، لأنه الصف الذي يحمل القيمة العظمى الكلية.Divide each row by its own scaleاقسم كل صف على الـ scale الخاص به
Most codes do not change. The one that does is in oc2: -1.03 / 1.92 = -0.536 → -1, where per-tensor gave -1.03 / 2.12 = -0.486 → 0. Shrinking the step from 2.12 to 1.92 pushed it just past half a step.معظم الرموز لا تتغير. الرمز الذي يتغير موجود في oc2: -1.03 / 1.92 = -0.536 → -1، بينما أعطى per-tensor القيمة -1.03 / 2.12 = -0.486 → 0. تصغير الخطوة من 2.12 إلى 1.92 دفعه إلى ما بعد نصف الخطوة بقليل.Reconstruct row by rowأعد البناء صفًا صفًا
Each row is multiplied by its own scale, written .يُضرب كل صف في الـ scale الخاص به، ونكتب ذلك .Measure the errorقِس الخطأ
Resultالنتيجة
Per-channel error 2.08 is below per-tensor 2.28, with one code changed.خطأ per-channel البالغ 2.08 أقل من خطأ per-tensor البالغ 2.28، مع تغيّر رمز واحد فقط.
Where did the improvement come from? Not only from the one flipped code. Break the squared error down by row:
من أين جاء التحسّن؟ ليس فقط من الرمز الواحد الذي انقلب. فكّك الخطأ المربّع حسب الصف:
| Channelالقناة | Per-tensor SS في per-tensor | Per-tensor squared errorالخطأ المربّع في per-tensor | Per-channel S_iS_i في per-channel | Per-channel squared errorالخطأ المربّع في per-channel |
|---|---|---|---|---|
| oc0oc0 | 2.122.12 | 1.3791.379 | 2.092.09 | 1.3411.341 |
| oc1oc1 | 2.122.12 | 1.1041.104 | 2.122.12 | 1.1041.104 |
| oc2oc2 | 2.122.12 | 1.9291.929 | 1.921.92 | 1.6201.620 |
| oc3oc3 | 2.122.12 | 0.8080.808 | 1.871.87 | 0.2600.260 |
| Totalالمجموع | 5.219 → √ = 2.285.219 → √ = 2.28 | 4.32 → √ = 2.084.32 → √ = 2.08 |
oc3 gains the most, and none of its codes changed: its nonzero weights 1.87, 1.53, 1.49 are now reconstructed as 1.87 instead of 2.12, much closer. oc2 gains from the flipped code (error on that entry falls from 1.03 to |-1.03 + 1.92| = 0.89) and from 1.92 now being exact. oc1 is unchanged because its scale is unchanged. The lesson: a smaller, better-fitted scale helps both by moving values onto nonzero codes and by placing the levels closer to the values.
oc3 يستفيد أكثر من غيره، ولم يتغير أي من رموزه: أوزانه غير الصفرية 1.87, 1.53, 1.49 يُعاد بناؤها الآن كـ 1.87 بدل 2.12، وهذا أقرب بكثير. ويستفيد oc2 من الرمز المنقلب (ينخفض الخطأ في ذلك المدخل من 1.03 إلى |-1.03 + 1.92| = 0.89) ومن أن 1.92 أصبحت الآن دقيقة تمامًا. أما oc1 فلا يتغير لأن الـ scale الخاص به لم يتغير. الدرس: الـ scale الأصغر والأكثر ملاءمة يساعد بطريقتين: بنقل القيم إلى رموز غير صفرية، وبوضع المستويات أقرب إلى القيم.
Recall
Compute -0.91 / 1.92 and round it. Does the first weight of oc2 change code under per-channel quantization?احسب -0.91 / 1.92 وقرّبه. هل يتغير رمز الوزن الأول في oc2 في تكميم per-channel؟
-0.91 / 1.92 = -0.474, which rounds to 0, the same as per-tensor (-0.91 / 2.12 = -0.429 → 0). A near miss: it would need |W| ≥ 0.96 to reach code -1. So in oc2 only -1.03 flips.
-0.91 / 1.92 = -0.474، ويُقرَّب إلى 0، تمامًا كما في per-tensor (-0.91 / 2.12 = -0.429 → 0). كاد أن يتغير: كان سيحتاج إلى |W| ≥ 0.96 ليصل إلى الرمز -1. لذلك في oc2 لا ينقلب إلا -1.03.
Try it live. Switch between the two schemes and watch the highlighted cell; then change the bit width. At 3 and 4 bits per-channel is actually a hair worse on this particular matrix (0.710 versus 0.699 at 3 bits), because its row ranges are almost equal (1.87 to 2.12) and which side of a rounding boundary each value lands on is partly luck. Per-channel wins reliably when ranges differ a lot, which is exactly the MobileNetV2 situation.
جرّبه مباشرة. بدّل بين الطريقتين وراقب الخلية المظلَّلة، ثم غيّر عدد البتات. عند 3 و4 bits يكون per-channel في الواقع أسوأ بفارق ضئيل على هذه المصفوفة بالذات (0.710 مقابل 0.699 عند 3 bits)، لأن مديات صفوفها متساوية تقريبًا (من 1.87 إلى 2.12)، وفي أي جانب من حد التقريب تقع كل قيمة هو جزئيًا مسألة حظ. يفوز per-channel بشكل موثوق عندما تختلف المديات كثيرًا، وهذا بالضبط وضع MobileNetV2.
Why output channels, not input channelsلماذا قنوات الخرج وليس قنوات الدخل
The slides draw the scale arrows along rows, the output channels, and the convolution picture boxes the filter dimension c_o. That is not arbitrary; it is what keeps integer arithmetic possible. Output i of a layer is a dot product over the inputs j. Write the weights as S_i q_ij and the activations as s_x x_j with integer x_j:
ترسم الشرائح أسهم الـ scale على طول الصفوف، أي قنوات الخرج، وصورة الالتفاف تؤطّر بُعد المرشح c_o. هذا ليس اعتباطيًا؛ بل هو ما يُبقي الحساب بالأعداد الصحيحة ممكنًا. الخرج i لطبقة ما هو جداء نقطي (dot product) على المدخلات j. اكتب الأوزان على شكل S_i q_ij والتنشيطات (activations) على شكل s_x x_j حيث x_j عدد صحيح:
Because S_i is the same for every term of the sum, the hardware accumulates Σ_j q_ij x_j in an integer register and applies one multiplication by S_i s_x at the end, a step it already performs per output anyway. If the scale instead varied with the input index j, it would sit inside the sum, and every product would need its own rescale before being added, destroying the point of integer accumulation. The same argument is why per-channel scales on activations are hard: an activation scale per input channel cannot be pulled out of the summation (Nagel et al., 2021). This is also why TensorFlow Lite quantizes convolution weights per axis along the output channel dimension.
لأن S_i هو نفسه في كل حد من حدود المجموع، يراكم العتاد Σ_j q_ij x_j في مسجّل (register) للأعداد الصحيحة ثم يطبّق عملية ضرب واحدة في S_i s_x في النهاية، وهي خطوة يؤديها أصلًا لكل خرج على أي حال. لو كان الـ scale يتغيّر بدلًا من ذلك مع فهرس الدخل j، لبقي داخل المجموع، ولاحتاج كل حاصل ضرب إلى إعادة قياس خاصة به قبل جمعه، مما يُفقد المراكمة بالأعداد الصحيحة فائدتها. والحجة نفسها هي سبب صعوبة مقاييس per-channel على التنشيطات: لا يمكن إخراج scale تنشيط خاص بكل قناة دخل من المجموع (Nagel et al., 2021). ولهذا أيضًا يكمّم TensorFlow Lite أوزان الالتفاف لكل محور (per axis) على طول بُعد قناة الخرج.
Quick checkاختبار سريع
Why are per-channel weight scales taken over output channels rather than input channels?لماذا تؤخذ مقاييس الأوزان per-channel على قنوات الخرج وليس على قنوات الدخل؟
Recapالخلاصة
If you remember nothing elseإن لم تتذكر شيئاً آخر فتذكّر هذا
- PTQ takes a trained floating-point model and picks (S, Z) without retraining. The lecture splits the choice into granularity, dynamic range clipping and rounding.يأخذ PTQ نموذجًا مدرّبًا بالفاصلة العائمة ويختار (S, Z) دون إعادة تدريب. تقسّم المحاضرة هذا الاختيار إلى granularity وdynamic range clipping وrounding.
- Symmetric weight quantization: Z = 0, |r|_max = |W|_max, S = |r|_max / q_max with q_max = 2^(N-1) - 1, and q = clip(round(W / S)).تكميم الأوزان المتماثل: Z = 0، و|r|_max = |W|_max، وS = |r|_max / q_max حيث q_max = 2^(N-1) - 1، وq = clip(round(W / S)).
- For N = 2, q_max = 1, so only the codes -1, 0, 1 appear. The code -2 exists in two's complement but the restricted symmetric grid never uses it.عند N = 2 تكون q_max = 1، فلا تظهر إلا الرموز -1 و0 و1. الرمز -2 موجود في تمثيل two's complement لكن الشبكة المتماثلة المقيّدة لا تستخدمه أبدًا.
- Per-tensor uses one S for the whole tensor. It works for large models but fails on small ones whose output channel ranges differ by more than 100x (the lecture's figure; MobileNetV2 evidence from Nagel et al. 2019).يستخدم per-tensor قيمة S واحدة للـ tensor كله. ينجح مع النماذج الكبيرة لكنه يفشل مع الصغيرة التي تختلف مديات قنوات الخرج فيها بأكثر من 100x (شكل المحاضرة، ودليل MobileNetV2 من Nagel et al. 2019).
- Per-channel gives output channel i its own S_i = max_j |W_ij| / q_max, so an outlier channel no longer inflates the step size of every other channel.يعطي per-channel قناة الخرج i قيمة خاصة بها S_i = max_j |W_ij| / q_max، فلا تعود القناة الشاذة تضخّم حجم الخطوة لكل قناة أخرى.
- Worked example: per-tensor S = 2.12, error ||W - S q||_F = 2.28. Per-channel S = (2.09, 2.12, 1.92, 1.87), one code changes (-1.03 goes from 0 to -1), error 2.08.المثال المحلول: في per-tensor تكون S = 2.12 والخطأ ||W - S q||_F = 2.28. وفي per-channel تكون S = (2.09, 2.12, 1.92, 1.87)، ويتغيّر رمز واحد (-1.03 ينتقل من 0 إلى -1)، والخطأ 2.08.
- Scales must sit on output channels because y_i = S_i s_x Σ_j q_ij x_j: the scale factors out of the integer dot product, so accumulation stays in integers.يجب أن تكون المقاييس على قنوات الخرج لأن y_i = S_i s_x Σ_j q_ij x_j: الـ scale يخرج كعامل مشترك من الجداء النقطي الصحيح، فتبقى المراكمة بالأعداد الصحيحة.
Sourcesالمصادر
- Data-Free Quantization Through Weight Equalization and Bias CorrectionPaperNagel, van Baalen, Blankevoort, Welling, ICCV 2019Source of the MobileNetV2 per-channel weight range box plot, the [-128, 128] versus (-0.5, 0.5) example, and the 71.72% / 0.12% / 70.65% results.مصدر مخطط الصندوق لمديات أوزان MobileNetV2 لكل قناة، ومثال [-128, 128] مقابل (-0.5, 0.5)، والنتائج 71.72% / 0.12% / 70.65%.(opens in a new tab)(يفتح في تبويب جديد)
- A White Paper on Neural Network QuantizationPaperNagel et al., Qualcomm AI Research, 2021Sections 2.2.3 and 2.4.2: granularity, why per-channel weight scales need no rescaling, and why per-channel activations are hard.القسمان 2.2.3 و2.4.2: مستويات الدقة (granularity)، ولماذا لا تحتاج مقاييس الأوزان per-channel إلى إعادة قياس، ولماذا يصعب تطبيق per-channel على التنشيطات.(opens in a new tab)(يفتح في تبويب جديد)
- Quantizing deep convolutional networks for efficient inference: A whitepaperPaperKrishnamoorthi, Google, 2018Per-channel weights with per-layer activations at 8 bits stay within 2% of floating point post-training.الأوزان per-channel مع تنشيطات per-layer عند 8 bits تبقى ضمن 2% من دقة الفاصلة العائمة بعد التدريب.(opens in a new tab)(يفتح في تبويب جديد)
- Quantization and Training of Neural Networks for Efficient Integer-Arithmetic-Only InferencePaperJacob et al., CVPR 2018The integer-only inference scheme behind r = S(q - Z), cited on slide 7.طريقة الاستدلال بالأعداد الصحيحة فقط التي تقوم عليها r = S(q - Z)، والمذكورة في الشريحة 7.(opens in a new tab)(يفتح في تبويب جديد)
- LiteRT 8-bit quantization specificationDocsGoogle AI EdgeWeights are symmetric int8 in [-127, 127] with zero point 0, quantized per axis along the output channel.الأوزان int8 متماثلة في [-127, 127] ونقطة الصفر 0، وتُكمَّم لكل محور (per axis) على طول قناة الخرج.(opens in a new tab)(يفتح في تبويب جديد)
- TinyML and Efficient Deep Learning Computing (6.5940), Quantization Part IIDocsMIT Han LabThe course these slides are adapted from.المقرر الذي اقتُبست منه هذه الشرائح.(opens in a new tab)(يفتح في تبويب جديد)