Mundarija (22)
- 1. Kirish va motivatsiya
- 2. Nazariya — chuqur tushuntirish
- 2.1. Pretraining → fine-tuning paradigmasi
- 2.2. MLM maqsadi: maskalash va bog'langan vaznlar
- 2.3. Pretraining nimani o'rgatadi
- 2.4. O'rganish egri chizig'i va halol taqqoslash
- 2.5. Fine-tuning usullari
- 2.6. Katastrofik unutish
- 2.7. Hugging Face ekotizimi — kontseptual xarita
- 2.8. Tuzoqlar
- 3. Tez ma'lumotnoma
- 4. Batafsil misollar
- Misol 1 — MLM pretraining: korpus, maskalash va o'rganilgan bilim
- Misol 2 — O'rganish egri chizig'i: noldan va pretrained
- Misol 3 — Fine-tuning usullari: to'liq, faqat bosh, muzlatish
- Misol 4 — Katastrofik unutish va pretrained modelni saqlash
- 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.10-dars: Pretraining va fine-tuning
24-QISM — TRANSFORMERLAR · 10-dars
1. Kirish va motivatsiya
Oldingi darslarda transformerni qismlarga ajratib qurdik: attention, ko'p boshli attention, pozitsion kodlash, blok, encoder, decoder. 24.8-darsda BERT uslubidagi maskali til modelini (MLM), 24.9-darsda GPT uslubidagi generatsiyani ko'rdik. Lekin bitta muhim savol ochiq qoldi: nega butun dunyo katta modellarni avval belgisiz matnda o'rgatib, keyin kichik belgili to'plamga moslaydi?
Javob — belgili ma'lumot qimmat, belgisiz matn esa arzon. Sharhlarga "ijobiy/salbiy" yorlig'ini odam qo'yadi, internetda esa yorliqsiz sharhlar millionlab. Pretraining (oldindan o'rgatish) — modelni belgisiz matnda o'z-o'zini nazorat qiluvchi vazifa bilan (masalan, yashirilgan so'zni tiklash) o'rgatish. Fine-tuning (moslash) — shu modelni kichik belgili to'plamda kerakli vazifaga qo'shimcha o'rgatish. Birinchi bosqich tilni o'rgatadi, ikkinchisi — vazifani.
Bu darsda butun zanjirni noldan quramiz: sintetik o'zbekcha sharhlar korpusida kichik transformer encoder ni MLM bilan o'rgatamiz, keyin uni 50, 200 va 1000 ta belgili misolda tonallik klassifikatsiyasiga moslaymiz va noldan o'rgatilgan xuddi shunday model bilan juftlashgan urug'larda solishtiramiz. So'ng fine-tuning ning uch usulini (to'liq, faqat bosh, qatlamlarni muzlatish) o'lchaymiz va katastrofik unutishni — fine-tuning dan keyin modelning til bilimi qanchalik buzilishini — raqam bilan ko'ramiz. Oxirida bu g'oyalar Hugging Face ekotizimida qanday nomlanishini jadvalda bog'laymiz.
Real vaziyat. Kichik startap mahsulot sharhlarini tonallik bo'yicha ajratmoqchi. Qo'lda 200 ta sharh belgilandi, ustiga transformer noldan o'rgatildi — testda aniqlik 61%. Jamoa "transformer bizga to'g'ri kelmaydi, kam ma'lumot" degan xulosaga keldi. Ayni paytda ularning bazasida 20000 ta yorliqsiz sharh yotgan edi. Xuddi shu arxitekturani avval o'sha sharhlarda MLM bilan o'rgatib, keyin 200 ta belgili misolga moslaganda aniqlik 91% ga chiqdi — va belgili to'plamda umuman uchramagan so'zlar ("beg'ubor", "mo'rt") bor sharhlarda ham model to'g'ri ishladi. Bu darsning 2-misoli aynan shu vaziyatni takrorlaydi.
Bu darsda pretraining → fine-tuning paradigmasini noldan quramiz va uning foydasini halol o'lchaymiz.
Bu darsda:
- Pretraining → fine-tuning paradigmasi
- MLM: maskalash 80/10/10, bog'langan vaznlar
- Pretraining nimani o'rgatadi: embedding geometriyasi va bo'shliqni to'ldirish
- O'rganish egri chizig'i: noldan va pretrained, juftlashgan urug'lar
- Fine-tuning usullari: to'liq, faqat bosh (linear probe), muzlatish
- Katastrofik unutish
- Hugging Face ekotizimi — kontseptual xarita
- Tuzoqlar
ℹ Misollar real torch/numpy bilan (Python 3.14, torch 2.14 CPU).
2. Nazariya — chuqur tushuntirish
2.1. Pretraining → fine-tuning paradigmasi
1-BOSQICH - PRETRAINING (belgisiz matn, ko'p):
korpus: 20000 sharh, yorliq YO'Q
vazifa: o'z-o'zini nazorat (self-supervised) - yorliq matnning o'zidan
MLM (BERT): "telefon juda [MASK] ekan" -> "a'lo"
CLM (GPT): "telefon juda a'lo" -> keyingi so'z
natija: encoder vaznlari = tilning "umumiy bilimi"
2-BOSQICH - FINE-TUNING (belgili matn, kam):
50 / 200 / 1000 sharh + yorliq (ijobiy/salbiy)
encoder = pretrained vaznlar; ustiga YANGI bosh (Linear(d, 2), tasodifiy)
hammasi (yoki bir qismi) kichik lr bilan o'rgatiladi
NIMA UCHUN ISHLAYDI:
belgili 200 misol 48 ta sifatning faqat bir qismini ko'rsatadi
korpus esa "beg'ubor" va "a'lo" bir xil kontekstda kelishini ko'rsatgan
-> ularning vakillari yaqin -> bosh bittasida o'rgangan narsa ikkinchisiga o'tadi
TRANSFER O'RGANISH (22-qismda rasmlar bilan ko'rgan g'oya):
ImageNet da o'rgatilgan CNN -> 200 ta rasm bilan yangi sinflar
bu darsda: sharhlar korpusida MLM -> 200 ta sharh bilan tonallikPretraining tilni o'rgatadi, fine-tuning — vazifani; belgili ma'lumot kam bo'lganda birinchi bosqich hal qiluvchi.
2.2. MLM maqsadi: maskalash va bog'langan vaznlar
MASKALASH (BERT retsepti, maskala() funksiyasi):
har tokenni 15% ehtimol bilan TANLASH ([PAD], [CLS] tanlanmaydi)
tanlanganlarning:
80% -> [MASK] "telefon juda [MASK] ekan"
10% -> tasodifiy so'z "telefon juda kitob ekan"
10% -> o'zgarmaydi "telefon juda a'lo ekan"
nishon Y: tanlangan joyda asl token, qolgan joyda -100 (ignore_index)
NEGA 80/10/10:
faqat [MASK] bo'lsa - fine-tuning da [MASK] hech qachon uchramaydi,
model "[MASK] bo'lmagan joyda o'ylamasa ham bo'ladi" deb o'rganadi
tasodifiy/o'zgarmagan tokenlar: model HAR pozitsiyani tekshirishga majbur
LOSS: faqat tanlangan pozitsiyalarda cross-entropy
boshlang'ich qiymat ~ ln V (tekis taqsimot): V = 110 -> ln 110 = 4.700
BOG'LANGAN VAZNLAR (weight tying):
logit = h @ E^T + b (E - kirish embedding matritsasi, V x d)
alohida Linear(d, V) yo'q -> parametr kam, embedding ikki tomondan o'rganadi
MLMBosh da faqat bias (110 parametr) - 1-misol1-misolda maskalash statistikasi retseptga mos chiqdi: tanlangan tokenlar 0.155, ulardan [MASK] — 0.803, tasodifiy — 0.095, o'zgarmagan — 0.102. Nazorat to'plamidagi MLM loss boshida 4.696 edi — ln 110 = 4.700 ga deyarli teng, ya'ni tasodifiy model hamma so'zga teng ehtimol beradi. 2000 qadamdan keyin loss 1.668 ga tushdi.
Nega loss noldan ancha uzoqda qoldi? Chunki vazifa tabiatan noaniq: "telefon juda [MASK] ekan" da 24 ta ijobiy sifatdan istalgani to'g'ri. Eng yaxshi model ham ularga taxminan teng ehtimol berishi kerak — 1-misoldagi top-3 ehtimollar 0.08, 0.08, 0.06 aynan shunday.
MLM — yorliqsiz matndan o'rganish uchun eng oddiy "savol": 15% token yashiriladi va model ularni kontekstdan tiklaydi.
2.3. Pretraining nimani o'rgatadi
1. SO'Z VAKILLARI (embeddinglar):
bir xil kontekstda keladigan so'zlar yaqinlashadi (23.6-darsdagi word2vec g'oyasi)
1-misol, kosinus o'xshashlik o'rtachasi:
ijobiy-ijobiy ijobiy-salbiy
tasodifiy init -0.016 +0.006
pretraining dan keyin +0.815 +0.563
'a'lo' ga eng yaqin: shinam, qulay, toza, mazali (hammasi ijobiy)
'iflos' ga eng yaqin: xira, shovqinli, qo'pol, mo'rt (hammasi salbiy)
2. KONTEKST MANTIG'I (attention qatlamlari):
"kafe juda [MASK] edi boshqa kelmayman" P(ijobiy) 0.40 P(salbiy) 0.59
"kafe juda [MASK] emas edi boshqa kelmayman" P(ijobiy) 0.61 P(salbiy) 0.37
'emas' qo'shilganda taqsimot teskari tomonga siljidi:
model inkor + salbiy dum -> ijobiy sifat ekanini korpusdan o'rgangan
3. NIMANI O'RGANA OLMAYDI:
korpusda YO'Q bog'lanishni
"kecha [MASK] juda mazali edi" -> klinika, sartaroshxona, kafe (har biri 0.08)
sintetik korpusda mavzu va sifat mustaqil tanlangan - "mazali" ovqatga
bog'liqligini model bilmaydi. Real korpusda bu bog'lanish bor bo'lardi.Ikki qatlamli kichik encoder 2000 qadamda nafaqat "qaysi so'zlar sinonim", balki "inkor tonallikni teskari qiladi" degan qoidani ham o'rgandi — bu yorliqlarsiz, faqat so'zlarning birga kelishidan. Lekin model korpusdagi statistikadan tashqariga chiqa olmaydi: pretraining sifati korpus sifatidan yuqori bo'lmaydi.
Pretraining — korpus statistikasining siqilgan nusxasi; u sinonimlarni va sintaktik qoidalarni o'rganadi, lekin korpusda yo'q narsani emas.
2.4. O'rganish egri chizig'i va halol taqqoslash
TAJRIBA DIZAYNI (2-misol):
belgili hovuz: 3000 sharh, faqat 32/48 sifat bilan (16 ijobiy + 16 salbiy)
test: 2000 sharh, 48 sifatning hammasi -> 33.0% jumlada ko'rilmagan sifat
n = 50, 200, 1000; 3 urug' (s = 0, 1, 2)
BIR XIL: urug' -> bir xil belgili misollar, bir xil bosh init, bir xil batchlar
qadamlar 100, lr 1e-3, batch 16 - ikkala model uchun
JUFTLASHGAN FARQ: d_s = aniq_pretrained,s - aniq_noldan,s
SE = std(d) / sqrt(3); |mean(d)| > 2*SE -> sezilarli
NATIJA (test aniqligi):
n noldan pretrained farq SE
50 0.536 0.810 +0.274 0.018
200 0.611 0.915 +0.303 0.031
1000 0.757 0.997 +0.240 0.023
KO'RILGAN va KO'RILMAGAN sifatlar bo'yicha foyda:
ko'rilgan: n=50 +0.252, n=200 +0.247, n=1000 +0.086 -> kamayadi
ko'rilmagan: n=50 +0.319, n=200 +0.418, n=1000 +0.554 -> kamaymaydi
noldan model ko'rilmagan sifatlarda n=1000 da ham 0.438 (tasodifdan past!)Bu jadvalda ikki xil hodisa bor va ularni ajratish muhim. Ko'rilgan sifatlarda pretraining ning foydasi belgili ma'lumot ko'paygan sari kamayadi: n=50 da +0.252, n=1000 da +0.086. Bu klassik o'rganish egri chizig'i — yetarli yorliq bo'lsa, noldan model ham vazifani o'rganadi (n=1000 da ko'rilgan sifatlarda 0.914).
Ko'rilmagan sifatlarda esa foyda aksincha o'sadi: +0.319 → +0.554. Noldan model bu so'zlarni hech qachon ko'rmagan — ularning embeddinglari tasodifiy qolgan. Belgili misollar ko'paygani bu so'zlar haqida hech narsa o'rgatmaydi. Hatto 0.438 — tasodifdan past: model "emas" so'zini ko'rsa javobni teskari qilishni o'rgangan, tasodifiy sifat bilan esa bu qoida noto'g'ri tomonga ishlaydi. Pretrained model esa bu sifatlarni korpusdan "taniydi" — n=1000 da ko'rilmagan sifatlarda 0.992.
Juftlashtirishning ahamiyati: n=50 da urug'lar orasidagi aniqlik tebranishi katta (qaysi 50 ta misol tushgani muhim), lekin bir urug' ichida ikkala model bir xil 50 ta misolni ko'radi — shuning uchun farqning SE si atigi 0.018.
Pretraining foydasi belgili ma'lumot kam bo'lganda va test yangi so'zlarni o'z ichiga olganda eng katta; taqqoslash bir xil misollar, bir xil qadamlar va juftlashgan farq bilan qilinadi.
2.5. Fine-tuning usullari
o'rgatiladi lr 3-misol (n=200)
noldan hammasi (tasodifiy) 1e-3 0.611
faqat bosh (probe) Linear(48, 2) = 98 1e-2 0.761 (0.2%)
yuqori blok + bosh 2-blok + ln + bosh 1e-3 0.822 (45.3%)
to'liq FT hammasi (pretrained) 1e-3 0.915 (100%)
FAQAT BOSH (linear probe):
encoder muzlatilgan (requires_grad=False), faqat bosh o'rganadi
vakillar "qanchalik tayyor" ekanini o'lchaydi; eng arzon, unutish yo'q
bosh kichik - lr kattaroq (1e-2)
MUZLATISH (pastki qatlamlar):
pastki qatlamlar - umumiy xususiyatlar (so'z ma'nosi)
yuqori qatlamlar - vazifaga yaqin xususiyatlar
muzlatilgan qism: embedding, pozitsiya, 1-blok
TO'LIQ FINE-TUNING:
hamma vaznlar, KICHIK lr (pretraining dagidan kichik yoki teng)
eng kuchli, lekin eng ko'p unutadi (2.6)3-misolda to'liq fine-tuning qolgan uch usulning har biridan sezilarli yaxshi chiqdi: faqat bosh bilan farq +0.154 (2*SE = 0.038), muzlatilgan pastki blok bilan +0.093 (2*SE = 0.029). Bu natija shu model va shu vazifaga tegishli: 2 qatlamli kichik encoder da har bir blok muhim, va MLM vakillari tonallikni to'g'ridan-to'g'ri chiziqli ajratish uchun "tayyor" emas — ular so'zni tiklash uchun o'rgatilgan. Katta modellarda (12-24 qatlam) pastki qatlamlarni muzlatish ko'pincha deyarli hech narsa yo'qotmaydi va xotirani tejaydi.
E'tibor bering: faqat bosh ham noldan o'rgatilgan to'liq modeldan yaxshi (0.761 va 0.611) — atigi 98 parametr bilan. Pretrained vakillar shunchalik foydali.
Usulni tanlash — sifat, xotira va unutish orasidagi murosa; uni o'lchab tanlang, taxmin bilan emas.
2.6. Katastrofik unutish
HODISA: fine-tuning encoder vaznlarini vazifa uchun o'zgartiradi
-> pretraining da o'rganilgan boshqa bilim (MLM) buziladi
O'LCHASH: fine-tuning dan keyingi encoder + ASL MLM boshi -> nazorat MLM loss
4-MISOL (n=1000, pretraining dan keyin MLM loss 1.665):
usul test aniqlik MLM loss o'sish
faqat bosh, lr 1e-2 0.743 1.665 +0.000
to'liq, lr 3e-4 0.808 1.759 +0.094
to'liq, lr 1e-3 0.999 2.367 +0.702
to'liq, lr 3e-3, 300 qadam 1.000 3.669 +2.004
NIMA QILISH MUMKIN:
kichik lr, kam qadam - kam unutadi, lekin vazifani ham kam o'rganadi
muzlatish / faqat bosh - unutish yo'q, sifat past 2.5-bob
LoRA kabi adapterlar - asl vaznlar o'zgarmaydi (keyingi dars)
aralash o'rgatish - fine-tuning loss + kichik vazn bilan MLM lossEng qiziq qator — oxirgi ikkitasi. lr 1e-3 va lr 3e-3 da test aniqligi deyarli bir xil (0.999 va 1.000), lekin MLM loss 2.367 va 3.669. Ya'ni vazifa nuqtai nazaridan farq yo'q, ammo ikkinchi model til bilimining ko'p qismini "unutgan" — MLM loss boshlang'ich 4.696 ga yaqinlashib bormoqda. Agar bu modeldan keyinroq boshqa vazifa uchun foydalanmoqchi bo'lsangiz — u endi yaxshi boshlang'ich nuqta emas.
Shuning uchun amaliy qoida: pretrained vaznlarni alohida saqlang va har vazifa uchun ulardan yangi nusxa oling (copy.deepcopy yoki qayta yuklash). Bitta modelni ketma-ket bir necha vazifaga moslash — unutishga yo'l.
Fine-tuning "tekin" emas: u til bilimini buzadi, va buzilish lr va qadamlar soni bilan o'sadi — vazifa aniqligi esa buni ko'rsatmaydi.
2.7. Hugging Face ekotizimi — kontseptual xarita
Amalda hech kim BERT ni noldan o'rgatmaydi — tayyor pretrained modellar Hugging Face Hub da. transformers kutubxonasi ular bilan ishlashni standartlashtirgan. Kutubxona bu kursning muhitida o'rnatilmagan, shuning uchun uning kodini faqat sxema sifatida ko'rsatamiz:
# Hugging Face bilan odatiy fine-tuning (KONTSEPTUAL, bu kursda ishga tushirilmaydi)
from transformers import AutoTokenizer, AutoModelForSequenceClassification
from transformers import Trainer, TrainingArguments
nom = "tashkilot/uzbek-bert-base" # Hub dagi model nomi
tok = AutoTokenizer.from_pretrained(nom) # lug'at + tokenizatsiya qoidalari
model = AutoModelForSequenceClassification.from_pretrained(nom, num_labels=2)
# encoder vaznlari yuklanadi, klassifikatsiya boshi TASODIFIY yaratiladi
kirish = tok(["telefon juda a'lo ekan"], padding=True, truncation=True,
return_tensors="pt") # input_ids, attention_mask
args = TrainingArguments(output_dir="natija", learning_rate=2e-5,
num_train_epochs=3, per_device_train_batch_size=16)
Trainer(model=model, args=args, train_dataset=oquv, eval_dataset=val).train()
model.save_pretrained("mening_modelim") # config.json + model.safetensors
tok.save_pretrained("mening_modelim") # tokenizer fayllariBu darsdagi noldan yozilgan kodimiz aynan shu qismlarga mos keladi:
| Bizning kod (bu dars) | Hugging Face | Vazifasi |
|---|---|---|
Lugat, Lugat.kodla |
AutoTokenizer, tok(...) |
Matn → input_ids; [PAD], [CLS], [MASK], [UNK] |
X != PAD |
attention_mask |
Qaysi pozitsiya haqiqiy token |
Encoder |
AutoModel (masalan BertModel) |
Embedding + bloklar → yashirin holatlar |
Encoder + MLMBosh |
AutoModelForMaskedLM |
Pretraining modeli (bog'langan vaznlar bilan) |
Klassifikator |
AutoModelForSequenceClassification |
Encoder + yangi tasodifiy bosh |
maskala |
DataCollatorForLanguageModeling |
15% va 80/10/10 maskalash |
pretrain, fine_tune |
Trainer + TrainingArguments |
O'rgatish sikli, optimizator, lr |
requires_grad_(False) |
xuddi shu (yoki peft kutubxonasi) |
Muzlatish, adapterlar |
paket["konfig"] |
config.json |
Arxitektura giperparametrlari |
paket["lugat"] |
vocab.txt / tokenizer.json |
Tokenizator holati |
paket["encoder"] |
model.safetensors |
Vaznlar |
paket["karta"] |
README.md (model kartasi) |
Ma'lumot, maqsad, cheklovlar, metrikalar |
torch.load(..., weights_only=True) |
safetensors formati |
Xavfsiz yuklash (kod bajarilmaydi) |
Model kartasi (model card) — Hub dagi har modelning README fayli: qaysi korpusda, qaysi vazifa bilan, qancha o'rgatilgani, qaysi tillarda ishlashi, ma'lum cheklovlar va noxolisliklar, litsenziya. Pretrained model tanlashda birinchi o'qiladigan hujjat — masalan, faqat ingliz matnida o'rgatilgan model o'zbek apostrofi va qo'shimchalarini yaxshi ko'rmaydi. 4-misoldagi paket["karta"] — shu g'oyaning eng kichik ko'rinishi.
Ikki muhim farq: birinchidan, HF modellarining tokenizatori subword (WordPiece, BPE — 23.3-dars), bizniki so'z darajasida; ikkinchidan, HF da from_pretrained bilan yuklangan modelning lug'ati va tokenizatori model bilan birga keladi — ularni almashtirib bo'lmaydi. Bizda ham Lugat korpusdan bir marta quriladi va paketga yoziladi.
Hugging Face — shu darsdagi zanjirning standartlashtirilgan versiyasi: tokenizator, encoder, bosh, Trainer va model kartasi; noldan yozgan kodingiz uni tushunish kaliti.
2.8. Tuzoqlar
Asosiy tuzoqlar: pretrained va noldan modelni turli qadamlar, turli lr yoki turli belgili misollarda solishtirish (taqqoslash juftlashgan bo'lishi kerak); bitta urug' bilan "pretraining yordam bermadi" deyish; fine-tuning da pretraining dagidan katta lr ishlatish (unutish tezlashadi); faqat bosh o'rgatilganda ham encoder parametrlarini optimizatorga berib requires_grad ni unutish; pretrained modelni bir vazifaga moslab, keyin uni boshqa vazifa uchun "pretrained" deb ishlatish (u allaqachon unutgan); lug'atni fine-tuning ma'lumotidan qayta qurish (so'z indekslari pretrained embeddinglarga mos kelmay qoladi); MLM loss ni hamma pozitsiyada hisoblash (-100 ni unutish); [PAD] va [CLS] ni maskalash; pooling da [PAD] pozitsiyalarini o'rtachaga qo'shish; test to'plami faqat ko'rilgan so'zlardan iborat bo'lsa, pretraining foydasini kam baholash; model kartasini o'qimasdan boshqa tilda o'rgatilgan modelni olish.
3. Tez ma'lumotnoma
import torch
import torch.nn.functional as F
# MLM maskalash: 15% tanlash, 80% [MASK], 10% tasodifiy, 10% o'zi
Xm, Y = maskala(X, g, V) # Y: tanlanmaganlar -100
logit = enc(Xm) @ enc.emb.weight.T + bias # bog'langan vaznlar
loss = F.cross_entropy(logit.reshape(-1, V), Y.reshape(-1)) # ignore_index=-100
# fine-tuning: pretrained encoder + yangi bosh
enc = Encoder(V); enc.load_state_dict(pretrained_holat)
model = Klassifikator(enc) # bosh - tasodifiy
for p in model.enc.parameters(): # faqat bosh (linear probe)
p.requires_grad_(False)
opt = torch.optim.AdamW([p for p in model.parameters() if p.requires_grad], lr=1e-2)
# halol taqqoslash: bir urug' - bir xil misollar, bir xil init, bir xil batchlar
d = aniq_pretrained - aniq_noldan # urug'lar bo'yicha massiv
sezilarli = abs(d.mean()) > 2 * d.std(ddof=1) / len(d) ** 0.5
# unutishni o'lchash: fine-tuned encoder + ASL MLM boshi
L_keyin = mlm_loss(model.enc, mlm_bosh, Xn, Yn) # qat'iy maskalar bilan
# saqlash (from_pretrained g'oyasi)
torch.save({"konfig": {...}, "lugat": itos, "encoder": enc.state_dict()}, yol)
p = torch.load(yol, weights_only=True)Pretraining va fine-tuning xulosasi
pretraining: belgisiz korpus + MLM (15%, 80/10/10) -> til bilimi
fine-tuning: pretrained encoder + yangi bosh + kichik lr -> vazifa
foyda: kam yorliq va yangi so'zlarda eng katta; juftlashgan urug'lar bilan o'lchang
usullar: faqat bosh < muzlatish < to'liq (sifat), teskari tartibda (unutish)
katastrofik unutish: lr va qadamlar bilan o'sadi; pretrained vaznlarni saqlang
HF: AutoTokenizer + AutoModel... + Trainer + Hub + model kartasi4. Batafsil misollar
Misollar real torch/numpy bilan (Python 3.14, torch 2.14 CPU).
Misol 1 — MLM pretraining: korpus, maskalash va o'rganilgan bilim
"""MLM pretraining: belgisiz sharhlar korpusida maskalangan so'zlarni tiklash."""
import numpy as np
import torch
import torch.nn as nn
import torch.nn.functional as F
MAVZU = ["telefon", "noutbuk", "kitob", "kafe", "mehmonxona", "avtobus", "dastur",
"kurs", "film", "do'kon", "restoran", "poyabzal", "kamera", "sumka", "taksi",
"klinika", "sartaroshxona", "televizor"]
IJOBIY = ["a'lo", "ajoyib", "zo'r", "yaxshi", "qulay", "chiroyli", "tez", "sifatli",
"mazali", "toza", "arzon", "ishonchli", "shinam", "samimiy", "foydali",
"qiziqarli", "mukammal", "puxta", "yoqimli", "maroqli", "chidamli", "oson",
"zamonaviy", "beg'ubor"]
SALBIY = ["yomon", "sekin", "qimmat", "iflos", "noqulay", "xunuk", "sifatsiz", "bemaza",
"eski", "zerikarli", "ishonchsiz", "qo'pol", "buzuq", "chalkash", "nosoz", "xira",
"tor", "shovqinli", "befoyda", "sovuq", "mo'rt", "murakkab", "dag'al", "g'alati"]
DARAJA = ["juda", "ancha", "biroz", "rosa", "", ""]
OXIR = ["ekan", "edi", "", "chiqdi"]
BOSH = ["kecha", "o'tgan hafta", "shahardagi", "yangi", "onlayn", "", "", ""]
DUM = {1: ["hammaga tavsiya qilaman", "yana kelaman", "juda mamnunman", "pulimga arzidi",
"do'stlarimga aytaman", "rahmat sizlarga"],
0: ["hech kimga tavsiya qilmayman", "pulimni qaytarib oldim", "boshqa kelmayman",
"vaqtim behuda ketdi", "shikoyat yozdim", "afsuslandim"]}
PAD, CLS, MASK, UNK = 0, 1, 2, 3
def tanla(rng, royxat):
return royxat[int(rng.integers(len(royxat)))]
def gap(rng, dum_ehtimol, sifatlar=(IJOBIY, SALBIY)):
"""Sharh: (matn, tonallik, sifat). 25% holatda 'emas' tonallikni teskari qiladi."""
q = int(rng.integers(2))
sif = tanla(rng, sifatlar[0] if q else sifatlar[1])
inkor = rng.random() < 0.25
y = 1 - q if inkor else q
s = [tanla(rng, BOSH), tanla(rng, MAVZU), tanla(rng, DARAJA), sif,
"emas" if inkor else "", tanla(rng, OXIR)]
if rng.random() < dum_ehtimol:
s.append(tanla(rng, DUM[y]))
return " ".join(" ".join(s).split()), y, sif
class Lugat:
"""So'z darajasidagi tokenizator: korpusdan quriladi, 4 ta maxsus token."""
def __init__(self, matnlar):
sozlar = sorted({w for m in matnlar for w in m.split()})
self.itos = ["[PAD]", "[CLS]", "[MASK]", "[UNK]"] + sozlar
self.stoi = {w: i for i, w in enumerate(self.itos)}
def kodla(self, matnlar, T=16):
X = torch.zeros(len(matnlar), T, dtype=torch.long)
for i, m in enumerate(matnlar):
ids = [CLS] + [self.stoi.get(w, UNK) for w in m.split()][:T - 1]
X[i, :len(ids)] = torch.tensor(ids)
return X
class Blok(nn.Module):
"""Pre-LN transformer bloki: self-attention + FFN, qoldiq ulanishlar."""
def __init__(self, d, h):
super().__init__()
self.h = h
self.ln1, self.ln2 = nn.LayerNorm(d), nn.LayerNorm(d)
self.qkv, self.proj = nn.Linear(d, 3 * d), nn.Linear(d, d)
self.ffn = nn.Sequential(nn.Linear(d, 4 * d), nn.GELU(), nn.Linear(4 * d, d))
def forward(self, x, maska):
B, T, d = x.shape
q, k, v = self.qkv(self.ln1(x)).view(B, T, 3, self.h, d // self.h).permute(2, 0, 3, 1, 4)
a = F.scaled_dot_product_attention(q, k, v, attn_mask=maska[:, None, None, :])
x = x + self.proj(a.transpose(1, 2).reshape(B, T, d))
return x + self.ffn(self.ln2(x))
class Encoder(nn.Module):
def __init__(self, V, d=48, L=2, h=4, T=16):
super().__init__()
self.emb, self.poz = nn.Embedding(V, d), nn.Embedding(T, d)
self.bloklar = nn.ModuleList([Blok(d, h) for _ in range(L)])
self.ln = nn.LayerNorm(d)
nn.init.normal_(self.emb.weight, std=0.02)
nn.init.normal_(self.poz.weight, std=0.02)
def forward(self, X):
maska = X != PAD
x = self.emb(X) + self.poz(torch.arange(X.shape[1]))
for b in self.bloklar:
x = b(x, maska)
return self.ln(x)
class MLMBosh(nn.Module):
"""MLM boshi: vazni embedding bilan bog'langan (weight tying), faqat bias o'rganiladi."""
def __init__(self, V):
super().__init__()
self.bias = nn.Parameter(torch.zeros(V))
def forward(self, enc, X):
return enc(X) @ enc.emb.weight.T + self.bias
def kes(X):
"""Batchdagi eng uzun jumlagacha qirqish (ortiqcha PAD ustunlari kerak emas)."""
return X[:, :int((X != PAD).sum(1).max())]
def maskala(X, g, V, p=0.15):
"""BERT uslubi: 15% token tanlanadi; ulardan 80% [MASK], 10% tasodifiy, 10% o'zi."""
Y = X.clone()
tanl = (torch.rand(X.shape, generator=g) < p) & (X > UNK)
Y[~tanl] = -100
r = torch.rand(X.shape, generator=g)
X = X.clone()
X[tanl & (r < 0.8)] = MASK
tas = tanl & (r >= 0.8) & (r < 0.9)
X[tas] = torch.randint(4, V, (int(tas.sum()),), generator=g)
return X, Y
def mlm_loss(enc, bosh, X, Y):
V = enc.emb.num_embeddings
return F.cross_entropy(bosh(enc, X).reshape(-1, V), Y.reshape(-1))
def pretrain(V, X, qadam, seed=0, bs=32, lr=2e-3, kuzat=None):
"""MLM pretraining: belgisiz korpusda maskalangan so'zlarni tiklash."""
torch.manual_seed(seed)
enc, bosh = Encoder(V), MLMBosh(V)
opt = torch.optim.AdamW(list(enc.parameters()) + list(bosh.parameters()),
lr=lr, weight_decay=0.01)
g = torch.Generator().manual_seed(seed)
for q in range(1, qadam + 1):
xb, yb = maskala(kes(X[torch.randint(0, len(X), (bs,), generator=g)]), g, V)
loss = mlm_loss(enc, bosh, xb, yb)
opt.zero_grad()
loss.backward()
opt.step()
if kuzat is not None:
kuzat(q, loss.item())
enc.eval()
return enc, bosh
class Klassifikator(nn.Module):
"""Encoder + o'rtacha pooling (PAD siz) + chiziqli bosh."""
def __init__(self, enc, sinflar=2):
super().__init__()
self.enc = enc
self.bosh = nn.Linear(enc.emb.embedding_dim, sinflar)
def forward(self, X):
h = self.enc(X)
m = (X != PAD).float()[..., None]
return self.bosh((h * m).sum(1) / m.sum(1))
def fine_tune(model, X, y, seed, qadam=100, lr=1e-3, bs=16):
"""Faqat requires_grad=True parametrlar yangilanadi."""
opt = torch.optim.AdamW([p for p in model.parameters() if p.requires_grad],
lr=lr, weight_decay=0.01)
g = torch.Generator().manual_seed(seed)
model.train()
for _ in range(qadam):
idx = torch.randint(0, len(X), (min(bs, len(X)),), generator=g)
loss = F.cross_entropy(model(kes(X[idx])), y[idx])
opt.zero_grad()
loss.backward()
opt.step()
model.eval()
return model
@torch.no_grad()
def bashorat(model, X):
return model(kes(X)).argmax(1)
def main() -> None:
torch.set_num_threads(1)
rng = np.random.default_rng(0)
korpus = [gap(rng, 0.7)[0] for _ in range(20000)]
lug = Lugat(korpus)
V = len(lug.itos)
X = lug.kodla(korpus)
X_oquv, X_nazorat = X[:19000], X[19000:]
print("=== 1. Belgisiz korpus (pretraining uchun) ===")
for m in korpus[:3]:
print(f" {m}")
uz = (X != PAD).sum(1).float()
print(f" jumlalar {len(korpus)}, lug'at {V} (4 maxsus + {V - 4} so'z), "
f"o'rtacha uzunlik {uz.mean():.2f} token ([CLS] bilan)")
print(" yorliq YO'Q: model faqat matnning o'zidan o'rganadi")
print("\n=== 2. Maskalash (80/10/10) ===")
g = torch.Generator().manual_seed(1)
Xm, Ym = maskala(X_nazorat, g, V)
tanl = Ym != -100
haqiqiy = (X_nazorat > UNK).sum().item()
print(f" tanlangan tokenlar: {tanl.sum().item()} / {haqiqiy} = "
f"{tanl.sum().item() / haqiqiy:.3f}")
print(f" [MASK] ga almashdi: {(Xm[tanl] == MASK).float().mean():.3f}")
print(f" tasodifiy so'z: {((Xm[tanl] != MASK) & (Xm[tanl] != Ym[tanl])).float().mean():.3f}")
print(f" o'zgarmadi: {(Xm[tanl] == Ym[tanl]).float().mean():.3f}")
kir = " ".join(lug.itos[i] for i in Xm[0].tolist() if i != PAD)
print(f" misol kirish: {kir}")
print("\n=== 3. MLM pretraining (2000 qadam, batch 32) ===")
jurnal = []
def kuzat(q, loss):
jurnal.append(loss)
if q in (1, 500, 1000, 1500, 2000):
print(f" qadam {q:>4}: o'quv loss (oxirgi 50 o'rtacha) {np.mean(jurnal[-50:]):.3f}")
torch.manual_seed(0)
enc0, bosh0 = Encoder(V), MLMBosh(V)
with torch.no_grad():
boshl = mlm_loss(enc0, bosh0, Xm, Ym).item()
enc, bosh = pretrain(V, X_oquv, 2000, kuzat=kuzat)
with torch.no_grad():
oxir = mlm_loss(enc, bosh, Xm, Ym).item()
print(f" nazorat MLM loss: boshida {boshl:.3f} (ln V = {np.log(V):.3f}) -> {oxir:.3f}")
print(f" parametrlar: encoder {sum(p.numel() for p in enc.parameters())}, "
f"MLM boshi {sum(p.numel() for p in bosh.parameters())} (faqat bias)")
print("\n=== 4. Model bo'shliqni to'ldiradi (top-3) ===")
ij = torch.tensor([lug.stoi[w] for w in IJOBIY])
sa = torch.tensor([lug.stoi[w] for w in SALBIY])
jumlalar = ["telefon juda [MASK] ekan hammaga tavsiya qilaman",
"kafe juda [MASK] edi boshqa kelmayman",
"kafe juda [MASK] emas edi boshqa kelmayman",
"kecha [MASK] juda mazali edi"]
for j in jumlalar:
Xj = lug.kodla([j])[:, :len(j.split()) + 1]
with torch.no_grad():
p = torch.softmax(bosh(enc, Xj)[0, (Xj[0] == MASK).nonzero()[0, 0]], 0)
top = p.topk(3)
pij = p[ij].sum().item()
psa = p[sa].sum().item()
print(f" {j}")
print(" -> " + ", ".join(f"{lug.itos[i]} {v:.2f}"
for v, i in zip(top.values.tolist(), top.indices.tolist()))
+ f" | P(ijobiy sifat) {pij:.2f}, P(salbiy sifat) {psa:.2f}")
print("\n=== 5. Sifatlar embeddinglari: o'xshashlik (kosinus) ===")
for nom, E in [("tasodifiy init", enc0.emb.weight), ("pretraining dan keyin", enc.emb.weight)]:
E = F.normalize(E.detach(), dim=1)
ichki = ((E[ij] @ E[ij].T).sum() - len(ij)) / (len(ij) * (len(ij) - 1))
orasi = (E[ij] @ E[sa].T).mean()
print(f" {nom:<22} ijobiy-ijobiy {ichki:+.3f} ijobiy-salbiy {orasi:+.3f}")
E = F.normalize(enc.emb.weight.detach(), dim=1)
for w in ["a'lo", "iflos"]:
o = E @ E[lug.stoi[w]]
o[lug.stoi[w]] = -1
print(f" '{w}' ga eng yaqin: " + ", ".join(lug.itos[i] for i in o.topk(4).indices.tolist()))
print(" hech kim 'a'lo' va 'zo'r' sinonim deb aytmadi - model buni kontekstdan topdi")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. Belgisiz korpus (pretraining uchun) ===
shahardagi telefon juda qiziqarli ekan
sumka rosa oson
yangi klinika rosa sovuq emas ekan
jumlalar 20000, lug'at 110 (4 maxsus + 106 so'z), o'rtacha uzunlik 7.06 token ([CLS] bilan)
yorliq YO'Q: model faqat matnning o'zidan o'rganadi
=== 2. Maskalash (80/10/10) ===
tanlangan tokenlar: 943 / 6091 = 0.155
[MASK] ga almashdi: 0.803
tasodifiy so'z: 0.095
o'zgarmadi: 0.102
misol kirish: [CLS] yangi dastur ancha [MASK] ekan pulimga arzidi
=== 3. MLM pretraining (2000 qadam, batch 32) ===
qadam 1: o'quv loss (oxirgi 50 o'rtacha) 4.654
qadam 500: o'quv loss (oxirgi 50 o'rtacha) 1.895
qadam 1000: o'quv loss (oxirgi 50 o'rtacha) 1.786
qadam 1500: o'quv loss (oxirgi 50 o'rtacha) 1.742
qadam 2000: o'quv loss (oxirgi 50 o'rtacha) 1.702
nazorat MLM loss: boshida 4.696 (ln V = 4.700) -> 1.668
parametrlar: encoder 62688, MLM boshi 110 (faqat bias)
=== 4. Model bo'shliqni to'ldiradi (top-3) ===
telefon juda [MASK] ekan hammaga tavsiya qilaman
-> oson 0.08, yoqimli 0.08, toza 0.06 | P(ijobiy sifat) 0.88, P(salbiy sifat) 0.11
kafe juda [MASK] edi boshqa kelmayman
-> oson 0.04, tor 0.04, sekin 0.04 | P(ijobiy sifat) 0.40, P(salbiy sifat) 0.59
kafe juda [MASK] emas edi boshqa kelmayman
-> oson 0.06, sifatli 0.06, arzon 0.05 | P(ijobiy sifat) 0.61, P(salbiy sifat) 0.37
kecha [MASK] juda mazali edi
-> klinika 0.08, sartaroshxona 0.08, kafe 0.08 | P(ijobiy sifat) 0.00, P(salbiy sifat) 0.00
=== 5. Sifatlar embeddinglari: o'xshashlik (kosinus) ===
tasodifiy init ijobiy-ijobiy -0.016 ijobiy-salbiy +0.006
pretraining dan keyin ijobiy-ijobiy +0.815 ijobiy-salbiy +0.563
'a'lo' ga eng yaqin: shinam, qulay, toza, mazali
'iflos' ga eng yaqin: xira, shovqinli, qo'pol, mo'rt
hech kim 'a'lo' va 'zo'r' sinonim deb aytmadi - model buni kontekstdan topdiNima ko'rsatdi: 2.2, 2.3-bo'limlar. Korpusda yorliq yo'q, lekin 2000 qadamdan keyin nazorat MLM loss ln V darajasidagi 4.696 dan 1.668 ga tushdi. Model ijobiy dumli jumlaga 0.88 ehtimol bilan ijobiy sifat taklif qildi, "emas" qo'shilganda esa taqsimotni teskari tomonga siljitdi (0.40 → 0.61). Embeddinglarda bir xil tonallikdagi sifatlar bir-biriga yaqinlashdi (+0.815), qarama-qarshilari esa kamroq (+0.563); 'a'lo' va 'iflos' ning eng yaqin qo'shnilari hammasi o'z tonalligidan. Mavzu so'zini tiklashda esa model ikkilandi (0.08 atrofida) — korpusda mavzu va sifat mustaqil, o'rganadigan bog'lanish yo'q.
Misol 2 — O'rganish egri chizig'i: noldan va pretrained
"""O'rganish egri chizig'i: noldan o'rgatish va pretraining + fine-tuning, juftlashgan urug'lar."""
import numpy as np
import torch
import torch.nn as nn
import torch.nn.functional as F
MAVZU = ["telefon", "noutbuk", "kitob", "kafe", "mehmonxona", "avtobus", "dastur",
"kurs", "film", "do'kon", "restoran", "poyabzal", "kamera", "sumka", "taksi",
"klinika", "sartaroshxona", "televizor"]
IJOBIY = ["a'lo", "ajoyib", "zo'r", "yaxshi", "qulay", "chiroyli", "tez", "sifatli",
"mazali", "toza", "arzon", "ishonchli", "shinam", "samimiy", "foydali",
"qiziqarli", "mukammal", "puxta", "yoqimli", "maroqli", "chidamli", "oson",
"zamonaviy", "beg'ubor"]
SALBIY = ["yomon", "sekin", "qimmat", "iflos", "noqulay", "xunuk", "sifatsiz", "bemaza",
"eski", "zerikarli", "ishonchsiz", "qo'pol", "buzuq", "chalkash", "nosoz", "xira",
"tor", "shovqinli", "befoyda", "sovuq", "mo'rt", "murakkab", "dag'al", "g'alati"]
DARAJA = ["juda", "ancha", "biroz", "rosa", "", ""]
OXIR = ["ekan", "edi", "", "chiqdi"]
BOSH = ["kecha", "o'tgan hafta", "shahardagi", "yangi", "onlayn", "", "", ""]
DUM = {1: ["hammaga tavsiya qilaman", "yana kelaman", "juda mamnunman", "pulimga arzidi",
"do'stlarimga aytaman", "rahmat sizlarga"],
0: ["hech kimga tavsiya qilmayman", "pulimni qaytarib oldim", "boshqa kelmayman",
"vaqtim behuda ketdi", "shikoyat yozdim", "afsuslandim"]}
PAD, CLS, MASK, UNK = 0, 1, 2, 3
def tanla(rng, royxat):
return royxat[int(rng.integers(len(royxat)))]
def gap(rng, dum_ehtimol, sifatlar=(IJOBIY, SALBIY)):
"""Sharh: (matn, tonallik, sifat). 25% holatda 'emas' tonallikni teskari qiladi."""
q = int(rng.integers(2))
sif = tanla(rng, sifatlar[0] if q else sifatlar[1])
inkor = rng.random() < 0.25
y = 1 - q if inkor else q
s = [tanla(rng, BOSH), tanla(rng, MAVZU), tanla(rng, DARAJA), sif,
"emas" if inkor else "", tanla(rng, OXIR)]
if rng.random() < dum_ehtimol:
s.append(tanla(rng, DUM[y]))
return " ".join(" ".join(s).split()), y, sif
class Lugat:
"""So'z darajasidagi tokenizator: korpusdan quriladi, 4 ta maxsus token."""
def __init__(self, matnlar):
sozlar = sorted({w for m in matnlar for w in m.split()})
self.itos = ["[PAD]", "[CLS]", "[MASK]", "[UNK]"] + sozlar
self.stoi = {w: i for i, w in enumerate(self.itos)}
def kodla(self, matnlar, T=16):
X = torch.zeros(len(matnlar), T, dtype=torch.long)
for i, m in enumerate(matnlar):
ids = [CLS] + [self.stoi.get(w, UNK) for w in m.split()][:T - 1]
X[i, :len(ids)] = torch.tensor(ids)
return X
class Blok(nn.Module):
"""Pre-LN transformer bloki: self-attention + FFN, qoldiq ulanishlar."""
def __init__(self, d, h):
super().__init__()
self.h = h
self.ln1, self.ln2 = nn.LayerNorm(d), nn.LayerNorm(d)
self.qkv, self.proj = nn.Linear(d, 3 * d), nn.Linear(d, d)
self.ffn = nn.Sequential(nn.Linear(d, 4 * d), nn.GELU(), nn.Linear(4 * d, d))
def forward(self, x, maska):
B, T, d = x.shape
q, k, v = self.qkv(self.ln1(x)).view(B, T, 3, self.h, d // self.h).permute(2, 0, 3, 1, 4)
a = F.scaled_dot_product_attention(q, k, v, attn_mask=maska[:, None, None, :])
x = x + self.proj(a.transpose(1, 2).reshape(B, T, d))
return x + self.ffn(self.ln2(x))
class Encoder(nn.Module):
def __init__(self, V, d=48, L=2, h=4, T=16):
super().__init__()
self.emb, self.poz = nn.Embedding(V, d), nn.Embedding(T, d)
self.bloklar = nn.ModuleList([Blok(d, h) for _ in range(L)])
self.ln = nn.LayerNorm(d)
nn.init.normal_(self.emb.weight, std=0.02)
nn.init.normal_(self.poz.weight, std=0.02)
def forward(self, X):
maska = X != PAD
x = self.emb(X) + self.poz(torch.arange(X.shape[1]))
for b in self.bloklar:
x = b(x, maska)
return self.ln(x)
class MLMBosh(nn.Module):
"""MLM boshi: vazni embedding bilan bog'langan (weight tying), faqat bias o'rganiladi."""
def __init__(self, V):
super().__init__()
self.bias = nn.Parameter(torch.zeros(V))
def forward(self, enc, X):
return enc(X) @ enc.emb.weight.T + self.bias
def kes(X):
"""Batchdagi eng uzun jumlagacha qirqish (ortiqcha PAD ustunlari kerak emas)."""
return X[:, :int((X != PAD).sum(1).max())]
def maskala(X, g, V, p=0.15):
"""BERT uslubi: 15% token tanlanadi; ulardan 80% [MASK], 10% tasodifiy, 10% o'zi."""
Y = X.clone()
tanl = (torch.rand(X.shape, generator=g) < p) & (X > UNK)
Y[~tanl] = -100
r = torch.rand(X.shape, generator=g)
X = X.clone()
X[tanl & (r < 0.8)] = MASK
tas = tanl & (r >= 0.8) & (r < 0.9)
X[tas] = torch.randint(4, V, (int(tas.sum()),), generator=g)
return X, Y
def mlm_loss(enc, bosh, X, Y):
V = enc.emb.num_embeddings
return F.cross_entropy(bosh(enc, X).reshape(-1, V), Y.reshape(-1))
def pretrain(V, X, qadam, seed=0, bs=32, lr=2e-3, kuzat=None):
"""MLM pretraining: belgisiz korpusda maskalangan so'zlarni tiklash."""
torch.manual_seed(seed)
enc, bosh = Encoder(V), MLMBosh(V)
opt = torch.optim.AdamW(list(enc.parameters()) + list(bosh.parameters()),
lr=lr, weight_decay=0.01)
g = torch.Generator().manual_seed(seed)
for q in range(1, qadam + 1):
xb, yb = maskala(kes(X[torch.randint(0, len(X), (bs,), generator=g)]), g, V)
loss = mlm_loss(enc, bosh, xb, yb)
opt.zero_grad()
loss.backward()
opt.step()
if kuzat is not None:
kuzat(q, loss.item())
enc.eval()
return enc, bosh
class Klassifikator(nn.Module):
"""Encoder + o'rtacha pooling (PAD siz) + chiziqli bosh."""
def __init__(self, enc, sinflar=2):
super().__init__()
self.enc = enc
self.bosh = nn.Linear(enc.emb.embedding_dim, sinflar)
def forward(self, X):
h = self.enc(X)
m = (X != PAD).float()[..., None]
return self.bosh((h * m).sum(1) / m.sum(1))
def fine_tune(model, X, y, seed, qadam=100, lr=1e-3, bs=16):
"""Faqat requires_grad=True parametrlar yangilanadi."""
opt = torch.optim.AdamW([p for p in model.parameters() if p.requires_grad],
lr=lr, weight_decay=0.01)
g = torch.Generator().manual_seed(seed)
model.train()
for _ in range(qadam):
idx = torch.randint(0, len(X), (min(bs, len(X)),), generator=g)
loss = F.cross_entropy(model(kes(X[idx])), y[idx])
opt.zero_grad()
loss.backward()
opt.step()
model.eval()
return model
@torch.no_grad()
def bashorat(model, X):
return model(kes(X)).argmax(1)
def main() -> None:
torch.set_num_threads(1)
rng = np.random.default_rng(0)
korpus = [gap(rng, 0.7)[0] for _ in range(20000)]
lug = Lugat(korpus)
V = len(lug.itos)
enc_pre, _ = pretrain(V, lug.kodla(korpus), 2000)
holat = enc_pre.state_dict()
print("=== 1. Belgili ma'lumot: kam va 'tor' ===")
korilgan = (IJOBIY[:16], SALBIY[:16]) # belgili to'plamda faqat shular
rng = np.random.default_rng(1)
hovuz = [gap(rng, 0.0, korilgan) for _ in range(3000)]
test = [gap(rng, 0.0) for _ in range(2000)]
Xh, yh = lug.kodla([h[0] for h in hovuz]), torch.tensor([h[1] for h in hovuz])
Xt, yt = lug.kodla([t[0] for t in test]), torch.tensor([t[1] for t in test])
yangi = torch.tensor([t[2] not in korilgan[0] + korilgan[1] for t in test])
print(f" belgili hovuz {len(hovuz)} (sifatlarning 32/48 tasi), test {len(test)} "
f"(hammasi 48 ta)")
print(f" testda ko'rilmagan sifatli jumlalar: {yangi.sum().item()} ({yangi.float().mean():.1%})")
print(" belgili jumlalarda dum ('tavsiya qilaman' ...) yo'q - faqat sifat va 'emas'")
print("\n=== 2. Egri chiziq: bir xil urug'lar, bir xil qadamlar (100, lr 1e-3) ===")
olchamlar = [50, 200, 1000]
natija = {}
for n in olchamlar:
for s in range(3):
idx = torch.tensor(np.random.default_rng(100 + s).choice(len(hovuz), n, replace=False))
for nom in ["noldan", "pretrained"]:
torch.manual_seed(s)
enc = Encoder(V)
if nom == "pretrained":
enc.load_state_dict(holat)
torch.manual_seed(s)
model = fine_tune(Klassifikator(enc), Xh[idx], yh[idx], seed=s)
p = bashorat(model, Xt) == yt
natija[(n, s, nom)] = (p.float().mean().item(), p[yangi].float().mean().item(),
p[~yangi].float().mean().item())
print(f" {'n':>5} {'noldan':>8} {'pretrained':>11} {'farq':>8} {'SE':>7} {'sezilarli':>10}")
for n in olchamlar:
a0 = np.array([natija[(n, s, "noldan")][0] for s in range(3)])
a1 = np.array([natija[(n, s, "pretrained")][0] for s in range(3)])
d = a1 - a0
se = d.std(ddof=1) / np.sqrt(len(d))
print(f" {n:>5} {a0.mean():>8.3f} {a1.mean():>11.3f} {d.mean():>+8.3f} {se:>7.3f} "
f"{str(abs(d.mean()) > 2 * se):>10}")
print("\n=== 3. Ko'rilgan va ko'rilmagan sifatlar (test aniqligi) ===")
print(f" {'n':>5} {'model':<11} {'korilgan':>9} {'korilmagan':>11}")
for n in olchamlar:
for nom in ["noldan", "pretrained"]:
k = np.mean([natija[(n, s, nom)][2] for s in range(3)])
y_ = np.mean([natija[(n, s, nom)][1] for s in range(3)])
print(f" {n:>5} {nom:<11} {k:>9.3f} {y_:>11.3f}")
y0 = np.mean([natija[(1000, s, "noldan")][1] for s in range(3)])
y1 = np.mean([natija[(1000, s, "pretrained")][1] for s in range(3)])
if y1 - y0 > 0.1:
print(f" n=1000 da ham noldan model yangi sifatlarda {y0:.3f}: u ularni hech qachon "
"ko'rmagan")
print(" pretrained model ularni korpusdan 'tanigan' - bilim belgisiz matndan keldi")
print("\n=== 4. Xulosa (natijadan) ===")
for qism, k in [("korilgan", 2), ("korilmagan", 1)]:
f = [np.mean([natija[(n, s, "pretrained")][k] - natija[(n, s, "noldan")][k]
for s in range(3)]) for n in olchamlar]
print(f" {qism:<11} sifatlarda foyda: " + ", ".join(
f"n={n} {v:+.3f}" for n, v in zip(olchamlar, f)))
if f[-1] < f[0] / 2:
print(" -> belgili misollar ko'paygan sari foyda kamaydi")
elif f[-1] > 0.3:
print(" -> foyda kamaymadi: bu so'zlarni belgili ma'lumot umuman o'rgatmaydi")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. Belgili ma'lumot: kam va 'tor' ===
belgili hovuz 3000 (sifatlarning 32/48 tasi), test 2000 (hammasi 48 ta)
testda ko'rilmagan sifatli jumlalar: 660 (33.0%)
belgili jumlalarda dum ('tavsiya qilaman' ...) yo'q - faqat sifat va 'emas'
=== 2. Egri chiziq: bir xil urug'lar, bir xil qadamlar (100, lr 1e-3) ===
n noldan pretrained farq SE sezilarli
50 0.536 0.810 +0.274 0.018 True
200 0.611 0.915 +0.303 0.031 True
1000 0.757 0.997 +0.240 0.023 True
=== 3. Ko'rilgan va ko'rilmagan sifatlar (test aniqligi) ===
n model korilgan korilmagan
50 noldan 0.562 0.482
50 pretrained 0.814 0.802
200 noldan 0.677 0.478
200 pretrained 0.924 0.895
1000 noldan 0.914 0.438
1000 pretrained 1.000 0.992
n=1000 da ham noldan model yangi sifatlarda 0.438: u ularni hech qachon ko'rmagan
pretrained model ularni korpusdan 'tanigan' - bilim belgisiz matndan keldi
=== 4. Xulosa (natijadan) ===
korilgan sifatlarda foyda: n=50 +0.252, n=200 +0.247, n=1000 +0.086
-> belgili misollar ko'paygan sari foyda kamaydi
korilmagan sifatlarda foyda: n=50 +0.319, n=200 +0.418, n=1000 +0.554
-> foyda kamaymadi: bu so'zlarni belgili ma'lumot umuman o'rgatmaydiNima ko'rsatdi: 2.4-bo'lim. Uchala o'lchamda ham pretrained model sezilarli yaxshi (+0.274, +0.303, +0.240; har birida SE farqdan o'n barobardan ko'p kichik). Ko'rilgan sifatlarda foyda n=1000 da +0.086 gacha kamaydi — yetarli yorliq bilan noldan model ham o'rganadi. Ko'rilmagan sifatlarda esa foyda +0.554 gacha o'sdi: bu so'zlar haqidagi bilim faqat belgisiz korpusdan kelishi mumkin edi.
Misol 3 — Fine-tuning usullari: to'liq, faqat bosh, muzlatish
"""Fine-tuning usullari: to'liq, faqat bosh (linear probe) va pastki qatlamlarni muzlatish."""
import numpy as np
import torch
import torch.nn as nn
import torch.nn.functional as F
MAVZU = ["telefon", "noutbuk", "kitob", "kafe", "mehmonxona", "avtobus", "dastur",
"kurs", "film", "do'kon", "restoran", "poyabzal", "kamera", "sumka", "taksi",
"klinika", "sartaroshxona", "televizor"]
IJOBIY = ["a'lo", "ajoyib", "zo'r", "yaxshi", "qulay", "chiroyli", "tez", "sifatli",
"mazali", "toza", "arzon", "ishonchli", "shinam", "samimiy", "foydali",
"qiziqarli", "mukammal", "puxta", "yoqimli", "maroqli", "chidamli", "oson",
"zamonaviy", "beg'ubor"]
SALBIY = ["yomon", "sekin", "qimmat", "iflos", "noqulay", "xunuk", "sifatsiz", "bemaza",
"eski", "zerikarli", "ishonchsiz", "qo'pol", "buzuq", "chalkash", "nosoz", "xira",
"tor", "shovqinli", "befoyda", "sovuq", "mo'rt", "murakkab", "dag'al", "g'alati"]
DARAJA = ["juda", "ancha", "biroz", "rosa", "", ""]
OXIR = ["ekan", "edi", "", "chiqdi"]
BOSH = ["kecha", "o'tgan hafta", "shahardagi", "yangi", "onlayn", "", "", ""]
DUM = {1: ["hammaga tavsiya qilaman", "yana kelaman", "juda mamnunman", "pulimga arzidi",
"do'stlarimga aytaman", "rahmat sizlarga"],
0: ["hech kimga tavsiya qilmayman", "pulimni qaytarib oldim", "boshqa kelmayman",
"vaqtim behuda ketdi", "shikoyat yozdim", "afsuslandim"]}
PAD, CLS, MASK, UNK = 0, 1, 2, 3
def tanla(rng, royxat):
return royxat[int(rng.integers(len(royxat)))]
def gap(rng, dum_ehtimol, sifatlar=(IJOBIY, SALBIY)):
"""Sharh: (matn, tonallik, sifat). 25% holatda 'emas' tonallikni teskari qiladi."""
q = int(rng.integers(2))
sif = tanla(rng, sifatlar[0] if q else sifatlar[1])
inkor = rng.random() < 0.25
y = 1 - q if inkor else q
s = [tanla(rng, BOSH), tanla(rng, MAVZU), tanla(rng, DARAJA), sif,
"emas" if inkor else "", tanla(rng, OXIR)]
if rng.random() < dum_ehtimol:
s.append(tanla(rng, DUM[y]))
return " ".join(" ".join(s).split()), y, sif
class Lugat:
"""So'z darajasidagi tokenizator: korpusdan quriladi, 4 ta maxsus token."""
def __init__(self, matnlar):
sozlar = sorted({w for m in matnlar for w in m.split()})
self.itos = ["[PAD]", "[CLS]", "[MASK]", "[UNK]"] + sozlar
self.stoi = {w: i for i, w in enumerate(self.itos)}
def kodla(self, matnlar, T=16):
X = torch.zeros(len(matnlar), T, dtype=torch.long)
for i, m in enumerate(matnlar):
ids = [CLS] + [self.stoi.get(w, UNK) for w in m.split()][:T - 1]
X[i, :len(ids)] = torch.tensor(ids)
return X
class Blok(nn.Module):
"""Pre-LN transformer bloki: self-attention + FFN, qoldiq ulanishlar."""
def __init__(self, d, h):
super().__init__()
self.h = h
self.ln1, self.ln2 = nn.LayerNorm(d), nn.LayerNorm(d)
self.qkv, self.proj = nn.Linear(d, 3 * d), nn.Linear(d, d)
self.ffn = nn.Sequential(nn.Linear(d, 4 * d), nn.GELU(), nn.Linear(4 * d, d))
def forward(self, x, maska):
B, T, d = x.shape
q, k, v = self.qkv(self.ln1(x)).view(B, T, 3, self.h, d // self.h).permute(2, 0, 3, 1, 4)
a = F.scaled_dot_product_attention(q, k, v, attn_mask=maska[:, None, None, :])
x = x + self.proj(a.transpose(1, 2).reshape(B, T, d))
return x + self.ffn(self.ln2(x))
class Encoder(nn.Module):
def __init__(self, V, d=48, L=2, h=4, T=16):
super().__init__()
self.emb, self.poz = nn.Embedding(V, d), nn.Embedding(T, d)
self.bloklar = nn.ModuleList([Blok(d, h) for _ in range(L)])
self.ln = nn.LayerNorm(d)
nn.init.normal_(self.emb.weight, std=0.02)
nn.init.normal_(self.poz.weight, std=0.02)
def forward(self, X):
maska = X != PAD
x = self.emb(X) + self.poz(torch.arange(X.shape[1]))
for b in self.bloklar:
x = b(x, maska)
return self.ln(x)
class MLMBosh(nn.Module):
"""MLM boshi: vazni embedding bilan bog'langan (weight tying), faqat bias o'rganiladi."""
def __init__(self, V):
super().__init__()
self.bias = nn.Parameter(torch.zeros(V))
def forward(self, enc, X):
return enc(X) @ enc.emb.weight.T + self.bias
def kes(X):
"""Batchdagi eng uzun jumlagacha qirqish (ortiqcha PAD ustunlari kerak emas)."""
return X[:, :int((X != PAD).sum(1).max())]
def maskala(X, g, V, p=0.15):
"""BERT uslubi: 15% token tanlanadi; ulardan 80% [MASK], 10% tasodifiy, 10% o'zi."""
Y = X.clone()
tanl = (torch.rand(X.shape, generator=g) < p) & (X > UNK)
Y[~tanl] = -100
r = torch.rand(X.shape, generator=g)
X = X.clone()
X[tanl & (r < 0.8)] = MASK
tas = tanl & (r >= 0.8) & (r < 0.9)
X[tas] = torch.randint(4, V, (int(tas.sum()),), generator=g)
return X, Y
def mlm_loss(enc, bosh, X, Y):
V = enc.emb.num_embeddings
return F.cross_entropy(bosh(enc, X).reshape(-1, V), Y.reshape(-1))
def pretrain(V, X, qadam, seed=0, bs=32, lr=2e-3, kuzat=None):
"""MLM pretraining: belgisiz korpusda maskalangan so'zlarni tiklash."""
torch.manual_seed(seed)
enc, bosh = Encoder(V), MLMBosh(V)
opt = torch.optim.AdamW(list(enc.parameters()) + list(bosh.parameters()),
lr=lr, weight_decay=0.01)
g = torch.Generator().manual_seed(seed)
for q in range(1, qadam + 1):
xb, yb = maskala(kes(X[torch.randint(0, len(X), (bs,), generator=g)]), g, V)
loss = mlm_loss(enc, bosh, xb, yb)
opt.zero_grad()
loss.backward()
opt.step()
if kuzat is not None:
kuzat(q, loss.item())
enc.eval()
return enc, bosh
class Klassifikator(nn.Module):
"""Encoder + o'rtacha pooling (PAD siz) + chiziqli bosh."""
def __init__(self, enc, sinflar=2):
super().__init__()
self.enc = enc
self.bosh = nn.Linear(enc.emb.embedding_dim, sinflar)
def forward(self, X):
h = self.enc(X)
m = (X != PAD).float()[..., None]
return self.bosh((h * m).sum(1) / m.sum(1))
def fine_tune(model, X, y, seed, qadam=100, lr=1e-3, bs=16):
"""Faqat requires_grad=True parametrlar yangilanadi."""
opt = torch.optim.AdamW([p for p in model.parameters() if p.requires_grad],
lr=lr, weight_decay=0.01)
g = torch.Generator().manual_seed(seed)
model.train()
for _ in range(qadam):
idx = torch.randint(0, len(X), (min(bs, len(X)),), generator=g)
loss = F.cross_entropy(model(kes(X[idx])), y[idx])
opt.zero_grad()
loss.backward()
opt.step()
model.eval()
return model
@torch.no_grad()
def bashorat(model, X):
return model(kes(X)).argmax(1)
def muzlat(model, usul):
"""usul: 'toliq', 'bosh' (encoder muzlatilgan) yoki 'yuqori' (emb + 1-blok muzlatilgan)."""
for p in model.parameters():
p.requires_grad_(True)
if usul == "bosh":
for p in model.enc.parameters():
p.requires_grad_(False)
elif usul == "yuqori":
for m in [model.enc.emb, model.enc.poz, model.enc.bloklar[0]]:
for p in m.parameters():
p.requires_grad_(False)
return model
def main() -> None:
torch.set_num_threads(1)
rng = np.random.default_rng(0)
korpus = [gap(rng, 0.7)[0] for _ in range(20000)]
lug = Lugat(korpus)
V = len(lug.itos)
holat = pretrain(V, lug.kodla(korpus), 2000)[0].state_dict()
korilgan = (IJOBIY[:16], SALBIY[:16])
rng = np.random.default_rng(1)
hovuz = [gap(rng, 0.0, korilgan) for _ in range(3000)]
test = [gap(rng, 0.0) for _ in range(2000)]
Xh, yh = lug.kodla([h[0] for h in hovuz]), torch.tensor([h[1] for h in hovuz])
Xt, yt = lug.kodla([t[0] for t in test]), torch.tensor([t[1] for t in test])
yangi = torch.tensor([t[2] not in korilgan[0] + korilgan[1] for t in test])
print("=== 1. Usullar: nima o'rgatiladi (n=200, 100 qadam) ===")
usullar = [("noldan", "toliq", False, 1e-3), ("faqat bosh", "bosh", True, 1e-2),
("yuqori blok+bosh", "yuqori", True, 1e-3), ("to'liq FT", "toliq", True, 1e-3)]
torch.manual_seed(0)
jami = sum(p.numel() for p in Klassifikator(Encoder(V)).parameters())
print(f" {'usul':<18} {'pretrained':>10} {'lr':>6} {'orgatiladi':>11} {'ulush':>7}")
for nom, usul, pre, lr in usullar:
m = muzlat(Klassifikator(Encoder(V)), usul)
n_or = sum(p.numel() for p in m.parameters() if p.requires_grad)
print(f" {nom:<18} {str(pre):>10} {lr:>6.0e} {n_or:>11} {n_or / jami:>7.1%}")
print("\n=== 2. Natija (3 urug', test 2000) ===")
natija = {}
for s in range(3):
idx = torch.tensor(np.random.default_rng(100 + s).choice(len(hovuz), 200, replace=False))
for nom, usul, pre, lr in usullar:
torch.manual_seed(s)
enc = Encoder(V)
if pre:
enc.load_state_dict(holat)
torch.manual_seed(s)
model = muzlat(Klassifikator(enc), usul)
model = fine_tune(model, Xh[idx], yh[idx], seed=s, lr=lr)
p = bashorat(model, Xt) == yt
natija[(nom, s)] = (p.float().mean().item(), p[yangi].float().mean().item())
print(f" {'usul':<18} {'aniqlik':>8} {'korilmagan':>11} {'to`liq FT - usul':>17} {'2*SE':>7}"
.replace("`", "'"))
toliq = np.array([natija[("to'liq FT", s)][0] for s in range(3)])
yomon = {}
for nom, _, _, _ in usullar:
a = np.array([natija[(nom, s)][0] for s in range(3)])
k = np.mean([natija[(nom, s)][1] for s in range(3)])
d = toliq - a
se = d.std(ddof=1) / np.sqrt(3)
yomon[nom] = d.mean() > 2 * se
qator = f" {nom:<18} {a.mean():>8.3f} {k:>11.3f}"
if nom != "to'liq FT":
qator += f" {d.mean():>+17.3f} {2 * se:>7.3f}"
print(qator)
print("\n=== 3. Xulosa (natijadan) ===")
for nom in ["faqat bosh", "yuqori blok+bosh", "noldan"]:
print(f" {nom:<18} to'liq FT dan sezilarli yomonmi: {'ha' if yomon[nom] else "yo'q"}")
if not yomon["yuqori blok+bosh"]:
print(" pastki qatlamlarni muzlatish sifatni sezilarli tushirmadi - "
"kamroq parametr o'rgatildi")
else:
print(" muzlatish sifatni tushirdi: pastki blok ham vazifaga moslashishi kerak edi")
if yomon["faqat bosh"]:
print(" faqat bosh yetmadi: pretraining vakillari bu vazifa uchun 'tayyor' emas")
else:
print(" faqat bosh ham yetarli bo'ldi: pretraining vakillari vazifaga tayyor")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. Usullar: nima o'rgatiladi (n=200, 100 qadam) ===
usul pretrained lr orgatiladi ulush
noldan False 1e-03 62786 100.0%
faqat bosh True 1e-02 98 0.2%
yuqori blok+bosh True 1e-03 28466 45.3%
to'liq FT True 1e-03 62786 100.0%
=== 2. Natija (3 urug', test 2000) ===
usul aniqlik korilmagan to'liq FT - usul 2*SE
noldan 0.611 0.478 +0.303 0.062
faqat bosh 0.761 0.756 +0.154 0.038
yuqori blok+bosh 0.822 0.818 +0.093 0.029
to'liq FT 0.915 0.895
=== 3. Xulosa (natijadan) ===
faqat bosh to'liq FT dan sezilarli yomonmi: ha
yuqori blok+bosh to'liq FT dan sezilarli yomonmi: ha
noldan to'liq FT dan sezilarli yomonmi: ha
muzlatish sifatni tushirdi: pastki blok ham vazifaga moslashishi kerak edi
faqat bosh yetmadi: pretraining vakillari bu vazifa uchun 'tayyor' emasNima ko'rsatdi: 2.5-bo'lim. 98 parametrli bosh (0.2%) noldan o'rgatilgan to'liq modeldan yaxshi (0.761 va 0.611), lekin to'liq fine-tuning (0.915) dan sezilarli yomon. Pastki blokni muzlatish ham bu kichik modelda sezilarli yo'qotish berdi (+0.093, 2*SE = 0.029). Qoidalar natijadan hisoblanadi — boshqa model va vazifada tartib o'zgarishi mumkin.
Misol 4 — Katastrofik unutish va pretrained modelni saqlash
"""Katastrofik unutish va pretrained modelni saqlash/yuklash (from_pretrained g'oyasi)."""
import copy
import tempfile
from pathlib import Path
import numpy as np
import torch
import torch.nn as nn
import torch.nn.functional as F
MAVZU = ["telefon", "noutbuk", "kitob", "kafe", "mehmonxona", "avtobus", "dastur",
"kurs", "film", "do'kon", "restoran", "poyabzal", "kamera", "sumka", "taksi",
"klinika", "sartaroshxona", "televizor"]
IJOBIY = ["a'lo", "ajoyib", "zo'r", "yaxshi", "qulay", "chiroyli", "tez", "sifatli",
"mazali", "toza", "arzon", "ishonchli", "shinam", "samimiy", "foydali",
"qiziqarli", "mukammal", "puxta", "yoqimli", "maroqli", "chidamli", "oson",
"zamonaviy", "beg'ubor"]
SALBIY = ["yomon", "sekin", "qimmat", "iflos", "noqulay", "xunuk", "sifatsiz", "bemaza",
"eski", "zerikarli", "ishonchsiz", "qo'pol", "buzuq", "chalkash", "nosoz", "xira",
"tor", "shovqinli", "befoyda", "sovuq", "mo'rt", "murakkab", "dag'al", "g'alati"]
DARAJA = ["juda", "ancha", "biroz", "rosa", "", ""]
OXIR = ["ekan", "edi", "", "chiqdi"]
BOSH = ["kecha", "o'tgan hafta", "shahardagi", "yangi", "onlayn", "", "", ""]
DUM = {1: ["hammaga tavsiya qilaman", "yana kelaman", "juda mamnunman", "pulimga arzidi",
"do'stlarimga aytaman", "rahmat sizlarga"],
0: ["hech kimga tavsiya qilmayman", "pulimni qaytarib oldim", "boshqa kelmayman",
"vaqtim behuda ketdi", "shikoyat yozdim", "afsuslandim"]}
PAD, CLS, MASK, UNK = 0, 1, 2, 3
def tanla(rng, royxat):
return royxat[int(rng.integers(len(royxat)))]
def gap(rng, dum_ehtimol, sifatlar=(IJOBIY, SALBIY)):
"""Sharh: (matn, tonallik, sifat). 25% holatda 'emas' tonallikni teskari qiladi."""
q = int(rng.integers(2))
sif = tanla(rng, sifatlar[0] if q else sifatlar[1])
inkor = rng.random() < 0.25
y = 1 - q if inkor else q
s = [tanla(rng, BOSH), tanla(rng, MAVZU), tanla(rng, DARAJA), sif,
"emas" if inkor else "", tanla(rng, OXIR)]
if rng.random() < dum_ehtimol:
s.append(tanla(rng, DUM[y]))
return " ".join(" ".join(s).split()), y, sif
class Lugat:
"""So'z darajasidagi tokenizator: korpusdan quriladi, 4 ta maxsus token."""
def __init__(self, matnlar):
sozlar = sorted({w for m in matnlar for w in m.split()})
self.itos = ["[PAD]", "[CLS]", "[MASK]", "[UNK]"] + sozlar
self.stoi = {w: i for i, w in enumerate(self.itos)}
def kodla(self, matnlar, T=16):
X = torch.zeros(len(matnlar), T, dtype=torch.long)
for i, m in enumerate(matnlar):
ids = [CLS] + [self.stoi.get(w, UNK) for w in m.split()][:T - 1]
X[i, :len(ids)] = torch.tensor(ids)
return X
class Blok(nn.Module):
"""Pre-LN transformer bloki: self-attention + FFN, qoldiq ulanishlar."""
def __init__(self, d, h):
super().__init__()
self.h = h
self.ln1, self.ln2 = nn.LayerNorm(d), nn.LayerNorm(d)
self.qkv, self.proj = nn.Linear(d, 3 * d), nn.Linear(d, d)
self.ffn = nn.Sequential(nn.Linear(d, 4 * d), nn.GELU(), nn.Linear(4 * d, d))
def forward(self, x, maska):
B, T, d = x.shape
q, k, v = self.qkv(self.ln1(x)).view(B, T, 3, self.h, d // self.h).permute(2, 0, 3, 1, 4)
a = F.scaled_dot_product_attention(q, k, v, attn_mask=maska[:, None, None, :])
x = x + self.proj(a.transpose(1, 2).reshape(B, T, d))
return x + self.ffn(self.ln2(x))
class Encoder(nn.Module):
def __init__(self, V, d=48, L=2, h=4, T=16):
super().__init__()
self.emb, self.poz = nn.Embedding(V, d), nn.Embedding(T, d)
self.bloklar = nn.ModuleList([Blok(d, h) for _ in range(L)])
self.ln = nn.LayerNorm(d)
nn.init.normal_(self.emb.weight, std=0.02)
nn.init.normal_(self.poz.weight, std=0.02)
def forward(self, X):
maska = X != PAD
x = self.emb(X) + self.poz(torch.arange(X.shape[1]))
for b in self.bloklar:
x = b(x, maska)
return self.ln(x)
class MLMBosh(nn.Module):
"""MLM boshi: vazni embedding bilan bog'langan (weight tying), faqat bias o'rganiladi."""
def __init__(self, V):
super().__init__()
self.bias = nn.Parameter(torch.zeros(V))
def forward(self, enc, X):
return enc(X) @ enc.emb.weight.T + self.bias
def kes(X):
"""Batchdagi eng uzun jumlagacha qirqish (ortiqcha PAD ustunlari kerak emas)."""
return X[:, :int((X != PAD).sum(1).max())]
def maskala(X, g, V, p=0.15):
"""BERT uslubi: 15% token tanlanadi; ulardan 80% [MASK], 10% tasodifiy, 10% o'zi."""
Y = X.clone()
tanl = (torch.rand(X.shape, generator=g) < p) & (X > UNK)
Y[~tanl] = -100
r = torch.rand(X.shape, generator=g)
X = X.clone()
X[tanl & (r < 0.8)] = MASK
tas = tanl & (r >= 0.8) & (r < 0.9)
X[tas] = torch.randint(4, V, (int(tas.sum()),), generator=g)
return X, Y
def mlm_loss(enc, bosh, X, Y):
V = enc.emb.num_embeddings
return F.cross_entropy(bosh(enc, X).reshape(-1, V), Y.reshape(-1))
def pretrain(V, X, qadam, seed=0, bs=32, lr=2e-3, kuzat=None):
"""MLM pretraining: belgisiz korpusda maskalangan so'zlarni tiklash."""
torch.manual_seed(seed)
enc, bosh = Encoder(V), MLMBosh(V)
opt = torch.optim.AdamW(list(enc.parameters()) + list(bosh.parameters()),
lr=lr, weight_decay=0.01)
g = torch.Generator().manual_seed(seed)
for q in range(1, qadam + 1):
xb, yb = maskala(kes(X[torch.randint(0, len(X), (bs,), generator=g)]), g, V)
loss = mlm_loss(enc, bosh, xb, yb)
opt.zero_grad()
loss.backward()
opt.step()
if kuzat is not None:
kuzat(q, loss.item())
enc.eval()
return enc, bosh
class Klassifikator(nn.Module):
"""Encoder + o'rtacha pooling (PAD siz) + chiziqli bosh."""
def __init__(self, enc, sinflar=2):
super().__init__()
self.enc = enc
self.bosh = nn.Linear(enc.emb.embedding_dim, sinflar)
def forward(self, X):
h = self.enc(X)
m = (X != PAD).float()[..., None]
return self.bosh((h * m).sum(1) / m.sum(1))
def fine_tune(model, X, y, seed, qadam=100, lr=1e-3, bs=16):
"""Faqat requires_grad=True parametrlar yangilanadi."""
opt = torch.optim.AdamW([p for p in model.parameters() if p.requires_grad],
lr=lr, weight_decay=0.01)
g = torch.Generator().manual_seed(seed)
model.train()
for _ in range(qadam):
idx = torch.randint(0, len(X), (min(bs, len(X)),), generator=g)
loss = F.cross_entropy(model(kes(X[idx])), y[idx])
opt.zero_grad()
loss.backward()
opt.step()
model.eval()
return model
@torch.no_grad()
def bashorat(model, X):
return model(kes(X)).argmax(1)
def main() -> None:
torch.set_num_threads(1)
rng = np.random.default_rng(0)
korpus = [gap(rng, 0.7)[0] for _ in range(20000)]
lug = Lugat(korpus)
V = len(lug.itos)
enc_pre, mlm_bosh = pretrain(V, lug.kodla(korpus), 2000)
rng = np.random.default_rng(2)
nazorat = lug.kodla([gap(rng, 0.7)[0] for _ in range(1000)])
Xn, Yn = maskala(nazorat, torch.Generator().manual_seed(5), V) # qat'iy maskalar
hovuz = [gap(rng, 0.0) for _ in range(1000)]
test = [gap(rng, 0.0) for _ in range(2000)]
Xh, yh = lug.kodla([h[0] for h in hovuz]), torch.tensor([h[1] for h in hovuz])
Xt, yt = lug.kodla([t[0] for t in test]), torch.tensor([t[1] for t in test])
def mlm(enc):
with torch.no_grad():
return mlm_loss(enc, mlm_bosh, Xn, Yn).item()
L0 = mlm(enc_pre)
print("=== 1. Katastrofik unutish: fine-tuning dan keyin MLM loss ===")
print(f" pretraining dan keyin nazorat MLM loss: {L0:.3f}")
print(f" {'usul':<24} {'test aniqlik':>12} {'MLM loss':>9} {'o`sish':>8}".replace("`", "'"))
usullar = [("faqat bosh, lr 1e-2", True, 1e-2, 100),
("to'liq, lr 3e-4", False, 3e-4, 100),
("to'liq, lr 1e-3", False, 1e-3, 100),
("to'liq, lr 3e-3, 300 qadam", False, 3e-3, 300)]
natija = {}
for nom, muzlat, lr, qadam in usullar:
torch.manual_seed(0)
model = Klassifikator(copy.deepcopy(enc_pre))
if muzlat:
for p in model.enc.parameters():
p.requires_grad_(False)
model = fine_tune(model, Xh, yh, seed=0, qadam=qadam, lr=lr)
aniq = (bashorat(model, Xt) == yt).float().mean().item()
L = mlm(model.enc)
natija[nom] = (aniq, L)
print(f" {nom:<26} {aniq:>10.3f} {L:>9.3f} {L - L0:>+8.3f}")
eng = max(natija, key=lambda k: natija[k][1])
print(f" eng ko'p unutgan: {eng} (MLM loss {natija[eng][1]:.3f})")
if natija["faqat bosh, lr 1e-2"][1] == L0:
print(" faqat bosh: encoder o'zgarmadi -> MLM bilimi aynan saqlandi")
kich = natija["to'liq, lr 3e-4"]
if kich[1] - L0 < natija[eng][1] - L0:
print(f" kichik lr: aniqlik {kich[0]:.3f}, unutish {kich[1] - L0:+.3f} - "
"yumshoq moslashish")
print("\n=== 2. Pretrained modelni saqlash: konfig + lug'at + vaznlar ===")
with tempfile.TemporaryDirectory() as papka:
yol = Path(papka) / "uzbert_kichik.pt"
paket = {
"konfig": {"V": V, "d": 48, "L": 2, "h": 4, "T": 16},
"lugat": list(lug.itos),
"encoder": enc_pre.state_dict(),
"mlm_bias": mlm_bosh.bias.detach().clone(),
"karta": {"korpus": "20000 sintetik sharh", "vazifa": "MLM 15%",
"qadamlar": 2000, "nazorat_mlm_loss": round(L0, 4)},
}
torch.save(paket, yol)
p = torch.load(yol, weights_only=True)
print(f" kalitlar: {sorted(p)}")
print(f" encoder tenzorlari: {len(p['encoder'])}, lug'at {len(p['lugat'])} ta so'z")
print("\n=== 3. Yuklash (from_pretrained kabi) va tekshirish ===")
k = p["konfig"]
enc2 = Encoder(k["V"], k["d"], k["L"], k["h"], k["T"])
enc2.load_state_dict(p["encoder"])
enc2.eval()
lug2_stoi = {w: i for i, w in enumerate(p["lugat"])}
print(f" lug'at mos: {lug2_stoi == lug.stoi}")
with torch.no_grad():
farq = (enc2(nazorat) - enc_pre(nazorat)).abs().max().item()
print(f" chiqishlar farqi (max |a-b|): {farq}")
torch.manual_seed(0)
yangi = Klassifikator(enc2)
print(f" ustiga yangi bosh: {sum(q.numel() for q in yangi.bosh.parameters())} parametr "
"(tasodifiy) - endi fine-tuning ga tayyor")
print(f" model kartasi: {p['karta']}")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. Katastrofik unutish: fine-tuning dan keyin MLM loss ===
pretraining dan keyin nazorat MLM loss: 1.665
usul test aniqlik MLM loss o'sish
faqat bosh, lr 1e-2 0.743 1.665 +0.000
to'liq, lr 3e-4 0.808 1.759 +0.094
to'liq, lr 1e-3 0.999 2.367 +0.702
to'liq, lr 3e-3, 300 qadam 1.000 3.669 +2.004
eng ko'p unutgan: to'liq, lr 3e-3, 300 qadam (MLM loss 3.669)
faqat bosh: encoder o'zgarmadi -> MLM bilimi aynan saqlandi
kichik lr: aniqlik 0.808, unutish +0.094 - yumshoq moslashish
=== 2. Pretrained modelni saqlash: konfig + lug'at + vaznlar ===
kalitlar: ['encoder', 'karta', 'konfig', 'lugat', 'mlm_bias']
encoder tenzorlari: 28, lug'at 110 ta so'z
=== 3. Yuklash (from_pretrained kabi) va tekshirish ===
lug'at mos: True
chiqishlar farqi (max |a-b|): 0.0
ustiga yangi bosh: 98 parametr (tasodifiy) - endi fine-tuning ga tayyor
model kartasi: {'korpus': '20000 sintetik sharh', 'vazifa': 'MLM 15%', 'qadamlar': 2000, 'nazorat_mlm_loss': 1.6649}Nima ko'rsatdi: 2.6, 2.7-bo'limlar. Faqat bosh o'rgatilganda MLM loss aynan o'zgarmadi (+0.000). To'liq fine-tuning da unutish lr bilan o'sdi: +0.094, +0.702, +2.004 — test aniqligi esa oxirgi ikkitasida deyarli bir xil (0.999 va 1.000). Paket torch.load(..., weights_only=True) bilan yuklandi, chiqishlar farqi 0.0 — bu from_pretrained ning mohiyati: konfigdan arxitekturani qurish va vaznlarni joyiga qo'yish.
5. To'g'ri va noto'g'ri tushunishlar
| Noto'g'ri fikr | To'g'risi |
|---|---|
| "Kam ma'lumotda transformer ishlamaydi" | Noldan ishlamaydi; pretraining bilan 200 misolda 0.611 → 0.915 (2-misol) |
| "Pretraining faqat ko'p ma'lumotli kompaniyalar uchun" | Belgisiz matn arzon; 20000 sharh ham yetdi |
| "Pretraining foydasi har doim ma'lumot bilan yo'qoladi" | Ko'rilgan so'zlarda kamayadi, ko'rilmagan so'zlarda o'sdi (+0.554) |
| "MLM loss nolga tushishi kerak" | Vazifa noaniq: 24 sinonimdan istalgani to'g'ri; 1.668 — yaxshi natija |
| "Faqat boshni o'rgatish har doim yetarli" | Bu yerda to'liq FT dan 0.154 ga yomon; vakillar vazifaga tayyor bo'lishi kerak |
| "Aniqlik bir xil bo'lsa, lr muhim emas" | lr 1e-3 va 3e-3 da aniqlik ~1.0, MLM loss 2.367 va 3.669 |
| "Fine-tuned model — yangi pretrained model" | U allaqachon unutgan; pretrained vaznlarni alohida saqlang |
| "HF modeli qora quti" | Tokenizator + encoder + bosh + Trainer — bu darsdagi zanjir |
6. Keng tarqalgan xatolar va yechimlari
1. Adolatsiz taqqoslash
noldan = orgat(Encoder(V), X[:200], qadam=50) # ⚠️
pre = orgat(pretrained, X[200:400], qadam=300) # ⚠️ boshqa misol, boshqa qadam
idx = rng_s.choice(len(X), 200); torch.manual_seed(s) # ✅ bir urug' - bir xil misol
noldan = fine_tune(Klassifikator(Encoder(V)), X[idx], y[idx], seed=s)2. Lug'atni fine-tuning ma'lumotidan qayta qurish
lug = Lugat(belgili_matnlar) # ⚠️ indekslar boshqa
enc.load_state_dict(pretrained) # embeddinglar mos emas
stoi = {w: i for i, w in enumerate(p["lugat"])} # ✅ pretraining lug'ati3. Maskalanmagan pozitsiyalarda loss
loss = F.cross_entropy(logit.reshape(-1, V), X.reshape(-1)) # ⚠️ nusxa ko'chirish vazifasi
Y[~tanlangan] = -100 # ✅ faqat tanlanganlar4. eval() ni muzlatish deb o'ylash
model.enc.eval() # "encoder muzlatildi" # ⚠️ vaznlar baribir o'zgaradi
for p in model.enc.parameters(): # ✅ gradient umuman hisoblanmaydi
p.requires_grad_(False)5. Juda katta fine-tuning lr
fine_tune(model, X, y, lr=3e-3, qadam=300) # ⚠️ MLM loss +2.004
fine_tune(model, X, y, lr=1e-3, qadam=100) # ✅ va unutishni o'lchang6. Pooling da [PAD]
h.mean(1) # ⚠️ PAD vakillari aralashadi
m = (X != PAD).float()[..., None]; (h * m).sum(1) / m.sum(1) # ✅7. Bitta pretrained nusxani ketma-ket vazifalarga moslash
model_a = Klassifikator(enc); fine_tune(model_a, ...) # ⚠️ enc o'zgardi
model_b = Klassifikator(enc); fine_tune(model_b, ...) # b - "unutgan" enc dan
model_b = Klassifikator(copy.deepcopy(enc_pre)) # ✅ har vazifaga toza nusxa7. Integratsiya — bu bilim qayerda kerak bo'ladi
- 22-qism (o'tilgan): Rasmlarda transfer o'rganish va muzlatish — xuddi shu g'oya, CNN bilan
- 23.6, 23.7-darslar (o'tilgan): word2vec — "bir xil kontekst → yaqin vektor"; pretraining ning eng sodda shakli
- 24.6, 24.8-darslar (o'tilgan): Transformer encoder va MLM — bu darsning pretraining bosqichi
- 18-qism (o'tilgan): Juftlashgan taqqoslash, SE, bir necha urug'
- Keyingi dars 24.11-bob: LoRA — unutmasdan moslash; parametr soni va masshtablash
- 24.12-dars: Loyihada pretraining foyda beradimi — bazaviylar bilan juftlashgan CV da tekshiramiz
- Katta til modellari qismida: Instruction tuning, RLHF — pretraining → fine-tuning ning keyingi bosqichlari; o'rgatishsiz (zero-shot) foydalanish
- MLOps va deploy qismida: Model kartalari, versiyalash, pretrained modellarni ro'yxatga olish
8. Eng yaxshi amaliyotlar
Belgisiz ma'lumotni qidiring — u ko'pincha bor va arzon.
Pretrained va noldan modelni bir xil misollar, bir xil qadamlar va bir necha urug' bilan solishtiring.
O'rganish egri chizig'ini chizing (50, 200, 1000...) — foyda qayerda ekanini ko'rasiz.
Testda ko'rilmagan so'zlar/holatlar uchun alohida o'lchov qo'ying.
Oddiydan boshlang: faqat bosh → muzlatish → to'liq FT; har birini o'lchang.
Fine-tuning lr ni pretraining dagidan kichik yoki teng qiling; unutishni o'lchang.
Pretrained vaznlar, lug'at va konfigni bitta paketda, alohida saqlang.
Pretrained model tanlashdan oldin uning kartasini o'qing: korpus, til, vazifa, cheklovlar.
9. Amaliy topshiriq
Vazifa 1: Bashorat qiling
1. # V = 110 bo'lsa tasodifiy modelning MLM loss i taxminan?
2. # 15% tanlangan tokenlarning qancha qismi [MASK] ga almashadi?
3. # nega faqat [MASK] ishlatilmaydi?
4. # bog'langan vaznlarda MLM logit formulasi?
5. # fine-tuning da klassifikatsiya boshi qayerdan keladi?
6. # "faqat bosh" usulida encoder parametrlari qanday belgilanadi?
7. # pretraining foydasi n oshganda qanday o'zgaradi (ko'rilgan so'zlarda)?
8. # ko'rilmagan so'zlarda-chi?
9. # katastrofik unutish qanday o'lchanadi?
10. # nega fine-tuning dan keyin MLM loss o'sadi?
11. # HF da `Lugat` va `Klassifikator` ning analoglari?
12. # model kartasida nima yoziladi?Javoblar
ln 110 = 4.700(1-misolda boshlang'ich4.696)- 80% (1-misolda
0.803) - Fine-tuning da
[MASK]uchramaydi — model har pozitsiyani tekshirishga o'rganishi uchun 10% tasodifiy va 10% o'zgarmagan tokenlar kerak logit = h @ E^T + b- Yangi, tasodifiy yaratiladi (
Linear(d, sinflar)) p.requires_grad_(False)va optimizatorga faqatrequires_grad=Trueparametrlar beriladi- Kamayadi (2-misol:
+0.252→+0.086) - Kamaymaydi, bu yerda o'sdi (
+0.319→+0.554) — belgili ma'lumot bu so'zlarni o'rgatmaydi - Fine-tuned encoder + asl MLM boshi bilan qat'iy maskalangan nazorat to'plamida MLM loss
- Encoder vaznlari vazifa gradienti bo'yicha o'zgaradi va MLM uchun kerakli tuzilma buziladi
AutoTokenizervaAutoModelForSequenceClassification- Korpus, pretraining vazifasi, til(lar), metrikalar, cheklovlar, noxolislik, litsenziya
Vazifa 2: Xatolarni tuzating
1. Y = X.clone()
loss = F.cross_entropy(model(Xm).reshape(-1, V), Y.reshape(-1))
2. model.enc.eval() # faqat boshni o'rgatmoqchimiz
opt = torch.optim.AdamW(model.parameters(), lr=1e-2, weight_decay=0.01)
3. enc_a = fine_tune(Klassifikator(enc_pre), Xa, ya, seed=0).enc
enc_b = fine_tune(Klassifikator(enc_pre), Xb, yb, seed=0).enc
4. lug = Lugat(belgili_matnlar)
enc.load_state_dict(torch.load("pretrained.pt", weights_only=True))
5. pooled = model.enc(X).mean(1)Javoblar
1. Xm, Y = maskala(X, g, V) # Y: tanlanmaganlar -100
loss = F.cross_entropy(model(Xm).reshape(-1, V), Y.reshape(-1))
2. for p in model.enc.parameters(): # eval() dropout/normni boshqaradi, muzlatmaydi
p.requires_grad_(False)
opt = torch.optim.AdamW([p for p in model.parameters() if p.requires_grad],
lr=1e-2, weight_decay=0.01)
3. enc_a = fine_tune(Klassifikator(copy.deepcopy(enc_pre)), Xa, ya, seed=0).enc
enc_b = fine_tune(Klassifikator(copy.deepcopy(enc_pre)), Xb, yb, seed=0).enc
4. p = torch.load("pretrained.pt", weights_only=True)
stoi = {w: i for i, w in enumerate(p["lugat"])} # pretraining lug'ati
enc.load_state_dict(p["encoder"])
5. m = (X != PAD).float()[..., None]
pooled = (model.enc(X) * m).sum(1) / m.sum(1)Vazifa 3: Pretraining
Modellang:
- Pretraining qadamlari 250, 500, 1000, 2000 — nazorat MLM loss va n=200 dagi fine-tuning aniqligi
- Maskalash ulushi 5%, 15%, 30%
- Faqat
[MASK](100/0/0) bilan maskalash — fine-tuning natijasi o'zgaradimi? - Bog'langan vaznlar o'rniga alohida
Linear(d, V)— parametr soni va loss
Yechim yo'nalishi
pretrain(V, X, qadam) ni har qiymat bilan chaqiring va 2-misoldagi fine_tune siklini n=200, 3 urug' bilan takrorlang. Qadamlar bo'yicha kutiladigan manzara: MLM loss bir tekis pasayadi, fine-tuning aniqligi esa ma'lum nuqtadan keyin (model inkor qoidasini o'rgangach) keskin oshadi — bu darsni tayyorlashda 1000 qadamli pretraining bilan n=200 dagi aniqlik ancha past chiqqan edi. Alohida Linear(d, V) qo'shimcha 48 * 110 parametr qo'shadi. Maskalash retseptini o'zgartirish uchun maskala dagi 0.8 va 0.9 chegaralarini parametr qiling.
Vazifa 4: Egri chiziq
Modellang:
- n = 20, 50, 100, 200, 500, 1000, 3000
- Noldan model uchun qadamlar sonini 100 dan 500 gacha oshiring — ko'rilgan sifatlarda farq yo'qoladimi?
- Ko'rilmagan sifatlar ulushini 0%, 33%, 66% qiling
- Har nuqtada juftlashgan farq va
2*SE
Yechim yo'nalishi
2-misoldagi olchamlar ro'yxatini kengaytiring va fine_tune(..., qadam=q) ni noldan model uchun alohida bering (adolat uchun pretrained ga ham xuddi shu qadamni bering). Kutilgan natija: ko'rilgan sifatlarda noldan model yetarli qadam va misol bilan pretrained ga yaqinlashadi; ko'rilmagan sifatlarda esa — yo'q, chunki bu embeddinglar gradient olmaydi. korilgan = (IJOBIY[:k], SALBIY[:k]) bilan ulushni boshqaring.
Vazifa 5: Usullar
Modellang:
- "Diskriminativ lr": encoder uchun 3e-4, bosh uchun 3e-3 (ikki parametr guruhi)
- Avval faqat bosh (50 qadam), keyin to'liq (50 qadam) — "ikki bosqichli" fine-tuning
- Pooling:
[CLS]vakili va o'rtacha pooling - Har usul uchun o'rgatiladigan parametr ulushi va aniqlik jadvali
Yechim yo'nalishi
opt = torch.optim.AdamW([
{"params": model.enc.parameters(), "lr": 3e-4},
{"params": model.bosh.parameters(), "lr": 3e-3}], weight_decay=0.01)[CLS] pooling: self.bosh(h[:, 0]). E'tibor bering: bizning MLM pretraining [CLS] ni hech qachon maskalamaydi va unga alohida vazifa bermaydi, shuning uchun uning vakili "tayyor" bo'lmasligi mumkin — o'rtacha pooling bilan juftlashgan taqqoslash qiling.
Vazifa 6: Unutish
Modellang:
- Fine-tuning qadamlari 50, 100, 200, 400 da MLM loss (lr 1e-3)
- Aralash o'rgatish:
loss = loss_klass + 0.5 * loss_mlm— unutish va aniqlik - Unutilgan encoder ni boshqa vazifaga (masalan, mavzuni aniqlash) moslang — toza pretrained bilan solishtiring
- Natijalarni jadvalda
Yechim yo'nalishi
Aralash o'rgatishda har qadamda ikki batch oling: belgili batch klassifikatsiya uchun va korpusdan maskala qilingan batch MLM uchun; mlm_bosh ni ham optimizatorga qo'shing. Kutilgan natija: MLM loss o'sishi ancha kichrayadi, klassifikatsiya aniqligi deyarli o'zgarmaydi. 3-bandda mavzu yorlig'i sifatida MAVZU indeksini oling (gap funksiyasini mavzuni ham qaytaradigan qilib o'zgartiring).
Vazifa 7: O'ylash
Hamkasbingiz aytdi: "Men Hub dan katta ko'p tilli modelni oldim va o'zbekcha sharhlarimizning 5000 tasida fine-tuning qildim — aniqlik 94%. Bizning TF-IDF bazaviyimiz esa 93%. Demak pretraining bizga deyarli foyda bermadi, katta modelni ishlatish shart emas." Siz nima deysiz?
Javob
Qisqa javob: xulosa shoshilinch. "Foyda yo'q" deyish uchun farqni to'g'ri o'lchash, uni qayerda qidirishni bilish va xarajatni hisobga olish kerak.
1. Farq sezilarlimi? Bitta bo'lish va bitta urug'dagi 94% va 93% — shovqin ichida bo'lishi mumkin. Bir xil foldlarda juftlashgan farq va SE kerak. Bu 24.12-darsda qiladigan ishimiz.
2. 5000 ta yorliq — ko'p. 2-misolda ko'rdik: ko'rilgan so'zlarda pretraining foydasi belgili ma'lumot ko'paygan sari kamayadi (+0.252 → +0.086). 5000 misolda bazaviy ham yaxshi o'rganadi. Pretraining ning kuchi kam yorliqda: 200 ta misol bilan ham 94% chiqsa — bu katta yutuq.
3. Qayerda foyda qidirish kerak. Umumiy aniqlik o'rtacha qiymat. 2-misolda pretraining ning eng katta foydasi ko'rilmagan so'zlarda edi (+0.554). Hamkasbingizning testi o'quv to'plami bilan bir davrdan, bir xil mahsulotlardan olingan bo'lsa — yangi so'zlar kam. Yangi mahsulot toifasi, yangi jargon, imlo xatolari, inkor va kontrast kabi guruhlarda alohida o'lchash kerak.
4. Model kartasi. Ko'p tilli modelning korpusida o'zbek tili qancha bo'lgan? Tokenizator o'zbekcha so'zlarni qanday bo'ladi (o' apostrofi, qo'shimchalar)? Agar o'zbek matni juda kam bo'lgan bo'lsa — model "o'zbek tilini bilmaydigan" pretrained model, va natijalar shunga yarasha.
5. Xarajat. Agar sezilarli farq bo'lmasa, qaror qoidasi aniq: eng yaxshisidan sezilarli yomon bo'lmagan eng sodda model. TF-IDF tez, arzon va tushunarli. Bu "pretraining foydasiz" degani emas — "bu vazifada, bu ma'lumot hajmida murakkablik o'zini oqlamadi" degani.
Tavsiya:
# 1. Bir xil 5 foldda juftlashgan CV: TF-IDF, katta model (+ kichikroq variant)
# 2. Guruhlar bo'yicha aniqlik: yangi so'zlar, inkor, kontrast, uzun matnlar
# 3. O'rganish egri chizig'i: 200, 1000, 5000 yorliqda ikkala model
# 4. Qaror qoidasi + xarajat (xotira, tezlik)Hamkasbga javob: "Farqni bitta bo'lishda emas, juftlashgan CV da o'lchaylik, va qiyin guruhlarni alohida ko'raylik. 5000 yorliqda bazaviy yaqin kelishi tabiiy — pretraining ning kuchi kam yorliqda va yangi so'zlarda. Agar farq sezilarli bo'lmasa, TF-IDF ni tanlaymiz — lekin buni o'lchovdan keyin aytamiz."
Nimani mustahkamlaydi: 2.2, 2.4, 2.5, 2.6-bo'limlar.
Xulosa
Bu darsda pretraining → fine-tuning zanjirini noldan qurdik va uning foydasi va narxini o'lchadik.
Eng muhim uch fikr:
Pretraining yorliqsiz matndan tilni o'rganadi. 1-misolda 20000 ta belgisiz sharhda 2000 qadam MLM (15% token, 80/10/10) nazorat loss ni
4.696dan (ln 110 = 4.700darajasi)1.668ga tushirdi. Hech kim model ga sinonimlarni ko'rsatmagan bo'lsa ham, bir xil tonallikdagi sifatlarning embeddinglari yaqinlashdi (kosinus+0.815, qarama-qarshi tonallik bilan+0.563),'a'lo'ning to'rtta eng yaqin qo'shnisi —shinam, qulay, toza, mazali. Model inkorni ham o'rgandi: "emas" qo'shilganda bo'shliqqa ijobiy sifat ehtimoli0.40dan0.61ga oshdi.Foyda kam yorliqda va yangi so'zlarda eng katta — va uni juftlashgan urug'lar bilan o'lchash kerak. 2-misolda pretrained model noldan o'rgatilganidan n=50 da
+0.274, n=200 da+0.303, n=1000 da+0.240ga yaxshi chiqdi (hammasi2*SEdan katta). Ko'rilgan sifatlarda foyda+0.252dan+0.086ga kamaydi, ko'rilmagan sifatlarda esa+0.554ga o'sdi — n=1000 da noldan model ularda atigi0.438, pretrained model0.992. 3-misolda to'liq fine-tuning (0.915) faqat bosh (0.761, 98 parametr) va pastki blokni muzlatishdan (0.822) sezilarli yaxshi chiqdi.Fine-tuning ning narxi — katastrofik unutish. 4-misolda faqat bosh o'rgatilganda MLM loss aynan saqlandi, to'liq fine-tuning da esa lr bilan o'sdi:
+0.094(3e-4),+0.702(1e-3),+2.004(3e-3, 300 qadam) — oxirgi ikkitasida test aniqligi deyarli bir xil (0.999va1.000). Shuning uchun pretrained vaznlar lug'at va konfig bilan alohida saqlanadi (weights_only=Truebilan yuklanganda chiqishlar farqi0.0), har vazifa uchun esa yangi nusxa olinadi. Hugging Face dagiAutoTokenizer,AutoModel...,Trainerva model kartasi — shu darsdagi qismlarning standart nomlari.
Keyingi darsda samaradorlik va masshtab: attention ning O(n^2) narxini hisoblaymiz, generatsiyani KV-cache bilan tezlashtiramiz, parametrlar soni va masshtablash qonunlarini o'z tajribamizda tekshiramiz, gradient checkpointing, aralash aniqlik va LoRA ni noldan quramiz — oxirgisi aynan shu darsdagi unutish muammosiga javob.
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!