Mundarija (21)
- 1. Kirish va motivatsiya
- 2. Nazariya — chuqur tushuntirish
- 2.1. Nega kerak: self-attention permutatsiyaga befarq
- 2.2. Sinusoidal kodlash
- 2.3. Nisbiy siljish — chiziqli almashtirish
- 2.4. O'rganiladigan pozitsion embedding
- 2.5. Uzunlikdan tashqariga ekstrapolyatsiya
- 2.6. RoPE — burish orqali nisbiy pozitsiya
- 2.7. Tuzoqlar
- 3. Tez ma'lumotnoma
- 4. Batafsil misollar
- Misol 1 — Permutatsiya va sinusoidal kodlash noldan
- Misol 2 — Pozitsiyasiz model tartibni ko'rmaydi
- Misol 3 — Uzunlikdan tashqariga: sinus va o'rganiladigan
- Misol 4 — RoPE noldan: burish va nisbiy pozitsiya
- 5. To'g'ri va noto'g'ri tushunishlar
- 6. Keng tarqalgan xatolar va yechimlari
- 7. Integratsiya — bu bilim qayerda kerak bo'ladi
- 8. Eng yaxshi amaliyotlar
- 9. Amaliy topshiriq
- Xulosa
24.4-dars: Pozitsion kodlash
24-QISM — TRANSFORMERLAR · 4-dars
1. Kirish va motivatsiya
Oldingi uch darsda attention mexanizmini, self-attention va multi-head attention ni qurdik. Ularning hammasida bitta jimgina muammo bor edi: self-attention so'zlar tartibini ko'rmaydi. U har pozitsiya uchun "qaysi so'zlarga qancha qarash kerak" ni skalyar ko'paytma orqali hisoblaydi, skalyar ko'paytma esa faqat vektorlarning o'ziga bog'liq — ular ketma-ketlikning qayerida turgani haqida hech narsa bilmaydi. "Ali Valini chaqirdi" va "Vali Alini chaqirdi" jumlalari self-attention uchun bir xil so'zlar to'plami, faqat qatorlar joyi almashgan.
RNN da bu muammo yo'q edi: u ketma-ketlikni chapdan o'ngga o'qiydi, tartib hisobning o'zida. Transformer esa rekurrentlikdan voz kechdi — barcha pozitsiyalar parallel hisoblanadi. Buning narxi: tartib haqidagi ma'lumotni alohida qo'shish kerak. Buni pozitsion kodlash (positional encoding) qiladi: har pozitsiyaga vektor beriladi va u so'z embeddingiga qo'shiladi (yoki attention skoriga boshqacha yo'l bilan kiritiladi).
Bu yerda uchta savol bor. Birinchisi — qanday vektor: asl Transformer maqolasidagi sinus va kosinuslardan qurilgan formula, BERT va GPT-2 dagi o'rganiladigan jadval, yoki zamonaviy til modellaridagi RoPE (burish). Ikkinchisi — nima uchun aynan sinus: formulaning ichida "k qadam siljish" ni chiziqli almashtirish bilan ifodalash xossasi yashiringan. Uchinchisi va amaliy jihatdan eng muhimi — uzunlikdan tashqariga ekstrapolyatsiya: model 512 tokenli matnlarda o'rgatilgan bo'lsa, 2000 tokenli matnda ishlaydimi?
Real vaziyat. Jamoa hujjatlarni tasniflash uchun kichik Transformer o'rgatdi, o'quv matnlari 256 tokengacha kesilgan edi. "Sinusoidal kodlash formulasi istalgan pozitsiya uchun vektor beradi, demak model uzun hujjatlarda ham ishlaydi" deb qaror qilindi. Ishga tushirilganda uzun hujjatlarda sifat keskin tushib ketdi. Formula haqiqatan har pozitsiya uchun vektor beradi — lekin model ularni hech qachon ko'rmagan. Bu darsning 3-misoli aynan shu holatni o'lchaydi.
Bu darsda pozitsion kodlashning uch turini noldan quramiz, ularning xossalarini raqam bilan tekshiramiz va uzunlikdan tashqarida qanday ishlashini halol o'lchaymiz.
Bu darsda:
- Nega kerak: self-attention permutatsiyaga befarq
- Sinusoidal kodlash: formula va chastotalar
- Nisbiy siljish — chiziqli almashtirish
- O'rganiladigan pozitsion embedding
- Uzunlikdan tashqariga ekstrapolyatsiya
- RoPE — burish orqali nisbiy pozitsiya
- Tuzoqlar
ℹ Misollar real torch/numpy bilan (Python 3.14, torch 2.14 CPU).
2. Nazariya — chuqur tushuntirish
2.1. Nega kerak: self-attention permutatsiyaga befarq
SELF-ATTENTION 24.2-bob:
Q = X W_q, K = X W_k, V = X W_v
chiqish = softmax(Q K^T / sqrt(d)) V
PERMUTATSIYA P (qatorlar joyini almashtirish):
X' = P X -> Q' = P Q, K' = P K, V' = P V
softmax(P Q K^T P^T) P V = P softmax(Q K^T) V
chiqish' = P * chiqish <- EKVIVARIANTLIK
MA'NOSI:
har so'zning chiqish vektori tartibdan QAT'I NAZAR bir xil,
faqat qator joyi almashadi
o'rtacha pooling qo'shilsa: P butunlay yo'qoladi <- INVARIANTLIK
"ali vali dan oldin" va "vali ali dan oldin" - bir xil vektor
1-MISOL: max |f(PX) - P f(X)| = 2.4e-07 (son xatosi)
2-MISOL: pozitsiyasiz model tartib vazifasida 0.5053 (tasodif 0.5),
sanoq vazifasida 1.0000Pozitsiya ma'lumoti bo'lmasa, Transformer "so'zlar qopi" modeli — FFN va LayerNorm ham har pozitsiyaga alohida qo'llanadi, ular ham tartibni qo'shmaydi.
2.2. Sinusoidal kodlash
FORMULA (Vaswani va boshq., 2017):
PE[p, 2i] = sin(p * w_i)
PE[p, 2i+1] = cos(p * w_i)
w_i = 1 / 10000^(2i / d), i = 0 .. d/2 - 1
kirish: x_p = E[token_p] + PE[p] (qo'shiladi, ulanmaydi)
XOSSALAR (1-misol, d = 16):
qiymatlar [-1, 1] oralig'ida, norma DOIM sqrt(d/2) = 2.8284
i = 0 -> to'lqin uzunligi 2*pi = 6.28 pozitsiya (tez o'zgaradi)
i = 7 -> 19869 pozitsiya (deyarli o'zgarmaydi)
"soat millari": sekundlik, minutlik, soatlik ... strelkalar
NIMA UCHUN KO'P CHASTOTA:
bitta sinus davriy - p va p + 2*pi*n farqlanmaydi
turli chastotalar birgalikda har pozitsiyaga yagona "barmoq izi"
1-misol: 100 pozitsiyada 100 ta har xil vektorSinusoidal kodlash — o'rganilmaydigan, istalgan pozitsiya uchun hisoblanadigan formula; parametr soni nol.
2.3. Nisbiy siljish — chiziqli almashtirish
BITTA CHASTOTA JUFTLIGI:
[sin(w(p+k)), cos(w(p+k))] = R(w k) [sin(w p), cos(w p)]
R(a) = [[ cos a, sin a],
[-sin a, cos a]] <- 2x2 burish matritsasi
BUTUN VEKTOR:
PE[p + k] = M_k PE[p], M_k = blok-diagonal (R(w_0 k), ..., R(w_{d/2-1} k))
M_k faqat k ga bog'liq, p ga EMAS
1-MISOL:
k = 1, 5, 20: max |PE[p+k] - M_k PE[p]| ~ 3e-15 (mashina aniqligi)
M_5 ni faqat p < 50 dan topib (eng kichik kvadratlar), p >= 50 da:
max xato 5.4e-07
SKALYAR KO'PAYTMA:
PE[p] . PE[p+k] = yig'indi_i cos(w_i k) <- faqat k ga bog'liq
1-misol: k = +5 da p = 10, 30, 70 uchun hammasi 6.1370
k = -5 da ham 6.1370: skalyar ko'paytma yo'nalishni bilmaydi
G'OYA:
model "3 qadam oldingi so'z" ni topishi uchun
mutlaq pozitsiyani emas, chiziqli almashtirishni o'rganishi mumkinSinusoidal kodlashda siljish — burish: bu xossa nisbiy pozitsiyani o'rganishni osonlashtiradi, lekin model uni haqiqatan o'rganishini kafolatlamaydi.
2.4. O'rganiladigan pozitsion embedding
G'OYA: pozitsiyani ham token kabi embedding qilish
pos = nn.Embedding(maks_uzunlik, d)
x_p = E[token_p] + pos(p)
BERT (512), GPT-2 (1024) - shu usul
AFZALLIGI:
ma'lumotdan o'rganadi, formula tanlash shart emas
qisqa ketma-ketlikda sinus bilan deyarli teng
(2-misol: ikkalasi ham tartib vazifasida 1.0000)
KAMCHILIGI:
parametr: maks_uzunlik * d (512 * 768 = 393 216)
maks_uzunlik dan uzun ketma-ketlik - jadvalda qator YO'Q (IndexError)
jadval kattaroq bo'lsa ham - o'quvda ko'rilmagan qatorlar
tasodifiy init holida qoladi (3-misol: p >= 16 da 0.140, tasodif 0.125)O'rganiladigan pozitsiya — jadval: faqat o'quvda ko'rilgan pozitsiyalar ma'noga ega.
2.5. Uzunlikdan tashqariga ekstrapolyatsiya
SAVOL: L = 16 da o'rgatilgan model L = 64 da ishlaydimi?
3-MISOL (vazifa: har pozitsiyada 3 qadam oldingi tokenni aytish):
L=16 L=32 L=64 p >= 16 (L=64)
pozitsiyasiz 0.268 0.218 0.186 0.187
sinus 1.000 0.561 0.391 0.235
o'rganiladigan 1.000 0.530 0.322 0.140
tasodif: 0.125
NIMA UCHUN SINUS HAM YIQILADI:
formula PE[40] ni beradi, lekin model PE[40] + E[token] kombinatsiyasini
hech qachon ko'rmagan; W_q, W_k shu hududda o'rgatilmagan
"nazariy imkoniyat" != "o'rganilgan xatti-harakat"
KO'RILGAN POZITSIYALAR HAM ZARAR KO'RADI:
L=64 ichidagi p < 16 - sinus 0.967, o'rganiladigan 0.993
(L=16 da ikkalasi 1.000): ko'p "begona" kalitlar attention ni chalg'itadi
AMALIYOT:
o'quvda kerakli uzunlikni ko'rsating (yoki uzunlik bo'yicha bosqichli o'rgatish)
uzunroq kontekst kerak bo'lsa: nisbiy usullar (RoPE, ALiBi) +
qisqa qo'shimcha o'rgatish"Formula istalgan pozitsiyani beradi" — ekstrapolyatsiya kafolati emas; uzunlik bo'yicha doim alohida o'lchang.
2.6. RoPE — burish orqali nisbiy pozitsiya
G'OYA (Su va boshq., 2021):
pozitsiyani x ga QO'SHISH o'rniga, q va k ni pozitsiyaga mos BURISH
q_m' = R(m) q_m, k_n' = R(n) k_n
R(p) - blok-diagonal, har (2i, 2i+1) juftlik p * w_i burchakka
ASOSIY XOSSA:
q_m' . k_n' = q_m^T R(m)^T R(n) k_n = q_m^T R(n - m) k_n
-> skor FAQAT nisbiy masofa (n - m) ga bog'liq
-> sinusdan farqli: yo'nalish ham saqlanadi (R(3) != R(-3))
KOD (juftlik bo'yicha):
y[2i] = x[2i] cos(p w_i) - x[2i+1] sin(p w_i)
y[2i+1] = x[2i] sin(p w_i) + x[2i+1] cos(p w_i)
4-MISOL:
norma o'zgarmaydi (3.3953 hamma p da)
m - n = 3 bo'lgan (5, 2), (25, 22), (105, 102): skor 1.1783, oraliq 7.2e-07
qo'shiladigan sinusda xuddi shu juftliklar: oraliq 5.3169
ekstrapolyatsiya, p >= 16 (L=64): RoPE 0.510, sinus 0.235
farq +0.2747, SE 0.0629 - sezilarli, lekin 1.000 dan uzoq
QAYERDA: LLaMA, Mistral, Qwen va boshqa ko'p zamonaviy til modellari
parametr yo'q; faqat attention ichida q va k ga qo'llanadi (v ga emas)RoPE nisbiy pozitsiyani attention skorining o'ziga kiritadi; ekstrapolyatsiyani yaxshilaydi, lekin uzun kontekstni "bepul" bermaydi.
2.7. Tuzoqlar
Asosiy tuzoqlar: pozitsion kodlashni umuman unutish (model xato bermaydi, faqat tartibni ko'rmaydi); pozitsiyani batch o'qi bo'yicha qo'shish (pe[:B] o'rniga pe[:L] kerak); sinus jadvalini requires_grad=True parametr qilib qo'yish yoki register_buffer qilmaslik (.to(device) da ko'chmay qoladi); embedding ni sqrt(d) ga ko'paytirish yoki ko'paytirmaslikni o'ylamasdan tanlash (masshtablar nisbati o'zgaradi); o'rganiladigan jadvaldan uzun ketma-ketlik berish (IndexError) yoki jadvalni kattalashtirib "ishladi" deb o'ylash; RoPE ni v ga ham qo'llash yoki q va k ga turli pozitsiyalar berish; sin va cos ni noto'g'ri juftlash ([0::2] va [1::2] o'rniga birinchi va ikkinchi yarim — ikkalasi ham ishlatiladi, lekin bir modelda bittasi); uzunlik bo'yicha umumlashishni o'quv uzunligida tekshirib qo'yish.
3. Tez ma'lumotnoma
import math
import torch
import torch.nn as nn
# sinusoidal (bufer - o'rganilmaydi, lekin .to(device) bilan ko'chadi)
def sinus_pe(n, d):
p = torch.arange(n)[:, None].float()
w = torch.exp(-math.log(10000.0) * torch.arange(0, d, 2).float() / d)
pe = torch.zeros(n, d)
pe[:, 0::2] = torch.sin(p * w)
pe[:, 1::2] = torch.cos(p * w)
return pe
self.register_buffer("pe", sinus_pe(maks, d))
x = self.emb(X) + self.pe[:X.shape[1]] # (B, L, d) + (L, d)
# o'rganiladigan
self.pos = nn.Embedding(maks, d)
x = self.emb(X) + self.pos(torch.arange(X.shape[1]))
# RoPE: q, k (B, h, L, d_h) ga, attention dan OLDIN
def rope(x, p):
a = p[:, None].float() * chastotalar(x.shape[-1]) # (L, d_h/2)
c, s = torch.cos(a), torch.sin(a)
x1, x2 = x[..., 0::2], x[..., 1::2]
y = torch.empty_like(x)
y[..., 0::2] = x1 * c - x2 * s
y[..., 1::2] = x1 * s + x2 * c
return y
q, k = rope(q, torch.arange(L)), rope(k, torch.arange(L))
# permutatsiya tekshiruvi
perm = torch.randperm(L)
(model(X)[:, perm] - model(X[:, perm])).abs().max() # pozitsiyasiz ~ 1e-7Pozitsion kodlash xulosasi
self-attention tartibni ko'rmaydi - pozitsiya alohida kerak
sinus: formula, parametrsiz, siljish = burish
o'rganiladigan: jadval, faqat ko'rilgan pozitsiyalar
ekstrapolyatsiya: formula != kafolat; o'lchang
RoPE: q va k ni burish, skor = f(n - m)4. Batafsil misollar
Misollar real torch/numpy bilan (Python 3.14, torch 2.14 CPU).
Misol 1 — Permutatsiya va sinusoidal kodlash noldan
"""Self-attention permutatsiyaga befarq; sinusoidal kodlash noldan va uning siljish xossasi."""
import math
import numpy as np
import torch
def self_attention(X, Wq, Wk, Wv):
q, k, v = X @ Wq, X @ Wk, X @ Wv
w = torch.softmax(q @ k.T / math.sqrt(q.shape[1]), dim=1)
return w @ v
def sinus_pe(L, d):
"""PE[p, 2i] = sin(p / 10000^(2i/d)), PE[p, 2i+1] = cos(p / 10000^(2i/d))."""
p = np.arange(L)[:, None]
w = 1.0 / 10000 ** (np.arange(0, d, 2) / d) # chastotalar, (d/2,)
pe = np.zeros((L, d))
pe[:, 0::2] = np.sin(p * w)
pe[:, 1::2] = np.cos(p * w)
return pe, w
def siljish_matritsasi(w, k):
"""PE[p + k] = M_k @ PE[p]: har chastota juftligi uchun 2x2 burish."""
M = np.zeros((2 * len(w), 2 * len(w)))
for i, wi in enumerate(w):
c, s = np.cos(wi * k), np.sin(wi * k)
M[2 * i:2 * i + 2, 2 * i:2 * i + 2] = [[c, s], [-s, c]]
return M
def main() -> None:
torch.manual_seed(0)
d = 16
lugat = ["men", "bugun", "kitob", "oldim"]
E = {s: torch.randn(d) for s in lugat}
Wq, Wk, Wv = (torch.randn(d, d) / math.sqrt(d) for _ in range(3))
print("=== 1. Pozitsiyasiz self-attention ===")
jumla = ["men", "bugun", "kitob", "oldim"]
tartib = [2, 0, 3, 1]
aralash = [jumla[i] for i in tartib]
X = torch.stack([E[s] for s in jumla])
Xp = torch.stack([E[s] for s in aralash])
Y, Yp = self_attention(X, Wq, Wk, Wv), self_attention(Xp, Wq, Wk, Wv)
print(f" A: {' '.join(jumla)}")
print(f" B: {' '.join(aralash)}")
farq = (Yp - Y[tartib]).abs().max().item()
print(f" max |f(B) - f(A) ning aralashtirilgani|: {farq:.1e}")
ort = (Yp.mean(0) - Y.mean(0)).abs().max().item()
print(f" o'rtacha pooling farqi: {ort:.1e}")
if farq < 1e-5:
print(" har so'z vektori tartibdan qat'i nazar BIR XIL - faqat joyi almashdi")
if ort < 1e-5:
print(" pooling dan keyin A va B ni ajratib bo'lmaydi")
print("\n=== 2. Sinusoidal kodlash (d = 16) ===")
L = 100
pe, w = sinus_pe(L, d)
print(f" {'p':>3} " + " ".join(f"{f'dim{j}':>7}" for j in (0, 1, 2, 3, 14, 15)))
for p in (0, 1, 2, 3, 50):
print(f" {p:>3} " + " ".join(f"{pe[p, j]:>7.3f}" for j in (0, 1, 2, 3, 14, 15)))
normalar = np.linalg.norm(pe, axis=1)
print(f" har pozitsiya normasi: min {normalar.min():.4f}, max {normalar.max():.4f}"
f" (sqrt(d/2) = {math.sqrt(d / 2):.4f})")
tol = 2 * np.pi / w
print(f" to'lqin uzunliklari: {tol[0]:.2f} ... {tol[-1]:.0f} pozitsiya")
takror = len({tuple(np.round(r, 6)) for r in pe})
print(f" {L} pozitsiyada har xil vektorlar soni: {takror}")
print("\n=== 3. Nisbiy siljish - chiziqli almashtirish ===")
for k in (1, 5, 20):
M = siljish_matritsasi(w, k)
xato = np.abs(pe[k:] - pe[:-k] @ M.T).max()
print(f" k = {k:>2}: max |PE[p+k] - M_k PE[p]| hamma p uchun = {xato:.1e}")
k = 5
A, B = pe[:50 - k], pe[k:50]
M_fit, *_ = np.linalg.lstsq(A, B, rcond=None)
xato_yangi = np.abs(pe[50:L - k] @ M_fit - pe[50 + k:]).max()
print(f" M_5 ni FAQAT p < 50 dan topib, p >= 50 da qo'llash: max xato {xato_yangi:.1e}")
print(" M_k faqat k ga bog'liq, p ga emas: 'k qadam o'ngga' - bitta matritsa")
print("\n=== 4. Skalyar ko'paytma faqat masofaga bog'liq ===")
print(f" {'':>10}" + "".join(f"{f'p={p}':>9}" for p in (10, 30, 70)))
for k in (1, 5, 20, -5):
qator = [pe[p] @ pe[p + k] for p in (10, 30, 70)]
print(f" {f'k = {k:+d}':>10}" + "".join(f"{v:>9.4f}" for v in qator))
k5, km5 = pe[30] @ pe[35], pe[30] @ pe[25]
if abs(k5 - km5) < 1e-9:
print(" +5 va -5 bir xil: skalyar ko'paytma YO'NALISHNI bilmaydi")
print(" ⭐ Sinusoidal kodlash: siljish = burish, o'xshashlik = masofa funksiyasi")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. Pozitsiyasiz self-attention ===
A: men bugun kitob oldim
B: kitob men oldim bugun
max |f(B) - f(A) ning aralashtirilgani|: 2.4e-07
o'rtacha pooling farqi: 6.0e-08
har so'z vektori tartibdan qat'i nazar BIR XIL - faqat joyi almashdi
pooling dan keyin A va B ni ajratib bo'lmaydi
=== 2. Sinusoidal kodlash (d = 16) ===
p dim0 dim1 dim2 dim3 dim14 dim15
0 0.000 1.000 0.000 1.000 0.000 1.000
1 0.841 0.540 0.311 0.950 0.000 1.000
2 0.909 -0.416 0.591 0.807 0.001 1.000
3 0.141 -0.990 0.813 0.583 0.001 1.000
50 -0.262 0.965 -0.103 -0.995 0.016 1.000
har pozitsiya normasi: min 2.8284, max 2.8284 (sqrt(d/2) = 2.8284)
to'lqin uzunliklari: 6.28 ... 19869 pozitsiya
100 pozitsiyada har xil vektorlar soni: 100
=== 3. Nisbiy siljish - chiziqli almashtirish ===
k = 1: max |PE[p+k] - M_k PE[p]| hamma p uchun = 2.7e-15
k = 5: max |PE[p+k] - M_k PE[p]| hamma p uchun = 2.9e-15
k = 20: max |PE[p+k] - M_k PE[p]| hamma p uchun = 2.7e-15
M_5 ni FAQAT p < 50 dan topib, p >= 50 da qo'llash: max xato 5.4e-07
M_k faqat k ga bog'liq, p ga emas: 'k qadam o'ngga' - bitta matritsa
=== 4. Skalyar ko'paytma faqat masofaga bog'liq ===
p=10 p=30 p=70
k = +1 7.4852 7.4852 7.4852
k = +5 6.1370 6.1370 6.1370
k = +20 5.7755 5.7755 5.7755
k = -5 6.1370 6.1370 6.1370
+5 va -5 bir xil: skalyar ko'paytma YO'NALISHNI bilmaydi
⭐ Sinusoidal kodlash: siljish = burish, o'xshashlik = masofa funksiyasiNatija tahlili. 1-bo'limda "men bugun kitob oldim" va uning aralashtirilgan varianti self-attention dan o'tkazildi: har so'zning chiqish vektori aynan bir xil chiqdi, faqat qator joyi almashdi (farq 2.4e-07 — float32 yaxlitlash xatosi). O'rtacha pooling dan keyin esa ikki jumla umuman farqlanmaydi (6.0e-08). 2-bo'limda sinusoidal jadval: p = 0 da juft o'lchovlar 0, toq o'lchovlar 1; dim0 va dim1 tez aylanadi (to'lqin uzunligi 6.28), dim14, dim15 esa 50-pozitsiyada ham deyarli o'zgarmagan (0.016 va 1.000). Hamma pozitsiyada norma bir xil — 2.8284. 3-bo'limda asosiy xossa: PE[p + k] ni PE[p] dan bitta matritsa bilan olish mumkin, xato 3e-15 atrofida. Bundan ham qiziqrog'i — M_5 ni faqat birinchi 50 pozitsiyadan topib, keyingi 45 pozitsiyada qo'llaganda xato 5.4e-07: matritsa haqiqatan pozitsiyaga bog'liq emas. 4-bo'limda skalyar ko'paytma: k = +5 uchun uch xil p da ham 6.1370, va k = -5 da ham aynan shu qiymat — sinus kodlash o'xshashlik orqali "qancha uzoq" ni biladi, "qaysi tomonda" ni bilmaydi.
Nima ko'rsatdi: 2.1, 2.2, 2.3-bo'limlar.
Misol 2 — Pozitsiyasiz model tartibni ko'rmaydi
"""Pozitsiyasiz model tartibga bog'liq vazifani yecha olmaydi: sintetik tajriba."""
import math
import numpy as np
import torch
import torch.nn as nn
import torch.nn.functional as F
SOZLAR = ["<pad>", "ali", "vali", "bugun", "maktabga", "keldi", "kitob",
"oldi", "tez", "uyga", "ertalab"]
V, L = len(SOZLAR), 10
ALI, VALI = 1, 2
def sinus_pe(n, d):
p = torch.arange(n)[:, None].float()
w = torch.exp(-math.log(10000.0) * torch.arange(0, d, 2).float() / d)
pe = torch.zeros(n, d)
pe[:, 0::2] = torch.sin(p * w)
pe[:, 1::2] = torch.cos(p * w)
return pe
class Model(nn.Module):
"""Bitta self-attention bloki + o'rtacha pooling; pe: yoq, sinus, organ."""
def __init__(self, pe, d=32, h=2):
super().__init__()
self.pe = pe
self.emb = nn.Embedding(V, d)
if pe == "organ":
self.pos = nn.Embedding(L, d)
self.register_buffer("sin", sinus_pe(L, d))
self.att = nn.MultiheadAttention(d, h, batch_first=True)
self.ln1, self.ln2 = nn.LayerNorm(d), nn.LayerNorm(d)
self.ffn = nn.Sequential(nn.Linear(d, 4 * d), nn.GELU(), nn.Linear(4 * d, d))
self.chiq = nn.Linear(d, 2)
def forward(self, X):
x = self.emb(X)
if self.pe == "sinus":
x = x + self.sin[:X.shape[1]]
elif self.pe == "organ":
x = x + self.pos(torch.arange(X.shape[1]))
y = self.ln1(x)
x = x + self.att(y, y, y, need_weights=False)[0]
x = x + self.ffn(self.ln2(x))
return self.chiq(x.mean(1))
def tartib_vazifa(n, g):
"""ali va vali bittadan; y = 1 agar ali vali dan OLDIN kelsa."""
X = torch.randint(3, V, (n, L), generator=g)
y = torch.randint(0, 2, (n,), generator=g)
joy = torch.rand(n, L, generator=g).argsort(1)[:, :2].sort(1).values
r = torch.arange(n)
X[r, joy[:, 0]] = torch.where(y == 1, ALI, VALI)
X[r, joy[:, 1]] = torch.where(y == 1, VALI, ALI)
return X, y
def sanoq_vazifa(n, g):
"""ali va vali 0-3 martadan (teng emas); y = 1 agar ali KO'P bo'lsa."""
X = torch.randint(3, V, (n, L), generator=g)
y = torch.randint(0, 2, (n,), generator=g)
juft = torch.rand(n, 4, generator=g).argsort(1)[:, :2]
ko, oz = juft.max(1).values, juft.min(1).values
ka = torch.where(y == 1, ko, oz)
kv = torch.where(y == 1, oz, ko)
rang = torch.rand(n, L, generator=g).argsort(1).argsort(1)
X = torch.where(rang < ka[:, None], ALI, X)
X = torch.where((rang >= ka[:, None]) & (rang < (ka + kv)[:, None]), VALI, X)
return X, y
def orgat(pe, vazifa, seed, qadam=200):
torch.manual_seed(seed)
m = Model(pe)
opt = torch.optim.Adam(m.parameters(), lr=0.003)
g = torch.Generator().manual_seed(seed)
for _ in range(qadam):
X, y = vazifa(64, g)
loss = F.cross_entropy(m(X), y)
opt.zero_grad()
loss.backward()
opt.step()
m.eval()
return m
def korsat(X):
return " ".join(SOZLAR[i] for i in X.tolist())
def main() -> None:
torch.set_num_threads(1)
print("=== 1. Ikki vazifa ===")
X, y = tartib_vazifa(2, torch.Generator().manual_seed(3))
for b in range(2):
print(f" TARTIB y={int(y[b])}: {korsat(X[b])}")
X, y = sanoq_vazifa(2, torch.Generator().manual_seed(3))
for b in range(2):
print(f" SANOQ y={int(y[b])}: {korsat(X[b])}")
print(" TARTIB: ali vali dan oldinmi? SANOQ: ali ko'pmi?")
testlar = {"tartib": tartib_vazifa(2000, torch.Generator().manual_seed(99)),
"sanoq": sanoq_vazifa(2000, torch.Generator().manual_seed(98))}
turlar = ["yoq", "sinus", "organ"]
natija = {(v, pe): [] for v in testlar for pe in turlar}
modellar = {}
for s in range(3):
for nom, vazifa in [("tartib", tartib_vazifa), ("sanoq", sanoq_vazifa)]:
for pe in turlar:
m = orgat(pe, vazifa, s)
Xt, yt = testlar[nom]
with torch.no_grad():
a = (m(Xt).argmax(1) == yt).float().mean().item()
natija[(nom, pe)].append(a)
modellar[(nom, pe, s)] = m
print("\n=== 2. Test aniqligi (200 qadam, 3 seed o'rtachasi) ===")
print(f" {'vazifa':<8}" + "".join(f"{pe:>9}" for pe in turlar))
for nom in testlar:
print(f" {nom:<8}" + "".join(f"{np.mean(natija[(nom, pe)]):>9.4f}"
for pe in turlar))
print(" tasodif darajasi: 0.5")
print("\n=== 3. Juftlashgan farq: pozitsiyali - pozitsiyasiz ===")
print(f" {'vazifa':<8} {'pe':<6} {'farq':>8} {'SE':>7} {'sezilarli':>10}")
for nom in testlar:
a0 = np.array(natija[(nom, "yoq")])
for pe in ["sinus", "organ"]:
f = np.array(natija[(nom, pe)]) - a0
se = f.std(ddof=1) / np.sqrt(len(f))
print(f" {nom:<8} {pe:<6} {f.mean():>+8.4f} {se:>7.4f} "
f"{str(abs(f.mean()) > 2 * se):>10}")
print("\n=== 4. Nima uchun: pozitsiyasiz model tartibni KO'RMAYDI ===")
m = modellar[("tartib", "yoq", 0)]
Xt, yt = testlar["tartib"]
perm = torch.randperm(L, generator=torch.Generator().manual_seed(1))
with torch.no_grad():
d = (m(Xt) - m(Xt[:, perm])).abs().max().item()
teskari = torch.where(Xt == ALI, VALI, torch.where(Xt == VALI, ALI, Xt))
almash = (m(Xt) - m(teskari)).abs().max().item()
print(f" max |logit(X) - logit(X aralashtirilgan)|: {d:.1e}")
print(f" max |logit(X) - logit(ali va vali almashgan)|: {almash:.1e}")
print(" almashtirish yorliqni TESKARI qiladi, so'zlar to'plami esa o'sha")
print(" -> ikkala yorliq uchun BIR XIL chiqish; eng yaxshi imkoniyat 0.5")
m2 = modellar[("tartib", "sinus", 0)]
with torch.no_grad():
d2 = (m2(Xt) - m2(Xt[:, perm])).abs().max().item()
print(f" sinus bilan xuddi shu farq: {d2:.2f} - tartib endi signal")
print(" ⭐ Pozitsiya ma'lumoti bo'lmasa, Transformer 'so'zlar qopi' modeli")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. Ikki vazifa ===
TARTIB y=0: keldi vali maktabga kitob bugun bugun bugun ali tez kitob
TARTIB y=1: keldi ali maktabga maktabga keldi vali ertalab uyga bugun oldi
SANOQ y=0: keldi bugun maktabga vali vali bugun bugun ali tez kitob
SANOQ y=1: keldi vali maktabga ali keldi ali ali vali bugun oldi
TARTIB: ali vali dan oldinmi? SANOQ: ali ko'pmi?
=== 2. Test aniqligi (200 qadam, 3 seed o'rtachasi) ===
vazifa yoq sinus organ
tartib 0.5053 1.0000 1.0000
sanoq 1.0000 1.0000 1.0000
tasodif darajasi: 0.5
=== 3. Juftlashgan farq: pozitsiyali - pozitsiyasiz ===
vazifa pe farq SE sezilarli
tartib sinus +0.4947 0.0025 True
tartib organ +0.4947 0.0025 True
sanoq sinus +0.0000 0.0000 False
sanoq organ +0.0000 0.0000 False
=== 4. Nima uchun: pozitsiyasiz model tartibni KO'RMAYDI ===
max |logit(X) - logit(X aralashtirilgan)|: 8.9e-08
max |logit(X) - logit(ali va vali almashgan)|: 8.9e-08
almashtirish yorliqni TESKARI qiladi, so'zlar to'plami esa o'sha
-> ikkala yorliq uchun BIR XIL chiqish; eng yaxshi imkoniyat 0.5
sinus bilan xuddi shu farq: 27.69 - tartib endi signal
⭐ Pozitsiya ma'lumoti bo'lmasa, Transformer 'so'zlar qopi' modeliNatija tahlili. Ikki vazifa bir xil so'zlar va bir xil model bilan qurilgan. TARTIB vazifasida javob faqat ali va vali ning joylashuviga bog'liq, SANOQ vazifasida esa faqat ularning soniga. Pozitsiyasiz model sanoqni mukammal yechdi (1.0000), tartibda esa tasodif darajasida qoldi (0.5053). Sinus va o'rganiladigan kodlash tartib vazifasini ham to'liq yechdi — juftlashgan farq +0.4947, SE 0.0025, ya'ni 2 × SE dan yuz baravar katta. Sanoqda esa pozitsiya hech narsa qo'shmadi (farq nol). 4-bo'lim sababni ko'rsatadi: pozitsiyasiz modelda ali va vali ning joyini almashtirish logitlarni o'zgartirmadi (8.9e-08), holbuki bu almashtirish yorliqni teskari qiladi. Bir xil kirishga ikki xil to'g'ri javob bo'lsa, eng yaxshi model ham 0.5 dan oshmaydi. Sinusli modelda esa xuddi shu permutatsiya logitlarni 27.69 ga o'zgartirdi — tartib endi signal.
Nima ko'rsatdi: 2.1, 2.4-bo'limlar.
Misol 3 — Uzunlikdan tashqariga: sinus va o'rganiladigan
"""Uzunlikdan tashqariga: 16 da o'rgatib, 32 va 64 da sinash (sinus va o'rganiladigan)."""
import math
import numpy as np
import torch
import torch.nn as nn
import torch.nn.functional as F
V, SILJISH, L_OQUV, MAKS = 8, 3, 16, 64
def sinus_pe(n, d):
p = torch.arange(n)[:, None].float()
w = torch.exp(-math.log(10000.0) * torch.arange(0, d, 2).float() / d)
pe = torch.zeros(n, d)
pe[:, 0::2] = torch.sin(p * w)
pe[:, 1::2] = torch.cos(p * w)
return pe
class Model(nn.Module):
"""Pre-LN blok, har pozitsiyada 3 qadam oldingi tokenni topish."""
def __init__(self, pe, d=32, h=2):
super().__init__()
self.pe, self.h = pe, h
self.emb = nn.Embedding(V, d)
if pe == "organ":
self.pos = nn.Embedding(MAKS, d) # 64 qator, o'quvda faqat 16 tasi
self.register_buffer("sin", sinus_pe(MAKS, d))
self.qkv, self.o = nn.Linear(d, 3 * d), nn.Linear(d, d)
self.ln1, self.ln2, self.ln3 = nn.LayerNorm(d), nn.LayerNorm(d), nn.LayerNorm(d)
self.ffn = nn.Sequential(nn.Linear(d, 4 * d), nn.GELU(), nn.Linear(4 * d, d))
self.chiq = nn.Linear(d, V)
def forward(self, X):
B, L = X.shape
x = self.emb(X)
if self.pe == "sinus":
x = x + self.sin[:L]
elif self.pe == "organ":
x = x + self.pos(torch.arange(L))
q, k, v = (self.qkv(self.ln1(x)).reshape(B, L, 3, self.h, -1)
.permute(2, 0, 3, 1, 4))
a = F.scaled_dot_product_attention(q, k, v)
x = x + self.o(a.transpose(1, 2).reshape(B, L, -1))
x = x + self.ffn(self.ln2(x))
return self.chiq(self.ln3(x))
def batch(n, L, g):
X = torch.randint(0, V, (n, L), generator=g)
Y = torch.full((n, L), -100)
Y[:, SILJISH:] = X[:, :-SILJISH] # nishon: 3 pozitsiya oldingi token
return X, Y
def orgat(pe, seed, qadam=400):
torch.manual_seed(seed)
m = Model(pe)
opt = torch.optim.Adam(m.parameters(), lr=0.003)
g = torch.Generator().manual_seed(seed)
for _ in range(qadam):
X, Y = batch(64, L_OQUV, g)
loss = F.cross_entropy(m(X).reshape(-1, V), Y.reshape(-1))
opt.zero_grad()
loss.backward()
opt.step()
m.eval()
return m
def olcha(m, L):
X, Y = batch(500, L, torch.Generator().manual_seed(100 + L))
with torch.no_grad():
togri = m(X).argmax(-1) == Y
ichki = togri[:, SILJISH:L_OQUV].float().mean().item()
tashqi = togri[:, L_OQUV:].float().mean().item() if L > L_OQUV else float("nan")
return togri[:, SILJISH:].float().mean().item(), ichki, tashqi
def main() -> None:
torch.set_num_threads(1)
print("=== 1. Vazifa ===")
X, Y = batch(1, 10, torch.Generator().manual_seed(0))
print(f" kirish: {X[0].tolist()}")
print(f" nishon: {['-' if t < 0 else t for t in Y[0].tolist()]}")
print(f" o'rgatish uzunligi {L_OQUV}; test {L_OQUV}, 32, 64; tasodif 1/{V} = {1 / V:.3f}")
turlar = ["yoq", "sinus", "organ"]
natija = {pe: [] for pe in turlar}
for s in range(3):
for pe in turlar:
m = orgat(pe, s)
natija[pe].append([olcha(m, L) for L in (16, 32, 64)])
r = {pe: np.array(v) for pe, v in natija.items()} # (seed, uzunlik, 3)
print("\n=== 2. Aniqlik uzunlik bo'yicha (400 qadam, 3 seed o'rtachasi) ===")
print(f" {'pe':<7} {'L=16':>7} {'L=32':>7} {'L=64':>7}")
for pe in turlar:
print(f" {pe:<7}" + "".join(f"{r[pe][:, j, 0].mean():>8.3f}" for j in range(3)))
print("\n=== 3. L=64 ichida: o'quvda ko'rilgan va ko'rilmagan pozitsiyalar ===")
print(f" {'pe':<7} {'p < 16':>8} {'p >= 16':>8}")
for pe in turlar:
print(f" {pe:<7} {r[pe][:, 2, 1].mean():>8.3f} {r[pe][:, 2, 2].mean():>8.3f}")
print(f" (L=16 dagi p < 16: sinus {r['sinus'][:, 0, 1].mean():.3f}, "
f"organ {r['organ'][:, 0, 1].mean():.3f})")
print("\n=== 4. Juftlashgan farq, p >= 16 (L=64): sinus - organ ===")
f = r["sinus"][:, 2, 2] - r["organ"][:, 2, 2]
se = f.std(ddof=1) / np.sqrt(len(f))
print(f" seedlar bo'yicha farq: {np.round(f, 3).tolist()}")
print(f" o'rtacha {f.mean():+.4f}, SE {se:.4f}")
if abs(f.mean()) <= 2 * se:
print(" farq 2*SE ichida - ekstrapolyatsiyada ikkalasi teng")
elif f.mean() > 0:
print(" sinus sezilarli yaxshi - lekin mutlaq qiymatga qarang")
else:
print(" organ sezilarli yaxshi")
eng = max(r[pe][:, 2, 2].mean() for pe in ["sinus", "organ"])
if eng < 0.5:
print(f" ikkalasi ham ko'rilmagan pozitsiyalarda <= {eng:.3f}: "
"ekstrapolyatsiya YO'Q")
print(" ⭐ Formula har pozitsiya uchun vektor beradi, lekin model ularni ko'rmagan")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. Vazifa ===
kirish: [4, 7, 5, 0, 3, 3, 3, 7, 1, 3]
nishon: ['-', '-', '-', 4, 7, 5, 0, 3, 3, 3]
o'rgatish uzunligi 16; test 16, 32, 64; tasodif 1/8 = 0.125
=== 2. Aniqlik uzunlik bo'yicha (400 qadam, 3 seed o'rtachasi) ===
pe L=16 L=32 L=64
yoq 0.268 0.218 0.186
sinus 1.000 0.561 0.391
organ 1.000 0.530 0.322
=== 3. L=64 ichida: o'quvda ko'rilgan va ko'rilmagan pozitsiyalar ===
pe p < 16 p >= 16
yoq 0.183 0.187
sinus 0.967 0.235
organ 0.993 0.140
(L=16 dagi p < 16: sinus 1.000, organ 1.000)
=== 4. Juftlashgan farq, p >= 16 (L=64): sinus - organ ===
seedlar bo'yicha farq: [0.131, 0.083, 0.071]
o'rtacha +0.0948, SE 0.0183
sinus sezilarli yaxshi - lekin mutlaq qiymatga qarang
ikkalasi ham ko'rilmagan pozitsiyalarda <= 0.235: ekstrapolyatsiya YO'Q
⭐ Formula har pozitsiya uchun vektor beradi, lekin model ularni ko'rmaganNatija tahlili. Vazifa sodda: har pozitsiyada 3 qadam oldingi tokenni aytish. O'quv uzunligida (L = 16) sinus ham, o'rganiladigan kodlash ham 1.000 ga yetdi. Pozitsiyasiz model 0.268 — tasodifdan (0.125) yuqori, chunki u ketma-ketlikda bor tokenlardan birini taxmin qila oladi, lekin qaysi biri 3 qadam oldin turganini bilmaydi. Uzunlik oshganda manzara o'zgaradi: L = 64 da sinus 0.391, o'rganiladigan 0.322. 3-bo'lim buni ikkiga ajratadi. O'quvda ko'rilmagan pozitsiyalarda (p ≥ 16) sinus 0.235, o'rganiladigan 0.140 — ikkinchisi deyarli tasodif, chunki uning jadvalidagi 16–63-qatorlar o'rgatilmagan tasodifiy vektorlar. Sinus biroz yaxshiroq: juftlashgan farq +0.0948, SE 0.0183 — sezilarli. Lekin mutlaq qiymat 0.235 — bu "ekstrapolyatsiya qiladi" degani emas. Formula PE[40] ni beradi, lekin model bunday vektorni hech qachon ko'rmagan. Yana bir kutilmagan natija: uzun ketma-ketlik ichidagi tanish pozitsiyalar ham zarar ko'rdi (sinus 0.967, L = 16 da 1.000 edi) — attention endi 64 ta kalit orasidan tanlaydi, ularning ko'pchiligi model uchun begona.
Nima ko'rsatdi: 2.4, 2.5-bo'limlar.
Misol 4 — RoPE noldan: burish va nisbiy pozitsiya
"""RoPE noldan: burish, nisbiy pozitsiya va uzunlikdan tashqariga sinov."""
import math
import numpy as np
import torch
import torch.nn as nn
import torch.nn.functional as F
V, SILJISH, L_OQUV, MAKS = 8, 3, 16, 64
def chastotalar(d):
return torch.exp(-math.log(10000.0) * torch.arange(0, d, 2).float() / d)
def sinus_pe(n, d):
p = torch.arange(n)[:, None].float()
pe = torch.zeros(n, d)
pe[:, 0::2] = torch.sin(p * chastotalar(d))
pe[:, 1::2] = torch.cos(p * chastotalar(d))
return pe
def rope(x, pozitsiya):
"""x: (..., L, d). Har (2i, 2i+1) juftlik p * w_i burchakka buriladi."""
burchak = pozitsiya[:, None].float() * chastotalar(x.shape[-1])
c, s = torch.cos(burchak), torch.sin(burchak)
x1, x2 = x[..., 0::2], x[..., 1::2]
y = torch.empty_like(x)
y[..., 0::2] = x1 * c - x2 * s
y[..., 1::2] = x1 * s + x2 * c
return y
class Model(nn.Module):
"""3-misoldagi model; pe = 'sinus' (kirishga qo'shiladi) yoki 'rope' (q, k ga)."""
def __init__(self, pe, d=32, h=2):
super().__init__()
self.pe, self.h = pe, h
self.emb = nn.Embedding(V, d)
self.register_buffer("sin", sinus_pe(MAKS, d))
self.qkv, self.o = nn.Linear(d, 3 * d), nn.Linear(d, d)
self.ln1, self.ln2, self.ln3 = nn.LayerNorm(d), nn.LayerNorm(d), nn.LayerNorm(d)
self.ffn = nn.Sequential(nn.Linear(d, 4 * d), nn.GELU(), nn.Linear(4 * d, d))
self.chiq = nn.Linear(d, V)
def forward(self, X):
B, L = X.shape
x = self.emb(X)
if self.pe == "sinus":
x = x + self.sin[:L]
q, k, v = (self.qkv(self.ln1(x)).reshape(B, L, 3, self.h, -1)
.permute(2, 0, 3, 1, 4))
if self.pe == "rope":
p = torch.arange(L)
q, k = rope(q, p), rope(k, p)
a = F.scaled_dot_product_attention(q, k, v)
x = x + self.o(a.transpose(1, 2).reshape(B, L, -1))
x = x + self.ffn(self.ln2(x))
return self.chiq(self.ln3(x))
def batch(n, L, g):
X = torch.randint(0, V, (n, L), generator=g)
Y = torch.full((n, L), -100)
Y[:, SILJISH:] = X[:, :-SILJISH]
return X, Y
def orgat(pe, seed, qadam=400):
torch.manual_seed(seed)
m = Model(pe)
opt = torch.optim.Adam(m.parameters(), lr=0.003)
g = torch.Generator().manual_seed(seed)
for _ in range(qadam):
X, Y = batch(64, L_OQUV, g)
loss = F.cross_entropy(m(X).reshape(-1, V), Y.reshape(-1))
opt.zero_grad()
loss.backward()
opt.step()
m.eval()
return m
def olcha(m, L):
X, Y = batch(500, L, torch.Generator().manual_seed(100 + L))
with torch.no_grad():
togri = m(X).argmax(-1) == Y
tashqi = togri[:, L_OQUV:].float().mean().item() if L > L_OQUV else float("nan")
return togri[:, SILJISH:].float().mean().item(), tashqi
def nishon_ogirligi(m, L):
"""Har pozitsiyada (eng yaxshi bosh) p-3 kalitiga berilgan attention og'irligi."""
X, _ = batch(200, L, torch.Generator().manual_seed(7))
with torch.no_grad():
x = m.emb(X)
q, k, _ = (m.qkv(m.ln1(x)).reshape(len(X), L, 3, m.h, -1)
.permute(2, 0, 3, 1, 4))
p = torch.arange(L)
q, k = rope(q, p), rope(k, p)
w = torch.softmax(q @ k.transpose(-1, -2) / math.sqrt(q.shape[-1]), -1)
idx = torch.arange(SILJISH, L)
ogirlik = w[:, :, idx, idx - SILJISH].amax(1) # (B, pozitsiya)
ichki = ogirlik[:, :L_OQUV - SILJISH].mean().item()
tashqi = ogirlik[:, L_OQUV - SILJISH:].mean().item()
return ichki, tashqi
def main() -> None:
torch.set_num_threads(1)
torch.manual_seed(0)
d = 8
q, k = torch.randn(d), torch.randn(d)
print("=== 1. RoPE - vektorni burish ===")
for p in (0, 1, 10, 100):
qp = rope(q[None], torch.tensor([p]))[0]
print(f" p = {p:>3}: norma {qp.norm():.4f} birinchi juftlik "
f"({qp[0]:+.3f}, {qp[1]:+.3f})")
print(f" asl norma {q.norm():.4f} - burish uzunlikni o'zgartirmaydi")
print("\n=== 2. Skor faqat m - n ga bog'liq ===")
print(f" {'m':>4} {'n':>4} {'m-n':>4} {'RoPE skor':>10} {'sinus skor':>11}")
pe = sinus_pe(200, d)
rope_skor, sinus_skor = [], []
for m_, n_ in [(5, 2), (25, 22), (105, 102), (7, 2), (107, 102)]:
qm = rope(q[None], torch.tensor([m_]))[0]
kn = rope(k[None], torch.tensor([n_]))[0]
rs = (qm @ kn).item()
ss = ((q + pe[m_]) @ (k + pe[n_])).item()
rope_skor.append(rs)
sinus_skor.append(ss)
print(f" {m_:>4} {n_:>4} {m_ - n_:>4} {rs:>10.4f} {ss:>11.4f}")
oraliq_r = max(rope_skor[:3]) - min(rope_skor[:3])
oraliq_s = max(sinus_skor[:3]) - min(sinus_skor[:3])
print(f" m-n = 3 bo'lgan uch juftlikda skor oralig'i: RoPE {oraliq_r:.1e}, "
f"qo'shiladigan sinus {oraliq_s:.4f}")
if oraliq_r < 1e-4 < oraliq_s:
print(" RoPE: skor AYNAN nisbiy masofaning funksiyasi; sinus: mutlaq p ham kiradi")
print("\n=== 3. 3-misoldagi vazifa: sinus va RoPE (400 qadam, 3 seed) ===")
natija = {"sinus": [], "rope": []}
modellar = {}
for s in range(3):
for pe_turi in natija:
m = orgat(pe_turi, s)
modellar[(pe_turi, s)] = m
natija[pe_turi].append([olcha(m, L) for L in (16, 32, 64)])
r = {k_: np.array(v) for k_, v in natija.items()}
print(f" {'pe':<6} {'L=16':>7} {'L=32':>7} {'L=64':>7} {'p>=16 (L=64)':>13}")
for nom in r:
print(f" {nom:<6}" + "".join(f"{r[nom][:, j, 0].mean():>8.3f}" for j in range(3))
+ f"{r[nom][:, 2, 1].mean():>14.3f}")
print("\n=== 4. Juftlashgan farq, p >= 16 (L=64): RoPE - sinus ===")
f = r["rope"][:, 2, 1] - r["sinus"][:, 2, 1]
se = f.std(ddof=1) / np.sqrt(len(f))
print(f" seedlar bo'yicha RoPE: {np.round(r['rope'][:, 2, 1], 3).tolist()}")
print(f" farq {f.mean():+.4f}, SE {se:.4f}")
if f.mean() > 2 * se:
print(" RoPE sezilarli yaxshi ekstrapolyatsiya qiladi")
elif abs(f.mean()) <= 2 * se:
print(" farq 2*SE ichida - bu tajribada RoPE ustunligi isbotlanmadi")
m = modellar[("rope", 0)]
ich16, _ = nishon_ogirligi(m, 16)
ich64, tash64 = nishon_ogirligi(m, 64)
print(f" RoPE (seed 0): p-3 kalitiga og'irlik L=16: {ich16:.3f} "
f"L=64, p<16: {ich64:.3f} L=64, p>=16: {tash64:.3f}")
if tash64 < ich16 - 0.05:
print(" uzun ketma-ketlikda og'irlik ko'p kalitga yoyiladi - "
"RoPE ham L=16 dagidek ishlamaydi")
print(" ⭐ RoPE nisbiy pozitsiyani skorning o'ziga kiritadi - ekstrapolyatsiya "
"yaxshilanadi, kafolatlanmaydi")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. RoPE - vektorni burish ===
p = 0: norma 3.3953 birinchi juftlik (+1.541, -0.293)
p = 1: norma 3.3953 birinchi juftlik (+1.080, +1.138)
p = 10: norma 3.3953 birinchi juftlik (-1.453, -0.592)
p = 100: norma 3.3953 birinchi juftlik (+1.180, -1.033)
asl norma 3.3953 - burish uzunlikni o'zgartirmaydi
=== 2. Skor faqat m - n ga bog'liq ===
m n m-n RoPE skor sinus skor
5 2 3 1.1783 4.1280
25 22 3 1.1783 -0.9895
105 102 3 1.1783 4.3274
7 2 5 0.6681 3.8318
107 102 5 0.6681 4.2476
m-n = 3 bo'lgan uch juftlikda skor oralig'i: RoPE 7.2e-07, qo'shiladigan sinus 5.3169
RoPE: skor AYNAN nisbiy masofaning funksiyasi; sinus: mutlaq p ham kiradi
=== 3. 3-misoldagi vazifa: sinus va RoPE (400 qadam, 3 seed) ===
pe L=16 L=32 L=64 p>=16 (L=64)
sinus 1.000 0.561 0.391 0.235
rope 1.000 0.740 0.531 0.510
=== 4. Juftlashgan farq, p >= 16 (L=64): RoPE - sinus ===
seedlar bo'yicha RoPE: [0.637, 0.373, 0.519]
farq +0.2747, SE 0.0629
RoPE sezilarli yaxshi ekstrapolyatsiya qiladi
RoPE (seed 0): p-3 kalitiga og'irlik L=16: 0.852 L=64, p<16: 0.528 L=64, p>=16: 0.444
uzun ketma-ketlikda og'irlik ko'p kalitga yoyiladi - RoPE ham L=16 dagidek ishlamaydi
⭐ RoPE nisbiy pozitsiyani skorning o'ziga kiritadi - ekstrapolyatsiya yaxshilanadi, kafolatlanmaydiNatija tahlili. 1-bo'lim: RoPE vektorni buradi, uzunligini o'zgartirmaydi — norma p = 0 dan p = 100 gacha 3.3953. 2-bo'lim — RoPE ning asosiy xossasi. Masofasi 3 bo'lgan uchta juftlik (5, 2), (25, 22) va (105, 102) uchun RoPE skori aynan bir xil (1.1783, oraliq 7.2e-07), masofa 5 bo'lganda boshqa, lekin yana o'zaro teng qiymat (0.6681). Qo'shiladigan sinusda esa xuddi shu juftliklar skori -0.99 dan 4.33 gacha sakraydi (oraliq 5.3169): (q + PE_m) · (k + PE_n) ichida q · PE_n va PE_m · k kabi mutlaq pozitsiyaga bog'liq hadlar bor. 3-bo'lim: 3-misoldagi vazifada RoPE ko'rilmagan pozitsiyalarda 0.510, sinus 0.235; farq +0.2747, SE 0.0629 — sezilarli. Lekin halol bo'laylik: seedlar bo'yicha RoPE 0.373 dan 0.637 gacha tarqoq, va L = 16 dagi 1.000 dan juda uzoq. 4-bo'lim sababni ko'rsatadi: seed 0 modelida kerakli (p - 3) kalitga berilgan og'irlik L = 16 da 0.852, L = 64 da esa tanish pozitsiyalarda ham 0.528 ga, yangi pozitsiyalarda 0.444 ga tushdi. Skor nisbiy bo'lsa ham, softmax ko'proq kalit orasida taqsimlanadi — "attention yoyilishi". Amaliyotda uzun kontekstli modellar RoPE ga qo'shimcha ravishda uzun matnlarda qisqa qo'shimcha o'rgatishdan o'tkaziladi.
Nima ko'rsatdi: 2.3, 2.5, 2.6-bo'limlar.
5. To'g'ri va noto'g'ri tushunishlar
| Noto'g'ri fikr | To'g'risi |
|---|---|
| "Self-attention so'zlar tartibini o'zi biladi" | Permutatsiyaga ekvivariant; 1-misolda farq 2.4e-07 |
| "Pozitsiyasiz model xato beradi" | Xato bermaydi — jimgina "so'zlar qopi" bo'ladi (2-misol: tartibda 0.5053) |
| "Hamma vazifaga pozitsiya kerak" | Sanoq kabi tartibga bog'liq bo'lmagan vazifada farq nol |
| "Sinus formulasi — uzun matnga kafolat" | 3-misolda ko'rilmagan pozitsiyalarda 0.235 |
| "O'rganiladigan jadvalni kattalashtirsa, uzun matn ishlaydi" | Ko'rilmagan qatorlar o'rgatilmagan: 0.140, tasodif 0.125 |
| "Sinus skalyar ko'paytmasi yo'nalishni biladi" | k = +5 va k = -5 da bir xil (6.1370) |
| "RoPE — embeddingga qo'shiladigan yana bir vektor" | Qo'shilmaydi: q va k buriladi, skor f(n - m) |
| "RoPE bilan ekstrapolyatsiya muammosi yo'q" | Yaxshilanadi (0.510 va 0.235), lekin 1.000 dan uzoq |
6. Keng tarqalgan xatolar va yechimlari
1. Pozitsiya unutilgan
x = self.emb(X) # ⚠️
x = self.emb(X) + self.pe[:X.shape[1]] # ✅2. Noto'g'ri o'q bo'yicha kesish
x = self.emb(X) + self.pe[:X.shape[0]] # batch o'lchami! # ⚠️
x = self.emb(X) + self.pe[:X.shape[1]] # ketma-ketlik uzunligi # ✅3. Sinus jadvali oddiy atribut
self.pe = sinus_pe(512, d) # .to("cuda") da qoladi # ⚠️
self.register_buffer("pe", sinus_pe(512, d)) # ✅4. Sinus jadvali o'rganiladigan parametr
self.pe = nn.Parameter(sinus_pe(512, d)) # endi bu sinus emas # ⚠️
self.register_buffer("pe", sinus_pe(512, d)) # yoki ongli nn.Embedding # ✅5. Jadvaldan uzun ketma-ketlik
self.pos(torch.arange(L)) # L > maks: IndexError # ⚠️
assert L <= self.pos.num_embeddings, "o'quvdan uzun kirish" # ✅6. RoPE v ga ham qo'llangan
q, k, v = rope(q, p), rope(k, p), rope(v, p) # ⚠️
q, k = rope(q, p), rope(k, p) # v o'zgarmaydi # ✅7. Ekstrapolyatsiyani tekshirmaslik
aniq = baholash(model, test_L16) # faqat o'quv uzunligi # ⚠️
for L in (16, 32, 64): print(L, baholash(model, test(L))) # ✅7. Integratsiya — bu bilim qayerda kerak bo'ladi
- 23.8, 23.9-darslar (o'tilgan): RNN, LSTM — tartib hisobning o'zida
- 24.2, 24.3-darslar (o'tilgan): self-attention va multi-head attention — bu darsdagi kodlash ularning kirishiga qo'shiladi
- 18-qism (o'tilgan): bir necha seed, juftlashgan farq va SE
- Keyingi darslar: Transformer bloki va encoder da pozitsiya embedding qatlamidan keyin qo'shiladi; decoder va GPT da RoPE va kauzal niqob birga ishlaydi
- Katta til modellari qismida: uzun kontekst, RoPE masshtablash usullari va ALiBi
8. Eng yaxshi amaliyotlar
Modelni permutatsiya bilan tekshiring: pozitsiyasiz holatda logitlar o'zgarmasligi kerak, pozitsiyali holatda o'zgarishi kerak.
Sinus jadvalini
register_bufferbilan saqlang.Qisqa, qat'iy uzunlikdagi vazifada o'rganiladigan va sinus deyarli teng — soddasini tanlang.
Uzun kontekst kerak bo'lsa — nisbiy usul (RoPE) va o'quvda kerakli uzunlik.
Uzunlik bo'yicha umumlashishni alohida jadvalda o'lchang: o'quv uzunligi, 2x, 4x.
Ko'rilgan va ko'rilmagan pozitsiyalarni alohida hisoblang.
Pozitsion kodlash turlarini bir necha seed da, juftlashgan farq va SE bilan taqqoslang.
Maksimal uzunlikni kod ichida aniq tekshiring (
assert).
9. Amaliy topshiriq
Vazifa 1: Bashorat qiling
1. # self-attention da qatorlar almashtirilsa chiqish nima bo'ladi?
2. # o'rtacha pooling dan keyin-chi?
3. # PE[p, 2i] va PE[p, 2i+1] formulalari?
4. # d = 16 da PE[p] normasi?
5. # eng qisqa to'lqin uzunligi?
6. # PE[p + k] va PE[p] qanday bog'langan?
7. # PE[p] . PE[p + k] nimaga bog'liq?
8. # o'rganiladigan jadvalda maks_uzunlik = 512, d = 768 - parametrlar?
9. # jadvaldan uzun ketma-ketlik berilsa?
10. # RoPE q va k ga nima qiladi?
11. # RoPE da q_m' . k_n' nimaga bog'liq?
12. # RoPE v ga qo'llanadimi?Javoblar
- Chiqish qatorlari xuddi shunday almashadi (ekvivariantlik)
- Hech narsa o'zgarmaydi (invariantlik)
sin(p / 10000^(2i/d))vacos(p / 10000^(2i/d))sqrt(d/2) = sqrt(8) = 2.82842*pi = 6.28pozitsiya (i = 0)PE[p + k] = M_k PE[p],M_k— faqat k ga bog'liq blok-diagonal burish- Faqat k ga (va
+k,-kda bir xil) 512 * 768 = 393 216IndexError(jadval kattalashtirilsa — o'rgatilmagan qatorlar)- Har (2i, 2i+1) juftlikni
p * w_iburchakka buradi - Faqat
n - mga (va q, k ning o'ziga) - Yo'q
Vazifa 2: Xatolarni tuzating
1. x = self.emb(X) + self.pe[:X.shape[0]]
2. class Model(nn.Module):
def __init__(self):
super().__init__()
self.pe = sinus_pe(512, 64)
3. self.pos = nn.Embedding(128, d)
x = self.emb(X) + self.pos(torch.arange(X.shape[1])) # X uzunligi 300
4. q, k, v = rope(q, p), rope(k, p), rope(v, p)
5. print("uzun matnlarga tayyor:", baholash(model, test_L16))Javoblar
1. x = self.emb(X) + self.pe[:X.shape[1]]
2. self.register_buffer("pe", sinus_pe(512, 64))
3. assert X.shape[1] <= self.pos.num_embeddings
# yoki uzun matnni bo'laklarga bo'lish / RoPE ga o'tish
4. q, k = rope(q, p), rope(k, p)
5. for L in (16, 32, 64):
print(L, baholash(model, test(L)))Vazifa 3: Permutatsiya
Modellang:
- Self-attention noldan
- Jumla va uning aralashtirilgan varianti
- Ekvivariantlik va invariantlik
- Pozitsiya qo'shilganda farq
Vazifa 4: Sinus xossalari
Modellang:
sinus_pefunksiyasi- Normalar va to'lqin uzunliklari
M_ksiljish matritsasi- Skalyar ko'paytma jadvali
Vazifa 5: Tartib vazifasi
Modellang:
- TARTIB va SANOQ generatorlari
- Uch xil pozitsiya bilan bir xil model
- 3 seed, juftlashgan farq
- Almashtirish tekshiruvi
Vazifa 6: Ekstrapolyatsiya va RoPE
Modellang:
- Siljish vazifasi
- Sinus, o'rganiladigan, RoPE
- Ko'rilgan va ko'rilmagan pozitsiyalar
- Kerakli kalitga attention og'irligi
Vazifa 7: O'ylash
Hamkasbingiz aytdi: "Bizning modelimiz 512 tokenda o'rgatilgan, sinusoidal kodlash bor. Formula har qanday pozitsiya uchun ishlaydi, shuning uchun mijozning 4000 tokenli hujjatlarini to'g'ridan-to'g'ri beraveramiz. O'rganiladigan kodlashda bu mumkin emas edi — bizga omad kulib boqdi." Siz nima deysiz?
Javob
Qisqa javob: texnik jihatdan model 4000 tokenni qabul qiladi, lekin bu uning shu uzunlikda ishlashini anglatmaydi. Buni o'lchash kerak — va natija yomon bo'lishi ehtimoli yuqori.
1. Formula va o'rganilgan xatti-harakat. Sinus formulasi PE[3000] ni hisoblaydi, lekin model W_q, W_k ni faqat 0–511 pozitsiyalardagi vektorlar bilan o'rgangan. 3-misolda L = 16 da o'rgatilgan sinusli model ko'rilmagan pozitsiyalarda 0.235 aniqlik berdi (o'quv uzunligida 1.000, tasodif 0.125).
2. Tanish pozitsiyalar ham zarar ko'radi. 3-misolda uzun ketma-ketlik ichidagi dastlabki 16 pozitsiya ham 1.000 dan 0.967 ga tushdi: attention ko'proq kalit orasida taqsimlanadi. 4-misolda kerakli kalitga og'irlik 0.852 dan 0.528 ga tushdi.
3. "Omad" — faqat IndexError yo'qligi. O'rganiladigan kodlashda xato darhol ko'rinardi. Sinusda esa model jimgina yomon javob beradi — bu xavfliroq.
4. Nima qilish kerak:
# 1. Uzunlik bo'yicha baholash: 512, 1024, 2048, 4000 - alohida
# 2. Ko'rilmagan pozitsiyalardagi sifatni alohida hisoblash
# 3. Oddiy yechim: hujjatni 512 li bo'laklarga bo'lib, natijani birlashtirish
# 4. Uzun kontekst kerak bo'lsa: RoPE + uzun matnlarda qo'shimcha o'rgatish5. Bazaviy. Bo'laklarga bo'lish (sliding window) yondashuvini uzun kontekstli model bilan bir xil test to'plamida solishtiring — ko'p hollarda u yetarli bo'ladi.
Hamkasbga javob: "Model 4000 tokenni qabul qiladi, lekin uni ko'rmagan. Kichik tajribada o'quv uzunligidan tashqarida sinusli model tasodifga yaqin ishladi. Avval uzunlik bo'yicha baholaymiz; ungacha hujjatlarni 512 li bo'laklarga bo'lib ishlatamiz."
Nimani mustahkamlaydi: 2.1, 2.5, 2.6-bo'limlar.
Xulosa
Bu darsda pozitsion kodlashning uch turini noldan qurdik va ularni tartib hamda uzunlik bo'yicha umumlashish vazifalarida o'lchadik.
Eng muhim uch fikr:
Self-attention tartibni ko'rmaydi — pozitsiya alohida kerak. 1-misolda aralashtirilgan jumla uchun self-attention chiqishi aynan aralashtirilgan asl chiqish bo'ldi (farq
2.4e-07), o'rtacha pooling dan keyin esa ikki jumla farqlanmadi (6.0e-08). 2-misolda pozitsiyasiz model "ali vali dan oldinmi?" vazifasida tasodif darajasida qoldi (0.5053), "ali ko'pmi?" vazifasida esa1.0000berdi. Sinus va o'rganiladigan kodlash tartib vazifasini to'liq yechdi: farq+0.4947, SE0.0025. Sabab — pozitsiyasiz modeldaalivavalini almashtirish logitlarni o'zgartirmaydi (8.9e-08), yorliq esa teskari bo'ladi.Sinusoidal kodlashda siljish — burish, lekin bu ekstrapolyatsiya kafolati emas. 1-misolda
PE[p + k] = M_k PE[p]hamma p uchun3e-15aniqlikda bajarildi vaM_5ni birinchi 50 pozitsiyadan topib, keyingilarida5.4e-07xato bilan qo'llash mumkin bo'ldi; skalyar ko'paytma faqat masofaga bog'liq (6.1370hamma p da,k = +5vak = -5da ham). Shunga qaramay, 3-misolda L = 16 da o'rgatilgan model L = 64 dagi ko'rilmagan pozitsiyalarda sinus bilan0.235, o'rganiladigan jadval bilan0.140aniqlik berdi (tasodif0.125). Sinus sezilarli yaxshiroq (+0.0948, SE0.0183), lekin ikkalasi ham o'quv uzunligidagi1.000dan juda uzoq.RoPE — nisbiy pozitsiya skorning ichida. 4-misolda masofasi 3 bo'lgan uch juftlik uchun RoPE skori bir xil (
1.1783, oraliq7.2e-07), qo'shiladigan sinusda esa oraliq5.3169. Ko'rilmagan pozitsiyalarda RoPE0.510berdi — sinusdan+0.2747yaxshi (SE0.0629, sezilarli). Lekin seedlar orasida0.373–0.637tarqoqlik bor va kerakli kalitga attention og'irligi0.852dan0.444ga tushdi: uzun ketma-ketlikda softmax yoyiladi. RoPE ekstrapolyatsiyani yaxshilaydi, lekin uzun kontekst baribir o'lchov va qo'shimcha o'rgatishni talab qiladi.
Keyingi darsda Transformer bloki: attention, FFN, residual ulanish va LayerNorm ni bitta blokka yig'amiz, pre-LN va post-LN ni chuqur stekda solishtiramiz va parametrlar sonini formula bilan hisoblaymiz.
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!