Inference کو سستا بنانا: KV cache، Batching اور Quantization
ایک ہی model کا ایک ہی جواب 8.8 اور 78.9 سیکنڈ میں؛ output یکساں۔ پھر INT4 کو تین طریقوں سے ناپا، صرف دعویٰ نہیں۔
اس صفحے پر
وہی model، اسی مشین پر، اسی سوال کا جواب انہی 48 tokens کے ساتھ دے رہا ہے۔ دونوں outputs token بہ token identical ہیں — جانچا گیا، فرض نہیں کیا گیا۔
with a key-value cache: 8.85 s ( 6.01 tokens/second)
without a key-value cache: 78.95 s ( 0.60 tokens/second)صرف ایک argument بدلا: use_cache=False۔ model، prompt، sampling یا arithmetic میں کچھ بھی مختلف نہیں، اور دوسری run اپنی مشقت کے بدلے زیادہ درست بھی نہیں۔ وہ بلاوجہ نو گنا سست ہے۔
یہی اس chapter کی شکل ہے۔ اس میں موجود ہر چیز — cache، batch، quantized weights — یا تو اس کام کی قیمت دوبارہ نہ دینے کی کوشش ہے جو جواب کو بدلتا نہیں، یا یہ جاننے کی کہ سستا جواب کس قیمت پر آتا ہے۔ Chapter 10 نے training کی price list قائم کی تھی۔ یہ اس side کی price list ہے جس کی قیمت آپ ہمیشہ دیتے رہتے ہیں: deployed model اپنی زندگی کے باقی حصے میں ہر request پر، ہر emitted token کے لیے تقریباً FLOPs خرچ کرتا ہے۔
دوسری run کا وقت کہاں گیا
اس حصے کا لنک: دوسری run کا وقت کہاں گیاایک token generate کرنے کے لیے decoder-only transformer اب تک کی پوری sequence لیتا ہے، اسے ہر layer سے گزارتا ہے، اور آخری position سے probability distribution پڑھتا ہے۔ پھر وہ منتخب token append کرتا ہے اور دوبارہ یہی کرتا ہے۔ یہ description درست ہے، اور slow run یہی کرتی ہے۔
یہ غیر معمولی حد تک wasteful بھی ہے، اور وجہ Chapter 9 کا causal mask ہے۔ position 7 کے key اور value vectors position 7 کے input اور اس سے پہلے والی positions سے compute ہوتے ہیں۔ جب position 8 آتی ہے، position 7 اسے دیکھ نہیں سکتی — causal کا یہی مطلب ہے — اس لیے position 7 کے key اور value بالکل وہی numbers رہتے ہیں جو پہلے تھے۔ slow run پھر بھی انہیں ہر step پر دوبارہ compute کرتی ہے۔
تو انہیں store کر لیں۔ یہ store key-value cache ہے، language model serving میں سب سے زیادہ consequential optimisation:
out = model(prompt_ids, use_cache=True) # prefill: the whole prompt
past = out.past_key_values
nxt = out.logits[:, -1].argmax(-1, keepdim=True)
for _ in range(n - 1):
out = model(nxt, past_key_values=past, use_cache=True)
past = out.past_key_values
nxt = out.logits[:, -1].argmax(-1, keepdim=True)دیکھیں loop کے اندر model کو کیا feed کیا جاتا ہے: nxt، ایک token۔ sequence نہیں۔ نئے token کا query ہر cached key کے خلاف attend کرتا ہے، اور cached keys بدلنے والی تھیں ہی نہیں۔ یہ approximation نہیں — اوپر identical-output check کا یہی مقصد ہے۔ cache quality کو speed کے بدلے trade نہیں کرتا؛ یہ redundant arithmetic حذف کرتا ہے۔
scaling صاف دیکھنے کے لیے transformer کو الگ کریں اور کے ساتھ ایک single attention head کو time کریں، generation کا ایک step دونوں طریقوں سے compute کر کے:
| context میں tokens | سب کچھ recompute | cache کے ساتھ | ratio | score matrix |
|---|---|---|---|---|
| 128 | 0.59 ms | 0.062 ms | 10x | 65,536 B vs 512 B |
| 256 | 1.20 ms | 0.163 ms | 7x | 262,144 B vs 1,024 B |
| 512 | 7.03 ms | 0.078 ms | 90x | 1,048,576 B vs 2,048 B |
| 1024 | 17.31 ms | 0.114 ms | 152x | 4,194,304 B vs 4,096 B |
| 2048 | 59.83 ms | 0.214 ms | 279x | 16,777,216 B vs 8,192 B |
| 4096 | 236.18 ms | 0.284 ms | 832x | 67,108,864 B vs 16,384 B |
دائیں طرف والا column وجہ ہے۔ recomputing ہر step پر مکمل attention matrix بناتی ہے — Chapter 9 کے asymptotic-notation box کا ، ہر token کے لیے ایک بار ادا کیا گیا۔ cache کے ساتھ آپ اس کے بجائے row بناتے ہیں: 4,096 tokens پر scores کے 67 MB کے مقابلے میں 16 KB۔
milliseconds کے بجائے multiply-accumulates گننے سے machine argument سے نکل جاتی ہے۔ cold start سے tokens generate کرنے کے لیے:
| generated tokens | cache کے ساتھ | recomputing | ratio |
|---|---|---|---|
| 128 | 2.6 M | 192.0 M | 73x |
| 512 | 23.1 M | 7.36 G | 318x |
| 2048 | 293.7 M | 392.6 G | 1,336x |
ہر step پر cached version context میں linear ہے اور uncached version quadratic؛ پوری generation پر جمع کریں تو کے مقابلے میں ، ratio بغیر حد کے بڑھتا ہے۔ opening میں نو گنا فرق 48 tokens پر measure کیا گیا تھا — اس table کی پہلی row سے بھی کم۔
cache یہ بھی بدلتا ہے کہ memory میں کیا ہونا ضروری ہے۔ 8 GB laptop GPU پر fp16 میں 256 tokens generate کرتے ہوئے، allocator کی peak سے resident weights subtract کرنے پر:
| peak working memory | |
|---|---|
| cache کے ساتھ | 21.8 MB |
| recomputing | 181.7 MB |
8.3 گنا زیادہ memory، انہی tokens کو زیادہ آہستہ produce کرنے کے لیے خرچ ہوئی۔ یہ Chapter 5 میں کیا گیا وعدہ ہے، مگر ایک unexpected direction سے آتا ہوا: وہاں reverse-mode autodiff کو backward pass کے لیے ہر intermediate کو alive رکھنا پڑتا تھا، اور activations training memory پر غالب تھیں۔ inference میں backward pass نہیں اور اس کے لیے retain کرنے کو کچھ نہیں — اس لیے memory پر غالب چیز cache ہے، اور یہ unavoidable cost کے بجائے deliberate choice ہے۔
Prefill اور decode دو مختلف machines ہیں
اس حصے کا لنک: Prefill اور decode دو مختلف machines ہیںfast run کو دوبارہ دیکھیں: اس کا پہلا token باقی سینتالیس سے مختلف behave کرتا ہے۔
prefill, 40 prompt tokens : 1.0224 s -> 25.6 ms per token
decode, 47 steps : 0.1665 s mean per stepprompt کی cost 25.6 ms per token تھی اور ہر generated token کی cost 166 ms۔ وہی model، وہی hardware، وہی weights، per token چھ گنا فرق — اور یہ اس سمت جاتا ہے جس کی اکثر لوگ توقع نہیں کرتے۔ prompt سستا حصہ ہے۔ Generation دو phases میں بٹتی ہے جن کی physics واقعی مختلف ہے:
Prefill
اس حصے کا لنک: Prefillپورے prompt پر ایک forward pass۔ ہر token parallel میں process ہوتا ہے، اس لیے ہر weight matrix memory سے ایک بار load ہوتی ہے اور سینکڑوں token vectors کی matrix کے خلاف multiply ہوتی ہے — matrix-matrix product، moved byte کے مقابلے میں بہت arithmetic، یعنی وہ کام جس کے لیے GPU بنا ہے۔ Prefill compute-bound ہے، اور اس کی cost prompt length میں تقریباً linear ہے۔
Decode
اس حصے کا لنک: Decodeہر token کے لیے ایک forward pass، batch of one اور sequence of one۔ ہر weight matrix پھر بھی مکمل طور پر memory سے load ہوتی ہے، اور single vector کے خلاف multiply ہوتی ہے — matrix-vector product، moved byte کے مقابلے میں تقریباً کوئی arithmetic نہیں۔ Decode memory-bandwidth-bound ہے، اور اس کی per token cost context کی length پر مشکل ہی سے depend کرتی ہے۔
دونوں halves measurable ہیں۔ Prefill، tokens پر ایک pass:
| prompt tokens | seconds | ms per token |
|---|---|---|
| 16 | 0.3515 | 21.97 |
| 32 | 0.5254 | 16.42 |
| 64 | 1.0491 | 16.39 |
| 128 | 1.6552 | 12.93 |
| 256 | 3.0965 | 12.10 |
Decode، کے cache کے خلاف ایک token:
| cached tokens | ایک token کے لیے ms |
|---|---|
| 16 | 110.05 |
| 64 | 97.57 |
| 256 | 108.53 |
| 1024 | 103.86 |
دوسری table کو دو بار پڑھیں۔ context کے 16 tokens سے 1,024 تک جانا — attend کرنے کے لیے چونسٹھ گنا زیادہ history — step کی cost کو کسی measurable حد تک نہیں بدلتا۔ cache کے خلاف attention حقیقی کام ہے، مگر ایک vector produce کرنے کے لیے نصف ارب weights کو memory bus سے گھسیٹنے کی fixed cost کے سامنے یہ بہت چھوٹا ہے۔ یہی fixed cost اگلے section میں ہر چیز کی وجہ ہے۔
یہ دو phases ہر serving system کے report کیے گئے دو numbers کی origin ہیں۔ Time to first token essentially prefill ہے، اور یہ prompt کے ساتھ بڑھتا ہے، اسی لیے long conversation شروع ہونے میں سست محسوس ہوتی ہے۔ Tokens per second ہے، اور یہ تقریباً constant ہے، اسی لیے reply پھر برابر flow کرتی ہے۔ ایسی chat جو آہستہ شروع ہو اور پھر smoothly stream کرے، rendering trick نہیں۔ یہ یہی دو tables ہیں۔
cache بھی bill ہے
اس حصے کا لنک: cache بھی bill ہےcache arithmetic کو memory کے بدلے trade کرتا ہے، اور جس memory کی اسے ضرورت ہے وہ چھوٹی نہیں۔ context میں ہر token کے لیے، ہر layer ہر key-value head پر ایک key vector اور ایک value vector رکھتی ہے:
2 keys اور values کے لیے ہے؛ باقی سب architecture ہے۔ اس chapter میں measured model کے لیے — 24 layers، 14 query heads، 2 key-value heads، head dimension 64 — fp16 میں یہ bytes per token ہے۔
اس field میں formulae اکثر factor of two سے غلط نکلتے ہیں، اس لیے اس پر یقین کرنے کے بجائے allocator کے خلاف check کریں:
KV cache tensors per layer: (1, 2, 295, 64) float16
measured: 3,624,960 bytes for 295 tokens = 12,288 bytes/token
formula : 2 * 24 * 2 * 64 * 2 = 12,288 bytes/tokenExact، اور tried ہر shape میں exact رہتا ہے:
| batch | context | measured cache | predicted | peak working memory |
|---|---|---|---|---|
| 1 | 512 | 6.0 MB | 6.0 MB | 15.4 MB |
| 1 | 16,384 | 192.0 MB | 192.0 MB | 207.3 MB |
| 1 | 65,536 | 768.0 MB | 768.0 MB | 793.7 MB |
| 8 | 4,096 | 384.0 MB | 384.0 MB | 401.5 MB |
| 32 | 2,048 | 768.0 MB | 768.0 MB | 794.2 MB |
| 64 | 1,024 | 768.0 MB | 768.0 MB | 797.0 MB |
| 128 | 512 | 768.0 MB | 768.0 MB | 816.4 MB |
آخری تین rows دوبارہ دیکھنے کے قابل ہیں۔ 2,048 tokens each کے ساتھ بتیس users، 1,024 کے ساتھ چونسٹھ، 512 کے ساتھ ایک سو اٹھائیس — cache ہر case میں 768 MB ہے، کیونکہ تینوں میں 65,536 tokens resident ہیں۔ cache صرف resident tokens کی total number پر depend کرتا ہے، اس پر نہیں کہ وہ users میں کیسے distributed ہیں۔ یہی fact batching section کی foundation ہے۔
MQA اور GQA کہاں سے آتے ہیں
اس حصے کا لنک: MQA اور GQA کہاں سے آتے ہیںChapter 9 نے multi-query اور grouped-query attention introduce کیا اور وجہ اس chapter تک defer کی۔ وجہ وہ formula ہے، اور خاص طور پر اس میں ۔
Standard multi-head attention ہر query head کو اپنے key اور value heads دیتا ہے۔ یہاں model کے 14 query heads ہیں؛ full multi-head attention کے ساتھ اس کا cache bytes per token ہوتا — 12 KB کے بجائے 84 KB، بالکل سات گنا زیادہ، query heads اور key-value heads کے ratio کے برابر۔
Multi-query attention1 اسے حد تک لے جاتا ہے: تمام query heads ایک single key-value head share کرتے ہیں۔ Grouped-query attention2 وہ compromise ہے جو جیتا — کچھ key-value heads، جن میں ہر ایک query heads کے group سے shared — کیونکہ MQA کی quality loss real تھی اور GQA کی نہیں۔ دونوں arithmetic نہیں خریدتے۔ وہ اس formula کو integer سے divide کرنے کے لیے موجود ہیں، اور long contexts نے cache کو binding constraint بنایا تو یہ پوری industry میں پھیل گئے۔
اور یہ جلدی ہوتا ہے۔ 32 layers اور dimension 128 کے 8 key-value heads والے 7B-class model کے لیے، fp16 میں cache 128 KB per token ہے:
| context tokens | ایک user | 8 users | 64 users |
|---|---|---|---|
| 4,000 | 0.49 GB | 3.91 GB | 31.2 GB |
| 32,000 | 3.91 GB | 31.25 GB | 250.0 GB |
| 128,000 | 15.62 GB | 125.00 GB | 1,000.0 GB |
| 1,000,000 | 122.07 GB | 976.56 GB | 7,812.5 GB |
اس model کے اپنے weights fp16 میں 13.0 GB ہیں، chapter کے آخر کی table والا figure۔ تو 128,000-token context پر، ایک user کا cache model سے بڑا ہے۔ یہی arithmetic Chapter 16 money میں بدلتا ہے، اور یہی وجہ ہے کہ long conversation محض slow نہیں ہوتی — وہ request alive رہنے تک machine کا ایک fixed slice occupy کرتی ہے۔
Batching: وہ number جو اوپر جاتا ہے اور وہ جو نیچے جاتا ہے
اس حصے کا لنک: Batching: وہ number جو اوپر جاتا ہے اور وہ جو نیچے جاتا ہےDecode memory-bound ہے: weights bus سے گھسیٹے جاتے ہیں تاکہ ایک token produce ہو، اور arithmetic units idle رہتے ہیں۔ تو اسی step میں زیادہ work ڈالیں۔ کئی requests ایک ساتھ run کریں، اور weights، ایک بار read ہو کر، ان سب کو serve کریں۔ اسی model پر measured، ہر request 64-token cache رکھتی ہوئی اور ایک token decode کرتی ہوئی:
| batch | latency per step | throughput | latency vs B=1 |
|---|---|---|---|
| 1 | 0.1286 s | 7.78 tok/s | 1.00x |
| 2 | 0.1839 s | 10.88 tok/s | 1.43x |
| 4 | 0.1909 s | 20.95 tok/s | 1.49x |
| 8 | 0.2781 s | 28.76 tok/s | 2.16x |
| 16 | 0.3430 s | 46.64 tok/s | 2.67x |
| 32 | 0.6302 s | 50.78 tok/s | 4.90x |
دائیں طرف کے دونوں columns کو ایک دوسرے کے مقابل پڑھیں، کیونکہ یہی اصل بات ہے۔ ایک request سے سولہ تک جانا throughput کو 6.0 سے multiply کرتا ہے اور کسی individual request کے wait کو 2.67 سے multiply کرتا ہے۔ batch نے server کو بہتر اور ہر user کو بدتر بنایا۔
یہ کوئی bug نہیں جسے tune کر کے ختم کیا جائے؛ یہی trade ہے، اور دونوں sides پر اس کے نام ہیں۔ Latency وہ ہے جو reply کا انتظار کرتا انسان experience کرتا ہے۔ Throughput وہ ہے جس سے invoice divide ہوتا ہے۔ کوئی setting دونوں کو بہتر نہیں کرتی۔
یہ بھی نوٹ کریں کہ یہ کہاں رک جاتا ہے۔ 16 سے 32 تک، throughput 9 % gain کرتا ہے جبکہ latency تقریباً double ہو جاتی ہے: step memory-bound رہنا چھوڑ کر compute-bound ہو چکا ہے، اور اس knee کے بعد batch کچھ نہیں خریدتا۔ ہر deployment میں ایسا knee ہوتا ہے؛ اس کی location آپ کے setup پر measure کرنی پڑتی ہے، مگر اس کا existence نہیں۔
Static batching اپنی جیتی ہوئی زیادہ تر چیز waste کر دیتی ہے
اس حصے کا لنک: Static batching اپنی جیتی ہوئی زیادہ تر چیز waste کر دیتی ہےbatch کرنے کا naive طریقہ یہ ہے کہ requests collect کریں، انہیں together run کریں، اور جب سب done ہوں تو return کریں۔ مگر وہ together finish نہیں ہوتیں: کچھ replies بیس tokens کی ہیں اور کچھ پانچ سو کی۔ fixed batch اپنے longest member کے finish ہونے تک چلتا ہے، اور ہر finished request تب تک اپنی slot occupy کرتی رہتی ہے، padding contribute کرتی ہوئی۔
64 requests لیں جن کی output lengths میں realistic skew ہو — median 18 tokens، longest 231، total 1,874 — اور آٹھ slots کے measured per-step cost پر دونوں policies simulate کریں:
| policy | wall clock | throughput | mean latency per request | wasted slot-steps |
|---|---|---|---|---|
| static batches of 8 | 176.9 s | 10.6 tok/s | 83.2 s | 3,214 |
| continuous, 8 slots | 109.0 s | 17.2 tok/s | 8.1 s | 0 |
Throughput 1.6x بہتر ہوتا ہے۔ Mean latency دس گنا سے زیادہ بہتر ہوتی ہے، کیونکہ static batching کے تحت ایک request جو چار steps میں finish ہوئی تھی، پھر بھی 231-token neighbour کا انتظار کرتی ہے اس سے پہلے کہ کوئی اسے سن سکے۔
Continuous batching3 fix ہے، اور یہ اتنی ہی simple ہے جتنی سنائی دیتی ہے: batch کوئی group نہیں بلکہ slots کا set ہے، اور جو slot free ہو وہ اگلے ہی step پر next queued request admit کر لیتی ہے۔ scheduler ایک request کے بجائے ایک token کی granularity پر کام کرتا ہے۔ production میں ہر serving stack اب یہی کرتا ہے۔
اس کا دوسرا half cache ہے۔ آتی جاتی slots cache memory کو fragmented چھوڑتی ہیں، اور ہر slot کے maximum possible context کو reserve کرنا reservation کا زیادہ تر حصہ waste کرتا ہے۔ PagedAttention4 operating systems سے جواب ادھار لیتا ہے: cache کو fixed-size blocks میں store کریں، ہر sequence کے لیے block table کے ساتھ، تاکہ sequence کا cache physically scattered ہو سکتا ہے مگر logically contiguous رہے — جس سے shared prefix والی دو sequences اسے hold کرنے والے blocks بھی share کر سکتی ہیں۔ vLLM اسی پر built ہے، اور اسی لیے serving engine دراصل transformer attached ایک memory allocator ہے۔
Quantization، اور پہلی چیز جو خراب ہوتی ہے
اس حصے کا لنک: Quantization، اور پہلی چیز جو خراب ہوتی ہےbill کا دوسرا half weights themselves ہیں۔ نصف ارب parameters چار bytes each پر 1.98 GB ہیں؛ دو bytes پر 0.99 GB؛ ایک byte پر 0.49 GB۔ ہر weight کے fewer bits model کو disk پر چھوٹا کرتے ہیں، memory میں چھوٹا کرتے ہیں، اور — چونکہ decode bandwidth-bound ہے — ہر step کو faster بناتے ہیں، کیونکہ move کرنے کے لیے bytes کم ہیں۔
سب سے simple scheme symmetric absolute-maximum quantization ہے، اور یہ تین lines میں fit ہوتی ہے:
qmax = 2 ** (bits - 1) - 1
scale = W.abs().max() / qmax
Wq = torch.round(W / scale).clamp(-qmax - 1, qmax)
W_hat = Wq * scale # dequantizedscale چنیں تاکہ largest weight largest integer پر map ہو، divide کریں، round کریں، integers اور scale store کریں۔ reconstruct multiplying back سے کریں۔ اس میں clever کچھ نہیں، اور یہ کام کرتا ہے — عین اس وقت تک جب نہیں کرتا۔
model کے real weights پر measured: تمام 168 projection matrices، 357.8 million parameters، relative error :
| scheme | mean relative error | worst matrix |
|---|---|---|
| INT8، پوری matrix کے لیے ایک scale | 0.0400 | 0.1487 |
| INT8، ہر output row کے لیے ایک scale | 0.0100 | 0.0149 |
| INT4، پوری matrix کے لیے ایک scale | 0.6026 | 0.9931 |
| INT4، ہر output row کے لیے ایک scale | 0.1790 | 0.2589 |
| INT4، 128 کے ہر group کے لیے ایک scale | 0.1323 | 0.1992 |
| NF4، 64 کے ہر block کے لیے ایک scale | 0.0952 | 0.1205 |
| INT3، 128 کے ہر group کے لیے ایک scale | 0.3044 | 0.4123 |
| INT2، 128 کے ہر group کے لیے ایک scale | 0.7790 | 0.8076 |
چوتھی row collapse ہے۔ worst matrix پر 0.99 کا relative error یعنی reconstruction اصل کا تقریباً کچھ بھی retain نہیں کرتی — matrix تقریباً right magnitude کے noise سے replace ہو گئی ہے۔ cause ایک single matrix پر اسی experiment میں visible ہے:
model.layers.12.mlp.down_proj.weight (896 x 4864)
mean |w| 0.01386 std 0.01822 max |w| 0.43945 max/std 24.1
weights beyond 6 sigma: 692 of 4,358,144 (0.016 %)چھ ہزار میں ایک weight چھ standard deviations سے باہر بیٹھا ہے، اور largest 24 out ہے۔ پوری matrix کے لیے single scale کے ساتھ، وہ ایک weight ان تمام 4.3 million weights کے لیے step size set کرتا ہے۔ 8 bits پر 256 steps ہیں اور typical weight پھر بھی meaningful step پر land کرتا ہے۔ 4 bits پر 16 ہیں، outermost ایک ایسی value کے لیے reserved ہے جو تقریباً کسی کے پاس نہیں، اور ordinary weights — یعنی تقریباً سب — دو یا تین distinct levels پر round ہو جاتے ہیں۔
اس row کے بعد ہر چیز مختلف granularities پر یہی repair ہے: scale کو چھوٹا territory دیں۔ per output row error کو 3.4 سے divide کرتی ہے؛ 128 consecutive weights کے per group اسے دوبارہ divide کرتا ہے۔ cost bookkeeping ہے — 128 کے ہر group کے لیے 16-bit scale bits per weight کے بجائے 4 — اور یہ gap کا زیادہ تر حصہ واپس خرید لیتا ہے۔
NF4 دوسری طرف سے حملہ کرتا ہے۔5 levels کا equally spaced ہونا ضروری نہیں۔ block کے اندر weights تقریباً normally distributed ہوتے ہیں، اس لیے سولہ levels کو normal distribution کے quantiles کے طور پر choose کریں: zero کے قریب dense جہاں weights واقعی ہیں، tails میں sparse جہاں وہ نہیں۔ وہی four bits، وہی block scaling، چھوٹے block پر — group-128 کے 4.125 کے مقابلے میں 4.25 bits per weight — اور measured error 0.1323 سے 0.0952 تک گر جاتا ہے، 28 % lower۔ اس کا کچھ حصہ finer block ہے اور باقی mass جہاں ہے وہاں levels رکھنے سے ہے، اور دونوں کو separate کرنے کے لیے third row چاہیے ہو گی۔
outlier features
اس حصے کا لنک: outlier featuresChapter 2 کا floating-point box ایک وعدے پر ختم ہوا تھا: کہ یہ chapter weights کو 8 اور 4 bits پر quantize کرے گا اور چند outlier features پائے گا جو squeezed ہونے سے انکار کریں گے۔ یہ رہے، اور یہ بتاتے ہیں کہ activations پر “بس numbers round کر دو” کبھی کام کیوں نہیں کرنے والا تھا۔
اوپر والے weights badly behaved تھے۔ activations ایک مختلف league میں ہیں۔ ایک ordinary 84-token prompt لیں، ہر layer پر residual stream capture کریں، اور 896 dimensions میں سے ہر dimension کی reached largest magnitude measure کریں:
| layer | largest |h| | median dimension کی largest |h| | ratio | median سے 6x اوپر dimensions |
|---|---|---|---|---|
| 1 | 6.19 | 0.339 | 18x | 2 |
| 4 | 1543.48 | 1.550 | 996x | 34 |
| 8 | 1571.63 | 1.498 | 1049x | 36 |
| 12 | 1575.03 | 1.546 | 1019x | 34 |
| 16 | 1579.60 | 1.617 | 977x | 32 |
| 20 | 1577.98 | 2.361 | 668x | 24 |
| 24 | 204.44 | 10.760 | 19x | 12 |
Dimension 62 1,579.6 تک پہنچتا ہے جبکہ median dimension کبھی 1.6 سے اوپر نہیں جاتا۔ یہ ایک token یا ایک layer کا fluke نہیں: یہی dimension layer 4 پر موجود ہے اور layer 20 پر بھی تقریباً اسی value کے ساتھ موجود ہے۔ یہ outlier features ہیں،6 اور یہ systematic ہیں — trained model کی property، input کی نہیں۔
layer 16 پر ان 896 per-dimension maxima کا histogram shape کو unmistakable بنا دیتا ہے:
0 - 1 | ######################################## 254
1 - 2 | ######################################## 283
2 - 4 | ######################################## 226
4 - 8 | ######################################## 93
8 - 16 | ################## 18
16 - 32 | ######### 9
32 - 64 | ####### 7
64 - 128 | ##### 5
128 - 256 | 0
256 - 512 | 0
512 - 1024 | 0
1024 - 4096 | # 1نو سو dimensions 8 سے نیچے ایک tidy pile میں، تین octaves تک کچھ بھی نہیں، پھر far end پر اکیلی ایک dimension۔ اب اس tensor کو INT8 میں quantize کریں اور گنیں کیا ہوتا ہے:
| scheme | relative error | پورے tensor میں used distinct integer levels |
|---|---|---|
| پورے tensor کے لیے ایک scale | 0.1083 | 14 of 256 |
| ہر token کے لیے ایک scale (per row) | 0.0433 | 158 |
| whole tensor، 1 outlier dimension fp32 میں رکھی گئی | 0.0442 | 48 |
| whole tensor، 4 outlier dimensions fp32 میں رکھی گئیں | 0.0279 | 57 |
| whole tensor، 16 outlier dimensions fp32 میں رکھی گئیں | 0.0085 | 102 |
256 میں سے چودہ levels۔ scale 1,579.6 نے set کیا تھا، اس لیے ہر step 12.44 wide ہے، اور typical activation — median magnitude 0.26، ninety-ninth percentile 2.51 — کے land کرنے کی جگہ نہیں۔ per dimension یہ اور شدید ہے:
single tensor-wide scale = 12.4378
dim 826 (max |h| = 4.77): 1 distinct level out of 256
dim 336 (max |h| = 1.62): 1 distinct level out of 256
dim 96 (max |h| = 0.69): 1 distinct level out of 256
after excluding the top 4 dimensions, scale = 0.5749 (22x smaller)
dim 826: 8 levels dim 336: 4 levels dim 96: 3 levelsایک level۔ پوری dimension، ہر token، ایک ہی number میں quantize ہو گئی۔ آٹھ bits allocate کیے گئے اور تقریباً zero استعمال ہوئے، اور ان activations کو پڑھنے والے model کو constant دیا گیا۔
یہ measurement ہر technique کا justification ہے جو لوگ واقعی استعمال کرتے ہیں:
outliers کو اس سے باہر رکھیں۔ LLM.int8()6 matrix multiply کو decompose کرتا ہے: extreme magnitudes والی dimensions 16 bits میں compute ہوتی ہیں، باقی سب INT8 میں، اور halves summed ہوتے ہیں۔ اوپر کی table receipt ہے — چار dimensions remove کرنے سے error تقریباً چار کے factor سے cut ہوتا ہے۔ SmoothQuant7 اس کے بجائے difficulty migrate کرتا ہے: activations کو per-channel factor سے divide کریں اور matching weight column کو اس سے multiply کریں، جس سے product unchanged رہتا ہے اور outlier اس tensor سے نکل جاتا ہے جو اسے absorb نہیں کر سکتا، اس tensor میں جس میں وہ ہو سکتا ہے۔
rounding choose کریں، صرف round نہ کریں۔ اوپر کچھ بھی یہ نہیں پوچھتا کہ matrix کس کام کے لیے ہے۔ GPTQ8 column by column quantize کرتا ہے اور ہر column کے بعد باقی full-precision columns کو already committed error compensate کرنے کے لیے adjust کرتا ہے — weights کے بجائے real inputs پر layer کے output کے error کو minimise کرتے ہوئے۔ AWQ9 نوٹ کرتا ہے کہ weight channels کا ایک چھوٹا fraction باقی سب سے کہیں زیادہ matter کرتا ہے، انہیں activation statistics سے find کرتا ہے، اور quantizing سے پہلے انہیں scale up کرتا ہے تاکہ وہ finer levels پر land کریں۔ دونوں کو calibration set چاہیے؛ neither needs gradients۔
تفصیلات دکھائیں
GGUF، اور file format کا اس سب سے کیا تعلق ہے۔
GGUF quantization method نہیں؛ یہ وہ container ہے جو llama.cpp استعمال کرتا ہے، اور gguf vs gptq comparisons میں confusion دونوں کو ایک ہی قسم کی چیز سمجھنے سے آتی ہے۔ GGUF tensors، tokenizer، architecture metadata اور chat template کو ایک memory-mappable file میں رکھتا ہے، اور اپنے اندر block schemes کی ایک family لے کر چلتا ہے — Q4_K_M جیسے names bits per weight، block size، اور یہ encode کرتے ہیں کہ کچھ tensors higher precision پر رکھے گئے ہیں یا نہیں۔
اہم engineering difference: GPTQ اور AWQ ایسے weights produce کرتے ہیں جو GPU kernel کے لیے optimised ہوتے ہیں، جبکہ GGUF کی schemes CPU پر file کو loaded کے بجائے mapped رکھتے ہوئے cheaply decoded ہوتی ہیں۔ اسی لیے وہی nominal “4-bit 7B model” دونوں worlds میں different sizes اور different quality پر موجود ہے، اور اسی لیے honest comparison کبھی format نہیں — بلکہ نیچے والی measurement ہے، آپ کے اپنے task پر run کی ہوئی۔
Quantization کی حقیقی cost، measured
اس حصے کا لنک: Quantization کی حقیقی cost، measuredquantization پر تقریباً ہر article پچھلے section پر رک جاتا ہے: method explain کرتا ہے، compression ratio quote کرتا ہے، اور assert کرتا ہے کہ quality “largely preserved” ہے۔ Chapter 4 اپنے آپ کو دھوکا نہ دینے کے بارے میں تھا، تو آئیے معلوم کرتے ہیں۔
وہی model، weights ہر scheme کے ساتھ in place quantized، پھر تین measurements: held-out English prose کے 2,048 tokens پر perplexity — یہاں، اس course کا draft، اسی لیے repository ایک fixed public-domain book substitute کرتی ہے اور اسی shape کی table different numbers کے ساتھ print کرتی ہے — known answers والے 16 short factual questions کی battery under greedy decoding، اور وہ fraction of tokens جس پر quantized model identical context given full-precision model سے agree کرتا ہے۔
| scheme | mean weight error | perplexity | question battery | fp32 سے agreement |
|---|---|---|---|---|
| fp32 (reference) | 0.0000 | 23.08 | 13/16 | 100.0 % |
| INT8 per tensor | 0.0400 | 23.58 | 13/16 | — |
| INT8 per row | 0.0100 | 22.96 | 13/16 | 98.6 % |
| INT4 per tensor | 0.6026 | 365,416,000 | 0/16 | — |
| INT4 per row | 0.1790 | 46.18 | 6/16 | 58.3 % |
| INT4 group 128 | 0.1323 | 31.08 | 10/16 | 71.5 % |
| NF4 block 64 | 0.0952 | 24.55 | 11/16 | 84.7 % |
| INT3 group 128 | 0.3044 | 213.09 | 0/16 | 5.6 % |
| INT2 group 128 | 0.7790 | 26,325,436 | 0/16 | 0.0 % |
اس table میں چار چیزیں صاف کہنا ضروری ہے۔
INT8 properly کیا جائے تو free ہے۔ Per-row INT8 reference کے 23.08 کے مقابلے میں 22.96 score کرتا ہے — دو سو میں ایک part کا gap، جو noise ہے اور “identical” پڑھا جانا چاہیے۔ noise کس طرف point کرتی ہے stable نہیں: repository کے public-domain corpus پر یہی دونوں schemes 22.18 کے مقابلے میں 22.24 آتی ہیں: آدھی distance، اور دوسری طرف point کرتی ہوئی۔ یہ 144 generated tokens میں سے 142 پر full-precision model سے agree کرتا ہے۔ fp32 reference کے مقابلے میں memory کا quarter، fp16 کے مقابلے میں half جسے آپ واقعی deploy کریں گے، اور no detectable cost۔ INT8 carelessly کیا جائے تو بھی nearly free ہے: فی matrix ایک scale 0.5 perplexity points اور no battery answers cost کرتا ہے۔ Eight bits اتنے forgiving ہیں کہ granularity barely matter کرتی ہے، یہی وجہ ہے کہ لوگ INT8 سے INT4 پر generalise کرتے ہیں اور hurt ہوتے ہیں۔
INT4 with one scale per tensor model کو destroy کر دیتا ہے۔ Perplexity 365 million: degraded نہیں، annihilated۔ پھر granularity ہی پوری game ہے — per-tensor 365,416,000، per-row 46.18، per-group-of-128 31.08، NF4 24.55۔ وہی four bits per weight، worst اور best کے درمیان پندرہ million کا factor۔
Perplexity ایک coarse instrument ہے اور battery اس سے بھی coarse۔ NF4 اور group-128 INT4 کے درمیان perplexity gap 6.5 points ہے اور battery ایک question سے differ کرتی ہے — اور Chapter 4 کا confidence interval کہتا ہے کہ sixteen میں ایک question کچھ بھی distinguish نہیں کرتا۔ interval سے بھی sharper demonstration ہے: یہی battery model کی stock repetition penalty switched off کے ساتھ run کریں، یعنی greedy decoding حقیقت میں کیا معنی رکھتا ہے، اور وہ دو rows places swap کر لیتے ہیں۔ sixteen میں ایک question small effect نہیں، no effect ہے۔ Chapter 8 کی warning بھی apply ہوتی ہے: perplexity صرف ان models کے درمیان comparable ہے جو tokenizer share کرتے ہیں، اس لیے کسی اور کے write-up کا number آپ کے number سے compare نہیں کیا جا سکتا۔
agreement column تینوں میں سب سے sharp ہے، اور تقریباً free: full-precision model کو greedily run کریں، پھر quantized model سے ہر position پر پوچھیں کہ given same prefix وہ کیا choose کرتا۔ اس کے پاس 16 کے بجائے 144 independent observations ہیں، ground truth نہیں چاہیے، اور جہاں battery jumps میں degrade ہوتی ہے وہاں یہ smoothly degrade ہوتا ہے۔ یہ بالکل وہ quantity بھی ہے جس کی next section کو ضرورت ہے۔
یہ وہ وعدہ ہے جو Chapter 1 نے اس chapter کے بارے میں کیا تھا، وقت پر پہنچتا ہوا: mathematics کہتی ہے 4-bit model possible ہے، اور engineering decide کرتی ہے کہ آیا یہ usable ہے۔
Speculative decoding
اس حصے کا لنک: Speculative decodingChapter 12 نے اسے announce کیا تھا اور bill یہاں چھوڑا تھا۔
idea prefill/decode split سے سیدھا آتا ہے۔ tokens کی proposed sequence verify کرنے کی cost positions پر ایک forward pass ہے — matrix-matrix product، ایک position کے pass سے barely زیادہ expensive۔ تو:
Draft
اس حصے کا لنک: Draftایک small، cheap model candidate tokens autoregressively generate کرتا ہے۔
Verify
اس حصے کا لنک: Verifylarge model تمام candidates پر ایک ساتھ ایک forward pass run کرتا ہے، یہ produce کرتے ہوئے کہ وہ ہر position پر کیا کہتا۔
Accept
اس حصے کا لنک: Acceptوہ longest prefix رکھیں جس پر دونوں agree کریں، plus وہ token جو first disagreement پر large model free میں supply کرتا ہے۔ باقی discard کریں اور دوبارہ start کریں۔
output distribution unchanged ہے۔ greedy decoding کے ساتھ یہ obvious ہے — token صرف تب accept ہوتا ہے جب target نے اسے produce کیا ہوتا۔ sampling کے ساتھ modified acceptance rule چاہیے، اور Leviathan et al. prove کرتے ہیں کہ resulting distribution exactly target کی ہے۔10 یہ اس chapter کی دوسری exact optimisation ہے۔
اس لیے سب کچھ acceptance rate پر depend کرتا ہے، جو measurable ہے — یہ اوپر والا agreement column ہے، اسی لیے وہاں compute کیا گیا۔ ہر quantized model کو full-precision target کے draft کے طور پر استعمال کرتے ہوئے، 144 generated positions پر:
| draft model | acceptance | longest accepted run | expected tokens per target pass، |
|---|---|---|---|
| fp32 (target خود) | 100.0 % | 48 | 5.00 |
| INT8 per row | 98.6 % | 48 | 4.86 |
| NF4 block 64 | 84.7 % | 20 | 3.69 |
| INT4 group 128 | 71.5 % | 13 | 2.85 |
| INT4 per row | 58.3 % | 7 | 2.24 |
| INT3 group 128 | 5.6 % | 2 | 1.06 |
| INT2 group 128 | 0.0 % | 0 | 1.00 |
draft length پر، expected tokens accepted per verification pass ہے
اور net speedup اسے draft کی اپنی cost سے divide کرتا ہے، target per token کا fraction :
| acceptance | ، | ، | ، | ، |
|---|---|---|---|---|
| 30 % | 1.19x | 1.02x | 0.79x | 0.79x |
| 50 % | 1.61x | 1.38x | 1.08x | 1.11x |
| 70 % | 2.31x | 1.98x | 1.54x | 1.78x |
| 90 % | 3.41x | 2.93x | 2.28x | 3.40x |
bold entry یاد رکھنے والی ہے: speculative decoding generation کو slower بنا سکتی ہے۔ 30 % acceptance پر، ایسے draft کے ساتھ جو target کا fifth cost کرتا ہے، آپ پانچ forward passes کی قیمت دیتے ہیں اور 1.4 tokens رکھتے ہیں۔ last column دوسری trap ہے — longer draft صرف تب help کرتا ہے جب acceptance high ہو، کیونکہ -token guess کی tail تقریباً کبھی reached نہیں ہوتی۔ 90 % acceptance پر 3.40x worth ہے اور 30 % پر 0.79x: وہی configuration، win یا loss، آپ کی traffic پر measured number کے مطابق۔
Distillation، اور soft label کیا carry کرتا ہے
اس حصے کا لنک: Distillation، اور soft label کیا carry کرتا ہےQuantization model کو اسی function کو fewer bits میں store کر کے shrink کرتی ہے۔ Distillation اسے smaller model کو larger one کی imitation train کر کے shrink کرتی ہے11 — ایک idea جو deep learning سے تقریباً ایک decade پہلے کا ہے۔12
subtle حصہ یہ ہے کہ student کس چیز سے learns کرتا ہے۔ correct answer نہیں: اس پر direct train کیا جا سکتا تھا۔ teacher جو add کرتا ہے وہ whole distribution ہے۔ model سے پوچھیں کہ phrase کے بعد کیا آتا ہے اور argmax سے آگے دیکھیں:
"She poured the milk into the"
' jug' 0.1355 ' cup' 0.1051 ' bowl' 0.0605 ' large' 0.0380 ' milk' 0.0360hard label کہتا ہے jug اور کچھ نہیں۔ soft label کہتا ہے jug، اور یہ بھی کہ cup تقریباً اتنا ہی اچھا تھا، bowl plausible، اور large — ایک adjective، بالکل مختلف grammatical continuation — ابھی بھی live تھا۔ یہی original argument ہے: یہ 7 ہے، مگر یہ 1 جیسا کافی لگتا ہے، اور resemblance وہ information ہے جسے hard label throw away کر دیتا ہے۔
اسی لیے distillation temperature استعمال کرتی ہے۔ softmax سے پہلے logits کو سے divide کرنا distribution کو flatten کرتا ہے اور runners-up کا relative weight raise کرتا ہے: اس phrase پر، top token اور third کے درمیان ratio پر 2.24 سے پر 1.50 تک گر جاتا ہے — first کا square root، جو logits کو two سے divide کرنے سے ratio کے ساتھ ہوتا ہے۔ same ordering، loss کی attention کا زیادہ حصہ near misses پر۔ student کا gradient teacher کی uncertainty carry کرتا ہے، صرف verdict نہیں۔
8، 16 اور 24 GB میں کیا fit ہوتا ہے
اس حصے کا لنک: 8، 16 اور 24 GB میں کیا fit ہوتا ہےاس chapter کی ہر چیز اب ایک sum ہے:
جہاں تمام concurrent requests کے across resident total tokens ہیں۔ اسے apply کرتے ہوئے: 7B اور 70B rows dimension 128 کے 8 key-value heads assume کرتی ہیں، 13B row 40 heads کے ساتھ full multi-head attention، کیونکہ ان generations کے model اسی طرح built تھے — اور یہ ظاہر ہوتا ہے۔
8 GB
| model | precision | weights | overhead کے بعد free | fit ہونے والے context tokens |
|---|---|---|---|---|
| 7B | fp16 | 13.0 GB | does not fit | — |
| 7B | int8 | 6.5 GB | does not fit | — |
| 7B | int4 (g128) | 3.4 GB | 3.1 GB | 25,710 |
| 13B | int4 (g128) | 6.2 GB | 0.3 GB | 337 |
| 70B | int4 (g128) | 33.6 GB | does not fit | — |
16 GB
| model | precision | weights | overhead کے بعد free | fit ہونے والے context tokens |
|---|---|---|---|---|
| 7B | fp16 | 13.0 GB | 1.5 GB | 11,972 |
| 7B | int8 | 6.5 GB | 8.0 GB | 65,378 |
| 7B | int4 (g128) | 3.4 GB | 11.1 GB | 91,246 |
| 13B | int8 | 12.1 GB | 2.4 GB | 3,136 |
| 13B | int4 (g128) | 6.2 GB | 8.3 GB | 10,822 |
24 GB
| model | precision | weights | overhead کے بعد free | fit ہونے والے context tokens |
|---|---|---|---|---|
| 7B | fp16 | 13.0 GB | 9.5 GB | 77,508 |
| 7B | int8 | 6.5 GB | 16.0 GB | 130,914 |
| 7B | int4 (g128) | 3.4 GB | 19.1 GB | 156,782 |
| 13B | int8 | 12.1 GB | 10.4 GB | 13,622 |
| 13B | int4 (g128) | 6.2 GB | 16.3 GB | 21,308 |
| 70B | int4 (g128) | 33.6 GB | does not fit | — |
8 GB table میں 13B row دیکھیں۔ weights fit ہیں — 8 میں سے 6.2 GB — اس لیے usual way of talking کے مطابق، 13B model “8 GB card پر run کرتا ہے”۔ اس کے پاس 337 tokens of context ہیں، جو conversation نہیں بلکہ barely prompt ہے۔ “کیا یہ fit ہوتا ہے” غلط سوال ہے۔ درست سوال ہے “کتنے context کے ساتھ، اور ایک ساتھ کتنے users کے لیے”۔
16 GB کی دونوں int8 rows بھی دیکھیں۔ 7B کو 65,378 tokens ملتے ہیں اور 13B کو 3,136 — extra weights کے 5.6 GB سے twenty-fold difference، کیونکہ یہاں 13B میں multi-head attention ہے اور اس کا cache 7B کے 128 KB کے مقابلے میں 800 KB per token cost کرتا ہے۔ similar size کے دو models، ایک long context کے لیے unusable، ایسی وجہ سے جو کسی model card کی headline میں ظاہر نہیں ہوتی۔
یہ آگے کہاں جاتا ہے
اس حصے کا لنک: یہ آگے کہاں جاتا ہےتیرہ chapters پہلے یہ دو weights اور ایک bias والا perceptron تھا۔ اب یہ transformer ہے جسے design، train، align کیا گیا، hard questions پر compute spend کرنا سکھایا گیا، اور measured cost per token پر serve کیا گیا — اس کے اندر کوئی box unopened نہیں بچا۔
یہ یہاں ختم ہوتا ہے، اور intentional طور پر ختم ہوتا ہے۔
Chapter 14 model کو کہیں اور سے شروع کرتا ہے۔ آپ کے process میں نہیں، آپ کی memory میں نہیں، کسی variable میں نہیں جسے آپ print کر سکیں: ایک ایسی machine پر جسے آپ administer نہیں کرتے، API key، port اور bill کے پیچھے۔ یہاں measured ہر چیز پھر بھی ہو رہی ہے — پہلے token سے پہلے prefill پھر بھی run کرتا ہے، cache conversation کے ساتھ پھر بھی grow کرتا ہے، جس batch میں آپ ہیں وہ پھر بھی کسی اور کا ہے اور پھر بھی آپ کی latency decide کرتا ہے — مگر اب سے آپ اسے Server-Sent Events کی stream، ایک finish_reason، اور Retry-After header کے ساتھ HTTP 429 کے ذریعے observe کرتے ہیں۔ vantage point کے ساتھ questions بدلتے ہیں: یہ gradient کیسے compute ہوتا ہے نہیں بلکہ میرا invoice triple کیوں ہوا۔ language بھی بدلتی ہے، اور Chapter 14 اس rule کو announce کرنے کے بجائے explain کرتا ہے — یہاں تک code نے weights، gradients، logits اور tokenizer bytes hold کیے؛ وہاں سے آگے یہ connection، retry، cancellation اور accumulated state hold کرتا ہے۔ آپ کے پیچھے تیرہ chapters crossing سے discard نہیں ہوتے۔ وہ port کے دوسری طرف running چیز کی description ہیں۔
Sources and method
اس حصے کا لنک: Sources and methodدو omissions deliberate ہیں۔ FlashAttention (Dao et al., arXiv:2205.14135) different attention نہیں — یہ اسی function کو operation tile کر کے compute کرتا ہے تاکہ score matrix کبھی memory میں written نہ ہو، اسی لیے اس chapter کی second table کا 67 MB practice میں arithmetic کے suggest کرنے سے چھوٹا ہے۔ اور kernels themselves delegated ہیں: Stanford کے CS336 کا lecture 10 inference systems کو اس depth میں cover کرتا ہے جس کی یہ کوشش نہیں کرتا، اور llama.cpp repository اور GGUF specification CPU side کے primary sources ہیں۔
حوالہ جات
اس حصے کا لنک: حوالہ جات-
Shazeer, N. Fast Transformer Decoding: One Write-Head is All You Need. arXiv:1911.02150 (2019). paper بڑی حد تک memory-bandwidth argument ہے، اور اسی طرح پڑھتا ہے۔ ↩
-
Ainslie, J. et al. GQA: Training Generalized Multi-Query Transformer Models from Multi-Head Checkpoints. arXiv:2305.13245 (2023). uptraining recipe شامل ہے جو existing multi-head checkpoint کو convert کرتی ہے، اسی لیے GQA اتنی تیزی سے پھیلا۔ ↩
-
Yu, G.-I., Jeong, J. S., Kim, G.-W., Kim, S. and Chun, B.-G. Orca: A Distributed Serving System for Transformer-Based Generative Models. OSDI 2022. iteration-level scheduling — continuous batching — اور selective batching introduce کرتا ہے۔ ↩
-
Kwon, W. et al. Efficient Memory Management for Large Language Model Serving with PagedAttention. arXiv:2309.06180 (2023), SOSP 2023. وہ paper جس پر vLLM built ہے؛ §3 operating-systems analogy کو مکمل طور پر بیان کرتا ہے۔ ↩
-
Dettmers, T., Pagnoni, A., Holtzman, A. and Zettlemoyer, L. QLoRA: Efficient Finetuning of Quantized LLMs. arXiv:2305.14314 (2023). NF4 §3 میں defined ہے؛ اوپر measurement میں used سولہ level values وہی ہیں جو یہ paper derive کرتا ہے۔ ↩
-
Dettmers, T., Lewis, M., Belkada, Y. and Zettlemoyer, L. LLM.int8(): 8-bit Matrix Multiplication for Transformers at Scale. arXiv:2208.07339 (2022). §4 میں outlier-feature analysis اوپر measured phenomenon کا source ہے، جس میں یہ finding بھی شامل ہے کہ outliers scale پر systematically emerge ہوتے ہیں۔ ↩ ↩2
-
Xiao, G., Lin, J., Seznec, M., Wu, H., Demouth, J. and Han, S. SmoothQuant: Accurate and Efficient Post-Training Quantization for Large Language Models. arXiv:2211.10438 (2022). ↩
-
Frantar, E., Ashkboos, S., Hoefler, T. and Alistarh, D. GPTQ: Accurate Post-Training Quantization for Generative Pre-trained Transformers. arXiv:2210.17323 (2022). ↩
-
Lin, J. et al. AWQ: Activation-aware Weight Quantization for LLM Compression and Acceleration. arXiv:2306.00978 (2023). ↩
-
Leviathan, Y., Kalman, M. and Matias, Y. Fast Inference from Transformers via Speculative Decoding. arXiv:2211.17192 (2022). Theorem 1 proof ہے کہ output distribution unchanged ہے؛ Chen et al. (arXiv:2302.01318) نے یہی idea independently publish کیا۔ ↩
-
Hinton, G., Vinyals, O. and Dean, J. Distilling the Knowledge in a Neural Network. arXiv:1503.02531 (2015). temperature اور “dark knowledge” argument۔ ↩
-
Buciluă, C., Caruana, R. and Niculescu-Mizil, A. Model Compression. KDD 2006. Distillation، نو سال پہلے، transformers کے بجائے ensembles کے لیے۔ ↩