IlmHamroh
Data Science va sun'iy intellekt/Katta til modellari1/14-dars48 daqiqa
Mundarija (25)

25.1-dars: LLM nima

25-QISM — KATTA TIL MODELLARI · 1-dars


1. Kirish va motivatsiya

24-qism oxirida shunday degan edik: keyingi qism — Katta til modellari, ya'ni kichik korpusda o'n minglab parametr bilan qilgan ishimizni milliardlab parametr va trillionlab token bilan qilganda nima o'zgaradi. Bu darsda shu savolga javob beramiz. Qisqa javob: arxitektura deyarli o'zgarmaydi. 24.9-darsdagi GPT — kauzal decoder-only stek va "keyingi tokenni bashorat qil" maqsadi — zamonaviy katta til modellarining (LLM, Large Language Model) o'zagi. O'zgaradigani uchta narsa: masshtab (parametrlar, ma'lumot, hisob), o'rgatish bosqichlari (pretrainingdan keyin yana ikki bosqich) va shular natijasida paydo bo'ladigan xulq (savolga javob berish, misollardan o'rganish, ba'zan esa ishonch bilan xato gapirish).

Real vaziyat. Kompaniya ichki yordamchi qurish uchun ochiq vaznli "base" modelni yukladi va unga xodimlar savolini berdi: "Ta'til uchun ariza qanday yoziladi?". Model javob o'rniga yana beshta savol yozdi: "Kasallik varaqasi qanday topshiriladi? Ish haqi qachon beriladi? ...". Jamoa "model buzuq" deb o'yladi. Aslida model aynan o'rgatilgan ishni qildi: internetda savollar ko'pincha ro'yxat bo'lib keladi (FAQ sarlavhalari, test varaqalari), shuning uchun savoldan keyin eng ehtimolli davom — yana savol. "Javob berish" — alohida o'rgatiladigan ko'nikma, u instruction tuning deb ataladi. Bu darsning 1-misoli aynan shu vaziyatni kichik modelda takrorlaydi va o'lchaydi.

Ikkinchi vaziyat. Xuddi shu yordamchi (endi instruction tuning qilingan) yangi xodim haqidagi savolga — uning ma'lumoti hech qayerda yo'q edi — ishonch bilan aniq lavozim aytdi. Bu gallyutsinatsiya: model "bilmayman" demaydi, u eng ehtimolli davomni beradi. 3-misolda buning mexanizmini raqam bilan ko'ramiz.

Bu darsda LLM ning hayot siklini (pretraining → SFT → afzallik bo'yicha moslash) kichik modellarda noldan quramiz, masshtab hisob-kitobini qilamiz va gallyutsinatsiya sababini o'lchaymiz.

Bu darsda:

  • LLM = katta masshtabdagi GPT
  • Hayot sikli: pretraining, instruction tuning (SFT), afzallik bo'yicha moslash
  • Base model va instruct model farqi
  • Masshtab: parametr, token, hisob (6·N·D), xotira
  • In-context learning va "emergent" qobiliyatlar
  • Gallyutsinatsiya va kalibrlash
  • RLHF va DPO g'oyasi
  • Model tanlash mezonlari
  • Tuzoqlar

ℹ Misollar real torch/numpy bilan (Python 3.14, torch 2.14 CPU). Hech bir misol tashqi API yoki internetni ishlatmaydi: "LLM" o'rnida o'zimiz o'rgatgan so'z darajasidagi kichik GPT ishlaydi. Katta modellar haqidagi raqamlar formula bilan hisoblanadi va "faraziy" deb belgilanadi.


2. Nazariya — chuqur tushuntirish

2.1. LLM = katta masshtabdagi GPT

text
24.9-DARSDAGI GPT:
  token + pozitsiya embedding -> N ta kauzal blok -> LayerNorm -> Linear(d, V)
  maqsad: loss = cross_entropy(logit[:, t], x[:, t+1])
  bizniki: 2 qatlam, d = 48, belgi darajasi, 43 133 parametr

ZAMONAVIY LLM - O'SHA SKELET, BOSHQA MASSHTAB:
  qatlamlar       2        ->  30-100+
  kenglik d       48       ->  4 000-16 000
  lug'at V        29 belgi ->  30 000-200 000 subword token (BPE, 23.3)
  kontekst L      48       ->  o'n minglab - yuz minglab token
  parametrlar     43 ming  ->  milliardlar - yuzlab milliard
  o'quv tokenlari ~0.2 mln ->  trillionlab

MAYDA ARXITEKTURA FARQLARI (g'oya o'zgarmaydi):
  pozitsiya: o'rgatiladigan embedding o'rniga aylanma (RoPE) kodlash
  normallash: LayerNorm o'rniga RMSNorm, "pre-norm"
  FFN: GELU o'rniga "gated" variantlar (SwiGLU)
  attention: bir nechta bosh bitta K/V ni bo'lishadi (GQA) - KV-cache kichrayadi
  ba'zilarida "mixture of experts": har token FFN larning faqat bir qismidan o'tadi

LLM — 24.9 dagi GPT ning o'zi, faqat ming-million barobar katta; yangi xulq arxitekturadan emas, masshtab va o'rgatish bosqichlaridan keladi.

2.2. Hayot sikli: uch bosqich

text
1. PRETRAINING (oldindan o'rgatish)            -> BASE MODEL
   ma'lumot: trillionlab token (veb, kitoblar, kod), yorliqsiz
   maqsad:   keyingi token (24.9 bilan aynan bir xil)
   natija:   tilni, faktlarni, uslublarni biladi; lekin "hujjatni davom ettiradi"
   narx:     hisobning 90%+ qismi shu yerda

2. INSTRUCTION TUNING (SFT, supervised fine-tuning)   -> INSTRUCT MODEL
   ma'lumot: o'n minglab (ko'rsatma, javob) juftlari, odamlar yozgan yoki tanlagan
   maqsad:   keyingi token, lekin loss FAQAT javob tokenlarida (savol niqoblanadi)
   natija:   savolga JAVOB beradi, formatga amal qiladi, suhbat rollarini biladi

3. AFZALLIK BO'YICHA MOSLASH (RLHF / DPO)         -> "CHAT" MODEL
   ma'lumot: bir savolga ikki javob + qaysi biri yaxshi (odam yoki model belgilaydi)
   maqsad:   yaxshi javob ehtimolini oshirish, yomonini pasaytirish,
             boshlang'ich modeldan juda uzoqlashmaslik (KL cheklov)
   natija:   foydaliroq, xavfsizroq, uslubi mos javoblar

Bu bosqichlarning vazifasi turlicha. Pretraining bilim beradi, SFT — format va xulq, afzallik bosqichi — "qaysi javob yaxshiroq" degan nozik didni. 1-misolda buni to'g'ridan-to'g'ri o'lchaymiz: SFT faqat 15 ta ism uchun savol-javob ko'rsatadi, lekin model SFT da umuman bo'lmagan 15 ta boshqa ism haqida ham to'g'ri javob beradi — chunki faktlar pretrainingdan keladi, SFT esa faqat "javob berish formatini" o'rgatadi.

text
1-MISOL NATIJASI (15 ta SFT ko'rmagan ism x 2 seed):
  usul              format (javob:)   to'g'ri kasb
  base zero-shot         0.0%            0.0%     <- savolni savol bilan davom ettiradi
  base 2 misolli       100.0%           76.7%     <- in-context learning
  SFT zero-shot        100.0%          100.0%

Pretraining — bilim, SFT — format va xulq, afzallik bosqichi — did; SFT yangi faktlarni o'rgatish uchun emas.

2.3. Base model va instruct model

text
BASE MODEL:
  "savol : gulnora kim ?"  ->  "savol : temur kim"      (1-misol, seed 0)
  hujjat qanday davom etishi ehtimolli bo'lsa, shunday davom ettiradi
  foydali: matn davom ettirish, few-shot, o'z fine-tuning ingiz uchun asos

INSTRUCT / CHAT MODEL:
  "savol : gulnora kim ?"  ->  "javob : oshpaz ."
  maxsus format: rollar (system, user, assistant), maxsus tokenlar
  API orqali ishlatiladigan modellarning deyarli hammasi shu turda

AMALIY OQIBAT:
  base modelga "ko'rsatma" berish ishonchsiz - uni hujjat ko'rinishida bering
  ("Savol: ... Javob:" shabloni yoki bir nechta misol)
  instruct modelga esa aniq ko'rsatma bering (25.4-dars)

Base model hujjatni davom ettiradi, instruct model javob beradi — ularni bir xil prompt bilan ishlatish xato.

2.4. SFT ning texnik tafsiloti: niqoblangan loss

text
KETMA-KETLIK:  <d> savol : laylo kim ?  javob : dehqon .
               |------ savol ------|   |--- javob ---|
YORLIQLAR:     -100 -100 -100 ... -100  javob : dehqon .
                (loss hisoblanmaydi)    (loss faqat shu yerda)

NEGA NIQOBLAYMIZ:
  model savol matnini "yodlashi" kerak emas, faqat javob yozishni o'rganadi
  F.cross_entropy(..., ignore_index=-100) - PyTorch standart usuli

AMALDA:
  suhbat shabloni: har rolning boshi/oxiri maxsus tokenlar bilan
  loss faqat "assistant" qismlarida
  kichik lr va kam qadam - pretraining bilimini buzmaslik uchun
  (katastrofik unutish, 24.10-dars)

SFT = pretraining bilan bir xil loss, faqat savol tokenlari niqoblangan — yangi arxitektura ham, yangi maqsad ham yo'q.

2.5. Masshtab: parametr, token, hisob va xotira

text
PARAMETRLAR 24.11-bob:  N ~ 12 * L * d^2  +  V * d
  2-misol: L=6, d=256 da bloklar 4 738 560, formula 4 718 592 (farq 0.4%)

HISOB:  C ~ 6 * N * D  FLOP   (D - o'quv tokenlari soni)
  forward ~2N FLOP/token, backward ~4N FLOP/token
  2-misol: torch FlopCounterMode o'lchagani == 6*N*D (nisbat 1.00)
  attention o'z hissasini qo'shadi (12 * L * T * d / token): kichik T da 5-10%

MA'LUMOT VA MODEL NISBATI ("hisob-optimal" qoidasi, taxminiy):
  berilgan hisob byudjetida D ~ 20 * N token atrofida eng past loss
  amalda ko'p modellar undan ANCHA ko'p tokenda o'rgatiladi -
  chunki kichik modelni ishlatish (inference) arzonroq

2-MISOL (FARAZIY apparat: 1e15 FLOP/s, 40% foydalanish):
  7B sinf:  N = 6.7B, D = 134B token, C = 5.4e21 FLOP
            1 tezlatgichda 156 kun, 1024 tada 0.2 kun
  70B sinf: C = 5.1e23 FLOP - 1024 tezlatgichda 14.5 kun

XOTIRA (faqat vaznlar):   N x bayt
                 fp32  bf16  int8  int4
  7B sinf (GB)   26.8  13.4   6.7   3.4
  o'rgatish (AdamW, fp32 master + m + v + grad) ~16 bayt/param -> 107 GB
  KV-cache: 2 * L * d * bayt har token -> 7B sinfda 0.52 MB/token,
            8000 token 4.2 GB, 32 parallel so'rov 134 GB

Bu jadvaldan ikki amaliy xulosa chiqadi. Birinchisi: o'rgatish va ishlatish — butunlay boshqa masshtabdagi masalalar. 7B sinfdagi modelni noldan o'rgatish yuzlab tezlatgich-kun talab qiladi, uni int4 da ishga tushirish esa 3.4 GB — oddiy videokartaga sig'adi. Shuning uchun deyarli hamma jamoalar tayyor modelni oladi va uni prompt, RAG yoki kichik fine-tuning bilan moslaydi (25.4, 25.8, 25.11-darslar). Ikkinchisi: uzun kontekst qimmat. KV-cache token soniga chiziqli o'sadi; 32 ta parallel uzun suhbat model vaznlaridan o'n barobar ko'p xotira oladi.

N ~ 12Ld^2, C ~ 6ND, xotira = N x bayt — uch formula LLM haqidagi deyarli har bir "qancha turadi" savoliga birinchi javobni beradi.

2.6. Kvantlash: xotirani 4-8 barobar kamaytirish

text
SIMMETRIK KVANTLASH:
  w ~ shkala * q,  q - butun son [-(2^(b-1)-1), 2^(b-1)-1]
  shkala = max|w| / (2^(b-1)-1)       int8: 127 daraja, int4: 7 daraja

SHKALA QAYERDAN OLINADI:
  butun matritsa bo'yicha bitta shkala - sodda, lekin bitta katta qiymat
  hammasini buzadi
  qator (kanal) bo'yicha - har chiqish kanali o'z shkalasi bilan

2-MISOL (512x512, x @ w nisbiy xatosi):
                          int8 butun  int8 qator  int4 butun  int4 qator
  oddiy (normal)            0.0105      0.0074      0.1899      0.1343
  20 ta chetli qiymat       0.1025      0.0217      0.9128      0.2170

Chetli qiymatlar (outlier) haqiqiy LLM larda uchraydi va aynan shu sababli amaliy usullar guruhli shkala (masalan, har 64-128 vazn uchun alohida) va chetlilarni alohida saqlash kabi hiylalarni ishlatadi. int4 ning xatosi oddiy matritsada ham 0.13-0.19 — bu "bepul" emas; kvantlangan modelni o'z vazifangizda baholash shart (25.10-dars).

Kvantlash — xotira va sifat orasidagi savdo; shkalani qanchalik mahalliy olsangiz, chetli qiymatlar shunchalik kam zarar beradi.

2.7. In-context learning va "emergent" qobiliyatlar

text
IN-CONTEXT LEARNING (ICL, kontekstdan o'rganish):
  vaznlar O'ZGARMAYDI; model promptdagi misollardan vazifani "tushunadi"
  1-misol: base model, prompt boshida 2 ta savol-javob:
    format 0.0% -> 100.0%, to'g'ri kasb 0.0% -> 76.7%

NEGA ISHLAYDI:
  pretraining korpusida FAQ hujjatlari bor edi (10%):
    "savol : X kim ? javob : Y . savol : Z kim ? javob : ..."
  model "bu hujjat FAQ turida - demak savoldan keyin javob keladi" degan
  qonuniyatni o'rgangan; misollar hujjat turini aniqlashga yordam beradi

"EMERGENT" (paydo bo'luvchi) QOBILIYATLAR:
  kuzatuv: ba'zi vazifalar kichik modellarda deyarli nol, ma'lum masshtabdan
  keyin keskin o'sadi (ko'p bosqichli arifmetika, ko'rsatmaga amal qilish)
  ehtiyot: "keskinlik" ko'pincha METRIKADAN - "aniq moslik" kabi hammasi-yoki-hech
  metrika silliq yaxshilanishni ham sakrash qilib ko'rsatadi;
  token darajasidagi loss bilan qaralsa, o'sish silliqroq ko'rinadi

In-context learning — vaznlarni o'zgartirmay, prompt orqali vazifani ko'rsatish; u pretraining ma'lumotidagi qonuniyatlardan kelib chiqadi, sehr emas.

2.8. Gallyutsinatsiya va kalibrlash

text
SABAB - MAQSAD FUNKSIYASINING O'ZIDA:
  model P(keyingi token | kontekst) ni o'rganadi
  "X kasbi ..." dan keyin korpusda DOIM kasb keladi
  -> X haqida fakt bo'lmasa ham model kasb aytadi: "bilmayman" davomi
     korpusda yo'q edi

3-MISOL (40 ism, fakt 0/1/3/10 marta, 2 seed):
  fakt soni  kasbga massa  ishonch  aniqlik  ishonch - aniqlik
      0          0.987      0.727    0.150       +0.577   <- to'qish
      1          0.979      0.679    0.800       -0.121
      3          0.988      0.857    0.900       -0.043
     10          0.990      0.983    1.000       -0.017
  ko'rilmagan faktda aniqlik tasodif darajasida (1/6), ishonch esa 0.727

KALIBRLASH:
  yaxshi kalibrlangan model: "0.8 ishonch" bilan aytganlarining ~80% i to'g'ri
  ECE = sum (ulush * |o'rtacha ishonch - aniqlik|) ishonch oraliqlari bo'yicha
  3-misol: ECE 0.099; eng katta xato - hech ko'rilmagan faktlarda

KAMAYTIRISH YO'LLARI (keyingi darslarda):
  RAG - javobni topilgan hujjatga bog'lash (25.8-25.9)
  "bilmayman" javoblarini SFT/afzallik ma'lumotiga qo'shish
  manbani keltirishni talab qilish va uni avtomatik tekshirish
  bir necha namunaning o'zaro mosligini tekshirish (25.10)

Muhim nuans: 3-misolda model bir marta ko'rgan faktlarda (0.800 aniqlik) kam ishonch bilan (0.679) javob berdi — ya'ni u yerda ortiqcha ehtiyotkor. Ortiqcha ishonch faqat umuman bilmagan joyda keskin. Bu gallyutsinatsiyaning tipik ko'rinishi: model bilmasligini bilmaydi, chunki uning uchun "bilmayman" — shunchaki boshqa token ketma-ketligi, u esa o'quv matnida bu kontekstda uchramagan.

Gallyutsinatsiya — "ehtimolli davom ettirish" maqsadining tabiiy natijasi: model ko'rmagan faktni ham shakl jihatdan to'g'ri va ishonchli qilib yozadi.

2.9. Afzallik bo'yicha moslash: RLHF va DPO

text
RLHF (klassik, uch qadam):
  1. afzallik ma'lumoti: (savol, javob_A, javob_B, qaysi yaxshi)
  2. mukofot modeli r(x, y): "yaxshi" javobga yuqori ball berishni o'rganadi
  3. RL (PPO): siyosat pi mukofotni oshiradi, KL(pi || pi_ref) jarimasi bilan
  murakkab: to'rtta model (siyosat, reference, mukofot, qiymat), beqaror

DPO (Direct Preference Optimization):
  mukofot modelisiz, to'g'ridan-to'g'ri juftlar ustida:
  loss = -log sigmoid( beta * [ (log pi(y_w|x) - log ref(y_w|x))
                              - (log pi(y_l|x) - log ref(y_l|x)) ] )
  y_w - tanlangan, y_l - rad etilgan javob; ref - muzlatilgan SFT model
  beta - KL "tasmasi": katta beta -> ref dan kam uzoqlashadi

4-MISOL (15 juft: qisqa javob > "suvli" javob; B guruhda o'lchov, 40 qadam):
  usul              P(qisqa)  KL(pi||ref)  kasb (15 tadan)
  boshlang'ich        0.444       -             15
  DPO beta=0.1        0.938     0.793           13
  DPO beta=1.0        0.798     0.357           15
  SFT (tanlanganda)   0.948     0.790           14

DPO — afzallik juftlaridan to'g'ridan-to'g'ri o'rganish; beta modelni reference ga qanchalik "bog'lab" turishini boshqaradi.

2.10. Model tanlash mezonlari

text
SAVOL                         NIMA QARAYDI
sifat                         o'z vazifangizdagi baho to'plami 25.10-bob, umumiy
                              reyting emas
narx                          kirish va chiqish tokenlari narxi 25.2-bob, hajm
kechikish                     birinchi token vaqti, token/s; interaktivmi, fondami
kontekst oynasi               hujjatlaringiz sig'adimi 25.2-bob
tillar                        o'zbekcha sifati va token "solig'i" 25.2-bob
maxfiylik va joylashuv        ma'lumot qayerga ketadi; o'z serverida kerakmi
ochiq vazn / API              fine-tuning, kvantlash imkoniyati va xizmat yuki
litsenziya                    tijorat maqsadida ishlatish shartlari

AMALIY QOIDA:
  eng kichik/arzon modeldan boshlang, o'z baho to'plamingizda o'lchang,
  yetmasa kattasiga o'ting - "eng yaxshisidan sezilarli yomon bo'lmagan
  eng arzon" (18-qismdagi qaror qoidasining o'zi)

Model tanlash — o'lchov masalasi: umumiy reyting emas, o'z vazifangizdagi sifat, narx va kechikish.

2.11. Tuzoqlar

Asosiy tuzoqlar: base modelga instruct model kabi ko'rsatma berish; SFT orqali yangi faktlarni "o'rgatishga" urinish (SFT format o'rgatadi, faktlar pretraining yoki RAG dan keladi); SFT da savol tokenlarini niqoblamaslik; modelning ishonchli ohangini to'g'rilik belgisi deb qabul qilish; "emergent" sakrashni metrika tanlovini tekshirmay e'lon qilish; o'rgatish xotirasini faqat vaznlar bilan hisoblash (AdamW holati, gradientlar va aktivatsiyalarni unutish); KV-cache ni hisobga olmay "model 16 GB ga sig'adi" deyish; kvantlangan modelni o'z vazifasida baholamay ishga tushirish; DPO da reference modelni muzlatmaslik yoki uni boshqa model bilan almashtirish; umumiy reyting bo'yicha model tanlash; katta modellarning parametr/narx raqamlarini manbasiz yozish.


3. Tez ma'lumotnoma

python
# masshtab
N = 12 * qatlamlar * d * d + V * d            # parametrlar (taxminan)
C = 6 * N * D                                 # o'rgatish FLOP
kun = C / (choqqi_flops * foydalanish) / 86400
xotira_gb = N * bayt / 1e9                    # fp32 4, bf16 2, int8 1, int4 0.5
orgatish_gb = N * 16 / 1e9                    # AdamW: vazn + grad + m + v
kv_bayt_token = 2 * qatlamlar * d * 2         # K va V, bf16

# SFT: savol niqoblangan loss
y = [-100] * (len(savol) - 1) + javob
loss = F.cross_entropy(logit.reshape(-1, V), y.reshape(-1), ignore_index=-100)

# DPO
loss = -F.logsigmoid(beta * ((pi_w - ref_w) - (pi_l - ref_l))).mean()

# kalibrlash (ECE)
ece = sum(ulush * abs(ishonch.mean() - aniqlik.mean()) for ulush, ishonch, aniqlik in oraliqlar)

# instruct modelni API orqali chaqirish (faqat ko'rinish; kalit muhit o'zgaruvchisidan)
import anthropic

client = anthropic.Anthropic()                # ANTHROPIC_API_KEY muhitdan o'qiladi
javob = client.messages.create(
    model="claude-haiku-4-5-20251001",
    max_tokens=200,
    system="Sen kadrlar bo'limi yordamchisisan. Bilmasang, 'bilmayman' de.",
    messages=[{"role": "user", "content": "Ta'til uchun ariza qanday yoziladi?"}],
)
print(javob.content[0].text)
print(javob.usage.input_tokens, javob.usage.output_tokens)

LLM xulosasi

LLM = katta masshtabdagi GPT (kauzal decoder, keyingi token)
pretraining -> base (davom ettiradi); SFT -> instruct (javob beradi); DPO/RLHF -> did
bilim pretrainingdan, format SFT dan
N ~ 12Ld^2, C ~ 6ND, xotira = N x bayt (+ KV-cache)
ICL: misollar promptda, vaznlar o'zgarmaydi
gallyutsinatsiya: ehtimolli davom; ishonch != to'g'rilik

4. Batafsil misollar

Misollar real torch/numpy bilan (Python 3.14, torch 2.14 CPU). "LLM" o'rnida o'zimiz o'rgatgan kichik so'z darajasidagi GPT; tashqi API yo'q.

Misol 1 — Base model va SFT: davom yozish va javob berish

python
"""Base model va instruction tuning (SFT): bir xil savolga davom yozish va javob berish."""

import copy
import math

import numpy as np
import torch
import torch.nn as nn
import torch.nn.functional as F

ISMLAR = ("anvar dilnoza bobur malika sardor nodira jasur zarina otabek madina "
          "sherzod gulnora farhod laylo rustam sevara aziz kamola bahrom shahlo "
          "temur nigora dilshod feruza jamshid mohira sanjar yulduz akmal lola").split()
KASBLAR = "shifokor muhandis oqituvchi dehqon haydovchi oshpaz".split()
JOYLAR = "bozorga maktabga shaharga bekatga dalaga bogga".split()
L = 24


def dunyo(seed=0):
    """Har ismga bitta kasb - bu "fakt". A guruh SFT da, B guruh faqat baholashda."""
    rng = np.random.default_rng(seed)
    kasb = {ism: str(rng.choice(KASBLAR)) for ism in ISMLAR}
    aralash = rng.permutation(ISMLAR)
    return kasb, [str(x) for x in aralash[:15]], [str(x) for x in aralash[15:]]


def fakt_gap(ism, k, rng):
    if rng.random() < 0.5:
        return f"{ism} {k} bo'lib ishlaydi ."
    return f"{ism} kasbi {k} ."


def pretrain_korpus(kasb, n_hujjat, rng):
    """Internet o'xshatmasi: fakt matnlari, savollar ro'yxati va kam uchraydigan FAQ."""
    hujjatlar = []
    for _ in range(n_hujjat):
        tur = rng.random()
        ismlar = rng.choice(ISMLAR, 4, replace=False)
        if tur < 0.60:                                     # oddiy matn
            gaplar = [fakt_gap(i, kasb[i], rng) if rng.random() < 0.7
                      else f"{i} {rng.choice(JOYLAR)} bordi ." for i in ismlar]
        elif tur < 0.90:                                   # savollar ro'yxati (test varag'i)
            gaplar = [f"savol : {i} kim ?" for i in ismlar]
        else:                                              # FAQ: savol-javob juftlari
            gaplar = [f"savol : {i} kim ? javob : {kasb[i]} ." for i in ismlar[:3]]
        hujjatlar.append("<d> " + " ".join(gaplar))
    return " ".join(hujjatlar)


class Blok(nn.Module):
    def __init__(self, d, boshlar):
        super().__init__()
        self.boshlar = boshlar
        self.ln1, self.ln2 = nn.LayerNorm(d), nn.LayerNorm(d)
        self.qkv = nn.Linear(d, 3 * d)
        self.proj = nn.Linear(d, d)
        self.ffn = nn.Sequential(nn.Linear(d, 4 * d), nn.GELU(), nn.Linear(4 * d, d))

    def forward(self, x):
        B, T, d = x.shape
        q, k, v = self.qkv(self.ln1(x)).split(d, dim=2)
        q, k, v = [t.view(B, T, self.boshlar, -1).transpose(1, 2) for t in (q, k, v)]
        o = F.scaled_dot_product_attention(q, k, v, is_causal=True)
        x = x + self.proj(o.transpose(1, 2).reshape(B, T, d))
        return x + self.ffn(self.ln2(x))


class GPT(nn.Module):
    def __init__(self, V, d=32, boshlar=4, qatlamlar=2):
        super().__init__()
        self.emb = nn.Embedding(V, d)
        self.poz = nn.Embedding(L, d)
        self.bloklar = nn.Sequential(*[Blok(d, boshlar) for _ in range(qatlamlar)])
        self.ln = nn.LayerNorm(d)
        self.chiqish = nn.Linear(d, V)

    def forward(self, x):
        x = x[:, -L:]
        h = self.emb(x) + self.poz(torch.arange(x.shape[1]))
        return self.chiqish(self.ln(self.bloklar(h)))


def pretrain(T, V, seed, qadamlar=200, B=32):
    """Keyingi token maqsadi, butun matn bo'yicha - hech qanday "vazifa" yo'q."""
    torch.manual_seed(seed)
    model = GPT(V)
    opt = torch.optim.AdamW(model.parameters(), lr=1e-2, weight_decay=0.01)
    g = torch.Generator().manual_seed(seed)
    for _ in range(qadamlar):
        bosh = torch.randint(0, len(T) - L - 1, (B,), generator=g)
        w = torch.stack([T[i:i + L + 1] for i in bosh.tolist()])
        loss = F.cross_entropy(model(w[:, :-1]).reshape(-1, V), w[:, 1:].reshape(-1))
        opt.zero_grad()
        loss.backward()
        opt.step()
    return model


def sft(model, juftlar, s2i, seed, qadamlar=60, B=16):
    """Instruction tuning: (savol, javob) juftlari, loss FAQAT javob tokenlarida."""
    V = model.chiqish.out_features
    opt = torch.optim.AdamW(model.parameters(), lr=1e-3, weight_decay=0.01)
    g = torch.Generator().manual_seed(1000 + seed)
    for _ in range(qadamlar):
        idx = torch.randint(0, len(juftlar), (B,), generator=g).tolist()
        x, y = [], []
        for i in idx:
            savol, javob = juftlar[i]
            s = [s2i[w] for w in savol.split()]
            j = [s2i[w] for w in javob.split()]
            t = s + j
            x.append(t[:-1])
            y.append([-100] * (len(s) - 1) + j)            # savol qismi niqoblangan
        loss = F.cross_entropy(model(torch.tensor(x)).reshape(-1, V),
                               torch.tensor(y).reshape(-1), ignore_index=-100)
        opt.zero_grad()
        loss.backward()
        opt.step()
    return model


@torch.no_grad()
def greedy(model, prompt, s2i, i2s, n=4):
    x = torch.tensor([[s2i[w] for w in prompt.split()]])
    for _ in range(n):
        x = torch.cat([x, model(x)[:, -1].argmax(-1, keepdim=True)], 1)
    return " ".join(i2s[i] for i in x[0, -n:].tolist())


def baholash(model, ismlar, kasb, s2i, i2s, oldin=""):
    """Har savol uchun: format (javob bilan boshladimi) va to'g'rilik (kasb to'g'rimi)."""
    fmt, togri = [], []
    for ism in ismlar:
        davom = greedy(model, f"<d> {oldin}savol : {ism} kim ?", s2i, i2s).split()
        fmt.append(float(davom[0] == "javob"))
        togri.append(float(davom[:3] == ["javob", ":", kasb[ism]]))
    return np.array(fmt), np.array(togri)


def main() -> None:
    torch.set_num_threads(1)
    kasb, A, B_guruh = dunyo()
    rng = np.random.default_rng(0)
    matn = pretrain_korpus(kasb, 3000, rng)
    sozlar = sorted(set(matn.split()) | {"javob"})
    s2i = {w: i for i, w in enumerate(sozlar)}
    i2s = {i: w for w, i in s2i.items()}
    T = torch.tensor([s2i[w] for w in matn.split()])
    sft_juftlar = [(f"<d> savol : {i} kim ?", f"javob : {kasb[i]} .") for i in A]

    print("=== 1. Ma'lumot ===")
    print(f"  pretraining: {len(T)} token, lug'at {len(sozlar)} so'z, 3000 hujjat")
    print("  hujjat turlari: 60% matn, 30% savollar ro'yxati, 10% savol-javob (FAQ)")
    print(f"  SFT: {len(sft_juftlar)} ta juft (A guruh), baholash - B guruhning 15 ismi")
    print(f"  SFT misol: {sft_juftlar[0][0][4:]} -> {sft_juftlar[0][1]}")

    natija = {k: ([], []) for k in ("base zero-shot", "base 2 misolli", "SFT zero-shot")}
    for seed in range(2):
        base = pretrain(T, len(sozlar), seed)
        oldin = "".join(f"savol : {a} kim ? javob : {kasb[a]} . " for a in A[:2])
        for nom, m, o in (("base zero-shot", base, ""), ("base 2 misolli", base, oldin)):
            f_, t_ = baholash(m, B_guruh, kasb, s2i, i2s, o)
            natija[nom][0].append(f_)
            natija[nom][1].append(t_)
        tuned = sft(copy.deepcopy(base), sft_juftlar, s2i, seed)
        if seed == 0:
            base0, tuned0 = base, tuned
        f_, t_ = baholash(tuned, B_guruh, kasb, s2i, i2s)
        natija["SFT zero-shot"][0].append(f_)
        natija["SFT zero-shot"][1].append(t_)

    print("\n=== 2. Bir savolga uch xil javob (seed 0) ===")
    ism = B_guruh[0]
    fs = f"savol : {A[0]} kim ? javob : {kasb[A[0]]} . "
    print(f"  savol: 'savol : {ism} kim ?'   (to'g'ri kasb: {kasb[ism]})")
    print(f"  base, zero-shot : {greedy(base0, f'<d> savol : {ism} kim ?', s2i, i2s)}")
    print(f"  base, 1 misolli : {greedy(base0, f'<d> {fs}savol : {ism} kim ?', s2i, i2s)}")
    print(f"  SFT dan keyin   : {greedy(tuned0, f'<d> savol : {ism} kim ?', s2i, i2s)}")

    print("\n=== 3. B guruh (SFT ko'rmagan 15 ism) x 2 seed ===")
    print("  usul             format (javob:)   to'g'ri kasb")
    for nom, (f_, t_) in natija.items():
        print(f"  {nom:<16} {np.mean(f_):>13.1%} {np.mean(t_):>14.1%}")

    print("\n=== 4. Juftlashgan farq (30 = 15 savol x 2 seed) ===")
    sft_t = np.concatenate(natija["SFT zero-shot"][1])
    for nom in ("base zero-shot", "base 2 misolli"):
        d = sft_t - np.concatenate(natija[nom][1])
        se = d.std(ddof=1) / math.sqrt(len(d))
        hukm = ("SFT sezilarli yaxshi" if d.mean() > 2 * se else
                "SFT sezilarli yomon" if d.mean() < -2 * se else "sezilarli farq yo'q")
        print(f"  SFT - {nom:<15}: {d.mean():+.3f}, SE {se:.3f} -> {hukm}")
    if np.mean(natija["base zero-shot"][0]) < 0.5:
        print("  base model savolni ko'pincha 'savol' bilan davom ettiradi - u javob bermaydi")
    print("  ⭐ B guruh faktlari SFT da YO'Q edi: bilim pretrainingdan, format SFT dan")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. Ma'lumot ===
  pretraining: 60024 token, lug'at 53 so'z, 3000 hujjat
  hujjat turlari: 60% matn, 30% savollar ro'yxati, 10% savol-javob (FAQ)
  SFT: 15 ta juft (A guruh), baholash - B guruhning 15 ismi
  SFT misol: savol : laylo kim ? -> javob : dehqon .

=== 2. Bir savolga uch xil javob (seed 0) ===
  savol: 'savol : gulnora kim ?'   (to'g'ri kasb: oshpaz)
  base, zero-shot : savol : temur kim
  base, 1 misolli : javob : oshpaz .
  SFT dan keyin   : javob : oshpaz .

=== 3. B guruh (SFT ko'rmagan 15 ism) x 2 seed ===
  usul             format (javob:)   to'g'ri kasb
  base zero-shot            0.0%           0.0%
  base 2 misolli          100.0%          76.7%
  SFT zero-shot           100.0%         100.0%

=== 4. Juftlashgan farq (30 = 15 savol x 2 seed) ===
  SFT - base zero-shot : +1.000, SE 0.000 -> SFT sezilarli yaxshi
  SFT - base 2 misolli : +0.233, SE 0.079 -> SFT sezilarli yaxshi
  base model savolni ko'pincha 'savol' bilan davom ettiradi - u javob bermaydi
  ⭐ B guruh faktlari SFT da YO'Q edi: bilim pretrainingdan, format SFT dan

Nima ko'rsatdi: pretraining korpusi (60 024 token, 53 so'zli lug'at) internetning kichik o'xshatmasi: 60% oddiy matn ("gulnora kasbi oshpaz ."), 30% savollar ro'yxati va atigi 10% savol-javob (FAQ). Bir xil savolga uch xil javob keldi. Base model savol : gulnora kim ? ni savol : temur kim bilan davom ettirdi — u buzuq emas, korpusda savoldan keyin eng ko'p keladigan narsa yana savol. Prompt boshiga bitta savol-javob misoli qo'yilganda o'sha base model javob : oshpaz . deb to'g'ri javob berdi — vaznlar o'zgarmadi, bu in-context learning. SFT dan keyin (15 ta juft, 60 qadam, loss faqat javobda) model misolsiz ham javob : oshpaz . dedi. 3-bo'limda 15 ta SFT ko'rmagan ism va 2 seed: base zero-shot formati 0.0%, 2 misolli promptda format 100.0% va to'g'ri kasb 76.7%, SFT dan keyin 100.0% va 100.0%. Juftlashgan farqlar: SFT - base zero-shot +1.000, SFT - base 2 misolli +0.233 (SE 0.079) — ikkalasi ham sezilarli. Eng muhim kuzatuv: B guruh faktlari SFT ma'lumotida yo'q edi — model ularni pretrainingdan olgan, SFT faqat "savolga javob formatida gapirish"ni o'rgatgan. Few-shot ham formatni to'liq berdi, lekin to'g'rilikda SFT dan orqada qoldi. Ehtimoliy sabab: ikki misol va savol birgalikda 22 token — 24 tokenli oynaning deyarli hammasi, model esa bunday uzun FAQ hujjatlarni kam ko'rgan (FAQ hujjatlarida 3 tadan juft). Bog'liq bo'limlar: 2.2, 2.3, 2.4, 2.7.

Misol 2 — Masshtab hisob-kitobi: parametr, FLOP, xotira, kvantlash

python
"""Masshtab hisob-kitobi: parametrlar, 6ND FLOP, xotira va kvantlash xatosi."""

import warnings

import torch
import torch.nn as nn
import torch.nn.functional as F
from torch.utils.flop_counter import FlopCounterMode

L_KONTEKST = 64

# FARAZIY konfiguratsiyalar: qatlamlar, d, lug'at (haqiqiy modellar boshqacha bo'lishi mumkin)
KONFIG = {
    "kichik (125M sinf)": (12, 768, 50000),
    "o'rta (1B sinf)": (16, 2048, 64000),
    "katta (7B sinf)": (32, 4096, 64000),
    "juda katta (70B sinf)": (80, 8192, 128000),
}
# FARAZIY apparat: bitta tezlatgichning cho'qqi tezligi va real foydalanish ulushi
CHOQQI_FLOPS = 1e15
FOYDALANISH = 0.40


class Blok(nn.Module):
    def __init__(self, d, boshlar):
        super().__init__()
        self.boshlar = boshlar
        self.ln1, self.ln2 = nn.LayerNorm(d), nn.LayerNorm(d)
        self.qkv = nn.Linear(d, 3 * d)
        self.proj = nn.Linear(d, d)
        self.ffn = nn.Sequential(nn.Linear(d, 4 * d), nn.GELU(), nn.Linear(4 * d, d))

    def forward(self, x):
        B, T, d = x.shape
        q, k, v = self.qkv(self.ln1(x)).split(d, dim=2)
        q, k, v = [t.view(B, T, self.boshlar, -1).transpose(1, 2) for t in (q, k, v)]
        o = F.scaled_dot_product_attention(q, k, v, is_causal=True)
        x = x + self.proj(o.transpose(1, 2).reshape(B, T, d))
        return x + self.ffn(self.ln2(x))


class GPT(nn.Module):
    def __init__(self, V, d, qatlamlar, boshlar=4):
        super().__init__()
        self.emb = nn.Embedding(V, d)
        self.poz = nn.Embedding(L_KONTEKST, d)
        self.bloklar = nn.Sequential(*[Blok(d, boshlar) for _ in range(qatlamlar)])
        self.ln = nn.LayerNorm(d)
        self.chiqish = nn.Linear(d, V, bias=False)

    def forward(self, x):
        h = self.emb(x) + self.poz(torch.arange(x.shape[1]))
        return self.chiqish(self.ln(self.bloklar(h)))


def parametrlar(qatlam, d, V):
    """12*L*d^2 bloklar + V*d embedding (chiqish qatlami embedding bilan bog'langan deb)."""
    return 12 * qatlam * d * d, V * d


def odam(n, birlik=""):
    for chegara, qoshimcha in ((1e12, "T"), (1e9, "B"), (1e6, "M"), (1e3, "K")):
        if n >= chegara:
            return f"{n / chegara:.1f}{qoshimcha}{birlik}"
    return f"{n:.0f}{birlik}"


def kvantla(w, bit, qator_boyicha):
    """Simmetrik kvantlash: w ~ shkala * butun_son, butun son [-(2^(b-1)-1), 2^(b-1)-1]."""
    qmax = 2 ** (bit - 1) - 1
    maks = w.abs().amax(dim=1, keepdim=True) if qator_boyicha else w.abs().max()
    shkala = maks / qmax
    return torch.clamp(torch.round(w / shkala), -qmax, qmax) * shkala


def main() -> None:
    torch.set_num_threads(1)
    torch.manual_seed(0)

    print("=== 1. Parametr soni: formula va torch sanog'i ===")
    for q, d, V in ((2, 64, 1000), (4, 128, 5000), (6, 256, 8000)):
        m = GPT(V, d, q)
        sanoq = sum(p.numel() for n, p in m.named_parameters() if n.startswith("bloklar"))
        blok, _ = parametrlar(q, d, V)
        print(f"  L={q} d={d:>3}: bloklar {sanoq:>9,}, 12*L*d^2 = {blok:>9,}"
              f"  (farq {abs(sanoq - blok) / sanoq:.1%})")

    print("\n=== 2. 6*N*D: torch FLOP hisoblagichi bilan tekshiruv ===")
    for q, d, V in ((2, 64, 1000), (4, 128, 5000)):
        m = GPT(V, d, q)
        x = torch.randint(0, V, (8, L_KONTEKST))
        with warnings.catch_warnings():
            warnings.simplefilter("ignore")
            with FlopCounterMode(display=False) as fc:
                loss = F.cross_entropy(m(x).reshape(-1, V), x.reshape(-1))
                loss.backward()
        olchangan = fc.get_total_flops()
        n_mat = sum(p.numel() for n, p in m.named_parameters()
                    if p.dim() == 2 and not n.startswith(("emb", "poz")))
        taxmin = 6 * n_mat * x.numel()
        attn = 6 * 2 * q * L_KONTEKST * d * x.numel()      # QK^T va w@V, forward + backward
        print(f"  L={q} d={d:>3}: o'lchangan {odam(olchangan)}, 6*N*D = {odam(taxmin)}, "
              f"nisbat {olchangan / taxmin:.2f}; attention qo'shimchasi +{attn / taxmin:.0%}")
    print("  (hisoblagich faqat mm/addmm ni sanadi; attention ni formula bilan qo'shdik)")

    print("\n=== 3. O'rgatish hisobi (D = 20 * N token, FARAZIY apparat) ===")
    print("  model                     N      D       FLOP     1 tezlatgichda   1024 tada")
    sekund_kun = 86400
    for nom, (q, d, V) in KONFIG.items():
        blok, emb = parametrlar(q, d, V)
        N = blok + emb
        D = 20 * N
        flop = 6 * N * D
        kun = flop / (CHOQQI_FLOPS * FOYDALANISH) / sekund_kun
        print(f"  {nom:<22} {odam(N):>7} {odam(D):>6} {flop:>10.1e} {kun:>11,.1f} kun "
              f"{kun / 1024:>8.1f} kun")

    print("\n=== 4. Og'irliklar xotirasi (faqat vaznlar, GB) ===")
    print("  model                   fp32    bf16    int8    int4   o'rgatish (16 B/param)")
    for nom, (q, d, V) in KONFIG.items():
        N = sum(parametrlar(q, d, V))
        qator = " ".join(f"{N * b / 1e9:>7.1f}" for b in (4, 2, 1, 0.5))
        print(f"  {nom:<22} {qator} {N * 16 / 1e9:>10.0f}")
    q, d, _ = KONFIG["katta (7B sinf)"]
    kv = 2 * q * d * 2                                  # K va V, har qatlam, bf16 (2 bayt)
    print(f"  KV-cache (7B sinf, bf16): token boshiga {kv / 1e6:.2f} MB; "
          f"8000 token -> {kv * 8000 / 1e9:.1f} GB; 32 so'rov x 8000 -> {kv * 8000 * 32 / 1e9:.0f} GB")

    print("\n=== 5. Kvantlash xatosi: haqiqiy matritsada o'lchaymiz ===")
    g = torch.Generator().manual_seed(0)
    w = torch.randn(512, 512, generator=g) * 0.02
    w_chetli = w.clone()
    w_chetli[torch.randint(0, 512, (20,), generator=g), torch.randint(0, 512, (20,), generator=g)] = 1.0
    x = torch.randn(64, 512, generator=g)
    print("  matritsa         bit  shkala       nisbiy xato (w)  nisbiy xato (x @ w)")
    xatolar = {}
    for nom, m in (("oddiy", w), ("20 ta chetli", w_chetli)):
        for bit in (8, 4):
            for qb in (False, True):
                wq = kvantla(m, bit, qb)
                e_w = ((wq - m).norm() / m.norm()).item()
                e_y = ((x @ wq - x @ m).norm() / (x @ m).norm()).item()
                xatolar[(nom, bit, qb)] = e_y
                print(f"  {nom:<16} {bit:>3}  {'qator' if qb else 'butun':<10} {e_w:>14.4f} {e_y:>18.4f}")
    if xatolar[("20 ta chetli", 4, False)] > 3 * xatolar[("oddiy", 4, False)]:
        print("  chetli qiymatlar butun matritsa shkalasini buzadi -> qator bo'yicha shkala yordam beradi")
    print("  ⭐ Xotira = N x bayt; hisob = 6ND; ikkalasi ham bir qatorda baholanadi")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. Parametr soni: formula va torch sanog'i ===
  L=2 d= 64: bloklar    99,968, 12*L*d^2 =    98,304  (farq 1.7%)
  L=4 d=128: bloklar   793,088, 12*L*d^2 =   786,432  (farq 0.8%)
  L=6 d=256: bloklar 4,738,560, 12*L*d^2 = 4,718,592  (farq 0.4%)

=== 2. 6*N*D: torch FLOP hisoblagichi bilan tekshiruv ===
  L=2 d= 64: o'lchangan 498.6M, 6*N*D = 498.6M, nisbat 1.00; attention qo'shimchasi +10%
  L=4 d=128: o'lchangan 4.4B, 6*N*D = 4.4B, nisbat 1.00; attention qo'shimchasi +5%
  (hisoblagich faqat mm/addmm ni sanadi; attention ni formula bilan qo'shdik)

=== 3. O'rgatish hisobi (D = 20 * N token, FARAZIY apparat) ===
  model                     N      D       FLOP     1 tezlatgichda   1024 tada
  kichik (125M sinf)      123.3M   2.5B    1.8e+18         0.1 kun      0.0 kun
  o'rta (1B sinf)         936.4M  18.7B    1.1e+20         3.0 kun      0.0 kun
  katta (7B sinf)           6.7B 134.1B    5.4e+21       156.1 kun      0.2 kun
  juda katta (70B sinf)    65.5B   1.3T    5.1e+23    14,884.5 kun     14.5 kun

=== 4. Og'irliklar xotirasi (faqat vaznlar, GB) ===
  model                   fp32    bf16    int8    int4   o'rgatish (16 B/param)
  kichik (125M sinf)         0.5     0.2     0.1     0.1          2
  o'rta (1B sinf)            3.7     1.9     0.9     0.5         15
  katta (7B sinf)           26.8    13.4     6.7     3.4        107
  juda katta (70B sinf)    261.9   130.9    65.5    32.7       1048
  KV-cache (7B sinf, bf16): token boshiga 0.52 MB; 8000 token -> 4.2 GB; 32 so'rov x 8000 -> 134 GB

=== 5. Kvantlash xatosi: haqiqiy matritsada o'lchaymiz ===
  matritsa         bit  shkala       nisbiy xato (w)  nisbiy xato (x @ w)
  oddiy              8  butun              0.0106             0.0105
  oddiy              8  qator              0.0075             0.0074
  oddiy              4  butun              0.1920             0.1899
  oddiy              4  qator              0.1354             0.1343
  20 ta chetli       8  butun              0.1041             0.1025
  20 ta chetli       8  qator              0.0215             0.0217
  20 ta chetli       4  butun              0.9159             0.9128
  20 ta chetli       4  qator              0.2168             0.2170
  chetli qiymatlar butun matritsa shkalasini buzadi -> qator bo'yicha shkala yordam beradi
  ⭐ Xotira = N x bayt; hisob = 6ND; ikkalasi ham bir qatorda baholanadi

Nima ko'rsatdi: 1-bo'limda 12·L·d^2 formulasi torch sanog'idan 1.7%, 0.8% va 0.4% farq qildi — d o'sgan sari farq (bias va LayerNorm) ahamiyatsizlashadi. 2-bo'lim 6·N·D ni haqiqiy o'lchov bilan tekshirdi: FlopCounterMode forward + backward dagi barcha matritsa ko'paytmalarini sanadi va natija aynan 6·N·D ga teng chiqdi (nisbat 1.00). Muhim nuans: hisoblagich scaled_dot_product_attention ichidagi QK^T va w @ V ni sanamadi — ularni formula bilan qo'shdik, bu kontekst 64 bo'lganda +10% va +5%. Kontekst uzun bo'lsa, attention ulushi o'sadi (24.11-dars). 3-bo'limda faraziy tezlatgich (sekundiga 1e15 FLOP, 40% foydalanish) bilan: 7B sinfdagi modelni D = 20N tokenda o'rgatish 5.4e21 FLOP — bitta tezlatgichda 156.1 kun, 1024 tasida 0.2 kun; 70B sinf — 1024 tezlatgichda ham 14.5 kun. 4-bo'lim: 7B sinf vaznlari fp32 da 26.8 GB, int4 da 3.4 GB; o'rgatish uchun esa 107 GB (aktivatsiyalarsiz). KV-cache: 8000 tokenli bitta suhbat 4.2 GB, 32 ta parallel suhbat 134 GB — vaznlardan ko'p. 5-bo'limda kvantlash haqiqatan bajarildi: oddiy matritsada int8 xatosi ~0.01, int4 — 0.13-0.19; 20 ta chetli qiymat butun matritsa shkalasini buzdi (int4 da 0.9128 — deyarli butun signal yo'qoldi), qator bo'yicha shkala uni 0.2170 gacha tushirdi. Bog'liq bo'limlar: 2.5, 2.6.

Misol 3 — Gallyutsinatsiya: ko'rilmagan faktni ishonch bilan to'qish

python
"""Gallyutsinatsiya: model ko'rmagan faktni ham ishonch bilan "to'qiydi"."""

import math

import numpy as np
import torch
import torch.nn as nn
import torch.nn.functional as F

ISMLAR = ("anvar dilnoza bobur malika sardor nodira jasur zarina otabek madina "
          "sherzod gulnora farhod laylo rustam sevara aziz kamola bahrom shahlo "
          "temur nigora dilshod feruza jamshid mohira sanjar yulduz akmal lola "
          "botir oydin hamid zuhra ilhom saida karim nilufar komil diyora").split()
KASBLAR = "shifokor muhandis oqituvchi dehqon haydovchi oshpaz".split()
JOYLAR = "bozorga maktabga shaharga bekatga dalaga bogga".split()
CHASTOTA = (0, 1, 3, 10)              # har guruhda fakt korpusda necha marta uchraydi
L = 24


def korpus(seed=0):
    """40 ism, 4 guruh: fakt 0, 1, 3 yoki 10 marta. Hamma ism boshqa gaplarda ham bor."""
    rng = np.random.default_rng(seed)
    ismlar = [str(x) for x in rng.permutation(ISMLAR)]
    kasb = {i: str(rng.choice(KASBLAR)) for i in ismlar}
    guruh = {i: CHASTOTA[k // 10] for k, i in enumerate(ismlar)}
    gaplar = []
    for i in ismlar:
        gaplar += [f"{i} kasbi {kasb[i]} ." for _ in range(guruh[i])]
        gaplar += [f"{i} {rng.choice(JOYLAR)} bordi ." for _ in range(8)]
    gaplar += ["mening kasbim yaxshi ." for _ in range(40)]
    rng.shuffle(gaplar)
    return " ".join(gaplar), kasb, guruh


class Blok(nn.Module):
    def __init__(self, d, boshlar):
        super().__init__()
        self.boshlar = boshlar
        self.ln1, self.ln2 = nn.LayerNorm(d), nn.LayerNorm(d)
        self.qkv = nn.Linear(d, 3 * d)
        self.proj = nn.Linear(d, d)
        self.ffn = nn.Sequential(nn.Linear(d, 4 * d), nn.GELU(), nn.Linear(4 * d, d))

    def forward(self, x):
        B, T, d = x.shape
        q, k, v = self.qkv(self.ln1(x)).split(d, dim=2)
        q, k, v = [t.view(B, T, self.boshlar, -1).transpose(1, 2) for t in (q, k, v)]
        o = F.scaled_dot_product_attention(q, k, v, is_causal=True)
        x = x + self.proj(o.transpose(1, 2).reshape(B, T, d))
        return x + self.ffn(self.ln2(x))


class GPT(nn.Module):
    def __init__(self, V, d=32, boshlar=4, qatlamlar=2):
        super().__init__()
        self.emb = nn.Embedding(V, d)
        self.poz = nn.Embedding(L, d)
        self.bloklar = nn.Sequential(*[Blok(d, boshlar) for _ in range(qatlamlar)])
        self.ln = nn.LayerNorm(d)
        self.chiqish = nn.Linear(d, V)

    def forward(self, x):
        x = x[:, -L:]
        h = self.emb(x) + self.poz(torch.arange(x.shape[1]))
        return self.chiqish(self.ln(self.bloklar(h)))


def orgat(T, V, seed, qadamlar=200, B=32):
    torch.manual_seed(seed)
    model = GPT(V)
    opt = torch.optim.AdamW(model.parameters(), lr=1e-2, weight_decay=0.01)
    g = torch.Generator().manual_seed(seed)
    for _ in range(qadamlar):
        bosh = torch.randint(0, len(T) - L - 1, (B,), generator=g)
        w = torch.stack([T[i:i + L + 1] for i in bosh.tolist()])
        loss = F.cross_entropy(model(w[:, :-1]).reshape(-1, V), w[:, 1:].reshape(-1))
        opt.zero_grad()
        loss.backward()
        opt.step()
    model.eval()
    return model


@torch.no_grad()
def sora(model, ism, s2i):
    """'<ism> kasbi' dan keyingi taqsimot: kasblar ulushi va kasblar ichidagi eng yuqori p."""
    x = torch.tensor([[s2i["."], s2i[ism], s2i["kasbi"]]])
    p = torch.softmax(model(x)[0, -1], -1)
    pk = torch.tensor([p[s2i[k]].item() for k in KASBLAR])
    return pk.sum().item(), pk / pk.sum()


def main() -> None:
    torch.set_num_threads(1)
    matn, kasb, guruh = korpus()
    sozlar = sorted(set(matn.split()))
    s2i = {w: i for i, w in enumerate(sozlar)}
    T = torch.tensor([s2i[w] for w in matn.split()])
    print("=== 1. Korpus ===")
    print(f"  {len(T)} token, 40 ism; har ism 8 marta oddiy gapda ('... bozorga bordi .')")
    print("  kasb fakti: 10 ismda 0 marta, 10 tasida 1, 10 tasida 3, 10 tasida 10 marta")
    print(f"  tasodifiy taxmin aniqligi: 1/{len(KASBLAR)} = {1 / len(KASBLAR):.3f}")

    print("\n=== 2. '<ism> kasbi ...' - javob, ishonch va to'g'rilik (2 seed) ===")
    qatorlar = []
    for seed in range(2):
        model = orgat(T, len(sozlar), seed)
        for ism in kasb:
            ulush, pk = sora(model, ism, s2i)
            k = int(pk.argmax())
            qatorlar.append((seed, guruh[ism], ulush, pk.max().item(), float(KASBLAR[k] == kasb[ism])))
    q = np.array(qatorlar)
    print("  fakt soni   kasbga massa   ishonch (maks p)   aniqlik   ishonch - aniqlik")
    ishonch, aniqlik = {}, {}
    for c in CHASTOTA:
        m = q[:, 1] == c
        ishonch[c], aniqlik[c] = q[m, 3].mean(), q[m, 4].mean()
        print(f"  {c:>9} {q[m, 2].mean():>14.3f} {ishonch[c]:>18.3f} {aniqlik[c]:>9.3f} "
              f"{ishonch[c] - aniqlik[c]:>+18.3f}")

    print("\n=== 3. Ko'rilmagan fakt: javob bermay qo'yadimi? ===")
    m0 = q[:, 1] == 0
    print(f"  0 marta ko'rilgan ismlarda kasbga massa {q[m0, 2].mean():.3f} - "
          f"model deyarli doim biror kasb aytadi")
    d = q[m0, 3] - 1 / len(KASBLAR)
    se = d.std(ddof=1) / math.sqrt(len(d))
    print(f"  ishonch - tasodif (1/6): {d.mean():+.3f}, SE {se:.3f} -> "
          f"{'tasodifdan sezilarli yuqori' if d.mean() > 2 * se else 'tasodifga yaqin'}")
    d2 = q[m0, 4] - 1 / len(KASBLAR)
    se2 = d2.std(ddof=1) / math.sqrt(len(d2))
    print(f"  aniqlik - tasodif:         {d2.mean():+.3f}, SE {se2:.3f} -> "
          f"{'tasodifdan sezilarli yuqori' if d2.mean() > 2 * se2 else 'tasodifdan farqsiz'}")

    print("\n=== 4. Kalibrlash: ishonch oraliqlari bo'yicha (hamma guruhlar) ===")
    chegaralar = [0.0, 0.4, 0.6, 0.8, 1.01]
    ece = 0.0
    for a, b in zip(chegaralar, chegaralar[1:]):
        m = (q[:, 3] >= a) & (q[:, 3] < b)
        if m.sum() == 0:
            continue
        ece += m.mean() * abs(q[m, 3].mean() - q[m, 4].mean())
        print(f"  ishonch {a:.1f}-{min(b, 1.0):.1f}: {int(m.sum()):>3} savol, "
              f"o'rtacha ishonch {q[m, 3].mean():.3f}, aniqlik {q[m, 4].mean():.3f}")
    print(f"  ECE (kutilgan kalibrlash xatosi): {ece:.3f}")
    if ishonch[0] - aniqlik[0] > ishonch[10] - aniqlik[10]:
        print("  eng katta ortiqcha ishonch - kam ko'rilgan faktlarda: bu gallyutsinatsiya")
    print("  ⭐ Model 'bilmayman' demaydi: u ehtimolli davomni beradi, bilim chegarasini emas")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. Korpus ===
  2000 token, 40 ism; har ism 8 marta oddiy gapda ('... bozorga bordi .')
  kasb fakti: 10 ismda 0 marta, 10 tasida 1, 10 tasida 3, 10 tasida 10 marta
  tasodifiy taxmin aniqligi: 1/6 = 0.167

=== 2. '<ism> kasbi ...' - javob, ishonch va to'g'rilik (2 seed) ===
  fakt soni   kasbga massa   ishonch (maks p)   aniqlik   ishonch - aniqlik
          0          0.987              0.727     0.150             +0.577
          1          0.979              0.679     0.800             -0.121
          3          0.988              0.857     0.900             -0.043
         10          0.990              0.983     1.000             -0.017

=== 3. Ko'rilmagan fakt: javob bermay qo'yadimi? ===
  0 marta ko'rilgan ismlarda kasbga massa 0.987 - model deyarli doim biror kasb aytadi
  ishonch - tasodif (1/6): +0.561, SE 0.050 -> tasodifdan sezilarli yuqori
  aniqlik - tasodif:         -0.017, SE 0.082 -> tasodifdan farqsiz

=== 4. Kalibrlash: ishonch oraliqlari bo'yicha (hamma guruhlar) ===
  ishonch 0.0-0.4:   3 savol, o'rtacha ishonch 0.327, aniqlik 0.000
  ishonch 0.4-0.6:  14 savol, o'rtacha ishonch 0.511, aniqlik 0.500
  ishonch 0.6-0.8:  14 savol, o'rtacha ishonch 0.714, aniqlik 0.643
  ishonch 0.8-1.0:  49 savol, o'rtacha ishonch 0.955, aniqlik 0.837
  ECE (kutilgan kalibrlash xatosi): 0.099
  eng katta ortiqcha ishonch - kam ko'rilgan faktlarda: bu gallyutsinatsiya
  ⭐ Model 'bilmayman' demaydi: u ehtimolli davomni beradi, bilim chegarasini emas

Nima ko'rsatdi: 40 ismning hammasi korpusda 8 martadan uchraydi, lekin kasb fakti 10 tasida umuman yo'q, qolganlarida 1, 3 yoki 10 marta. <ism> kasbi dan keyingi taqsimotda kasblar massasi hamma guruhda ~0.98-0.99 — ya'ni model deyarli har doim biror kasb aytadi, fakt bo'lmaganda ham. Hech ko'rilmagan faktlarda aniqlik 0.150 (tasodif 0.167 dan farqsiz: -0.017, SE 0.082), ishonch esa 0.727 — tasodifdan +0.561 yuqori (SE 0.050, sezilarli). Bu — gallyutsinatsiyaning sof ko'rinishi: shakl to'g'ri, ohang ishonchli, mazmun to'qilgan. Fakt ko'p takrorlangan sari ishonch va aniqlik birga o'sdi (10 marta: 0.983 va 1.000). Kutilmagan tomoni: bir marta ko'rilgan faktlarda model kam ishonchli edi (0.679 ishonch, 0.800 aniqlik) — ortiqcha ishonch faqat umuman bilmagan joyda keskin. 4-bo'limda ishonch oraliqlari: 0.8-1.0 oralig'idagi 49 savolda aniqlik 0.837, 0.4-0.6 da — 0.500; ECE 0.099. Bog'liq bo'lim: 2.8.

Misol 4 — DPO g'oyasi noldan

python
"""DPO g'oyasi noldan: afzallik juftlari bilan javob uslubini siljitish."""

import copy
import math

import numpy as np
import torch
import torch.nn as nn
import torch.nn.functional as F

ISMLAR = ("anvar dilnoza bobur malika sardor nodira jasur zarina otabek madina "
          "sherzod gulnora farhod laylo rustam sevara aziz kamola bahrom shahlo "
          "temur nigora dilshod feruza jamshid mohira sanjar yulduz akmal lola").split()
KASBLAR = "shifokor muhandis oqituvchi dehqon haydovchi oshpaz".split()
L = 24


def qisqa(k):
    return f"javob : {k} ."


def uzun(k):
    return f"javob : hmm , yaxshi savol , menimcha {k} ."


def dunyo(seed=0):
    rng = np.random.default_rng(seed)
    kasb = {i: str(rng.choice(KASBLAR)) for i in ISMLAR}
    aralash = [str(x) for x in rng.permutation(ISMLAR)]
    return kasb, aralash[:15], aralash[15:]


def sft_korpus(kasb, n, rng):
    """SFT dan chiqqan model o'xshatmasi: javoblarning yarmi qisqa, yarmi "suvli"."""
    qator = []
    for _ in range(n):
        i = str(rng.choice(ISMLAR))
        javob = qisqa(kasb[i]) if rng.random() < 0.5 else uzun(kasb[i])
        qator.append(f"<d> savol : {i} kim ? {javob}")
    return " ".join(qator)


class Blok(nn.Module):
    def __init__(self, d, boshlar):
        super().__init__()
        self.boshlar = boshlar
        self.ln1, self.ln2 = nn.LayerNorm(d), nn.LayerNorm(d)
        self.qkv = nn.Linear(d, 3 * d)
        self.proj = nn.Linear(d, d)
        self.ffn = nn.Sequential(nn.Linear(d, 4 * d), nn.GELU(), nn.Linear(4 * d, d))

    def forward(self, x):
        B, T, d = x.shape
        q, k, v = self.qkv(self.ln1(x)).split(d, dim=2)
        q, k, v = [t.view(B, T, self.boshlar, -1).transpose(1, 2) for t in (q, k, v)]
        o = F.scaled_dot_product_attention(q, k, v, is_causal=True)
        x = x + self.proj(o.transpose(1, 2).reshape(B, T, d))
        return x + self.ffn(self.ln2(x))


class GPT(nn.Module):
    def __init__(self, V, d=32, boshlar=4, qatlamlar=2):
        super().__init__()
        self.emb = nn.Embedding(V, d)
        self.poz = nn.Embedding(L, d)
        self.bloklar = nn.Sequential(*[Blok(d, boshlar) for _ in range(qatlamlar)])
        self.ln = nn.LayerNorm(d)
        self.chiqish = nn.Linear(d, V)

    def forward(self, x):
        x = x[:, -L:]
        h = self.emb(x) + self.poz(torch.arange(x.shape[1]))
        return self.chiqish(self.ln(self.bloklar(h)))


def orgat(T, V, seed=0, qadamlar=250, B=32):
    torch.manual_seed(seed)
    model = GPT(V)
    opt = torch.optim.AdamW(model.parameters(), lr=1e-2, weight_decay=0.01)
    g = torch.Generator().manual_seed(seed)
    for _ in range(qadamlar):
        bosh = torch.randint(0, len(T) - L - 1, (B,), generator=g)
        w = torch.stack([T[i:i + L + 1] for i in bosh.tolist()])
        loss = F.cross_entropy(model(w[:, :-1]).reshape(-1, V), w[:, 1:].reshape(-1))
        opt.zero_grad()
        loss.backward()
        opt.step()
    return model


def javob_logp(model, savollar, javoblar, s2i):
    """log pi(javob | savol) = javob tokenlari log-ehtimollari yig'indisi (batch)."""
    s = torch.tensor([[s2i[w] for w in x.split()] for x in savollar])
    j = torch.tensor([[s2i[w] for w in x.split()] for x in javoblar])
    t = torch.cat([s, j], 1)
    logp = torch.log_softmax(model(t[:, :-1]), -1)
    tok = logp.gather(2, t[:, 1:].unsqueeze(2)).squeeze(2)
    return tok[:, s.shape[1] - 1:].sum(1)


def dpo(ref, juftlar, s2i, beta, qadamlar=40, faqat_sft=False):
    """DPO: -log sigmoid(beta * [(log pi_w - log ref_w) - (log pi_l - log ref_l)])."""
    model = copy.deepcopy(ref)
    opt = torch.optim.AdamW(model.parameters(), lr=3e-4, weight_decay=0.0)
    sav = [s for s, _, _ in juftlar]
    yw = [w for _, w, _ in juftlar]
    yl = [l_ for _, _, l_ in juftlar]
    with torch.no_grad():
        ref_w, ref_l = javob_logp(ref, sav, yw, s2i), javob_logp(ref, sav, yl, s2i)
    for _ in range(qadamlar):
        pw = javob_logp(model, sav, yw, s2i)
        if faqat_sft:                                      # taqqoslash: faqat tanlanganda SFT
            loss = -pw.mean()
        else:
            pl = javob_logp(model, sav, yl, s2i)
            loss = -F.logsigmoid(beta * ((pw - ref_w) - (pl - ref_l))).mean()
        opt.zero_grad()
        loss.backward()
        opt.step()
    return model


@torch.no_grad()
def olcha(model, ref, ismlar, kasb, s2i):
    """Har ism: P(qisqa uslub), greedy kasb to'g'rimi, KL(pi || ref) javob boshida."""
    p_qisqa, togri, kl = [], [], []
    for i in ismlar:
        x = torch.tensor([[s2i[w] for w in f"<d> savol : {i} kim ? javob :".split()]])
        lp, lr = torch.log_softmax(model(x)[0, -1], -1), torch.log_softmax(ref(x)[0, -1], -1)
        p = lp.exp()
        p_qisqa.append(1 - p[s2i["hmm"]].item())
        kl.append((p * (lp - lr)).sum().item())
        k = max(KASBLAR, key=lambda k: p[s2i[k]].item())
        togri.append(float(k == kasb[i]))
    return np.array(p_qisqa), np.array(togri), np.array(kl)


def main() -> None:
    torch.set_num_threads(1)
    kasb, A, B_guruh = dunyo()
    matn = sft_korpus(kasb, 2500, np.random.default_rng(0))
    sozlar = sorted(set(matn.split()))
    s2i = {w: i for i, w in enumerate(sozlar)}
    T = torch.tensor([s2i[w] for w in matn.split()])
    ref = orgat(T, len(sozlar))
    juftlar = [(f"<d> savol : {i} kim ?", qisqa(kasb[i]), uzun(kasb[i])) for i in A]

    print("=== 1. Boshlang'ich (reference) model ===")
    print(f"  korpus: 2500 savol-javob, javoblarning ~50% i qisqa: '{qisqa('oshpaz')}'")
    print(f"                              ~50% i suvli: '{uzun('oshpaz')}'")
    print(f"  afzallik juftlari: {len(juftlar)} ta (A guruh), tanlangan = qisqa, rad = suvli")
    p0, t0, _ = olcha(ref, ref, B_guruh, kasb, s2i)
    print(f"  B guruhda: P(qisqa) {p0.mean():.3f}, kasb aniqligi {t0.mean():.3f}")

    print("\n=== 2. DPO va 'faqat tanlanganda SFT' (40 qadam, B guruh - juftlarda yo'q) ===")
    print("  usul                 P(qisqa)   kasb aniqligi   KL(pi||ref)")
    natija = {}
    for nom, beta, fs in (("DPO beta=0.1", 0.1, False), ("DPO beta=1.0", 1.0, False),
                          ("SFT tanlanganda", None, True)):
        torch.manual_seed(0)
        m = dpo(ref, juftlar, s2i, beta, faqat_sft=fs)
        natija[nom] = olcha(m, ref, B_guruh, kasb, s2i)
        pq, tg, kl = natija[nom]
        print(f"  {nom:<18} {pq.mean():>10.3f} {tg.mean():>15.3f} {kl.mean():>13.3f}")

    print("\n=== 3. Juftlashgan farqlar (15 ism) ===")
    for nom in natija:
        d = natija[nom][0] - p0
        se = d.std(ddof=1) / math.sqrt(len(d))
        print(f"  {nom:<18} P(qisqa) o'zgarishi {d.mean():+.3f}, SE {se:.3f} -> "
              f"{'sezilarli' if abs(d.mean()) > 2 * se else 'sezilarli emas'}")
    d = natija["DPO beta=1.0"][2] - natija["DPO beta=0.1"][2]
    se = d.std(ddof=1) / math.sqrt(len(d))
    print(f"  KL: beta=1.0 - beta=0.1 = {d.mean():+.3f}, SE {se:.3f}")

    print("\n=== 4. Nima o'zgardi, nima o'zgarmadi ===")
    for nom, (pq, tg, kl) in natija.items():
        d = tg - t0
        se = d.std(ddof=1) / math.sqrt(len(d)) if d.any() else 0.0
        hukm = "sezilarli tushdi" if d.mean() < -2 * se else "sezilarli o'zgarmadi"
        print(f"  {nom:<18} kasb: {int(t0.sum())}/15 -> {int(tg.sum())}/15, "
              f"farq {d.mean():+.3f}, SE {se:.3f} -> {hukm}")
    print("  ⭐ DPO mukofot modelisiz: faqat (tanlangan, rad etilgan) juftlar va reference model")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. Boshlang'ich (reference) model ===
  korpus: 2500 savol-javob, javoblarning ~50% i qisqa: 'javob : oshpaz .'
                              ~50% i suvli: 'javob : hmm , yaxshi savol , menimcha oshpaz .'
  afzallik juftlari: 15 ta (A guruh), tanlangan = qisqa, rad = suvli
  B guruhda: P(qisqa) 0.444, kasb aniqligi 1.000

=== 2. DPO va 'faqat tanlanganda SFT' (40 qadam, B guruh - juftlarda yo'q) ===
  usul                 P(qisqa)   kasb aniqligi   KL(pi||ref)
  DPO beta=0.1            0.938           0.867         0.793
  DPO beta=1.0            0.798           1.000         0.357
  SFT tanlanganda         0.948           0.933         0.790

=== 3. Juftlashgan farqlar (15 ism) ===
  DPO beta=0.1       P(qisqa) o'zgarishi +0.493, SE 0.030 -> sezilarli
  DPO beta=1.0       P(qisqa) o'zgarishi +0.354, SE 0.021 -> sezilarli
  SFT tanlanganda    P(qisqa) o'zgarishi +0.504, SE 0.031 -> sezilarli
  KL: beta=1.0 - beta=0.1 = -0.436, SE 0.048

=== 4. Nima o'zgardi, nima o'zgarmadi ===
  DPO beta=0.1       kasb: 15/15 -> 13/15, farq -0.133, SE 0.091 -> sezilarli o'zgarmadi
  DPO beta=1.0       kasb: 15/15 -> 15/15, farq +0.000, SE 0.000 -> sezilarli o'zgarmadi
  SFT tanlanganda    kasb: 15/15 -> 14/15, farq -0.067, SE 0.067 -> sezilarli o'zgarmadi
  ⭐ DPO mukofot modelisiz: faqat (tanlangan, rad etilgan) juftlar va reference model

Nima ko'rsatdi: reference model — SFT dan chiqqan model o'xshatmasi: javoblarning yarmi qisqa (javob : oshpaz .), yarmi "suvli" (javob : hmm , yaxshi savol , menimcha oshpaz .). U juftlarda bo'lmagan B guruhida 0.444 ehtimol bilan qisqa uslubni tanlaydi va kasbni 15 tadan 15 tasida to'g'ri biladi. Faqat 15 ta afzallik jufti (A guruh) bilan 40 qadam: DPO beta=0.1 P(qisqa) ni 0.938 ga, beta=1.0 — 0.798 ga ko'tardi; ikkala siljish ham sezilarli (+0.493 va +0.354, SE ~0.02-0.03) va juftlarda bo'lmagan ismlarga ham o'tdi — model "qisqa javob yaxshi" degan umumiy qoidani o'rgandi. beta nazariyadagidek ishladi: katta beta modelni reference ga yaqin tutdi — KL 0.357 va 0.793 (farq -0.436, SE 0.048). Bilim: beta=1.0 da 15/15 saqlandi, beta=0.1 da 13/15 (-0.133, SE 0.091 — 15 ism bilan sezilarli emas, lekin yo'nalish ogohlantiradi). Halol taqqoslash: bu oddiy vazifada "faqat tanlangan javobda SFT" ham deyarli xuddi shunday natija berdi (0.948, KL 0.790). DPO ning ustunligi rad etilgan javob o'ziga xos xato bo'lganda (masalan, xavfli maslahat, noto'g'ri fakt) ko'rinadi — SFT faqat yaxshisini ko'taradi, DPO esa yomonini aniq pasaytiradi. Bog'liq bo'lim: 2.9.


5. To'g'ri va noto'g'ri tushunishlar

Noto'g'ri fikr To'g'risi
"LLM — GPT dan butunlay boshqa arxitektura" O'sha kauzal decoder va keyingi token maqsadi; farq — masshtab va bosqichlar
"Base model savolga javob bermasa, u buzuq" U hujjatni davom ettiradi; 1-misolda savolga savol : temur kim bilan davom etdi
"SFT modelga yangi faktlarni o'rgatadi" 1-misolda SFT da yo'q 15 ism haqida 100% to'g'ri — faktlar pretrainingdan
"Few-shot — fine-tuning ning bepul o'rnini bosadi" Format berdi (100%), lekin to'g'rilikda SFT dan 0.233 orqada
"Ishonchli ohang — to'g'rilik belgisi" Ko'rilmagan faktda ishonch 0.727, aniqlik 0.150
"Model bilmasa 'bilmayman' deydi" Bunday javob o'rgatilmagan bo'lsa, kasbga massa 0.987
"7B model 7 GB xotira oladi" bf16 da 13.4 GB, int4 da 3.4 GB, o'rgatishda ~107 GB + KV-cache
"int4 — sifat yo'qotmasdan 8 barobar tejam" Oddiy matritsada ham nisbiy xato 0.13-0.19; o'z vazifangizda o'lchang
"DPO beta qancha kichik bo'lsa, shuncha yaxshi" Kichik beta ref dan ko'proq uzoqlashtirdi (KL 0.793 va 0.357)
"Emergent qobiliyat — sirli sakrash" Ko'pincha metrikaning hammasi-yoki-hech tabiatidan

6. Keng tarqalgan xatolar va yechimlari

1. SFT da savol ham loss ga kiradi

python
y = savol_va_javob[1:]                                              # ⚠️
y = [-100] * (len(savol) - 1) + javob                               # ✅
loss = F.cross_entropy(logit, y, ignore_index=-100)

2. Base modelga ko'rsatma

python
prompt = "Menga Toshkent haqida qisqa ma'lumot ber."                # ⚠️ base model
prompt = "Savol: Toshkent qanday shahar?\nJavob:"                   # ✅ hujjat shaklida

3. O'rgatish xotirasini faqat vaznlar bilan hisoblash

python
kerak_gb = N * 4 / 1e9                                              # ⚠️
kerak_gb = N * 16 / 1e9 + aktivatsiyalar_gb                         # ✅ AdamW

4. Inference xotirasida KV-cache ni unutish

python
kerak = vaznlar_gb                                                  # ⚠️
kerak = vaznlar_gb + 2 * L * d * bayt * tokenlar * parallel / 1e9   # ✅

5. Butun matritsaga bitta kvantlash shkalasi

python
shkala = w.abs().max() / 7                                          # ⚠️ chetli qiymat
shkala = w.abs().amax(dim=1, keepdim=True) / 7                      # ✅ qator bo'yicha

6. DPO da reference model o'rgatiladi

python
ref_w = javob_logp(model, savol, y_w)                               # ⚠️ o'sha model
with torch.no_grad():
    ref_w = javob_logp(ref_muzlatilgan, savol, y_w)                 # ✅

7. Ishonchni to'g'rilik deb qabul qilish

python
if p_max > 0.7: javobni_qabul_qil()                                 # ⚠️
if manba_topildi and p_max > chegara: javobni_qabul_qil()           # ✅ + kalibrlash

7. Integratsiya — bu bilim qayerda kerak bo'ladi

  • 24.9-dars (o'tilgan): GPT, kauzal decoder, generatsiya — LLM ning o'zagi
  • 24.10-dars (o'tilgan): pretraining va fine-tuning, katastrofik unutish — SFT va DPO ning asosi
  • 24.11-dars (o'tilgan): 12·L·d^2, KV-cache, aralash aniqlik, LoRA — masshtab hisob-kitobi
  • 23.3-dars (o'tilgan): BPE — LLM tokenlari (keyingi dars)
  • 18-qism (o'tilgan): juftlashgan taqqoslash va SE — har bir "yaxshiroq" da'vosi uchun
  • Keyingi darslar: tokenlar va narx 25.2-bob, generatsiya parametrlari 25.3-bob, prompt 25.4-bob, gallyutsinatsiyaga qarshi RAG (25.8-25.9), LLM ni baholash 25.10-bob, LoRA bilan fine-tuning (25.11)

8. Eng yaxshi amaliyotlar

  1. Base va instruct modelni farqlang; base modelga hujjat shaklida prompt bering.

  2. Yangi faktlar uchun SFT emas, RAG yoki pretraining ma'lumotini o'ylang; SFT — format va xulq uchun.

  3. SFT da savol tokenlarini niqoblang (ignore_index=-100).

  4. Xotirani to'liq hisoblang: vaznlar + (o'rgatishda) optimizator holati + KV-cache.

  5. Kvantlashdan keyin o'z vazifangizda baholang; guruhli/qator bo'yicha shkala ishlating.

  6. Modelning ishonchini kalibrlash bilan tekshiring; "bilmayman" imkonini bering.

  7. DPO da reference ni muzlating va beta ni KL bilan birga kuzating.

  8. Model tanlashda o'z baho to'plamingiz, narx va kechikishni birga o'lchang.


9. Amaliy topshiriq

Vazifa 1: Bashorat qiling

python
1.  # LLM va 24.9 dagi GPT ning asosiy arxitektura farqi?
2.  # base model "Savol: ...?" ga ko'pincha nima bilan javob beradi va nega?
3.  # SFT da qaysi tokenlar loss ga kiradi?
4.  # L = 32, d = 4096 bo'lsa, bloklardagi parametrlar taxminan?
5.  # N = 7e9, D = 1.4e11 bo'lsa, o'rgatish FLOP?
6.  # 7B model int4 da vaznlar uchun qancha xotira oladi?
7.  # AdamW bilan fp32 o'rgatishda parametr boshiga taxminan necha bayt?
8.  # in-context learning da vaznlar o'zgaradimi?
9.  # nega model ko'rmagan faktni ham ishonch bilan aytadi?
10. # DPO da beta oshirilsa, KL(pi || ref) qanday o'zgaradi?
11. # butun matritsa shkalasida bitta juda katta vazn nimaga olib keladi?
12. # "hisob-optimal" qoidada D va N nisbati taxminan?
Javoblar
  1. Asosiy farq yo'q — o'sha kauzal decoder; farq masshtab va mayda o'zgarishlarda (RoPE, RMSNorm, SwiGLU)
  2. Ko'pincha yana savol bilan — korpusda savollar ro'yxati ko'p (1-misol: savol : temur kim)
  3. Faqat javob tokenlari; savol -100 bilan niqoblanadi
  4. 12 * 32 * 4096^2 ≈ 6.4e9
  5. 6 * 7e9 * 1.4e11 ≈ 5.9e21
  6. 7e9 * 0.5 = 3.5 GB (plus KV-cache)
  7. ~16 bayt (vazn 4 + grad 4 + m 4 + v 4)
  8. Yo'q — faqat prompt o'zgaradi
  9. Maqsad — ehtimolli davom; "X kasbi" dan keyin korpusda doim kasb kelgan, "bilmayman" emas
  10. Kamayadi (4-misol: 0.793 → 0.357)
  11. Shkala kattalashadi, qolgan vaznlar bir nechta darajaga "yopishadi" — xato keskin oshadi (int4 da 0.9128)
  12. D ≈ 20 N

Vazifa 2: Xatolarni tuzating

python
1.  x = savol + javob
    loss = F.cross_entropy(model(x[:-1]), x[1:])        # SFT

2.  xotira_gb = 7e9 * 2 / 1e9                            # "7B modelni 32 ta 8000 tokenli
                                                          #  suhbat bilan ishlatamiz"

3.  ref = model                                          # DPO
    loss = -F.logsigmoid(beta * ((pi_w - ref_w) - (pi_l - ref_l))).mean()

4.  shkala = w.abs().max() / 7
    wq = torch.round(w / shkala) * shkala                # int4

5.  if javob_ishonchi > 0.9:
        print("fakt to'g'ri")
Javoblar
python
1.  y = [-100] * (len(savol) - 1) + javob               # savol niqoblangan
    loss = F.cross_entropy(model(x[:-1]), y, ignore_index=-100)

2.  vazn = 7e9 * 2 / 1e9                                 # 14 GB
    kv = 2 * 32 * 4096 * 2 * 8000 * 32 / 1e9             # ~134 GB
    xotira_gb = vazn + kv

3.  ref = copy.deepcopy(model).eval()                    # muzlatilgan nusxa
    for p in ref.parameters():
        p.requires_grad_(False)

4.  shkala = w.abs().amax(dim=1, keepdim=True) / 7       # qator bo'yicha
    wq = torch.clamp(torch.round(w / shkala), -7, 7) * shkala

5.  # ishonch != to'g'rilik: kalibrlash (ECE) va manba tekshiruvi kerak
    if manba_bilan_tasdiqlandi(javob) and javob_ishonchi > kalibrlangan_chegara:
        print("fakt tasdiqlangan")

Vazifa 3: Base va SFT

Modellang:

  1. Savollar ro'yxati va FAQ bor pretraining korpusi
  2. Base model: zero-shot va 1, 2, 4 misolli prompt
  3. SFT: faqat A guruh, niqoblangan loss
  4. B guruhda format va to'g'rilik, juftlashgan farq va SE

Vazifa 4: Masshtab kalkulyatori

Modellang:

  1. Konfiguratsiyadan N (formula va torch sanog'i)
  2. FlopCounterMode bilan 6·N·D tekshiruvi
  3. Faraziy apparatda o'rgatish kunlari
  4. fp32/bf16/int8/int4 xotira va KV-cache

Vazifa 5: Gallyutsinatsiya

Modellang:

  1. Fakt chastotasi 0/1/3/10 bo'lgan korpus
  2. Ishonch va aniqlik guruhlar bo'yicha
  3. ECE va ishonch oraliqlari jadvali
  4. Korpusga "X kasbi noma'lum ." gaplarini qo'shib, model yangi ismlarda "noma'lum" deya oladimi — tekshiring

Vazifa 6: DPO

Modellang:

  1. Ikki uslubli reference model
  2. javob_logp va DPO loss
  3. beta = 0.1, 0.3, 1.0 — P(tanlangan uslub), KL, bilim
  4. "Faqat tanlanganda SFT" bilan taqqoslash

Vazifa 7: O'ylash

Rahbaringiz aytdi: "Bizning ichki qoidalarimizni model bilsin. 500 ta savol-javob yozib, modelni SFT qilamiz — keyin u hamma qoidalarni biladi va hech qachon to'qimaydi." Siz nima deysiz?

Javob

Qisqa javob: SFT modelga javob berish formati va uslubini o'rgatadi, lekin qoidalarni ishonchli "bilishi" va to'qimasligi uchun yetarli emas. Faktlar uchun to'g'ri vosita — RAG (javobni hujjatga bog'lash), SFT esa format va xulq uchun.

1. SFT nimani o'rgatadi. 1-misolda SFT faqat 15 ism haqida savol-javob ko'rsatdi, lekin model qolgan 15 ism haqida ham to'g'ri javob berdi — chunki faktlar pretrainingdan kelgan edi. SFT ning asosiy ta'siri formatda: base modelda format 0%, SFT dan keyin 100%. Aksincha, faktni SFT orqali "yuklash" uchun har qoida ko'p marta, turli shakllarda takrorlanishi kerak — 500 ta savol-javob bunga yetmaydi va qoidalar o'zgarsa, qayta o'rgatish kerak bo'ladi.

2. To'qish yo'qolmaydi. 3-misolda model ko'rmagan faktlarda ham kasbga 0.987 massa berdi — ishonch 0.727, aniqlik tasodif darajasida. SFT dan keyin ham model 500 ta savolda bo'lmagan qoida haqida xuddi shunday ishonch bilan javob to'qiydi. "Hech qachon to'qimaydi" degan kafolat yo'q.

3. To'g'ri arxitektura. Qoidalar hujjatlarini indekslash va har savolga tegishli bo'laklarni promptga qo'yish (RAG, 25.8-dars); modelga "faqat berilgan hujjat asosida javob ber, topilmasa 'bilmayman' de" deb ko'rsatma berish 25.4-bob; javobda manbani ko'rsatish va uni tekshirish. SFT keyinroq kerak bo'lishi mumkin — masalan, kompaniya uslubida qisqa javob yozish uchun.

4. O'lchov. Qaysi yondashuv yaxshiligini 100-200 ta real savoldan iborat baho to'plamida o'lchang 25.10-bob: to'g'rilik, "bilmayman" to'g'ri ishlatilganmi, to'qilgan javoblar ulushi.

Tavsiya:

python
# 1. Qoidalar -> bo'laklar -> indeks (25.8)
# 2. Prompt: "faqat <hujjatlar> asosida; topilmasa 'bilmayman'" (25.4)
# 3. Baho to'plami: 150 savol, shu jumladan javobi YO'Q 30 savol (to'qishni o'lchash uchun)
# 4. SFT - faqat format/uslub yetmasa, va baho to'plamida juftlashgan taqqoslash bilan

Rahbarga javob: "SFT modelga bizning uslubda javob berishni o'rgatadi, lekin qoidalarni ishonchli bilishni emas — model bilmagan narsasini ham ishonch bilan to'qiydi. Qoidalarni har safar hujjatdan olib beradigan tizim (RAG) quramiz, 'bilmayman' ni ruxsat etamiz va javobi yo'q savollar bilan to'qish ulushini o'lchaymiz."

Nimani mustahkamlaydi: 2.2, 2.4, 2.5, 2.8, 2.9-bo'limlar.


Xulosa

Bu darsda LLM ni 24.9-darsdagi GPT ning katta masshtabdagi davomi sifatida ko'rdik: hayot siklining uch bosqichini kichik modellarda qurdik, masshtab hisob-kitobini formula va haqiqiy o'lchov bilan qildik va gallyutsinatsiya sababini raqam bilan ko'rsatdik.

Eng muhim uch fikr:

  1. Pretraining bilim beradi, SFT — format, afzallik bosqichi — did. 1-misolda base model savolni savol : temur kim bilan davom ettirdi (format 0.0%); ikki misolli prompt formatni 100.0% ga, to'g'rilikni 76.7% ga chiqardi (in-context learning); 15 ta juftli SFT dan keyin SFT ko'rmagan 15 ism haqida ham 100.0% to'g'ri — faktlar pretrainingdan. 4-misolda 15 ta afzallik jufti bilan DPO qisqa uslub ehtimolini 0.444 dan 0.798-0.938 ga ko'tardi, beta esa reference dan uzoqlashishni cheklab turdi (KL 0.357 va 0.793).

  2. Masshtab uch formula bilan hisoblanadi. N ~ 12Ld^2 torch sanog'idan 0.4-1.7% farq qildi; 6·N·D ni FlopCounterMode aynan tasdiqladi (attention formula bilan +5-10%). 7B sinf: D = 20N da 5.4e21 FLOP, vaznlar bf16 da 13.4 GB, int4 da 3.4 GB, o'rgatishda ~107 GB, 32 ta 8000 tokenli suhbatning KV-cache i 134 GB. Kvantlash bepul emas: int4 xatosi 0.13-0.19, chetli qiymatlar bilan butun matritsa shkalasida 0.91.

  3. Gallyutsinatsiya — maqsad funksiyasining tabiiy natijasi. 3-misolda ko'rilmagan faktlarda model 0.987 massani baribir kasblarga berdi, ishonch 0.727, aniqlik esa tasodif darajasida (0.150). Ishonch — to'g'rilik belgisi emas; unga qarshi vosita — javobni hujjatga bog'lash (RAG), "bilmayman" ni o'rgatish va kalibrlashni o'lchash.

Keyingi darsda tokenlar, kontekst va xarajat: LLM matnni qanday tokenlarga bo'lishi, o'zbekcha matn nega inglizchadan ko'proq token olishi, kontekst oynasiga nimani sig'dirish va har bir so'rov qancha turishini hisoblaymiz.

Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
25.1-dars: LLM nima — IlmHamroh