এই পর্বে যা শিখবেন
- Decoder-only model-এর ছবি, প্রতিটি ধাপের shape সহ
- Shifted label বানানো আর cross-entropy হাতে হিসাব, পরীক্ষার মতো করে
- GPT-2-এর module tree পড়া আর parameter হাতে মেলানো
- GPT-1, ২, ৩-এর প্রকাশিত তথ্য, আর বন্ধ model কী লুকায়
- RoPE, GQA আর MoE-র হিসাব: key-র সংখ্যা, cache-এর memory, সক্রিয় parameter
AI-এর ভিত্তি কোর্সের পর্ব ৭০-এ LLM-এর সরল ছবি দেখেছেন, আর পর্ব ৭১-এ model card পড়া শিখেছেন। পর্ব ৩৬-এ নিজে একটি ছোট MiniGPT লিখেছেন। এই পর্বে একই ছাঁচের আসল model খুলে দেখব, আর নিজের হাতে তার হিসাব মেলাব।
১ · একটাই কাজ — পরের token অনুমান
ক্রিকেটের ধারাভাষ্যকার ভাবুন। প্রতিটি বলের আগে তিনি অনুমান করেন, পরের বলে কী হতে পারে। বল হয়ে গেলে স্কোরকার্ডে আসল ফল ওঠে। পরের অনুমান আসল ফল দেখে হয়, তাঁর নিজের অনুমান দেখে নয়। আর ভবিষ্যতের বল তিনি দেখতে পান না। Decoder-only model-এর training ঠিক এমন।
Next-token prediction মানে: ক্রম x1, …, xt দেখে P(xt+1 | x1, …, xt) দেওয়া। এখানে x মানে token, P মানে সম্ভাব্যতা। Chain rule দিয়ে পুরো লেখার সম্ভাব্যতা হয় এই শর্তাধীন সম্ভাব্যতাগুলোর গুণ; এর বিস্তার আছে পর্ব ৪৬-এ (Language modeling — n-gram থেকে neural LM আর perplexity).
Decoder-only model নাম এসেছে ২০১৭ সালের Transformer-এর decoder থেকে। সেখানে দুই ধরনের attention ছিল: নিজের ওপর causal self-attention, আর encoder-এর ওপর cross-attention. Encoder বাদ দিলে cross-attention-এরও কাজ থাকে না। বাকি থাকে causal self-attention, FFN আর residual. প্রশ্ন, উত্তর, অনুবাদ সব একই লেখার ক্রম হয়ে যায়। পর্ব ৩০-এর encoder–decoder-এর সঙ্গে এটাই মূল পার্থক্য।
GPT-2 small — এক নজরে
B = batch, T = token-এর সংখ্যা। ডটেড রেখা: একই weight, weight tying
এই ছবিতে নতুন কিছু নেই। Block আছে পর্ব ৩৫-এ, attention পর্ব ৩৩-এ। আসল নতুন প্রশ্ন তিনটি: লক্ষ্য কীভাবে বানানো হয়, ভবিষ্যৎ কীভাবে ঢাকা থাকে, আর সংখ্যাগুলো কী করে মেলে।
Objective-টি এক লাইনে লেখা যায়। ধরুন ক্রমে T+1টি token আছে। তাহলে
loss = −(1/T) ∑t=1…T ln Pθ(xt+1 | x1, …, xt)
এখানে θ মানে model-এর সব weight, ln মানে স্বাভাবিক লগারিদম। এটি পর্ব ১৩-এর cross-entropy-ই, শুধু প্রতিটি ঘরে একবার করে। Training-এ শর্তের ভেতরে আসল আগের token বসে, model-এর নিজের অনুমান নয়। পর্ব ৩০-এ একেই teacher forcing বলেছিলাম। Causal mask থাকায় পুরো ক্রম একবারে পাঠানো যায়; T ঘরের জন্য T বার forward লাগে না। Decoder-only model-এর training এত দ্রুত হওয়ার বড় কারণ এটিই। কিন্তু generation-এ নিজের আগের অনুমানই input, তাই সেখানে token ধরে ধরে এগোতে হয়।
২ · Label shift — একই লেখা, এক ঘর সরানো
Label shift-এর জন্য আলাদা উত্তরপত্র লাগে না, লেখাটাই উত্তরপত্র। তাই একে self-supervised বলা হয়। এক বাক্যের ছোট batch-এ নিচে দেখুন। <pad> ঘর গড়ে গোনা হয় না; পর্ব ১৩-এর ignore_index সেই কাজ করে।
| ধাপ | |
| মান |
- পুরো ক্রম. শুরুতে
<bos>, শেষে<eos>, তারপর দুটি<pad>. মোট ৭টি id. - Input. শেষ ঘর বাদ। ৬টি ঘর থাকে। Model এগুলো দেখে।
- Target. প্রথম ঘর বাদ। এবারও ৬টি ঘর। ঘর t-র উত্তর এখন আসল ঘর t+1.
- Pad বাদ. Pad-এর ঘরে −100 বসে। এতে সেই ঘর loss থেকেও বাদ, গড়ের হর থেকেও বাদ। গোনা হয় ৬-এর মধ্যে ৪টি।
- ঘর ধরে −ln p. Softmax থেকে সঠিক token-এর সম্ভাব্যতা নিয়ে −ln p. যেমন প্রথম ঘরে p = 0.784, তাই −ln p = 0.243.
- গড়. Loss 0.378, perplexity 1.459. Model গড়ে যেন দেড়টির কম বিকল্পে দোটানায়। সংখ্যাগুলো হাতে বসানো logit-এর, সত্যিকারের model-এর নয়।
এবার একই হিসাব কোডে। সঙ্গে একটি সাধারণ বাগ: shift করতে ভুলে গেলে কী হয়। একটি নকল model নেওয়া হলো, যে শুধু input কপি করে।
import numpy as np
vocab = ["<bos>", "আমি", "শাড়ি", "কিনেছি", "<eos>", "<pad>"]
ids = np.array([0, 1, 2, 3, 4, 5, 5]) # one sentence, two pads
inp, tgt = ids[:-1], ids[1:].copy()
tgt[tgt == 5] = -100 # ignore_index
logits = np.array([
[0.2, 3.0, 0.1, 0.1, 0.1, 0], # after <bos>
[0.1, 0.2, 2.5, 1.0, 0.1, 0], # after আমি
[0.1, 0.1, 0.3, 2.8, 0.5, 0], # after শাড়ি
[0.1, 0.1, 0.2, 0.2, 2.2, 0], # after কিনেছি
[1.0, 1.0, 1.0, 1.0, 1.0, 0], # at <eos> (ignored)
[1.0, 1.0, 1.0, 1.0, 1.0, 0]]) # at <pad> (ignored)
p = np.exp(logits) / np.exp(logits).sum(1, keepdims=True)
keep = tgt != -100
pt = p[np.arange(len(tgt))[keep], tgt[keep]]
for a, b, q in zip(inp[keep], tgt[keep], pt):
print(f"{vocab[a]} -> {vocab[b]} p={q:.3f} -ln p={-np.log(q):.3f}")
loss = -np.log(pt).mean()
print(f"loss={loss:.3f} perplexity={np.exp(loss):.3f} counted={keep.sum()} of {len(tgt)}")
# a fake model that only copies its input
copy = np.full((len(ids), 6), -5.0)
copy[np.arange(len(ids)), ids] = 5.0
pc = np.exp(copy) / np.exp(copy).sum(1, keepdims=True)
shifted = -np.log(pc[np.arange(4), ids[1:5]]).mean()
no_shift = -np.log(pc[np.arange(5), ids[:5]]).mean()
print(f"copy model: shifted loss={shifted:.3f}, forgot-shift loss={no_shift:.4f}")শেষ লাইনটি মনে রাখুন:
<bos> -> আমি p=0.784 -ln p=0.243
আমি -> শাড়ি p=0.630 -ln p=0.462
শাড়ি -> কিনেছি p=0.726 -ln p=0.320
কিনেছি -> <eos> p=0.615 -ln p=0.486
loss=0.378 perplexity=1.459 counted=4 of 6
copy model: shifted loss=10.000, forgot-shift loss=0.0002
Shift ভুলে গেলে কপি করা model-এর loss প্রায় ০ আসে। Curve সুন্দর, কিন্তু model কিছুই অনুমান করতে শেখেনি। Loss হঠাৎ অবিশ্বাস্য কম হলে আগে এই বাগ খুঁজুন।
Hugging Face-এ shift কে করে? Model নিজে। labels=ids দিলে ভেতরে এক ঘর সরিয়ে নেয়, তাই নিজে আগে সরালে দুইবার সরানো হবে। আমাদের run-এ model(ids, labels=ids).loss আর হাতে সরানো cross_entropy(logits[:-1], ids[1:]) দুটোই 5.432972 এসেছে। আপনার version-এ এভাবেই যাচাই করুন।
হাতে একটি পরীক্ষার হিসাব, আর শুরুর loss
ধরুন একটি ঘরে V = 3, logit = [2, 1, 0], সঠিক token প্রথমটি। e² = 7.389, e¹ = 2.718, e⁰ = 1; যোগফল 11.107. তাই p = 7.389 ÷ 11.107 = 0.665, আর −ln p = 0.408 nat. Bit-এ নিতে ln 2 = 0.693 দিয়ে ভাগ: 0.589 bit. Perplexity = e0.408 = 1.50. এইটুকু খাতায় করে নিলে বড় model-এর লগ পড়তে ভয় লাগে না।
আরেকটি কাজের অভ্যাস: প্রশিক্ষণের আগে loss দেখা। না শেখা model সব token-এ প্রায় সমান সম্ভাব্যতা দেয়, তাই loss হওয়ার কথা ln V-এর কাছে। GPT-2-তে ln 50257 = 10.825. সত্যিকারের run-এ, একই ইংরেজি বাক্যে:
ln V = 10.825
seed 0 untrained loss 11.125
seed 1 untrained loss 10.98
seed 2 untrained loss 11.003
trained loss 3.358
না শেখা model তিন seed-এই প্রায় ১১, যা হিসাবের কাছাকাছি। শুরুতে loss অনেক কম বা অনেক বেশি এলে আগে ডেটা বা shift-এ বাগ খুঁজুন, তারপর training চালান।
৩ · Causal mask — ভবিষ্যৎ বর্তমানকে বদলাতে পারে না
পর্ব ৩৬-এ causal mask লিখেছিলেন। এবার দাবিটি পরীক্ষা করি। পরীক্ষার হলে খাতা ঢেকে লেখার মতো: ওপরের লাইন দেখা যায়, নিচের লাইন নয়। একাধিক স্তরেও কি ঢাকা থাকে? নিচে তিন স্তরের ছোট attention, শুধু শেষ token বদলে। Mask ছাড়া একই পরীক্ষাও আছে।
import numpy as np
rng = np.random.default_rng(42)
T, d = 5, 8
Wq, Wk, Wv = (rng.normal(size=(d, d)) / d**0.5 for _ in range(3))
def attn(x, masked):
Q, K, V = x @ Wq, x @ Wk, x @ Wv
s = Q @ K.T / d**0.5
if masked:
s = np.where(np.tril(np.ones((T, T))) == 1, s, -np.inf)
w = np.exp(s - s.max(1, keepdims=True)) # softmax, row by row
return (w / w.sum(1, keepdims=True)) @ V
def net(x, masked):
for _ in range(3): # three layers
x = x + attn(x, masked)
return x
x = rng.normal(size=(T, d))
y = x.copy()
y[4] += 10.0 # change only the LAST token
print(np.tril(np.ones((T, T), dtype=int)))
for masked in (True, False):
diff = np.abs(net(x, masked) - net(y, masked)).max(axis=1)
print("masked :" if masked else "no mask:", np.round(diff, 4))[[1 0 0 0 0]
[1 1 0 0 0]
[1 1 1 0 0]
[1 1 1 1 0]
[1 1 1 1 1]]
masked : [ 0. 0. 0. 0. 10.9639]
no mask: [36.7369 40.8886 24.4399 38.5548 20.2014]
প্রতিটি সংখ্যা এক ঘরের output-এর সর্বোচ্চ পরিবর্তন। Mask থাকলে আগের চার ঘরে ঠিক ০। তিন স্তর পরেও চুঁইয়ে আসেনি, কারণ প্রতিটি স্তরে ঘর t শুধু ≤ t দেখে। Mask না থাকলে সব ঘরই নড়েছে।
আসল GPT-2-তেও একই পরীক্ষা চালিয়েছি (সত্যিকারের run, CPU-তে): ৯ token-এর ইংরেজি বাক্যে শুধু শেষ token বদলে।
seq length 9 changed only position 8
max|diff| at positions 0..n-2: 0.00e+00
max|diff| at position n-1 : 15.67
এই পরীক্ষা ছোট, কিন্তু খুব কাজের। নিজে model লিখলে বা AI-এর লেখা কোড পেলে একে unit test বানান। Mask-এ বাগ থাকলে training loss দারুণ দেখায়, কিন্তু generation-এ model অকেজো, কারণ তখন আর ভবিষ্যৎ পাওয়া যায় না। এটি একধরনের data leakage.
দুটি mask গুলিয়ে ফেলবেন না। Causal mask স্থাপত্যের অংশ, ক্রমের ভবিষ্যৎ ঢাকে, প্রতিটি forward-এ একই নকশা। Attention mask batch-এর অংশ, <pad> ঢাকে, ব্যবহারকারী পাঠায়। GPT-2-এর নিজের pad token নেই; আমাদের run-এ pad_token_id-তে eos বসিয়েছি। Batch-এ generation করলে padding বাঁ দিকে দিতে হয়, নইলে শেষ ঘর হবে pad, আর “পরের token” অনুমান হবে pad-এর পরের। Hugging Face-এর docs এই নিয়ে সাবধান করে; ডান দিকের padding training-এ ঠিক থাকে, কারণ সেখানে label −100 দিয়ে ঢাকা।
৪ · GPT-2 খুলে দেখা — module tree আর হাতে গোনা
সত্যিকারের run, CPU-তে: openai-community/gpt2 (MIT licence, model card দেখে নেওয়া), লেখার সময়ে torch 2.15.0, transformers 5.22.2, Python 3.12. ডাউনলোডে কোনো token লাগেনি। আউটপুট print(model)-এর; কমান্ড সরল করে লেখা, আর ... দিয়ে কিছু অংশ ছোট করা:
$ cd ~/bazarghar-dl && uv run python run_gpt2.py
GPT2LMHeadModel(
(transformer): GPT2Model(
(wte): Embedding(50257, 768)
(wpe): Embedding(1024, 768)
(drop): Dropout(p=0.1, inplace=False)
(h): ModuleList(
(0-11): 12 x GPT2Block(
(ln_1): LayerNorm((768,), eps=1e-05, ...)
(attn): GPT2Attention(
(c_attn): Conv1D(nf=2304, nx=768)
(c_proj): Conv1D(nf=768, nx=768)
...
)
(ln_2): LayerNorm((768,), eps=1e-05, ...)
(mlp): GPT2MLP(
(c_fc): Conv1D(nf=3072, nx=768)
(c_proj): Conv1D(nf=768, nx=3072)
(act): NewGELUActivation()
...
)
)
)
(ln_f): LayerNorm((768,), eps=1e-05, ...)
)
(lm_head): Linear(in_features=768, out_features=50257, bias=False)
)
দুটি অদ্ভুত জিনিস। Conv1D এখানে নামেই convolution, কাজে linear layer; পর্ব ৩১-এর Conv1d নয়। আর c_attn একটিই layer, 768 থেকে 2304 = 3 × 768: Q, K, V একসঙ্গে বেরিয়ে তিন ভাগ হয়। Parameter গোনা শুরু করি।
Run-এ h[0]-এর ভেতরের সারিগুলো দেখুন; হিসাব মেলানোর জন্য এটুকুই লাগে:
h[0] detail:
ln_1.weight (768,) 768
ln_1.bias (768,) 768
attn.c_attn.weight (768, 2304) 1,769,472
attn.c_attn.bias (2304,) 2,304
attn.c_proj.weight (768, 768) 589,824
attn.c_proj.bias (768,) 768
ln_2.weight (768,) 768
ln_2.bias (768,) 768
mlp.c_fc.weight (768, 3072) 2,359,296
mlp.c_fc.bias (3072,) 3,072
mlp.c_proj.weight (3072, 768) 2,359,296
mlp.c_proj.bias (768,) 768
Shape-টি খেয়াল করুন: (768, 2304) মানে (in, out). PyTorch-এর nn.Linear-এ উল্টো: (out, in). পুরোনো checkpoint কোনো নিজের-লেখা nn.Linear model-এ ঢোকাতে গেলে এই matrix-গুলো transpose করতে হয়। AI-এর লেখা GPT-2 loader-এ এই ভুল প্রায়ই পাবেন; ফল ত্রুটি নয়, shape মিলে গেলে চুপচাপ ভুল (যেমন 768×768-এর c_proj).
| অংশ | |
| হিসাব | |
| জমা |
- Token table. প্রতিটি token-এর জন্য ৭৬৮টি সংখ্যা। শুধু এই অংশই মোটের প্রায় ৩১%.
- Position table. ১০২৪ ঘরের জন্য শেখা position embedding. এখান থেকেই context-এর সীমা ১০২৪.
- LayerNorm. প্রতিটিতে scale আর shift, দুটোই ৭৬৮। একটি block-এ দুটি LayerNorm. মোট ৩,০৭২। এবার block-এর ভেতরে ঢুকলাম।
- Q, K, V. একসঙ্গে 768 → 2304; bias ২,৩০৪ সহ ১৭,৭১,৭৭৬।
- Output projection. সব head জোড়া দেওয়ার পরের linear. লক্ষ্য করুন, head-এর সংখ্যা ১২ কোথাও আসেনি।
- FFN. 768 → 3072 → 768. প্রথমটিতে bias ৩,০৭২, দ্বিতীয়টিতে ৭৬৮, তাই সংখ্যা দুটি সামান্য আলাদা।
- একটি block. আসল run-এর
h[0]ঠিক ৭০,৮৭,৮৭২ দেখিয়েছে। - ১২টি block. Embedding-এর সঙ্গে যোগ করে জমা ১২,৪৪,৩৮,২৭২।
- শেষ LayerNorm. আরও ১,৫৩৬।
- LM head. Weight tying, তাই নতুন weight নেই। আসল model-এর
total = 124,439,808, হুবহু মিল। Run-এlm_head tied to wte: True.
এবার সূত্রটিকে calculator বানাই। V, ctx, d, L বদলে যেকোনো GPT-ধাঁচের decoder গোনা যায়।
def decoder_params(V, ctx, d, L, ff=4, tied=True):
tok, pos = V * d, ctx * d # token and position tables
attn = (d * 3*d + 3*d) + (d * d + d) # QKV together + output
mlp = (d * ff*d + ff*d) + (ff*d * d + d) # two linear layers, with bias
block = attn + mlp + 2 * (2*d) # two LayerNorms: scale + shift
head = 0 if tied else V * d # tied: no new weight
return tok, pos, block, L * block + 2*d + tok + pos + head
REAL_GPT2 = 124_439_808 # model.parameters(), desktop run
tok, pos, block, total = decoder_params(50257, 1024, 768, 12)
print(f"token {tok:>13,}\npos {pos:>13,}\nblock {block:>13,}\ntotal {total:>13,}")
print("matches real GPT-2:", total == REAL_GPT2)
print("if not tied:", f"{decoder_params(50257, 1024, 768, 12, tied=False)[3]:,}")
print("\n d L ctx total token share")
for d, L, c in [(768, 12, 1024), (1024, 24, 1024), (1280, 36, 1024),
(1600, 48, 1024), (12288, 96, 2048)]:
t, _, _, n = decoder_params(50257, c, d, L)
print(f"{d:>5} {L:>3} {c:>4} {n:>16,} {t/n:.1%}")
print("h never appeared: d stays fixed, each head gets d/h.")token 38,597,376
pos 786,432
block 7,087,872
total 124,439,808
matches real GPT-2: True
if not tied: 163,037,184
d L ctx total token share
768 12 1024 124,439,808 31.0%
1024 24 1024 354,823,168 14.5%
1280 36 1024 774,030,080 8.3%
1600 48 1024 1,557,611,200 5.2%
12288 96 2048 174,604,259,328 0.4%
h never appeared: d stays fixed, each head gets d/h.
প্রথম চারটি GPT-2-এর চার আকার (Hugging Face-এর config থেকে নেওয়া মাপ)। শেষটি GPT-3-এর প্রকাশিত মাপে; V সেখানে আমাদের ধরে নেওয়া। হিসাব প্রায় ১৭৪.৬ B, প্রবন্ধে ১৭৫.০ B. Model বড় হলে parameter বাড়ে প্রায় L·d²-এর হারে, আর token table-এর ভাগ কমে। Block-এর প্রধান পদ 12d²: FFN 8d², attention 4d²।
তিনটি সংখ্যা, যা আলাদা দেখায়। GPT-2 প্রবন্ধের সারণিতে ছোট model ১১৭M; আসল গণনায় ১২৪.৪M. বাকি আকারেও এমন পার্থক্য আছে (৭৬২M বনাম ৭৭৪M), প্রবন্ধে কারণ বলা নেই। আর Hugging Face-এর পাতায় লেখা ১৩,৭০,২২,৭২০। ফাইল খুলে দেখলাম: ১২টি h.N.attn.bias tensor, প্রতিটি 1024×1024 mask, মোট ১,২৫,৮২,৯১২ সংখ্যা; এগুলো শেখা parameter নয়। বিয়োগ করলে আবার ১২,৪৪,৩৯,৮০৮। ফাইলে lm_head-ও নেই, কারণ সেটি tied.
এই সংখ্যাগুলো থেকে দুটি কাজের হিসাব. ফাইলের আকার: 137,022,720 × 4 byte ≈ 522.7 MiB, Hub-এ দেখানো আকারের সঙ্গে মেলে। Context-এর সীমা: wpe-তে ১০২৪টি সারি, তাই সেটিই দেয়াল। সত্যিকারের run:
1024 ok (1, 1024, 50257)
1025 IndexError index out of range in self
“Context ছাড়িয়ে গেছে” কোনো সুন্দর বার্তা আসেনি; সাধারণ IndexError. লম্বা বাংলা লেখা এই model-এ দ্রুত এই দেয়ালে ধাক্কা খায়।
৫ · GPT-1, ২, ৩ — প্রবন্ধে যা আছে, আর GPT-4-এ যা নেই
নিচের তথ্য মূল প্রবন্ধ থেকে পড়া, ২০২৬ সালের নভেম্বরে। কোনো র্যাঙ্কিং নয়, শুধু প্রকাশিত মাপ।
| Model | Layer, d, head | Context | Parameter | Training-এর লেখা |
|---|---|---|---|---|
| GPT-1 (২০১৮) | 12, 768, 12 | 512 | GPT-2-র সারণিতে ১১৭M-এর সমান বলা | BooksCorpus, ৭,০০০-এর বেশি অপ্রকাশিত বই |
| GPT-2 (২০১৯) | 12–48, 768–1600 | 1024 | ১১৭M থেকে ১,৫৪২M, চার আকার | WebText: নিজস্ব web scrape, Reddit-এ শেয়ার করা link দিয়ে বাছা |
| GPT-3 (২০২০) | 96, 12288, 96 | 2048 | ১৭৫.০B | Common Crawl (ছাঁকা), WebText2, Books1, Books2, Wikipedia |
| GPT-4 (২০২৩) | প্রকাশিত নয় | — | প্রকাশিত নয় | প্রকাশিত নয় |
GPT-2 প্রবন্ধে নিজের বদল স্পষ্ট লেখা: LayerNorm সরে গেল প্রতিটি sub-block-এর input-এ, অর্থাৎ pre-norm; শেষ attention block-এর পরে আরেকটি LayerNorm; residual layer-এর শুরুর weight 1/√N দিয়ে ছোট করা; vocabulary ৫০,২৫৭; আর byte-level BPE. হিসাব করে দেখুন: প্রতি block-এ দুটি residual শাখা ধরলে N = 2 × 12 = 24, তাই 1/√24 ≈ 0.204. Hugging Face-এর কোডেও এই ধারণা 2 * n_layer হিসেবে আছে; ছোট model-এ এটি বড় প্রভাব নয়, ৯৬ স্তরে অনেক বড়। GPT-1 আগেই শেখা position embedding আর GELU নিয়েছিল। GPT-3 প্রবন্ধে আকার নিয়ে বিস্তারিত সারণি আছে; scaling-এর প্রশ্নে যাবে পর্ব ৫১ (Scaling — ডেটা, parameter, compute আর emergent আচরণের দাবি)।
এই ধারার একটি চিন্তা হলো: কাজটি prompt-এই বলে দেওয়া যায়। GPT-2 প্রবন্ধে সারাংশ পেতে লেখার পরে TL;DR: বসিয়ে দেখা হয়েছিল, কোনো আলাদা head ছাড়াই। GPT-3 প্রবন্ধের নামই “Language Models are Few-Shot Learners”: কয়েকটি উদাহরণ prompt-এ দিলে নতুন কাজের নকশা ধরা। তবে দুই প্রবন্ধেই ফল কাজভেদে অনেক আলাদা, আর আজকের assistant-গুলোতে এর ওপর সাধারণত আরও প্রশিক্ষণ থাকে; সেই ধাপ পরের মডিউলগুলোর বিষয়।
GPT-4 Technical Report (২০২৩)-এর “Scope and Limitations” অংশে লেখা: “Given both the competitive landscape and the safety implications of large-scale models like GPT-4, this report contains no further details about the architecture (including model size), hardware, training compute, dataset construction, training method, or similar.” মানে: আকার, hardware, compute, ডেটা তৈরি, training পদ্ধতি কিছুই সেখানে নেই। তাই “GPT-4-এর এত parameter” ধরনের সংখ্যা ওই প্রতিবেদনের তথ্য নয়।
ChatGPT, Gemini, Claude, Grok, Kimi নামগুলো ব্যবহারকারীর কাছে product. এদের পেছনের model-এর ভেতরের কতটা প্রকাশিত, তা নির্মাতা আর সংস্করণ ভেদে আলাদা। এই পর্বে আমরা তাদের ভেতরের নকশা নিয়ে কোনো দাবি করছি না। প্রকাশিত তথ্য তাদের নিজের নথিতে দেখুন, তারিখ মিলিয়ে; সেটি বদলাতে পারে।
৬ · GPT-2 বাংলা পড়লে কী হয়
GPT-2-এর tokenizer যেকোনো লেখা নিতে পারে, কারণ তার শুরু byte থেকে। কিন্তু ইংরেজি লেখায় শেখা merge বাংলায় তেমন কাজে লাগে না। বাংলার প্রতিটি অক্ষর UTF-8-এ ৩ byte, তাই বেশির ভাগ অক্ষর ভেঙে যায়। Tokenizer-এর হিসাব আছে পর্ব ৪০-এ। এখানে দেখব model-এর ওপর কী প্রভাব পড়ে। সত্যিকারের run:
bn chars 35 bytes 95 tokens 68
first ids [48071, 228, 48071, 106, 48071, 123, 220, 48071, 105, 48071, 122, 48071]
first tokens ['à¦', 'Ĩ', 'à¦', '®', 'à¦', '¿', 'Ġ', 'à¦', '¬', 'à¦', '¾', 'à¦']
decode one by one ['�', '�', '�', '�', '�', '�']
roundtrip ok: True
per-token loss first 15: [5.71, 0.93, 3.59, 0.63, 3.22, 3.41, 0.14, 2.4, 0.09, 1.13, 0.04, 4.53, 0.19, 1.6, 0.11]
“আমি বাজারঘর থেকে একটি শাড়ি কিনেছি।” বাক্যে ৩৫টি code point, ৬৮টি token. প্রথম তিনটি অক্ষরই ৬টি token: ঠ(অর্থাৎ বাংলা ব্লকের শুরুর দুই byte), তারপর শেষ byte. একা একটি token decode করলে � আসে। পুরো ক্রম একসঙ্গে decode করলে অক্ষর ফিরে আসে, তাই roundtrip ok: True.
এবার ছয়টি ইংরেজি বাক্য আর তাদের আমাদের করা বাংলা অনুবাদে (বাজারঘরের রিভিউ-ধাঁচে, হাতে লেখা) loss:
| মাপ | ইংরেজি | বাংলা |
|---|---|---|
| অক্ষর (code point) | 223 | 195 |
| Byte | 223 | 527 |
| গোনা token | 50 | 379 |
| প্রতি অক্ষরে token | 0.224 | 1.944 |
| প্রতি token-এ loss (nat) | 4.006 | 1.793 |
| Perplexity | 54.9 | 6.0 |
| প্রতি অক্ষরে bit | 1.296 | 5.029 |
| প্রতি byte-এ bit | 1.296 | 1.861 |
একটি local run, ছয়টি ছোট বাক্য; সাধারণ সিদ্ধান্ত নয়। কিন্তু শিক্ষাটি পরিষ্কার। প্রথম সারি দেখে মনে হবে, বাংলায় model ভালো। উল্টো। ওপরের per-token তালিকায় দেখুন: à¦-এর মতো পরের অংশ অনুমান করা সহজ, loss ০.১-এর কাছাকাছিও নামে। সহজ টুকরো গড় নামিয়ে দেয়। Perplexity তুলনা তখনই চলে, যখন tokenizer আর লেখা একই। ভিন্ন tokenizer বা ভিন্ন ভাষায় bit প্রতি অক্ষর বা প্রতি byte দেখুন। হিসাব: bit/অক্ষর = 1.793 × 379 ÷ ln 2 ÷ 195 ≈ ৫.০৩। এখানেও মনে রাখুন, ইংরেজি আর বাংলার তথ্য-ঘনত্ব এক নয়, তাই এটিও নিখুঁত তুলনা নয়।
GPT-2-র context ১০২৪ token. এই হারে প্রায় 1024 ÷ 0.224 ≈ ৪,৫৭০টি ইংরেজি অক্ষর ধরে, কিন্তু 1024 ÷ 1.944 ≈ ৫২৭টি বাংলা অক্ষর। হোস্টেড API-তেও খরচ আর সীমা গোনা হয় token-এ, তাই নিজের tokenizer-এ বাংলা গুনে দেখুন। আরও আছে পর্ব ৫২-তে (LLM-এর ভেতরে — tokenizer থেকে logits, context window আর hallucination).
বাজারঘরের কাজে এই হিসাবের অর্থ কী? কাল্পনিক দোকানটির তিনটি কাজ ভাবুন:
| কাজ | Next-token model লাগবে? | কী মাপবেন |
|---|---|---|
| রিভিউ ভালো না খারাপ | সাধারণত না; পর্ব ৪২-এর classifier, বা পর্ব ৪৮-এর (BERT পরিবার — encoder model আর fine-tuning) encoder | Macro-F1, একই split |
| গ্রাহকের প্রশ্নের খসড়া উত্তর | হ্যাঁ, তবে সেই ভাষায় শেখা model; মানুষের দেখা জরুরি | Bit প্রতি অক্ষর, পড়ে দেখা, ভুল তথ্যের হার |
| পণ্যের বর্ণনা স্বয়ংক্রিয় লেখা | হ্যাঁ, কিন্তু আসল তথ্য আলাদা জায়গা থেকে দিতে হবে | তথ্যের মিল, পুনরাবৃত্তি |
৭ · এক ধাপ next token — logit থেকে লেখা
এবার সত্যিকারের একটি ধাপ। Prompt “The capital of Bangladesh is”, GPT-2, CPU-তে। সংখ্যাগুলো run থেকে নেওয়া।
| ধাপ | |
| মান |
- Token. পাঁচটি token, id-তে।
- Forward. প্রতিটি ঘরের জন্য ৫০,২৫৭টি স্কোর। Training-এ সব ঘর লাগে, generation-এ শেষটি।
- শেষ সারি. “is”-এর পরে কী আসবে, তার স্কোর। আগের সারিগুলো ফেলে দেওয়া হয়; পর্ব ৩৭-এর KV cache এই অপচয় কমায়।
- Logit. Logit ঋণাত্মক, তাতে সমস্যা নেই। শুধু পার্থক্যই অর্থবহ।
- Softmax. পার্থক্য 0.600 মানে অনুপাত e−0.6 = 0.549: 0.1142 × 0.549 ≈ 0.0627. মিলে গেল।
- বাছাই. Greedy নেয় সবচেয়ে বড়টি। Sampling সম্ভাব্যতা ধরে দৈব বাছে; seed 42-তে এলো ২.২% সম্ভাব্যতার token. কৌশলের বিস্তার পর্ব ৫০-এ (Decoding — greedy, beam search, temperature, top-k আর top-p).
- জোড়া. নতুন token input-এর শেষে বসে, আবার forward. এটাই autoregressive generation.
পুরো top-10, ইংরেজি আর বাংলা prompt দুটোতেই (সত্যিকারের run; সংখ্যা হুবহু, ফোনে ধরার জন্য কলাম ছোট করে, আর �-এর পাশে আসল token লেখা):
prompt: The capital of Bangladesh is | tokens: 5
262 ' the' 0.1142
257 ' a' 0.0627
783 ' now' 0.0365
1363 ' home' 0.0261
635 ' also' 0.0251
5140 ' located' 0.0251
1900 ' known' 0.0236
287 ' in' 0.0228
19483 ' Bangladesh' 0.0218
407 ' not' 0.0211
top-10 mass 0.379
prompt: বাংলাদেশের রাজধানী | tokens: 38
48071 '�' (à¦) 0.7363
220 ' ' 0.1045
156 '�' (à) 0.0843
11 ',' 0.0074
198 '\n' 0.0041
837 ' ,' 0.0031
13 '.' 0.0019
357 ' (' 0.0017
24231 '�' (à¥) 0.0017
28225 ' �' (Ġà¤) 0.0015
top-10 mass 0.9466
দেখুন: ঢাকা top-10-এ নেই। Model তথ্য ভান্ডার নয়, ভাষার নকশা শিখেছে। বাংলা prompt-এ সে মূলত অনুমান করছে “এরপর আরেকটি বাংলা byte-এর শুরু”। অর্থের অনুমান এটি নয়। এরপর আসে ফাঁকা জায়গা আর বিরামচিহ্ন; শেষ দিকে ॠআর ठআসলে দেবনাগরী ব্লকের byte.
বাজারঘর-ধাঁচের ইংরেজি prompt “The saree I ordered from the online shop arrived”-এ top-5: in 0.2035, on 0.0935, within 0.0491, today 0.0481, with 0.0445. ব্যাকরণে যুক্তিসঙ্গত; ধারণা করা যায়, web লেখায় এমন বাক্য প্রচুর আছে। কিন্তু এটি নকশা ধরা, দোকানের কোনো তথ্য নয়।
এবার লেখা তৈরি। প্রতিটি ৪০ নতুন token, temperature 0.8, top-k 50, seed লেখা আছে। হুবহু আউটপুট, এক অক্ষরও বদলানো হয়নি:
seed 42 | 'The delivery from the online shop was made to the same address as in the case of the original orders. The order was then delivered to the addresses listed in the order form.\n\nThe original orders are not subject to the processing fees'
seed 7 | "The delivery from the online shop was only a few minutes, but the wait time was so long it made me question how I could let my daughter's birthday party go, let alone my business.'\n\nThe woman was not in the"
seed 42 | 'আমি বাজারঘর থেকে একটি শাড়ি কিনেছি। লািমি ন���্ \u09b4্যেঠহেক'
seed 7 | 'আমি বাজারঘর থেকে একটি শাড়ি কিনেছি। । इंदी प्क राक्न दीख्य्ं'
ইংরেজি ব্যাকরণ মোটামুটি ঠিক, অর্থ এলোমেলো। বাংলা সোজাসুজি অকেজো: অর্থহীন অক্ষর, ভাঙা byte (�), Unicode-এর ফাঁকা ঘর (\u09b4, repr-এ যেমন ছাপা হয়েছে), এমনকি seed 7-এ দেবনাগরী। সৎ উপসংহার: সাধারণ GPT-2 বাংলা লেখার জন্য নয়। এটি model-এর “বোকামি” নয়; তার training লেখা আর tokenizer-এর ফল।
গতির একটি হিসাব: ৪০ token-এ GPT-2 small CPU-তে প্রায় ১ সেকেন্ড (০.৯৮, ০.৯৪), Qwen2.5-0.5B প্রায় ৩.২ সেকেন্ড। প্রতি token-এ KV cache-সহ এক ধাপ; এক local run, CPU ভাগাভাগি করে চলা অবস্থায়, সাধারণ মাপ নয়। Model যত বড়, প্রতি token তত ভারী; দ্রুত করার উপায় পর্ব ১২ আর পর্ব ৫৯-এ (ছোট আর দ্রুত model — quantization, distillation আর pruning).
তুলনায় একটি ছোট বহুভাষিক open model
একই পরীক্ষা Qwen/Qwen2.5-0.5B-তে (সত্যিকারের run, CPU-তে; Apache 2.0, token ছাড়া নামানো যায়, weight প্রায় ১ GB). ২০২৬ সালের নভেম্বরে model card-এ যেমন দেখা গেছে: প্রায় ০.৪৯ B parameter, আর base model-কে কথোপকথনের জন্য সুপারিশ করা হয় না। নির্মাতাদের ব্লগ “২৯-এর বেশি ভাষা” বলে; উদাহরণের তালিকায় বাংলার নাম নেই। তাই আগে মাপি। প্রথম সারণি একই ছয় জোড়া বাক্যে, দুই model-এর লগ থেকে নেওয়া।
| মাপ (বাংলা লেখা) | GPT-2 small | Qwen2.5-0.5B |
|---|---|---|
| গোনা token | 379 | 203 |
| প্রতি অক্ষরে token | 1.944 | 1.041 |
| প্রতি token-এ loss (nat) | 1.793 | 1.712 |
| প্রতি অক্ষরে bit | 5.029 | 2.570 |
| প্রতি byte-এ bit | 1.861 | 0.951 |
| ইংরেজিতে প্রতি অক্ষরে bit | 1.296 | 1.337 |
প্রতি token-এ loss প্রায় সমান দেখাচ্ছে; প্রতি অক্ষরে খরচ প্রায় অর্ধেক। ওপরের নিয়মটি এখানেই কাজে লাগল। বাংলা prompt-এ Qwen2.5-এর top-10 আর generation (seed আর সেটিং GPT-2-র মতো, হুবহু):
bn chars 35 bytes 95 tokens 37
decode one by one ['আ', 'ম', 'ি', ' �', '�', 'া�', '�', 'া�', '�', '�', '�', 'র']
prompt: বাংলাদেশের রাজধানী | tokens: 19
35178 ' �' 0.7024
72258 'র' 0.1157
148156 'দ' 0.0343
11 ',' 0.0209
320 ' (' 0.0105
12 '-' 0.0098
220 ' ' 0.0089
148787 'গ' 0.0079
147645 'ত' 0.0062
198 '\n' 0.0061
top-10 mass 0.9227
seed 42 | 'আমি বাজারঘর থেকে একটি শাড়ি কিনেছি। তা করে আমাদের সমস্যা অময় ওড়াড়ার ই'
seed 7 | 'আমি বাজারঘর থেকে একটি শাড়ি কিনেছি। তার ছোট হাতে মাধব থেকে মালুর জন্তু এ'
seed 42 | 'বাংলাদেশের রাজধানী বিশ্বাসকুপের সমৃদ্ধি সাম্রাজ্যে বিক্র'
seed 7 | 'বাংলাদেশের রাজধানী নামের উন্নয়ন করিয়েছেন কোথাও কখন ? য'
পার্থক্য চোখে পড়ার মতো: বাংলা অক্ষর আর শব্দের চেহারা অনেকটা ঠিক, ভাঙা byte দেখা যায়নি। কিছু অক্ষর একা token হয়েছে (আ, ম, র), তবু কিছু অক্ষর এখনো byte-এ ভাঙে। কিন্তু অর্থ নেই, আর “রাজধানী”-র পরে ঢাকা আসেনি; ইংরেজি prompt-এ Dh এসেছিল চতুর্থ স্থানে (0.0559). এটি একটি base model-এর একটি run, ছোট পরীক্ষা, আর দুই model-এর আকার ও training আলাদা (প্রায় ৪ গুণ parameter), তাই কে “ভালো”, সে রায় এখান থেকে হয় না। শেখার কথা: সাবলীল চেহারা আর সত্য আলাদা জিনিস। আর Qwen2.5-0.5B-র মতো ছোট model দিয়ে কাজ চালানোর আগে নিজের ডেটায় মেপে নিন।
৮ · Open উত্তরসূরিরা — block-এ কী বদলাল
ছাঁচ একই: token embedding, causal block, LM head. বদলেছে block-এর ভেতরটা। উপাদানগুলো আগেই শিখেছেন: RoPE পর্ব ৩৪-এ, RMSNorm আর SwiGLU পর্ব ৩৫-এ, GQA পর্ব ৩৭-এ। নিচের সারণি প্রতিটির নিজের প্রবন্ধ বা config থেকে, ২০২৬ সালের নভেম্বরে নথিতে যেমন দেখা গেছে। এগুলো কোনো র্যাঙ্কিং নয়।
| Model | প্রকাশিত আকার | Block-এর উল্লেখযোগ্য বদল |
|---|---|---|
| LLaMA (২০২৩) | 6.7B–65.2B | Pre-norm RMSNorm, SwiGLU (মাঝের মাপ ⅔·4d), RoPE; শেখা position table নেই |
| Llama 2 (২০২৩) | 7B–70B | RoPE, RMSNorm, SwiGLU; 34B ও 70B-তে GQA; context 4k; vocabulary 32k |
| Mistral 7B (২০২৩) | 32 layer, d 4096 | 32 head, 8 kv-head, sliding window 4096; config-এ RoPE, untied; Apache 2.0 |
| Mixtral 8x7B (২০২৪) | প্রায় 47B; প্রতি token-এ প্রায় 13B | Mixture of experts: প্রতি স্তরে ৮টি expert, router ২টি বাছে; Apache 2.0 |
| Qwen (২০২৩) | 1.8B, 7B, 14B | Pre-norm RMSNorm, SwiGLU (প্রায় 8/3), RoPE, tied নয়; BPE, vocabulary প্রায় ১.৫২ লাখ |
| DeepSeek-V3 (২০২৪) | 671B; প্রতি token-এ 37B | MoE (১টি শেয়ার্ড + ২৫৬টি routed, ৮টি সক্রিয়), RMSNorm, SwiGLU, RoPE, latent attention (MLA) |
“প্রতি token-এ সক্রিয়” সংখ্যাটি লক্ষ্য করুন: MoE-তে মোট parameter আর প্রতি token-এর গণনা আলাদা। আর open weights মানেই open source নয়: weight পাওয়া যায়, কিন্তু training data সাধারণত পুরোপুরি প্রকাশিত থাকে না, আর licence প্রতিটির আলাদা। DeepSeek ও Llama-র ক্ষেত্রেও licence নিজে পড়ুন।
MoE-র ছোট হিসাব. Mixtral-এ সব expert মিলিয়ে প্রায় 47B, সক্রিয় প্রায় 13B, প্রতি স্তরে ৮-এর মধ্যে ২টি। ধরুন E = সব স্তরে এক expert-এর parameter, R = বাকি সব। তাহলে R + 8E = 47 আর R + 2E = 13. বিয়োগে 6E = 34, তাই E ≈ 5.67B, R ≈ 1.67B. সংখ্যাগুলো গোলানো, তাই হিসাবও মোটামুটি। কিন্তু সূত্র পরিষ্কার: memory-তে সব expert রাখতে হয়, গণনায় লাগে কম। “47B-এর model” আর “13B-এর গতি” তাই দুটিই আংশিক সত্য।
SwiGLU-র ছোট হিসাব. GELU-র FFN-এ দুটি matrix: 2·d·4d = 8d². SwiGLU-তে তিনটি: 3·d·m, যেখানে m মাঝের মাপ। m = 8d/3 নিলে আবার 8d²; কেন, সেটি পর্ব ৩৫-এ দেখেছেন। Mistral 7B-তে d = 4096, m = 14336, যা 8d/3-এর চেয়ে বড়, তাই একটি FFN-এ 3 × 4096 × 14336 = 176,160,768 সংখ্যা, 8d²-এর 134,217,728-এর জায়গায়। Config পড়লেই এই হিসাব করা যায়।
এবার তত্ত্ব মিলিয়ে দেখি। যে Qwen2.5-0.5B চালিয়েছি, তার module tree-ই বলে দেয় কী বদলেছে (সত্যিকারের run; অংশবিশেষ):
Qwen2ForCausalLM(
(model): Qwen2Model(
(embed_tokens): Embedding(151936, 896)
(layers): ModuleList(
(0-23): 24 x Qwen2DecoderLayer(
(self_attn): Qwen2Attention(
(q_proj): Linear(in=896, out=896, bias=True)
(k_proj): Linear(in=896, out=128, bias=True)
(v_proj): Linear(in=896, out=128, bias=True)
(o_proj): Linear(in=896, out=896, bias=False)
)
(mlp): Qwen2MLP(
(gate_proj): Linear(in=896, out=4864, bias=False)
(up_proj): Linear(in=896, out=4864, bias=False)
(down_proj): Linear(in=4864, out=896, bias=False)
(act_fn): SiLUActivation()
)
(input_layernorm): Qwen2RMSNorm((896,), eps=1e-06)
(post_attention_layernorm): Qwen2RMSNorm(...)
)
)
(norm): Qwen2RMSNorm((896,), eps=1e-06)
(rotary_emb): Qwen2RotaryEmbedding()
)
(lm_head): Linear(in=896, out=151936, bias=False)
)
config: heads 14, kv-heads 2, context 32768, tied True
total = 494,032,768
(in_features-কে জায়গার জন্য in লেখা হয়েছে; config-এর লাইনটিও ছোট করা।) GPT-2-র সঙ্গে মিলিয়ে দেখুন: position table নেই, তার জায়গায় rotary_emb; LayerNorm-এর জায়গায় RMSNorm; FFN-এ তিনটি matrix; K আর V মাত্র 128 মাপের, Q 896. Parameter হাতে: Q 803,712 + K 114,816 + V 114,816 + O 802,816 + FFN 3 × 4,358,144 + RMSNorm 2 × 896 = 14,912,384. ২৪ স্তরে 357,897,216; embedding 136,134,656; শেষ norm 896. যোগফল 494,032,768, হুবহু মিল। Card-এর “embedding বাদে ০.৩৬ B”-ও মিলে গেল। আর nn.Linear-এর weight এখানে (out, in): run-এ k_proj.weight-এর shape (128, 896).
GQA আর RoPE-এর হিসাবও হাতে করা যায়, এই model-এর মাপেই:
import numpy as np
d, L, h, g, T = 896, 24, 14, 2, 32768 # d, layers, heads, kv-heads, context
dh = d // h
qkv = lambda heads: d * heads * dh + heads * dh # one projection, with bias
print(f"head_dim={dh} Q={qkv(h):,}")
print(f"K+V, {h} kv-heads: {2*qkv(h):,}")
print(f"K+V, {g} kv-heads: {2*qkv(g):,} saved per layer {2*(qkv(h)-qkv(g)):,}")
def cache_gib(kv_heads, bytes_per=2): # KV cache: float16, batch 1
return 2 * L * kv_heads * dh * T * bytes_per / 2**30
print(f"cache at T={T}: full {cache_gib(h):.2f} GiB, GQA {cache_gib(g):.2f} GiB")
print(f"learned position table: {T*d:,} RoPE table: 0")
def rope(x, t, base=10000.0): # rotate pairs (a_i, b_i) by t*w_i
n = len(x) // 2
w = base ** (-np.arange(n) * 2 / len(x))
c, s = np.cos(t * w), np.sin(t * w)
a, b = x[:n], x[n:]
return np.concatenate([a * c - b * s, a * s + b * c])
rng = np.random.default_rng(42)
q, k = rng.normal(size=4), rng.normal(size=4)
for tq, tk in [(5, 3), (105, 103), (7, 3)]:
print(f"pos q={tq:>3} k={tk:>3} gap={tq-tk} q.k={rope(q, tq) @ rope(k, tk):+.6f}")head_dim=64 Q=803,712
K+V, 14 kv-heads: 1,607,424
K+V, 2 kv-heads: 229,632 saved per layer 1,377,792
cache at T=32768: full 2.62 GiB, GQA 0.38 GiB
learned position table: 29,360,128 RoPE table: 0
pos q= 5 k= 3 gap=2 q.k=+2.661916
pos q=105 k=103 gap=2 q.k=+2.661916
pos q= 7 k= 3 gap=4 q.k=+0.306416
প্রথম সারিগুলো আসল layer-এর সঙ্গে মেলে: run-এ q_proj ৮,০২,৮১৬ + ৮৯৬ = ৮,০৩,৭১২, আর K + V একত্রে ২,২৯,৬৩২। সব head-এ K, V থাকলে এই context-এ cache ২.৬২ GiB, GQA-তে ০.৩৮ GiB: ঠিক ৭ গুণ ছোট, কারণ ১৪/২ = ৭। Memory-র এই সূত্র পর্ব ৩৭-এর। RoPE-তে ব্যবধান ২ হলে স্কোর হুবহু এক, ঘর ৫-এ হোক বা ১০৫-এ; ব্যবধান ৪ হলে বদলায়। কোডের base 10000 শুধু উদাহরণ; এই model-এর config-এ rope_theta 1000000. আর RoPE-র কোনো শেখা table লাগে না, তাই ২.৯৪ কোটি সংখ্যা বাঁচে (context এত লম্বা হলে)। তবে এটি সূত্রের হিসাব; কোন পদ্ধতি কোন কাজে ভালো, সেই রায় এখানে নেই।
নতুন model দেখলে কী পড়বেন. এই পর্বের হিসাব যেকোনো decoder-এ চলে। Config থেকে নিন: vocabulary, d, layer, head, kv-head, FFN-এর মাপ, activation, position (RoPE না table), context, tied কি না। তারপর পাঁচটি প্রশ্ন: parameter হাতে মেলে কি? কোন token-এ আপনার ভাষা কতটা ভাঙে? KV cache কত memory চায়? Licence কী বলে? Card training data নিয়ে কী বলে, আর কী বলে না? এই অভ্যাস থাকলে কোনো নতুন নামের ঝলকে আপনি বিভ্রান্ত হবেন না।
আরও গভীরে: Mixtral প্রবন্ধে router প্রতি token-এ প্রতি স্তরে ২টি expert বাছে, আর সেই বাছাই ঘর ভেদে বদলাতে পারে। DeepSeek-V3-এর প্রতিবেদনে key আর value-কে ছোট latent vector-এ চাপা হয় (KV compression মাত্রা ৫১২), RMSNorm-ও বাড়তি বসে। উপাদানগুলোর উৎস: RoPE (Su ও সহলেখক, ২০২১), RMSNorm (Zhang ও Sennrich, ২০১৯), GLU রূপ (Shazeer, ২০২০), GQA (Ainslie ও সহলেখক, ২০২৩)। আর পুরোনো কথা: শেখা position table বাদ গেলে সর্বোচ্চ context-এর সীমা আর সরাসরি table-এ বাঁধা থাকে না, যদিও অনেক model-এর config একটি সীমা লেখে।
পরীক্ষা ও ইন্টারভিউতে:
- GPT-2 small-এর parameter? ১২,৪৪,৩৯,৮০৮; প্রতি block ৭০,৮৭,৮৭২; tied.
- Head-এর সংখ্যা parameter বদলায়? d একই থাকলে না, প্রতিটি head-এর মাপ শুধু d/h.
- Decoder-only-তে encoder-decoder-এর কী নেই? Encoder আর cross-attention.
- Target কী? Input-কে এক ঘর সরানো; pad ঘর −100.
- Per-token loss দুই ভাষায় তুলনা? চলে না; bit প্রতি অক্ষর বা byte দেখুন, tokenizer আলাদা হলে।
৯ · AI-এর যুগে — GPT নিয়ে AI-এর সাহায্য
এই পর্বের প্রতিটি হিসাব AI-কে দিয়ে করানো যায়। বিপদ হলো ভুলও একই আত্মবিশ্বাসে আসে। আমাদের নিজের কাজেই ধরা পড়েছে: GPT-2 medium-এর layer ১৬ ভেবে হিসাব মেলেনি; config দেখে পাওয়া গেল ২৪, xl-এর ৪৮।
| AI প্রায়ই যা করে | যাচাই |
|---|---|
Labels আগে নিজে shift করে আবার labels= দেয় | হাতে-সরানো cross-entropy-র সঙ্গে মেলান |
| পুরোনো argument বা removed class ব্যবহার | আপনার version-এর docs পড়ুন, ছোট batch-এ চালান |
model.eval() ভুলে যায়; আমাদের run-এ train mode-এ একই input-এর logit ৬৭.৪ পর্যন্ত বদলেছে, eval-এ ০ | একই input দুইবার চালিয়ে দেখুন |
| “GPT-4-এর এত parameter” বলে উৎস ছাড়া | মূল প্রতিবেদন বা নথি চান |
| Bangla-তে per-token loss তুলনা করে “ভালো” বলে | bit প্রতি অক্ষরে হিসাব করুন |
| “Model বুঝেছে” ধরনের ভাষা | Top-10 দেখুন; একটি seed-এর ফলে সিদ্ধান্ত নেবেন না |
নিচের prompt-এ AI-কে হিসাবটি দেখিয়ে দিতে বলা হয়েছে, আর আপনি নিজে চালিয়ে মেলাবেন।
ভাবনার প্রশ্ন
প্রতিটি প্রশ্ন নিয়ে নিজে কিছুক্ষণ ভাবুন, তারপর “→ উত্তর” চাপুন।
প্র ০১GPT-1 থেকে GPT-4: প্রকাশের ধরন এত বদলাল কেন, আর তাতে গবেষক ও ছাত্রের কী এসে যায়?
GPT-1 প্রবন্ধ (২০১৮) layer, d, head, learning rate, ডেটা সব লিখেছে। সেই বিবরণ দেখে আজও আপনি প্রায় একই model লিখতে পারেন। GPT-2-তে (২০১৯) প্রথম বড় বিতর্ক। বহুল-আলোচিত ঘটনা অনুযায়ী, OpenAI প্রথমে শুধু ছোট model প্রকাশ করে, misuse-এর ভয়ের কথা বলে, আর ধাপে ধাপে বছরের শেষ দিকে বড়টি। সমালোচকদের কারো মতে এটি অতিরিক্ত সতর্কতা ছিল, কারো মতে দায়িত্বশীল নজির। পরে একই ধরনের model নানা দলই বানিয়েছে। GPT-3-এর প্রবন্ধে স্থাপত্য আর ডেটার হিসাব ছিল, কিন্তু weight প্রকাশ করা হয়নি, শুধু API. GPT-4-এর প্রতিবেদন প্রতিযোগিতা আর নিরাপত্তার কথা বলে স্থাপত্য, আকার ও training বাদ দেয়।
এতে কী এসে যায়? প্রথমত, পুনরুৎপাদন কঠিন হয়। বিজ্ঞানে দাবি যাচাই করা যায় কারণ পদ্ধতি লেখা থাকে; এখানে বাইরে থেকে শুধু আচরণ মাপা যায়। দ্বিতীয়ত, গুজব জায়গা নেয়। “এত ট্রিলিয়ন parameter” ধরনের সংখ্যা ইন্টারনেটে ঘোরে, উৎস ছাড়াই। তৃতীয়ত, নিরাপত্তা-যুক্তিটিও উড়িয়ে দেওয়ার নয়; প্রকাশে ঝুঁকি থাকতে পারে, আর সেখানে সর্বসম্মত উত্তর নেই। অন্যদিকে Llama, Mistral, Qwen, DeepSeek-এর open weights আর প্রতিবেদন আবার বহু কিছু দেখার সুযোগ দিয়েছে, যদিও সেখানেও সাধারণত পুরো training data প্রকাশ হয় না।
মূল উপলব্ধি: তিন ধরনের তথ্য আলাদা করুন: যা নথিতে আছে, যা নিজে মাপা যায়, আর যা গুজব। পরীক্ষায় বা কাজে শুধু প্রথম দুটির ওপর দাঁড়ান, উৎস আর তারিখসহ।
প্র ০২Encoder-decoder তো আগে থেকেই ছিল। বহু LLM decoder-only হলো কেন? T5 বা BERT কি ভুল পথে ছিল?
না, ভুল পথ বলা যায় না। তিনটি নকশা তিন প্রশ্নের উত্তর। BERT (পর্ব ৪৮, BERT পরিবার) দুই দিকের context দেখে, তাই masked শব্দ পূরণ আর classification-এ স্বাভাবিক, কিন্তু সরাসরি পরের token লেখার জন্য বানানো নয়। T5 encoder-decoder, যেখানে input আর output আলাদা জগৎ: অনুবাদ, সারাংশ। GPT শুধু এক দিকে দেখে, আর একটিই লক্ষ্য রাখে: পরের token.
Decoder-only নকশার সুবিধা মূলত সরলতায়। প্রশ্ন, উত্তর, উদাহরণ সবই এক ক্রমে বসে, তাই নতুন কাজের জন্য স্থাপত্য বদলাতে হয় না। GPT-2 প্রবন্ধ এই যুক্তির একটি রূপ দেখায়: english text, french text এভাবে ক্রম সাজালে অনুবাদও language modeling. Generation-এর সময় হিসাবও সরল: পর্ব ৩৭-এর KV cache এক জায়গায় থাকে, আলাদা encoder pass লাগে না। Training ডেটা বিশাল: যেকোনো লেখাই উদাহরণ, জোড়া লাগে না।
কিন্তু দামও আছে। Decoder-only model-এ পুরো input-এর ওপর attention-এর খরচ T²-এর হারে বাড়ে, আর input-এর জন্য আলাদা ছোট encoder রাখার সুবিধা নেই। Retrieval বা classification-এ এখনো encoder ব্যাপক ব্যবহৃত হয়; embedding তৈরির বহু model encoder-ধাঁচের। পর্ব ৪৮-এ দেখেছেন, ছোট ডেটার classification-এ BERT-ধাঁচের model স্বাভাবিক পছন্দ।
একটি সতর্কতা: “LLM decoder-only হলো কারণ এটি সবচেয়ে ভালো”, এটি পরে তৈরি গল্প। বাজার, GPU, উপলব্ধ ডেটা আর কয়েকটি সফল প্রবন্ধের প্রভাবও ছিল। Bandwagon-এর ভূমিকা মাপা কঠিন।
মূল উপলব্ধি: স্থাপত্য বাছাই হয় কাজ আর খরচ দেখে। “কোনটি সেরা” না জিজ্ঞেস করে জিজ্ঞেস করুন, input আর output-এর সম্পর্ক কী, আর কত ডেটা ও memory আছে।
প্র ০৩Weight tying যদি ৩১% parameter বাঁচায়, তবে Qwen আর Mistral এটি বাদ দিল কেন?
আগে হিসাব। GPT-2 small-এ tying ৩.৮৬ কোটি সংখ্যা বাঁচায়, মোটের প্রায় ৩১%. কিন্তু একই V নিয়ে d আর L বাড়ালে ভাগ দ্রুত কমে: xl-এ প্রায় ৫%. Calculator-এ দেখেছেন। যুক্তির ওজন তাই আকারের সঙ্গে বদলায়।
চিন্তাটি পুরোনো। Press ও Wolf (২০১৬ সালে arXiv-এ), আর প্রায় একই সময়ে Inan ও সহলেখকেরা language model-এ input আর output embedding এক করার পক্ষে যুক্তি দেন: যে token-এর input vector যেমন, output-এও সে কাছাকাছি হওয়ার কথা। ফলে নিয়মিতকরণের মতো কাজ হয়, ছোট ডেটায় উপকার পাওয়ার রিপোর্ট আছে।
উল্টো যুক্তিও আছে। Input-এ embedding-এর কাজ token-এর পরিচয় দেওয়া; output-এ head-এর কাজ পরের token-এর স্কোর দেওয়া। দুটি কাজ একই নয়; আলাদা matrix বাড়তি স্বাধীনতা দেয়। Qwen প্রতিবেদন লেখে যে তারা বেশি memory মেনে নিয়ে untied পথ নিয়েছে, ভালো ফলের জন্য, আর Mistral 7B-র config-এ tie_word_embeddings: false. অন্যদিকে Qwen2.5-এর ছোট model-এ আবার tied (আমাদের run-এ tied: True). অর্থাৎ একই দলও আকার দেখে ভিন্ন সিদ্ধান্ত নিতে পারে।
কেউ কেউ বলেন, এই ধরনের নকশা-সিদ্ধান্ত ফল নিয়ে যতটা, ঐতিহ্য নিয়েও ততটা; তাই নিজের ডেটায় পরীক্ষা ছাড়া কোনো এক দিক “সঠিক” বলা ঠিক নয়।
মূল উপলব্ধি: নকশার নিয়ম কখনো মুখস্থ করবেন না; হিসাব করুন সেটি কতটা বাঁচায়। ছোট model আর ছোট ডেটায় tying প্রায়ই সহজ পছন্দ, বড় model-এ সিদ্ধান্ত খোলা।
প্র ০৪বাংলায় GPT-2-এর ব্যর্থতা কি byte-level BPE-র দোষ?
পুরোটা নয়। দুই কারণ আলাদা করা দরকার। Tokenizer: GPT-2 প্রবন্ধ byte-স্তর বেছেছে একটি সৎ কারণে: যেকোনো Unicode লেখাকে কোনো অচেনা token ছাড়াই ধরা যায়, আর ভিত্তি vocabulary ২৫৬-তে থাকে। Merge শেখা হয়েছে মূলত ইংরেজি WebText-এ, তাই বাংলা byte-জোড়া merge পায়নি। ফল আমাদের run-এ ১.৯৪ token প্রতি অক্ষর। ডেটা: প্রবন্ধের অনুবাদ অংশ বলে, WebText থেকে অ-ইংরেজি পাতা ইচ্ছা করে ছেঁকে ফেলা হয়েছিল; পরে byte-স্তরের ভাষা-শনাক্তকারীতে ফরাসি মিলেছিল মাত্র ১০ MB. বাংলার ভাগ প্রবন্ধে নেই, তবে খুব কম ছিল বলেই ধারণা করা যায়। Tokenizer ঠিক থাকলেও, যে লেখা model দেখেনি, তা থেকে সে শিখতে পারে না।
দুটি আলাদা তা কীভাবে জানবেন? পর্ব ৩৬-এর MiniGPT অক্ষর-স্তরে, খুব ছোট; তবু বাংলা অক্ষর ঠিক রেখে গল্পের ঢং নকল করে, কারণ সে শুধু বাংলাই দেখেছে। আর পর্ব ৪০-এ বাংলায় শেখা byte-level BPE-তে token অনেক কমে গেছে। মানে byte-level নিজে দোষী নয়; কোন লেখায় merge আর weight শেখা হলো, সেটি মূল।
বহুভাষিক model-এ হিসাব ভিন্ন, কিন্তু নিশ্চয়তা নয়। Bangla তাদের তালিকায় নাম ধরে না-ও থাকতে পারে, যেমন Qwen2.5-এর ব্লগের উদাহরণ তালিকায় ছিল না। তাই “২৯+ ভাষা” পড়ে ধরে নেবেন না; নিজের লেখায় মাপুন। বাংলাদেশে বাংলা-কেন্দ্রিক model-এর কাজও আছে, যেমন BanglaBERT (পর্ব ৪৮); সেই পথ ছোট কিন্তু লক্ষ্য স্পষ্ট।
মূল উপলব্ধি: কোনো model ভাষায় ব্যর্থ হলে আগে তিন প্রশ্ন: tokenizer কত টুকরো করছে, training লেখায় সেই ভাষা কতটা ছিল, আর আপনি মাপছেন কোন এককে।
প্র ০৫পরের token অনুমান করা আর “বোঝা” কি এক? Next-token দিয়ে কি অর্থ শেখা সম্ভব?
এই প্রশ্নে গবেষকদের মধ্যে সত্যিকারের মতভেদ আছে। এক পক্ষে Bender ও Koller (২০২০)-এর যুক্তি: শুধু ভাষার রূপ দেখে অর্থ শেখা যায় না, কারণ অর্থ বাইরের জগতের সঙ্গে সম্পর্ক। তাঁদের “অক্টোপাস” চিন্তা-পরীক্ষা বিখ্যাত। Bender, Gebru ও সহলেখকদের ২০২১ সালের “Stochastic Parrots” প্রবন্ধও একই সতর্কতা দেয়, সঙ্গে ডেটা আর খরচের প্রশ্ন।
অন্য পক্ষে কিছু পরীক্ষামূলক কাজ। Li ও সহলেখকদের Othello-GPT গবেষণায় (২০২২ সালে arXiv-এ) শুধু চালের ক্রমে প্রশিক্ষিত model-এর ভেতরে বোর্ডের অবস্থার একধরনের প্রতিনিধিত্ব পাওয়া যায় বলে রিপোর্ট করা হয়। তাতে বোঝা যায়, ক্রম অনুমান করতে গিয়ে model ভেতরে কাঠামো গড়তে পারে। তবে সেটিকে “বোঝা” বলা যায় কি না, প্রশ্নটি দর্শনেরও।
আমাদের run থেকে কী বলা যায়? GPT-2-এর “The capital of Bangladesh is” top-10-এ Dhaka নেই। এটি একটি ছোট, পুরোনো model-এর এক নমুনা; বড় model এই প্রশ্নে অন্য ফল দিতে পারে। কিন্তু objective একই থাকে: পরের token-এর log-probability. সেখানে সত্যের আলাদা সংকেত নেই। তাই সাবলীল ভুল আসতে পারে; আরও আছে পর্ব ৫২-তে।
কাজের ক্ষেত্রে দার্শনিক উত্তর লাগে না। প্রশ্ন হওয়া উচিত: এই কাজে, এই ডেটায়, model কতবার ঠিক, কীভাবে ভুল হয়, আর ভুল ধরার উপায় কী। “Model বুঝেছে” কথাটি যাচাইয়ের জায়গা নেয় না।
মূল উপলব্ধি: Objective যা মাপে, model তাই শেখে। অর্থ বা সত্য আলাদা কোনো সংকেত নয়। আচরণ মাপুন, আর দাবি লিখুন সতর্কভাবে।
অনুশীলন
খাতা আর calculator নিয়ে বসুন। উত্তর পরে মিলিয়ে নিন।
-
Parameter হাতে গুনুন: Decoder: V = 32,000, ctx = 512, d = 256, L = 6, h = 8, FFN 4d, bias সহ, LayerNorm-এ দুই ভাগ, tied. মোট কত? Tied না হলে কত?
Token 32000×256 = 8,192,000. Position 512×256 = 131,072. Attention: (256×768+768) + (256×256+256) = 197,376 + 65,792 = 263,168. FFN: (256×1024+1024) + (1024×256+256) = 263,168 + 262,400 = 525,568. LayerNorm দুটি: 1,024. Block = 789,760; ছয়টি = 4,738,560. ln_f = 512.
মোট = ১,৩০,৬২,১৪৪। Tied না হলে আরও ৮১,৯২,০০০ যোগে ২,১২,৫৪,১৪৪। লক্ষ্য করুন, এত ছোট model-এ token table-ই মোটের প্রায় ৬৩%; h = 8 হিসাবে আসেনি।
-
আউটপুট অনুমান করুন: কী ছাপা হবে?
ids = np.array([[5,8,2,9],[1,7,0,0]]);x, y = ids[:,:-1], ids[:,1:].copy();y[y==0] = -100;print(x.shape, y.tolist(), (y!=-100).sum())। আর V = 50257 হলে logits-এর shape?(2, 3) [[8, 2, 9], [7, -100, -100]] 4. ধরে নেওয়া: ০ হলো pad. প্রথম সারিতে ৩টি, দ্বিতীয় সারিতে ১টি ঘর গোনা হবে, মোট ৪টি। Logits-এর shape (2, 3, 50257). হর ৪, ৬ নয়; ignore_index-এর এটাই মানে। -
Cache-এর হিসাব: Mistral 7B-র প্রকাশিত মাপ: ৩২ layer, head_dim ১২৮, n_heads ৩২, n_kv_heads ৮। Float16-এ (২ byte), batch ১, T = ৪০৯৬ ঘরে KV cache কত? সব head-এ K, V থাকলে কত?
সূত্র: 2 · L · kv_heads · head_dim · T · bytes. GQA: 2 × 32 × 8 × 128 × 4096 × 2 = 536,870,912 byte = ০.৫ GiB. সব head-এ: 32/8 = ৪ গুণ, ২ GiB. Model-এর weight-এর memory আলাদা; এটি শুধু cache, আর sliding window থাকলে cache এই মাপের বেশি রাখার দরকার হয় না।
-
সমালোচনা ও নকশা: একজন লিখলেন: “GPT-2-এর বাংলা loss ১.৮, ইংরেজি ৪.০। তাই GPT-2 বাংলায় ভালো, বাজারঘরের রিভিউ লেখাতে এটিই নেব।” কোথায় ভুল? আপনি কী করবেন?
ভুল: ভিন্ন লেখা, আর এক token-এর অর্থ দুই ভাষায় আলাদা। Byte-এ ভাঙা বাংলার অনেক token প্রায় নিশ্চিত, তাই গড় কমে। প্রতি অক্ষরে bit হিসাবে ফল উল্টো (৫.০৩ বনাম ১.৩০)। আসল generation-ও দেখা হয়নি, যেখানে ফল অকেজো।
নকশা: (১) একটি held-out বাংলা রিভিউ সেট ঠিক করুন। (২) সব প্রার্থী model-কে সেখানে bit প্রতি অক্ষরে মাপুন। (৩) কয়েকটি seed-এ লেখা তৈরি করে মানুষ দিয়ে পড়ান। (৪) বাংলা-সমৃদ্ধ tokenizer আর model আগে বিবেচনা করুন; fine-tuning-এর পথ পর্ব ৫৪-তে (Transformer fine-tuning — classification, NER আর বাংলা ডেটা)। (৫) নিজের লেখা নিজে তৈরি করলে ডেটার গোপনীয়তা ভাবুন।
নিজেকে যাচাই করুন
ভুল হলে কারণসহ ব্যাখ্যা পাবেন, আবার চেষ্টাও করতে পারবেন।
ক্রমDecoder-only model-এ এক ধাপ generation সঠিক ক্রমে সাজান (▲▼ চেপে সরান)
- লেখা থেকে tokenizer-এ token id
- Token আর position embedding (অথবা RoPE)
- Causal block-এর ভেতর দিয়ে forward
- LM head থেকে logits, শেষ ঘর নেওয়া
- Softmax, তারপর একটি token বাছাই
- নতুন token input-এর শেষে জোড়া
Token id-র ক্রম [7, 3, 9, 2] থেকে next-token training-এ input আর target কী হবে?
- input [7, 3, 9, 2], target [7, 3, 9, 2]
- input [7, 3, 9], target [3, 9, 2]
- input [3, 9, 2], target [7, 3, 9]
- input [7, 3], target [9, 2]
GPT-ধাঁচের একটি decoder-এ V = 1000, d = 64, weight tied. LM head মোট কত নতুন parameter যোগ করে?
- 64,000
- 64,000 + 1,000 = 65,000
- ০
- 64
d = 768 একই রেখে multi-head attention-এর head ১২ থেকে ৮ করলে (প্রতি head-এর মাপ d/h হলে) parameter-এর কী হয়?
- বদলায় না
- ৮/১২ গুণ কমে
- ১২/৮ গুণ বাড়ে
- d-র মান কমে যায়, তাই কমে
কোনো decoder-এ শেষ token বদলালে আগের একটি ঘরের logit-ও বদলাচ্ছে (model.eval() অবস্থায়, একই batch). এর সবচেয়ে সম্ভাব্য কারণ কী?
- Weight tying চালু আছে
- RoPE ব্যবহার হচ্ছে
- Label shift ভুল হয়েছে
- Causal mask ঠিকমতো কাজ করছে না
একটি model-এ ইংরেজি লেখার loss ৪.০ nat/token, বাংলা ১.৮ nat/token; বাংলায় token প্রতি অক্ষরে প্রায় ২, ইংরেজিতে প্রায় ০.২২। সবচেয়ে ঠিক সিদ্ধান্ত কোনটি?
- বাংলায় model ভালো, কারণ loss কম
- Per-token তুলনা বিভ্রান্তিকর; প্রতি অক্ষরে বাংলার খরচ বেশি
- Perplexity দেখলেই সমস্যা মিটে যায়
- দুটি সংখ্যাই অর্থহীন, কিছুই বলা যায় না
GQA-তে ১৬টি query head কিন্তু ৪টি key-value head. সব head-এ K, V রাখা অবস্থার তুলনায় KV cache কতটা হয়?
- একই থাকে
- ৪ গুণ বড়
- ৪ ভাগের ১ ভাগ
- ২ ভাগের ১ ভাগ
শব্দকোষ
লেখার মধ্যে ডটেড দাগ দেওয়া শব্দে মাউস রাখুন বা চাপুন, অর্থ দেখাবে। এই পর্বের সব নতুন শব্দ এখানে একসাথে:
মনে রাখুন
- Decoder-only মানে causal block, encoder আর cross-attention নেই; কাজ পরের token অনুমান।
- Target হলো input-কে এক ঘর সরানো; pad ঘর −100. Hugging Face নিজেই সরায়।
- Parameter-এর প্রধান পদ 12·L·d²; GPT-2 small ১২,৪৪,৩৯,৮০৮, h-এর ওপর নির্ভর করে না।
- ভিন্ন tokenizer বা ভাষায় per-token loss তুলনা চলে না; bit প্রতি অক্ষর দেখুন। GPT-2 বাংলা লেখার জন্য নয়।
- Open model-এ RMSNorm, RoPE, SwiGLU, GQA, MoE; তথ্য নিন প্রবন্ধ, card আর config থেকে, তারিখসহ।
আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ
- পর্ব ৫০ · Decoding — greedy, beam search, temperature, top-k আর top-pপরবর্তী পর্বএকই model থেকে ভিন্ন লেখা বেরোনোর কৌশল, হাতে আর সত্যিকারের run-এ।
- পর্ব ৩৬ · নিজে Transformer লেখাপিছনেএকই ছাঁচের ছোট model আপনার নিজের হাতে।
- পর্ব ৩৭ · দক্ষ attentionপিছনেKV cache আর GQA-র সূত্র।
- ডিপ লার্নিং, NLP আর Generative AI · কোর্স হোম৯১টি পর্বপুরো কোর্সের রোডম্যাপ।
- AI-এর ভিত্তি · পর্ব ৭০ · LLM কীভাবে কাজ করেপূর্বশর্তToken, পরের শব্দের অনুমান আর সীমার সরল ছবি।