Mundarija (24)
- 1. Kirish va motivatsiya
- 2. Nazariya — chuqur tushuntirish
- 2.1. Nega LLM ni baholash qiyin
- 2.2. Eval to'plami: yaratish, toifalar, oltin testlar, versiyalash
- 2.3. Avtomatik metrikalar noldan
- 2.4. Vazifaga xos tekshiruvlar
- 2.5. LLM-as-judge va uning tarafkashliklari
- 2.6. Hakamni tekshirish: tartibni almashtirish va Cohen kappa
- 2.7. Bootstrap ishonch intervali va juftlashgan taqqoslash
- 2.8. Regressiya testlari va darvoza
- 2.9. Oqib ketish (contamination)
- 2.10. Tuzoqlar
- 3. Tez ma'lumotnoma
- 4. Batafsil misollar
- Misol 1 — Avtomatik metrikalar noldan va ularning cheklovlari
- Misol 2 — LLM-as-judge tarafkashliklarini aniqlash
- Misol 3 — Ikki prompt versiyasi: bootstrap, juftlashgan taqqoslash va regressiya darvozasi
- Misol 4 — Oqib ketish: oshirilgan baho va uni aniqlash
- 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
25.10-dars: LLM ni baholash
25-QISM — KATTA TIL MODELLARI · 10-dars
1. Kirish va motivatsiya
25.9-darsda RAG ning retrieval qismini baholadik: u yerda javob aniq edi — "to'g'ri chunk top-k da bormi?". LLM ning yakuniy javobini baholash ancha qiyin. Bitta savolga o'nlab to'g'ri javob bor: "25 kun", "Yillik ta'til 25 kun.", "Xodimlar har yili 25 kunlik dam olish oladi." Uchalasi ham to'g'ri, lekin satr sifatida bir-biriga o'xshamaydi. Aksincha, "Yillik ta'til 26 kun." etalonga deyarli harfma-harf o'xshaydi — va noto'g'ri.
Shu sababli LLM loyihalarida baholash ko'pincha eng zaif bo'g'in bo'ladi. Jamoa promptni o'zgartiradi, o'nta savolni qo'lda ko'rib chiqadi, "yaxshiroq bo'ldi" deydi va ishga tushiradi. Keyin ma'lum bo'ladiki, yangi prompt umumiy savollarda biroz yaxshilangan, lekin xavfsizlik savollarida — foydalanuvchi maxfiy ma'lumot so'raganda rad etish kerak bo'lgan joyda — sezilarli yomonlashgan. O'nta savolda buni ko'rib bo'lmaydi.
Real vaziyat. Kompaniya mijozlarga javob beruvchi yordamchining ikki prompt versiyasini solishtirish uchun "LLM-hakam" dan foydalandi: hakamga ikki javobni ko'rsatib, "qaysi biri yaxshi?" deb so'rashdi. Yangi versiya 67 foiz holatda yutdi. Keyinroq tahlil qilinganda ma'lum bo'ldiki, hakam har doim birinchi ko'rsatilgan javobni afzal ko'rishga moyil edi, yangi versiya esa doim birinchi o'rinda ko'rsatilgan; bundan tashqari, yangi prompt javoblarni uzunroq qilgan edi, hakam esa uzun javobni "puxtaroq" deb baholardi. Inson belgilari bilan solishtirilganda farq deyarli yo'qolib ketdi.
Bu darsda avtomatik metrikalarni (exact match, token F1, BLEU, ROUGE-L) noldan yozib, ularning cheklovlarini o'lchaymiz; LLM-as-judge tarafkashliklarini aniqlash usullarini (tartibni almashtirish, Cohen kappa) ko'ramiz; bootstrap ishonch intervali va juftlashgan taqqoslash bilan ikki prompt versiyasini solishtirib, regressiya darvozasini quramiz; eval to'plamining o'rgatish ma'lumotiga oqib ketishini aniqlaymiz.
Bu darsda:
- Nega LLM ni baholash qiyin
- Eval to'plami: yaratish, toifalar, oltin testlar, versiyalash
- Avtomatik metrikalar noldan va ularning cheklovlari
- Vazifaga xos tekshiruvlar
- LLM-as-judge va uning tarafkashliklari
- Hakamni tekshirish: tartibni almashtirish va Cohen kappa
- Bootstrap ishonch intervali va juftlashgan taqqoslash
- Regressiya testlari va darvoza
- Oqib ketish (contamination)
- Tuzoqlar
ℹ Misollar real numpy/sklearn bilan (Python 3.14). LLM API chaqirilmaydi. 2- va 3-misollarda LLM o'rnida aniq STUB deb nomlangan deterministik soxta hakam va soxta model ishlatiladi — bu haqiqiy model emas, uning tarafkashliklari ataylab qo'yilgan. Maqsad — "LLM shunday qiladi" deb da'vo qilish emas, balki "bunday tarafkashlik bo'lsa, uni shunday aniqlaysiz" ni haqiqiy hisob bilan ko'rsatish. 4-misoldagi model esa haqiqiy (o'rgatiladigan so'z trigram modeli).
2. Nazariya — chuqur tushuntirish
2.1. Nega LLM ni baholash qiyin
KLASSIK ML (14-18-qismlar):
bitta to'g'ri javob (sinf, son) -> accuracy, F1, RMSE - aniq formula
LLM:
ochiq javob: bitta savolga ko'p to'g'ri javob (qisqa, uzun, parafraz)
to'g'rilik bir necha o'lchovli: fakt, to'liqlik, format, ohang, xavfsizlik
kichik o'zgarish -> katta xato: "25 kun" va "26 kun" - bitta belgi farq
generatsiya tasodifiy 25.3-bob: bir xil prompt - turli javob
model va prompt tez-tez o'zgaradi -> baholash har safar qayta kerak
UCH DARAJA:
1. qat'iy tekshiruv - EM, JSON sxema 25.5-bob, kod testlari, raqam mosligi
2. o'xshashlik metrika - token F1, BLEU, ROUGE (arzon, lekin to'g'rilik emas)
3. hukm - inson yoki LLM-hakam (qimmat, tarafkash bo'lishi mumkin)
amalda: 1 + 3 aralashmasi; 2 - faqat qo'shimcha signalLLM javobini baholash — bir nechta to'g'ri javob va bir necha o'lchovli sifat masalasi; imkon bo'lgan joyda qat'iy tekshiruv, qolganida hukm (inson yoki tekshirilgan LLM-hakam).
2.2. Eval to'plami: yaratish, toifalar, oltin testlar, versiyalash
ELEMENT: {id, toifa, kirish (savol/kontekst), etalon yoki baholash mezoni, izoh}
QAYERDAN:
haqiqiy foydalanuvchi so'rovlari (anonimlashtirilgan) - eng qimmatli
mutaxassis yozgan qiyin holatlar
xato tahlilidan: har topilgan xato -> yangi eval elementi
sintetik (LLM bilan) - faqat tekshirilgandan keyin
TOIFALAR (3-misol): faktlar 160, hisob 100, format 100, xavfsizlik 40
har toifa alohida hisobot qilinadi - o'rtacha zaif joyni yashiradi
OLTIN TESTLAR: hech qachon yiqilmasligi kerak bo'lgan kichik to'plam
(masalan, maxfiy ma'lumotni rad etish) - "o'rtacha" bilan emas, bittalab
VERSIYALASH:
eval to'plamining barmoq izi: sha256(json.dumps(el, sort_keys=True))
3-misol: bitta element o'zgarsa, xesh butunlay o'zgaradi
natija = (model, prompt versiyasi, eval versiyasi, sozlamalar) - to'rttasi birga
turli eval versiyalaridagi sonlarni solishtirmangEval to'plami — kod kabi: toifalar, oltin testlar, versiya (xesh) va har natija yonida qaysi versiyada o'lchangani.
2.3. Avtomatik metrikalar noldan
NORMALLASHTIRISH: kichik harf, tinish belgilarini olib tashlash, bo'shliqlarni siqish
EXACT MATCH (EM) = normal(javob) == normal(etalon)
TOKEN F1: umumiy = |tokenlar(javob) ∩ tokenlar(etalon)| (takrorlar bilan)
P = umumiy / |javob|, R = umumiy / |etalon|, F1 = 2PR / (P + R)
BLEU (mashina tarjimasidan): n = 1..4 n-gram aniqligi (kesilgan), geometrik o'rtacha
x qisqalik jarimasi BP = exp(1 - |etalon| / |javob|), agar javob qisqa bo'lsa
(jumla darajasida +1 silliqlash - aks holda 4-gram yo'q bo'lsa 0)
ROUGE-L (xulosalashdan): eng uzun umumiy qism-ketma-ketlik (LCS) bo'yicha F
1-MISOL (210 javob, 7 tur, inson belgisi bilan):
tur inson EM token F1 BLEU
aynan 1 1.000 1.000 1.000
qisqa ("25 kun") 1 0.000 0.481 0.242
parafraz 1 0.000 0.270 0.209
xato_raqam 0 0.000 0.803 0.509 - noto'g'ri, lekin F1 eng yuqori
xato_qoshimcha 0 0.000 0.719 0.524
ROC AUC (inson belgisini ajratish): EM 0.625, token F1 0.425, BLEU 0.377
F1 va BLEU 0.5 dan past - ball TESKARI yo'nalishda ishlaydi
NIMA UCHUN:
n-gram metrikalar so'z o'xshashligini o'lchaydi, ma'no to'g'riligini emas
bitta raqam yoki "emas" so'zi ma'noni butunlay o'zgartiradi, ballni deyarli yo'q
to'g'ri parafraz boshqa so'zlarni ishlatadi -> past ball
QACHON FOYDALI:
javob shakli qat'iy (qisqa fakt - EM), yoki ko'p etalonli tarjima/xulosa,
va faqat trend kuzatish uchun, inson belgisi bilan tekshirilgandan keyinBLEU, ROUGE va token F1 — so'z o'xshashligi, to'g'rilik emas: 1-misolda noto'g'ri raqamli javob to'g'ri parafrazdan uch barobar yuqori F1 oldi.
2.4. Vazifaga xos tekshiruvlar
G'OYA: umumiy o'xshashlik o'rniga vazifaning o'zi nimani talab qilishini tekshirish
raqamli javob -> raqamlarni ajratib, etalon bilan solishtirish
strukturali -> JSON sxema, maydon qiymatlari (25.5-dars)
kod -> testlarni ishga tushirish
tasnif/tanlov -> javobni ruxsat etilgan qiymatlarga keltirish, keyin EM
rad etish -> "rad etdimi?" belgisi (qoida yoki hakam)
1-MISOL: raqam_mos AUC 0.833, aniqlik 0.857 (bazaviy "hammasi to'g'ri" 0.571)
LEKIN: "25 kun, lekin faqat rahbarlar uchun" - 30 / 30 holatda "to'g'ri" deb o'tdi
qat'iy tekshiruv o'zi tekshiradigan narsani ushlaydi, boshqasini - yo'q
-> bir necha tekshiruv (raqam + qo'shimcha da'vo yo'qligi) yoki hukm kerakVazifaga xos tekshiruv umumiy metrikadan ancha kuchli, lekin faqat o'zi mo'ljallangan xatoni ushlaydi — qolganini hakam yoki inson ko'rishi kerak.
2.5. LLM-as-judge va uning tarafkashliklari
G'OYA: kuchli LLM ga baholash mezonini berib, javobni baholatish
juftlik: "A va B dan qaysi biri savolga yaxshiroq javob beradi?"
shkala: "javobni 1-5 shkalada baholang: to'g'rilik, to'liqlik"
mezonli: "etalon: ... Javob etalon bilan mazmunan mosmi? ha/yo'q"
arzon, tez, ochiq javoblarda ishlaydi - lekin o'zi ham model
MA'LUM TARAFKASHLIKLAR (adabiyotda tasvirlangan):
pozitsiya - birinchi (yoki ikkinchi) ko'rsatilgan javobni afzal ko'rish
uzunlik - uzun, batafsil javobni "yaxshiroq" deb hisoblash
o'z-o'zini afzal ko'rish - hakam o'z oilasi modelining uslubini yoqtirishi
ishonchli ohang - xato, lekin ishonch bilan yozilgan javobga yuqori ball
tarafkashlik kattaligi model, prompt va vazifaga bog'liq -> O'Z TIZIMINGIZDA o'lchang
YUMSHATISH:
juftlikni ikki tartibda so'rash; kelishmasa - "teng"
etalon javob yoki aniq mezon (rubrika) berish
uzunlikni cheklash yoki normallashtirish, uslub belgilarini olib tashlash
hakamni baholanayotgan modeldan boshqa oiladan tanlash
eng muhimi: kichik inson belgili to'plamda hakamni tekshirish (2.6)LLM-hakam — o'lchov asbobi, uni ham kalibrlash kerak: pozitsiya, uzunlik va o'z uslubini afzal ko'rish kabi tarafkashliklar bo'lishi mumkin; ular sizning sozlamangizda bormi — o'lchab bilasiz.
2.6. Hakamni tekshirish: tartibni almashtirish va Cohen kappa
POZITSIYA TESTI:
har juftlikni (A, B) va (B, A) tartibda so'rash
P(birinchi tanlandi) ~ 0.5 bo'lishi kerak; 2*SE dan uzoq bo'lsa - tarafkashlik
izchillik: ikki tartibda bir xil hukm ulushi
UZUNLIK / USLUB TESTI:
inson "teng" degan juftliklarda: hakam uzunroq (yoki "Albatta!" li) javobni
qanchalik ko'p tanlaydi; betaraf hakamda ~0.5
COHEN KAPPA (inson bilan kelishuv):
kappa = (p_kuzatilgan - p_tasodifiy) / (1 - p_tasodifiy)
p_tasodifiy = sum_toifa P_inson(toifa) * P_hakam(toifa)
1 - to'liq kelishuv, 0 - tasodifiy darajada, < 0 - tasodifdan yomon
oddiy kelishuv foizi aldashi mumkin: toifalar nomutanosib bo'lsa tasodif ham yuqori
2-MISOL (STUB hakam, tarafkashliklar ataylab qo'yilgan, 240 juftlik):
birinchi o'rin tanlandi 0.627 (SE 0.022); ikki tartibda bir xil hukm 0.729
teng juftliklarda: uzunroq javob 0.731, "Albatta!" li javob 0.773
kappa: bitta tartib 0.221 -> ikki tartib 0.404 -> + uslub olib tashlangan 0.635Hakamni ikki tartibda so'rang va kichik inson belgili to'plamda Cohen kappa ni hisoblang — shundan keyingina uning sonlariga ishonish mumkin.
2.7. Bootstrap ishonch intervali va juftlashgan taqqoslash
BOOTSTRAP (11-qism):
eval elementlarini qaytarib tanlash bilan B = 2000 marta qayta namuna olish
har safar metrikani hisoblash -> 2.5 va 97.5 persentil = 95% CI
formulasiz ishlaydi: aniqlik, F1, kappa, median - istalgan metrika
JUFTLASHGAN (bir xil savollar, ikki versiya):
d_i = ball_v2(i) - ball_v1(i); elementlar bo'yicha bootstrap -> farq CI
savol qiyinligi ikki versiyada umumiy -> farqdan chiqib ketadi
3-misol: juftlashgan CI kengligi 0.100, juftlashmagan 0.128
SHOVQIN DARAJASI:
bir xil versiyani ikki marta ishga tushirish (T > 0 da) - farq qancha?
3-misol (STUB): v1 ikki yurish farqi -0.005
KERAKLI HAJM:
SE(farq) = sd(d) / sqrt(n) -> n ~ (2 * sd(d) / delta)^2
3-misol: 0.02 lik farqni sezish uchun ~2663 savol - 400 savol yetmaydi
KELISHMAGAN SAVOLLAR (McNemar g'oyasi):
faqat v1 to'g'ri 45, faqat v2 to'g'ri 62 - farq aynan shulardan kelib chiqadiIkki versiyani bir xil savollarda juftlashgan farq va bootstrap CI bilan solishtiring; farq CI si 0 ni o'z ichiga olsa — "yaxshilandi" deb bo'lmaydi.
2.8. Regressiya testlari va darvoza
REGRESSIYA TESTI: har o'zgarishda (prompt, model, RAG sozlamasi, kutubxona)
butun eval to'plami avtomatik ishga tushadi - xuddi unit testlar kabi (CI)
DARVOZA QOIDALARI (3-misol):
1. hech bir toifada sezilarli yomonlashish yo'q (farq CI si butunlay < 0)
2. oldingi versiyada o'tgan oltin testlar yiqilmagan
3. umumiy aniqlik sezilarli pasaymagan
birortasi buzilsa - O'TKAZILMAYDI, sabablari ro'yxat qilinadi
3-MISOL:
umumiy: v2 - v1 = +0.043, CI [-0.007, +0.092] - "yaxshiroq ko'rinadi"
xavfsizlik: -0.175, CI [-0.325, -0.050] - sezilarli YOMONLASHDI
oltin testlar: v1 8/10, v2 5/10 (v1 da o'tgan 3 tasi yiqildi)
-> darvoza o'tkazmaydi
MODEL YANGILANISHI: provayder modelni yangilasa ham xuddi shu jarayon;
model nomini aniq versiya bilan yozing (masalan, sanali nom)Har o'zgarish — regressiya testi: umumiy o'rtacha yaxshilanishi bir toifadagi jiddiy yomonlashishni yashirishi mumkin.
2.9. Oqib ketish (contamination)
MUAMMO: ochiq e'lon qilingan eval (benchmark) internetga tushadi ->
keyingi modellarning pretraining korpusiga kiradi -> model javobni "eslaydi"
natija: baho qobiliyatni emas, yodlashni o'lchaydi
4-MISOL (haqiqiy trigram model, o'rganib bo'lmaydigan faktlar "kod -> bo'lim"):
e'lon qilingan eval 0.400: oqqan qismi 1.000, toza qismi 0.133
yangi yopiq to'plam 0.092 (tasodifiy daraja 0.125)
ANIQLASH:
n-gram mosligi korpus bilan:
5-gram - faqat aynan nusxa (to'liqlik 0.446)
3-gram - hamma narsani belgilaydi (aniqlik 0.308)
3-gram, faqat noyob token (kod) bilan - aniqlik va to'liqlik 1.000
model ehtimoli: oqqan javoblarda log P -0.32, toza -3.61
(haqiqiy LLM larda bu signal ancha zaif va shovqinli)
yopiq to'plam: hech qayerda e'lon qilinmagan, xuddi shu taqsimotdagi yangi elementlar
HIMOYA:
ichki eval to'plamini ochiq joyga qo'ymang; kanareyka satri qo'shing
vaqti-vaqti bilan yangi elementlar bilan yangilang
o'z fine-tuning ma'lumotingizni eval bilan deduplikatsiya qiling (LLM fine-tuning darsi)E'lon qilingan eval o'rgatish ma'lumotiga oqishi mumkin: yopiq to'plam va n-gram/ehtimol tekshiruvlari oshirilgan bahoni aniqlaydi.
2.10. Tuzoqlar
Asosiy tuzoqlar: 10-20 ta savolni qo'lda ko'rib "yaxshilandi" deyish; BLEU/ROUGE ni to'g'rilik o'lchovi deb hisoblash; EM ni normallashtirishsiz ishlatish; LLM-hakamni inson belgilari bilan tekshirmasdan ishlatish; juftlikni bitta tartibda so'rash; yangi versiyani doim bir xil o'rinda ko'rsatish; hakam va baholanayotgan modelni bir oiladan tanlab, o'z-o'zini afzal ko'rishni tekshirmaslik; kelishuvni kappa o'rniga oddiy foiz bilan o'lchash; bir yurishdagi farqni shovqin darajasini bilmasdan talqin qilish; ikki versiyani turli savollarda solishtirish; faqat umumiy o'rtachaga qarab, toifa va oltin testlarni tekshirmaslik; eval to'plamini o'zgartirib, eski sonlar bilan solishtirish; ochiq benchmarkdagi yuqori ballni qobiliyat deb qabul qilish.
3. Tez ma'lumotnoma
import hashlib
import json
import os
import anthropic
import numpy as np
# eval versiyasi
versiya = hashlib.sha256(json.dumps(el, sort_keys=True).encode()).hexdigest()[:12]
# token F1
umumiy = sum((Counter(a) & Counter(b)).values())
f1 = 0.0 if umumiy == 0 else 2 * umumiy / (len(a) + len(b))
# bootstrap CI (juftlashgan farq)
d = ball_v2 - ball_v1
o = [d[rng.integers(0, n, n)].mean() for _ in range(2000)]
past, yuqori = np.percentile(o, [2.5, 97.5])
# Cohen kappa
po = np.mean(inson == hakam)
pe = sum(np.mean(inson == t) * np.mean(hakam == t) for t in toifalar)
kappa = (po - pe) / (1 - pe)
# LLM-hakam (haqiqiy API; kalit ANTHROPIC_API_KEY muhit o'zgaruvchisidan)
client = anthropic.Anthropic()
HAKAM = ("Siz baholovchisiz. Savol, etalon va ikki javob beriladi. Faqat to'g'rilikni "
"baholang; uzunlik va uslubga e'tibor bermang. Faqat 'A', 'B' yoki 'teng' yozing.")
def solishtir(savol, etalon, birinchi, ikkinchi):
r = client.messages.create(
model="claude-sonnet-5", max_tokens=5, system=HAKAM,
messages=[{"role": "user", "content":
f"Savol: {savol}\nEtalon: {etalon}\nA: {birinchi}\nB: {ikkinchi}"}])
return r.content[0].text.strip()
h1 = solishtir(s, e, j1, j2) # ikki tartib
h2 = solishtir(s, e, j2, j1)
hukm = "A" if (h1, h2) == ("A", "B") else "B" if (h1, h2) == ("B", "A") else "teng"LLM ni baholash xulosasi
eval to'plami: toifalar, oltin testlar, versiya (xesh)
qat'iy tekshiruv > vazifaga xos tekshiruv > n-gram metrika (faqat qo'shimcha)
LLM-hakam: ikki tartib, rubrika, inson bilan kappa
ikki versiya: bir xil savollar, juftlashgan bootstrap CI, shovqin darajasi
darvoza: toifalar + oltin testlar + umumiy
contamination: yopiq to'plam, n-gram va ehtimol tekshiruvi4. Batafsil misollar
Misollar real numpy/sklearn bilan (Python 3.14). 2- va 3-misollardagi hakam va model — STUB (deterministik soxta), haqiqiy LLM emas; baholash kodi esa haqiqiy LLM bilan aynan bir xil ishlaydi.
Misol 1 — Avtomatik metrikalar noldan va ularning cheklovlari
"""Avtomatik metrikalar noldan: exact match, token F1, BLEU, ROUGE-L va ularning cheklovlari."""
import math
import re
from collections import Counter
import numpy as np
from sklearn.metrics import roc_auc_score
BOLIMLAR = ["moliya", "marketing", "kadrlar", "axborot", "logistika", "savdo"]
# mavzu: (savol, etalon javob, parafraz, noto'g'ri - boshqa mazmun, qisqa javob)
MAVZULAR = [
("{b} bo'limida yillik ta'til necha kun?", "Yillik ta'til {n} kun.",
"Xodimlar har yili {n} kunlik dam olish oladi.", "Yillik ta'til berilmaydi.", "{n} kun"),
("{b} bo'limida parol kamida necha belgi?", "Parol kamida {n} belgidan iborat.",
"Maxfiy kod uzunligi {n} ta belgidan kam bo'lmasligi kerak.", "Parol talab qilinmaydi.", "{n} belgi"),
("{b} bo'limida noutbuk necha yilda almashtiriladi?", "Noutbuk har {n} yilda almashtiriladi.",
"Kompyuter {n} yil o'tgach yangisiga o'zgartiriladi.", "Noutbuk almashtirilmaydi.", "{n} yil"),
("{b} bo'limida tushlik uchun qancha beriladi?", "Tushlik uchun {n} ming so'm beriladi.",
"Ovqatga har kuni {n} ming so'm kompensatsiya to'lanadi.", "Tushlik puli berilmaydi.", "{n} ming so'm"),
("{b} bo'limida haftada necha soat masofaviy ishlash mumkin?",
"Haftada {n} soat masofaviy ishlash mumkin.",
"Uydan ishlashga har haftada {n} soatgacha ruxsat bor.", "Masofaviy ish taqiqlangan.", "{n} soat"),
]
TURLAR = ["aynan", "qisqa", "parafraz", "uzun", "xato_raqam", "xato_mazmun", "xato_qoshimcha"]
TOGRI = {"aynan": 1, "qisqa": 1, "parafraz": 1, "uzun": 1, # inson belgisi (1 - to'g'ri)
"xato_raqam": 0, "xato_mazmun": 0, "xato_qoshimcha": 0}
def eval_toplam(seed=0):
rng = np.random.default_rng(seed)
elementlar = []
for sav, etalon, parafraz, xato, qisqa in MAVZULAR:
for b in BOLIMLAR:
n = int(rng.integers(3, 30))
n2 = n + int(rng.choice([-2, -1, 1, 2]))
et = etalon.format(n=n)
nomzod = {
"aynan": et,
"qisqa": qisqa.format(n=n),
"parafraz": parafraz.format(n=n),
"uzun": f"Qoidaga ko'ra {b} bo'limida: {et[0].lower() + et[1:-1]}, bu "
f"barcha xodimlarga tegishli va rahbar tasdiqlaydi.",
"xato_raqam": etalon.format(n=n2),
"xato_mazmun": xato,
"xato_qoshimcha": et[:-1] + ", lekin faqat rahbarlar uchun.",
}
for t in TURLAR:
elementlar.append({"savol": sav.format(b=b.capitalize()), "etalon": et,
"javob": nomzod[t], "tur": t, "inson": TOGRI[t]})
return elementlar
def normal(matn):
return re.sub(r"\s+", " ", re.sub(r"[^\w' ]", " ", matn.lower())).strip()
def exact_match(j, e):
return float(normal(j) == normal(e))
def token_f1(j, e):
a, b = normal(j).split(), normal(e).split()
umumiy = sum((Counter(a) & Counter(b)).values())
if umumiy == 0:
return 0.0
p, r = umumiy / len(a), umumiy / len(b)
return 2 * p * r / (p + r)
def bleu(j, e, n_max=4):
"""Jumla BLEU: kesilgan n-gram aniqligi (n = 1..4, +1 silliqlash) x qisqalik jarimasi."""
a, b = normal(j).split(), normal(e).split()
logp = 0.0
for n in range(1, n_max + 1):
ga = Counter(tuple(a[i:i + n]) for i in range(len(a) - n + 1))
gb = Counter(tuple(b[i:i + n]) for i in range(len(b) - n + 1))
mos = sum((ga & gb).values())
logp += math.log((mos + 1) / (max(sum(ga.values()), 0) + 1)) / n_max
bp = 1.0 if len(a) > len(b) else math.exp(1 - len(b) / max(len(a), 1))
return bp * math.exp(logp)
def rouge_l(j, e):
a, b = normal(j).split(), normal(e).split()
d = np.zeros((len(a) + 1, len(b) + 1), dtype=int)
for i in range(len(a)):
for k in range(len(b)):
d[i + 1, k + 1] = d[i, k] + 1 if a[i] == b[k] else max(d[i, k + 1], d[i + 1, k])
lcs = d[-1, -1]
if lcs == 0:
return 0.0
p, r = lcs / len(a), lcs / len(b)
return 2 * p * r / (p + r)
def raqam_mos(j, e):
"""Vazifaga xos tekshiruv: javobdagi raqamlar etalondagiga tengmi."""
return float(re.findall(r"\d+", j) == re.findall(r"\d+", e) and bool(re.findall(r"\d+", j)))
METRIKALAR = {"EM": exact_match, "token F1": token_f1, "BLEU": bleu,
"ROUGE-L": rouge_l, "raqam_mos": raqam_mos}
def main() -> None:
print("=== 1. Bitta savol, yetti javob (etalon: birinchisi) ===")
el = eval_toplam()
for x in el[:len(TURLAR)]:
ball = " ".join(f"{f(x['javob'], x['etalon']):.2f}" for f in METRIKALAR.values())
print(f" [{x['tur']:<14}] inson {x['inson']} EM/F1/BLEU/RL/raqam {ball}")
print(f" {x['javob']}")
print(f" savol: {el[0]['savol']}")
print(f"\n=== 2. {len(el)} javob: tur bo'yicha o'rtacha ball ===")
print(" tur inson " + "".join(f"{n:>10}" for n in METRIKALAR))
tur = np.array([x["tur"] for x in el])
ball = {n: np.array([f(x["javob"], x["etalon"]) for x in el]) for n, f in METRIKALAR.items()}
for t in TURLAR:
m = tur == t
print(f" {t:<15} {TOGRI[t]:>5} " + "".join(f"{ball[n][m].mean():>10.3f}" for n in METRIKALAR))
print("\n=== 3. Metrika inson belgisini qanchalik ajratadi (ROC AUC) ===")
inson = np.array([x["inson"] for x in el])
auc = {n: roc_auc_score(inson, v) for n, v in ball.items()}
for n, a in auc.items():
togri, xato = ball[n][inson == 1].mean(), ball[n][inson == 0].mean()
print(f" {n:<10} AUC {a:.3f} o'rtacha: to'g'ri {togri:.3f}, noto'g'ri {xato:.3f}")
f1 = ball["token F1"]
xr, pf = f1[tur == "xato_raqam"].mean(), f1[tur == "parafraz"].mean()
print(f" token F1: noto'g'ri raqam {xr:.3f} > to'g'ri parafraz {pf:.3f}: {xr > pf}")
print("\n=== 4. Umumiy metrikalar va vazifaga xos tekshiruv ===")
print(f" bazaviy: doim 'to'g'ri' deyish - aniqlik {inson.mean():.3f}")
for n in ("EM", "token F1", "ROUGE-L"):
chegaralar = np.unique(ball[n])
aniqlik = max(((ball[n] >= c) == inson).mean() for c in chegaralar)
print(f" {n:<9} eng yaxshi chegara bilan aniqlik {aniqlik:.3f}")
print(f" raqam_mos aniqligi {((ball['raqam_mos'] >= 0.5) == inson).mean():.3f}")
xq = tur == "xato_qoshimcha"
print(f" raqam_mos 'xato_qoshimcha' ni to'g'ri deb o'tkazdi: {int(ball['raqam_mos'][xq].sum())} / {xq.sum()}")
eng = max(auc, key=auc.get)
print(f" eng yaxshi ajratuvchi: {eng} (AUC {auc[eng]:.3f})")
print(" ⭐ Umumiy n-gram metrikalar - so'z o'xshashligi, to'g'rilik emas; vazifaga xos tekshiruv yozing")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. Bitta savol, yetti javob (etalon: birinchisi) ===
[aynan ] inson 1 EM/F1/BLEU/RL/raqam 1.00 1.00 1.00 1.00 1.00
Yillik ta'til 25 kun.
[qisqa ] inson 1 EM/F1/BLEU/RL/raqam 0.00 0.67 0.37 0.67 1.00
25 kun
[parafraz ] inson 1 EM/F1/BLEU/RL/raqam 0.00 0.17 0.16 0.17 1.00
Xodimlar har yili 25 kunlik dam olish oladi.
[uzun ] inson 1 EM/F1/BLEU/RL/raqam 0.00 0.42 0.23 0.42 1.00
Qoidaga ko'ra moliya bo'limida: yillik ta'til 25 kun, bu barcha xodimlarga tegishli va rahbar tasdiqlaydi.
[xato_raqam ] inson 0 EM/F1/BLEU/RL/raqam 0.00 0.75 0.51 0.75 0.00
Yillik ta'til 26 kun.
[xato_mazmun ] inson 0 EM/F1/BLEU/RL/raqam 0.00 0.57 0.51 0.57 0.00
Yillik ta'til berilmaydi.
[xato_qoshimcha] inson 0 EM/F1/BLEU/RL/raqam 0.00 0.67 0.45 0.67 1.00
Yillik ta'til 25 kun, lekin faqat rahbarlar uchun.
savol: Moliya bo'limida yillik ta'til necha kun?
=== 2. 210 javob: tur bo'yicha o'rtacha ball ===
tur inson EM token F1 BLEU ROUGE-L raqam_mos
aynan 1 1.000 1.000 1.000 1.000 1.000
qisqa 1 0.000 0.481 0.242 0.481 1.000
parafraz 1 0.000 0.270 0.209 0.270 1.000
uzun 1 0.000 0.483 0.289 0.483 1.000
xato_raqam 0 0.000 0.803 0.509 0.803 0.000
xato_mazmun 0 0.000 0.310 0.269 0.310 0.000
xato_qoshimcha 0 0.000 0.719 0.524 0.719 1.000
=== 3. Metrika inson belgisini qanchalik ajratadi (ROC AUC) ===
EM AUC 0.625 o'rtacha: to'g'ri 0.250, noto'g'ri 0.000
token F1 AUC 0.425 o'rtacha: to'g'ri 0.559, noto'g'ri 0.611
BLEU AUC 0.377 o'rtacha: to'g'ri 0.435, noto'g'ri 0.434
ROUGE-L AUC 0.425 o'rtacha: to'g'ri 0.559, noto'g'ri 0.611
raqam_mos AUC 0.833 o'rtacha: to'g'ri 1.000, noto'g'ri 0.333
token F1: noto'g'ri raqam 0.803 > to'g'ri parafraz 0.270: True
=== 4. Umumiy metrikalar va vazifaga xos tekshiruv ===
bazaviy: doim 'to'g'ri' deyish - aniqlik 0.571
EM eng yaxshi chegara bilan aniqlik 0.571
token F1 eng yaxshi chegara bilan aniqlik 0.600
ROUGE-L eng yaxshi chegara bilan aniqlik 0.600
raqam_mos aniqligi 0.857
raqam_mos 'xato_qoshimcha' ni to'g'ri deb o'tkazdi: 30 / 30
eng yaxshi ajratuvchi: raqam_mos (AUC 0.833)
⭐ Umumiy n-gram metrikalar - so'z o'xshashligi, to'g'rilik emas; vazifaga xos tekshiruv yozingNima ko'rsatdi: eval to'plami 30 ta savoldan (5 mavzu x 6 bo'lim) va har savolga 7 turdagi javobdan iborat — jami 210 javob, har biriga inson belgisi (to'g'ri/noto'g'ri) javob turidan beriladi. 1-bo'limdagi bitta savol hammasini ko'rsatadi: to'g'ri parafraz (Xodimlar har yili 25 kunlik dam olish oladi.) token F1 0.17 va BLEU 0.16 oldi, noto'g'ri Yillik ta'til 26 kun. esa F1 0.75, BLEU 0.51. 2-bo'limda o'rtachalar: EM faqat aynan javobni taniydi (qolgan hamma to'g'ri javoblarda 0.000); token F1 noto'g'ri raqamli javobga 0.803, to'g'ri parafrazga 0.270 berdi. 3-bo'limdagi AUC bu metrikalar bu to'plamda inson belgisini umuman ajrata olmasligini ko'rsatadi: token F1 va ROUGE-L 0.425, BLEU 0.377 — 0.5 dan past, ya'ni o'rtacha hisobda noto'g'ri javoblarga yuqoriroq ball berildi (noto'g'ri 0.611, to'g'ri 0.559). ROUGE-L va token F1 bu yerda deyarli bir xil, chunki qisqa javoblarda so'z tartibi kam farq qiladi. 4-bo'lim: eng yaxshi chegara tanlanganda ham (bu hatto optimistik — chegara shu ma'lumotda tanlangan) token F1 aniqligi 0.600, bazaviy "hammasi to'g'ri" esa 0.571. Vazifaga xos raqam_mos ancha kuchli (AUC 0.833, aniqlik 0.857), lekin u raqami to'g'ri, ammo yolg'on qo'shimcha da'voli javoblarni (..., lekin faqat rahbarlar uchun.) 30 tadan 30 tasida "to'g'ri" deb o'tkazdi. Bu to'plamdagi xato turlarini biz o'zimiz qurganimiz uchun aniq sonlar shu tuzilishga bog'liq; lekin yo'nalish — n-gram o'xshashlik to'g'rilikni o'lchamasligi — umumiy. Bog'liq bo'limlar: 2.3, 2.4.
Misol 2 — LLM-as-judge tarafkashliklarini aniqlash
"""LLM-as-judge tarafkashliklarini aniqlash: STUB hakam, tartibni almashtirish, Cohen kappa."""
import zlib
import numpy as np
from sklearn.metrics import cohen_kappa_score
BOLIMLAR = ["moliya", "marketing", "kadrlar", "axborot", "logistika", "savdo"]
MAVZULAR = [
("{b} bo'limida yillik ta'til necha kun?", "Yillik ta'til {n} kun.", "{n} kun"),
("{b} bo'limida parol kamida necha belgi?", "Parol kamida {n} belgidan iborat.", "{n} belgi"),
("{b} bo'limida noutbuk necha yilda almashtiriladi?", "Noutbuk har {n} yilda almashtiriladi.",
"{n} yil"),
("{b} bo'limida tushlik uchun qancha beriladi?", "Tushlik uchun {n} ming so'm beriladi.",
"{n} ming so'm"),
]
def javob(shablon, qisqa, n, togri, uzun, rng):
son = n if togri else n + int(rng.choice([-3, -1, 2, 4]))
asosiy = shablon.format(n=son) if rng.random() < 0.5 else qisqa.format(n=son) + "."
if uzun:
asosiy += (" Bu qoida barcha xodimlarga tegishli, kadrlar xizmati tomonidan tasdiqlangan "
"va har yili qayta ko'rib chiqiladi.")
return asosiy
def juftliklar(n=240, seed=0):
"""A modeli javoblari "Albatta!" bilan boshlanadi (hakam bilan bir oila deb faraz qilamiz)."""
rng = np.random.default_rng(seed)
out = []
for i in range(n):
sav, shablon, qisqa = MAVZULAR[i % len(MAVZULAR)]
b = BOLIMLAR[(i // len(MAVZULAR)) % len(BOLIMLAR)]
son = int(rng.integers(3, 30))
ta, tb = rng.random() < 0.6, rng.random() < 0.6
a = "Albatta! " + javob(shablon, qisqa, son, ta, rng.random() < 0.4, rng)
bb = javob(shablon, qisqa, son, tb, rng.random() < 0.4, rng)
inson = "A" if ta > tb else "B" if tb > ta else "teng"
out.append({"savol": sav.format(b=b.capitalize()), "A": a, "B": bb,
"togri": {"A": ta, "B": tb}, "inson": inson})
return out
class SoxtaHakam:
"""STUB - haqiqiy LLM emas. Ataylab uch tarafkashlik bilan qurilgan deterministik hakam:
birinchi o'rin (+0.6), uzunlik (+0.06 har so'z), o'z oilasi uslubi (+0.8)."""
def __init__(self, togri_javoblar, pozitsiya=0.6, uzunlik=0.06, oila=0.8, shovqin=0.5):
self.togri = togri_javoblar
self.p, self.u, self.o, self.s = pozitsiya, uzunlik, oila, shovqin
def _ball(self, savol, j, orin):
urug = zlib.crc32(f"{savol}|{j}|{orin}".encode())
e = np.random.default_rng(urug).normal(0, self.s)
return (2.0 * self.togri(savol, j) + self.u * len(j.split())
+ self.o * j.startswith("Albatta") + (self.p if orin == 0 else 0.0) + e)
def solishtir(self, savol, birinchi, ikkinchi):
"""Qaysi javob yaxshi: 'birinchi' yoki 'ikkinchi' (xuddi LLM hakam prompti kabi)."""
return ("birinchi" if self._ball(savol, birinchi, 0) >= self._ball(savol, ikkinchi, 1)
else "ikkinchi")
def kappa(a, b):
"""Cohen kappa noldan: (kuzatilgan kelishuv - tasodifiy kelishuv) / (1 - tasodifiy)."""
toifalar = sorted(set(a) | set(b))
a, b = np.array(a), np.array(b)
po = (a == b).mean()
pe = sum((a == t).mean() * (b == t).mean() for t in toifalar)
return (po - pe) / (1 - pe)
def main() -> None:
jf = juftliklar()
togri_lugat = {(x["savol"], x[k].removeprefix("Albatta! ")): float(x["togri"][k])
for x in jf for k in ("A", "B")}
hakam = SoxtaHakam(lambda s, j: togri_lugat[(s, j.removeprefix("Albatta! "))])
print("=== 1. Ma'lumot va STUB hakam ===")
inson = [x["inson"] for x in jf]
print(f" juftliklar {len(jf)}; inson: A {inson.count('A')}, B {inson.count('B')}, "
f"teng {inson.count('teng')}")
print(f" namuna A: {jf[0]['A']}")
print(f" namuna B: {jf[0]['B']}")
print(" hakam - STUB: tarafkashliklar ataylab qo'yilgan; maqsad - ularni ANIQLASH usuli")
ab = [hakam.solishtir(x["savol"], x["A"], x["B"]) for x in jf] # A birinchi
ba = [hakam.solishtir(x["savol"], x["B"], x["A"]) for x in jf] # B birinchi
xom = ["A" if v == "birinchi" else "B" for v in ab]
teskari = ["B" if v == "birinchi" else "A" for v in ba]
print("\n=== 2. Pozitsiya tarafkashligi: tartibni almashtirish ===")
birinchi = np.mean([v == "birinchi" for v in ab + ba])
izchil = np.mean([x == y for x, y in zip(xom, teskari)])
n2 = 2 * len(jf)
se = np.sqrt(birinchi * (1 - birinchi) / n2)
print(f" birinchi o'rindagi javob tanlandi: {birinchi:.3f} (SE {se:.3f}); kutilgan 0.5")
print(f" ikki tartibda bir xil hukm: {izchil:.3f}")
if abs(birinchi - 0.5) > 2 * se:
print(" -> pozitsiya tarafkashligi aniqlandi")
print("\n=== 3. Uzunlik va o'z oilasini afzal ko'rish (inson 'teng' degan juftliklarda) ===")
teng = [i for i, x in enumerate(jf) if x["inson"] == "teng"]
uzunroq, oila = [], []
for i in teng: # har juftlik - ikki tartib hukmining o'rtachasi
la, lb = len(jf[i]["A"].split()), len(jf[i]["B"].split())
if abs(la - lb) >= 5:
uzun = "A" if la > lb else "B"
uzunroq.append(((xom[i] == uzun) + (teskari[i] == uzun)) / 2)
else:
oila.append(((xom[i] == "A") + (teskari[i] == "A")) / 2)
for nom, v in (("uzunroq javob tanlandi", uzunroq), ("A (Albatta) tanlandi, uzunlik yaqin", oila)):
v = np.array(v, float)
se = v.std(ddof=1) / np.sqrt(len(v))
print(f" {nom:<36} {v.mean():.3f} (SE {se:.3f}, n={len(v)}) -> "
f"{'tarafkashlik' if abs(v.mean() - 0.5) > 2 * se else 'aniqlanmadi'}")
a_hakam = np.mean([h == "A" for h in xom + teskari])
a_inson = np.mean([x["togri"]["A"] for x in jf]) - np.mean([x["togri"]["B"] for x in jf])
print(f" hakam bo'yicha A yutug'i {a_hakam:.3f}; inson bo'yicha to'g'rilik farqi A - B {a_inson:+.3f}")
print("\n=== 4. Inson bilan kelishuv: Cohen kappa (noldan va sklearn) ===")
birlashgan = [a if a == b else "teng" for a, b in zip(xom, teskari)]
toza = []
for x in jf:
a0 = x["A"].removeprefix("Albatta! ") # uslub belgisini olib tashlash
h1 = hakam.solishtir(x["savol"], a0, x["B"])
h2 = hakam.solishtir(x["savol"], x["B"], a0)
v1, v2 = ("A" if h1 == "birinchi" else "B"), ("B" if h2 == "birinchi" else "A")
toza.append(v1 if v1 == v2 else "teng")
for nom, h in (("bitta tartib (xom)", xom), ("ikki tartib, kelishmasa 'teng'", birlashgan),
("+ 'Albatta!' olib tashlangan", toza)):
k1, k2 = kappa(inson, h), cohen_kappa_score(inson, h)
kel = np.mean([a == b for a, b in zip(inson, h)])
print(f" {nom:<32} kelishuv {kel:.3f}, kappa {k1:.3f} (sklearn {k2:.3f})")
print(" ⭐ Hakamni ham baholang: tartibni almashtiring va inson belgilari bilan kappa hisoblang")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. Ma'lumot va STUB hakam ===
juftliklar 240; inson: A 59, B 65, teng 116
namuna A: Albatta! 25 kun. Bu qoida barcha xodimlarga tegishli, kadrlar xizmati tomonidan tasdiqlangan va har yili qayta ko'rib chiqiladi.
namuna B: 25 kun.
hakam - STUB: tarafkashliklar ataylab qo'yilgan; maqsad - ularni ANIQLASH usuli
=== 2. Pozitsiya tarafkashligi: tartibni almashtirish ===
birinchi o'rindagi javob tanlandi: 0.627 (SE 0.022); kutilgan 0.5
ikki tartibda bir xil hukm: 0.729
-> pozitsiya tarafkashligi aniqlandi
=== 3. Uzunlik va o'z oilasini afzal ko'rish (inson 'teng' degan juftliklarda) ===
uzunroq javob tanlandi 0.731 (SE 0.048, n=52) -> tarafkashlik
A (Albatta) tanlandi, uzunlik yaqin 0.773 (SE 0.033, n=64) -> tarafkashlik
hakam bo'yicha A yutug'i 0.673; inson bo'yicha to'g'rilik farqi A - B -0.025
=== 4. Inson bilan kelishuv: Cohen kappa (noldan va sklearn) ===
bitta tartib (xom) kelishuv 0.417, kappa 0.221 (sklearn 0.221)
ikki tartib, kelishmasa 'teng' kelishuv 0.592, kappa 0.404 (sklearn 0.404)
+ 'Albatta!' olib tashlangan kelishuv 0.758, kappa 0.635 (sklearn 0.635)
⭐ Hakamni ham baholang: tartibni almashtiring va inson belgilari bilan kappa hisoblangNima ko'rsatdi: bu misoldagi hakam — STUB: unga ataylab uch tarafkashlik qo'yilgan (birinchi o'ringa +0.6, har so'zga +0.06, "Albatta!" uslubiga +0.8) va urug'li shovqin qo'shilgan. Biz hakam ichiga qaramasdan, faqat uning hukmlaridan bu tarafkashliklarni topa olamizmi — shuni tekshirdik. 240 juftlikda inson belgilari: A 59, B 65, teng 116. 2-bo'lim: har juftlik ikki tartibda so'ralganda birinchi o'rindagi javob 0.627 holatda tanlandi (SE 0.022 — 0.5 dan 5 SE dan ko'p uzoq), hukmlar ikki tartibda faqat 0.729 holatda bir xil chiqdi. 3-bo'lim: inson "teng" degan juftliklarda hakam uzunroq javobni 0.731 (SE 0.048), uzunliklar yaqin bo'lganda esa "Albatta!" bilan boshlanadigan javobni 0.773 (SE 0.033) holatda tanladi — ikkalasi ham tarafkashlik sifatida aniqlandi. Natijada hakam bo'yicha A modeli 0.673 holatda yutadi, inson belgilari bo'yicha esa A ning to'g'riligi B dan biroz past (-0.025) — kirishdagi "real vaziyat" aynan shu. 4-bo'lim: Cohen kappa noldan va sklearn bilan bir xil chiqdi. Bitta tartibdagi xom hakam — kappa 0.221; ikki tartib (kelishmasa "teng") — 0.404; uslub belgisi olib tashlangandan keyin — 0.635. Uzunlik tarafkashligi hali ham qolgan — uni tuzatish uchun uzunlikni cheklash yoki rubrika kerak. Muhim: bu sonlar haqiqiy LLM ning tarafkashligi haqida hech narsa demaydi; ular faqat aniqlash usullari (tartibni almashtirish, "teng" juftliklarda tahlil, kappa) ishlashini ko'rsatadi. Haqiqiy hakamda xuddi shu kodni 100-200 inson belgili juftlikda ishga tushiring. Bog'liq bo'limlar: 2.5, 2.6.
Misol 3 — Ikki prompt versiyasi: bootstrap, juftlashgan taqqoslash va regressiya darvozasi
"""Ikki prompt versiyasi: eval versiyasi, bootstrap CI, juftlashgan taqqoslash va regressiya darvozasi."""
import hashlib
import json
import numpy as np
TOIFALAR = {"faktlar": 160, "hisob": 100, "format": 100, "xavfsizlik": 40}
# STUB "model" mahorati: har prompt versiyasi va toifa uchun (logit shkalada)
MAHORAT = {
"v1": {"faktlar": 1.2, "hisob": 0.3, "format": 1.0, "xavfsizlik": 2.5},
"v2": {"faktlar": 1.5, "hisob": 0.6, "format": 1.3, "xavfsizlik": 1.2},
}
def eval_toplam(seed=0):
rng = np.random.default_rng(seed)
el = []
for t, n in TOIFALAR.items():
for i in range(n):
el.append({"id": f"{t}-{i:03d}", "toifa": t, "qiyinlik": round(float(rng.normal(0, 2)), 3),
"oltin": bool(t == "xavfsizlik" and i < 10)})
return el
def versiya(el):
"""Eval to'plamining barmoq izi: tarkib o'zgarsa - xesh o'zgaradi."""
return hashlib.sha256(json.dumps(el, sort_keys=True).encode()).hexdigest()[:12]
def soxta_natija(el, v, urug=0):
"""STUB: haqiqiy LLM emas. P(to'g'ri) = sigmoid(mahorat - qiyinlik); deterministik urug'."""
out = []
for x in el:
p = 1 / (1 + np.exp(-(MAHORAT[v][x["toifa"]] - x["qiyinlik"])))
u = int(hashlib.sha256(f"{x['id']}|{v}|{urug}".encode()).hexdigest()[:8], 16) / 16 ** 8
out.append(float(u < p))
return np.array(out)
def bootstrap_ci(qiymat, rng, B=2000):
n = len(qiymat)
o = np.array([qiymat[rng.integers(0, n, n)].mean() for _ in range(B)])
return np.percentile(o, [2.5, 97.5])
def main() -> None:
print("=== 1. Eval to'plami va uning versiyasi ===")
el = eval_toplam()
print(f" elementlar {len(el)}: " + ", ".join(f"{t} {n}" for t, n in TOIFALAR.items()))
print(f" versiya (sha256[:12]): {versiya(el)}")
el2 = [dict(x) for x in el]
el2[5]["qiyinlik"] += 0.001
print(f" bitta elementni o'zgartirsak: {versiya(el2)} - natijalar endi taqqoslanmaydi")
print(f" oltin (majburiy) testlar: {sum(x['oltin'] for x in el)} ta xavfsizlik savoli")
print("\n=== 2. Aniqlik va bootstrap 95% CI (STUB model, ikki prompt) ===")
rng = np.random.default_rng(0)
a, b = soxta_natija(el, "v1"), soxta_natija(el, "v2")
a2 = soxta_natija(el, "v1", urug=1)
for nom, v in (("v1", a), ("v2", b), ("v1 qayta (boshqa urug')", a2)):
lo, hi = bootstrap_ci(v, rng)
print(f" {nom:<24} {v.mean():.3f} CI [{lo:.3f}, {hi:.3f}]")
print(f" v1 ning ikki yurishi farqi: {a2.mean() - a.mean():+.3f} - bu shovqin darajasi")
print("\n=== 3. v2 - v1: juftlashgan va juftlashmagan ===")
n = len(el)
d = b - a
juft = np.array([d[rng.integers(0, n, n)].mean() for _ in range(2000)])
mustaqil = np.array([b[rng.integers(0, n, n)].mean() - a[rng.integers(0, n, n)].mean()
for _ in range(2000)])
for nom, o in (("juftlashgan (bir xil savollar)", juft), ("juftlashmagan", mustaqil)):
lo, hi = np.percentile(o, [2.5, 97.5])
print(f" {nom:<31} farq {d.mean():+.3f} CI [{lo:+.3f}, {hi:+.3f}] kenglik {hi - lo:.3f}")
faqat_a, faqat_b = int(((a == 1) & (b == 0)).sum()), int(((a == 0) & (b == 1)).sum())
print(f" kelishmagan savollar: faqat v1 to'g'ri {faqat_a}, faqat v2 to'g'ri {faqat_b}")
sd = d.std(ddof=1)
print(f" 0.02 lik farqni 2*SE bilan sezish uchun kerak: ~{int((2 * sd / 0.02) ** 2)} savol")
print("\n=== 4. Toifalar bo'yicha va regressiya darvozasi ===")
toifa = np.array([x["toifa"] for x in el])
sabablar = []
lo_umumiy = np.percentile(juft, 2.5)
for t in TOIFALAR:
m = np.where(toifa == t)[0]
o = np.array([d[rng.choice(m, len(m))].mean() for _ in range(2000)])
lo, hi = np.percentile(o, [2.5, 97.5])
belgi = "YOMONLASHDI" if hi < 0 else "yaxshilandi" if lo > 0 else "farq aniq emas"
print(f" {t:<11} v1 {a[m].mean():.3f} v2 {b[m].mean():.3f} farq {d[m].mean():+.3f} "
f"CI [{lo:+.3f}, {hi:+.3f}] {belgi}")
if hi < 0:
sabablar.append(f"{t} sezilarli yomonlashdi")
oltin = np.array([x["oltin"] for x in el])
yiqilgan = int((oltin & (a == 1) & (b == 0)).sum())
if yiqilgan:
sabablar.append(f"v1 da o'tgan {yiqilgan} ta oltin test v2 da yiqildi")
if lo_umumiy < -0.01:
sabablar.append("umumiy aniqlik pastga ketgan bo'lishi mumkin")
print(f" oltin testlar: v1 {int(a[oltin].sum())}/{oltin.sum()}, v2 {int(b[oltin].sum())}/{oltin.sum()}")
print(f" DARVOZA: {'O`TKAZILMAYDI' if sabablar else 'o`tkaziladi'}".replace("`", "'"))
for s in sabablar:
print(f" - {s}")
print(" ⭐ Umumiy +farq regressiyani yashirishi mumkin: toifa va oltin testlarni alohida tekshiring")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. Eval to'plami va uning versiyasi ===
elementlar 400: faktlar 160, hisob 100, format 100, xavfsizlik 40
versiya (sha256[:12]): 11c20c16b5f5
bitta elementni o'zgartirsak: b6fe43d822db - natijalar endi taqqoslanmaydi
oltin (majburiy) testlar: 10 ta xavfsizlik savoli
=== 2. Aniqlik va bootstrap 95% CI (STUB model, ikki prompt) ===
v1 0.665 CI [0.620, 0.713]
v2 0.708 CI [0.662, 0.752]
v1 qayta (boshqa urug') 0.660 CI [0.615, 0.708]
v1 ning ikki yurishi farqi: -0.005 - bu shovqin darajasi
=== 3. v2 - v1: juftlashgan va juftlashmagan ===
juftlashgan (bir xil savollar) farq +0.043 CI [-0.007, +0.092] kenglik 0.100
juftlashmagan farq +0.043 CI [-0.022, +0.105] kenglik 0.128
kelishmagan savollar: faqat v1 to'g'ri 45, faqat v2 to'g'ri 62
0.02 lik farqni 2*SE bilan sezish uchun kerak: ~2663 savol
=== 4. Toifalar bo'yicha va regressiya darvozasi ===
faktlar v1 0.675 v2 0.725 farq +0.050 CI [-0.031, +0.131] farq aniq emas
hisob v1 0.540 v2 0.640 farq +0.100 CI [+0.000, +0.200] farq aniq emas
format v1 0.670 v2 0.730 farq +0.060 CI [-0.040, +0.150] farq aniq emas
xavfsizlik v1 0.925 v2 0.750 farq -0.175 CI [-0.325, -0.050] YOMONLASHDI
oltin testlar: v1 8/10, v2 5/10
DARVOZA: O'TKAZILMAYDI
- xavfsizlik sezilarli yomonlashdi
- v1 da o'tgan 3 ta oltin test v2 da yiqildi
⭐ Umumiy +farq regressiyani yashirishi mumkin: toifa va oltin testlarni alohida tekshiringNima ko'rsatdi: "model" — STUB: har element uchun to'g'ri javob ehtimoli sigmoid(mahorat - qiyinlik) va deterministik xesh-urug'. v2 prompt faktlar, hisob va formatda mahoratni oshiradi, xavfsizlikda esa ataylab pasaytiradi — biz bu regressiyani darvoza ushlaydimi, shuni tekshiramiz. 1-bo'lim: 400 elementli to'plamning barmoq izi 11c20c16b5f5; bitta element qiyinligini 0.001 ga o'zgartirsak — butunlay boshqa xesh. 2-bo'lim: v1 0.665 (CI [0.620, 0.713]), v2 0.708 (CI [0.662, 0.752]) — intervallar kuchli ustma-ust tushadi; v1 ni boshqa urug' bilan qayta ishlatish 0.660 berdi — bir yurishdan ikkinchisiga -0.005 lik shovqin. 3-bo'lim: farq +0.043; juftlashgan bootstrap CI [-0.007, +0.092] (kenglik 0.100) juftlashmagandan (0.128) tor, lekin baribir 0 ni o'z ichiga oladi — bu hajmda "v2 umuman yaxshiroq" deb bo'lmaydi. Farq 107 ta kelishmagan savoldan keladi (faqat v1 to'g'ri 45, faqat v2 to'g'ri 62). 0.02 lik farqni sezish uchun ~2663 savol kerak bo'lardi. 4-bo'lim eng muhim: toifalar bo'yicha faktlar, hisob va formatda farq musbat, lekin CI 0 ni qamraydi; xavfsizlikda esa -0.175, CI [-0.325, -0.050] — sezilarli yomonlashish. Oltin testlarda v1 da o'tgan 3 ta test v2 da yiqildi (v1 8/10, v2 5/10). Darvoza ikki sabab bilan o'tkazmadi. Umumiy o'rtacha (+0.043) esa buni butunlay yashirardi. Bog'liq bo'limlar: 2.2, 2.7, 2.8.
Misol 4 — Oqib ketish: oshirilgan baho va uni aniqlash
"""Eval to'plamining oqib ketishi (contamination): n-gram til modeli, oshirilgan baho va aniqlash."""
from collections import Counter
import numpy as np
from sklearn.metrics import roc_auc_score
BOLIMLAR = ["moliya", "marketing", "kadrlar", "axborot", "logistika", "savdo", "yuridik",
"omborxona"]
UMUMIY = ["{b} bo'limi xodimlari ertalab soat to'qqizda ishni boshlaydi.",
"{b} bo'limida yig'ilish har dushanba o'tkaziladi.",
"yangi xodim {b} bo'limiga qabul qilindi.",
"{b} bo'limi hisobotni oy oxirida topshiradi."]
def kod(rng):
return f"{''.join(rng.choice(list('ABCDEFGHKLMNPRST'), 2))}-{int(rng.integers(1000, 9999))}"
def malumot(seed=0, n_eval=240, oqish=0.3):
rng = np.random.default_rng(seed)
faktlar = [(kod(rng), str(rng.choice(BOLIMLAR))) for _ in range(n_eval + 120)]
eval_el, yangi = faktlar[:n_eval], faktlar[n_eval:] # yangi - hech qayerda e'lon qilinmagan
korpus = [s.format(b=rng.choice(BOLIMLAR)) for s in UMUMIY for _ in range(600)]
for _ in range(3000): # boshqa hujjatlar haqida faktlar
korpus.append(f"{kod(rng)} hujjati {rng.choice(BOLIMLAR)} bo'limiga tegishli.")
oqqan = rng.random(n_eval) < oqish
shakl = rng.random(n_eval) < 0.5 # True - aynan, False - boshqa shaklda
for (k, b), o, sh in zip(eval_el, oqqan, shakl):
if o: # eval forumda muhokama qilingan
korpus += ([f"{k} hujjati {b} bo'limiga tegishli."] if sh else
[f"{k} hujjati {b} bo'limi tomonidan yuritiladi deb eshitdim."]) * 2
rng.shuffle(korpus)
return eval_el, yangi, korpus, oqqan, shakl
class Trigram:
"""So'z trigram modeli, chiziqli interpolyatsiya (0.7, 0.2, 0.1) - haqiqiy, o'rgatiladigan model."""
def __init__(self, jumlalar):
self.c1, self.c2, self.c3 = Counter(), Counter(), Counter()
self.k1, self.k2 = Counter(), Counter()
for j in jumlalar:
t = ["<s>", "<s>"] + j.lower().split()
for i in range(2, len(t)):
self.c1[t[i]] += 1
self.c2[(t[i - 1], t[i])] += 1
self.k1[t[i - 1]] += 1
self.c3[(t[i - 2], t[i - 1], t[i])] += 1
self.k2[(t[i - 2], t[i - 1])] += 1
self.n = sum(self.c1.values())
def p(self, w2, w1, w):
p1 = (self.c1[w] + 1) / (self.n + len(self.c1) + 1)
p2 = self.c2[(w1, w)] / self.k1[w1] if self.k1[w1] else 0.0
p3 = self.c3[(w2, w1, w)] / self.k2[(w2, w1)] if self.k2[(w2, w1)] else 0.0
return 0.7 * p3 + 0.2 * p2 + 0.1 * p1
def javob(self, k):
"""Prompt '<kod> hujjati' -> keyingi so'z sifatida eng ehtimolli bo'lim."""
return max(BOLIMLAR, key=lambda b: self.p(k.lower(), "hujjati", b))
def main() -> None:
eval_el, yangi, korpus, oqqan, shakl = malumot()
model = Trigram(korpus)
print("=== 1. Ma'lumot: eval to'plamining bir qismi o'rgatish korpusiga oqqan ===")
print(f" eval {len(eval_el)} fakt ('<kod> hujjati qaysi bo'limga tegishli?'), korpus {len(korpus)} jumla")
print(f" oqqan: {oqqan.sum()} ta ({oqqan.mean():.0%}); aynan shaklda {int((oqqan & shakl).sum())}, "
f"boshqa shaklda {int((oqqan & ~shakl).sum())}")
print(f" model: so'z trigram, lug'at {len(model.c1)} so'z; tasodifiy daraja 1/8 = 0.125")
print("\n=== 2. Oshirilgan baho ===")
togri = np.array([model.javob(k) == b for k, b in eval_el])
yangi_t = np.array([model.javob(k) == b for k, b in yangi])
print(f" e'lon qilingan eval: {togri.mean():.3f}")
print(f" oqqan qismi {togri[oqqan].mean():.3f}, toza qismi {togri[~oqqan].mean():.3f}")
print(f" yangi yopiq to'plam (120 fakt): {yangi_t.mean():.3f}")
se = np.sqrt(togri.var(ddof=1) / len(togri) + yangi_t.var(ddof=1) / len(yangi_t))
f = togri.mean() - yangi_t.mean()
print(f" e'lon qilingan - yopiq = {f:+.3f} (SE {se:.3f}) -> "
f"{'oqish belgisi' if f > 2 * se else 'farq sezilarli emas'}")
print("\n=== 3. Aniqlash 1: n-gram mosligi korpus bilan ===")
korpus_ng = {n: set() for n in (3, 5)}
for j in korpus:
t = j.lower().split()
for n in korpus_ng:
korpus_ng[n].update(tuple(t[i:i + n]) for i in range(len(t) - n + 1))
for n, faqat_kod in ((5, False), (3, False), (3, True)):
topildi = []
for k, b in eval_el:
t = f"{k} hujjati {b} bo'limiga tegishli.".lower().split()
ng = [tuple(t[i:i + n]) for i in range(len(t) - n + 1)]
if faqat_kod: # faqat noyob token (kod) bor n-gramlar
ng = [g for g in ng if k.lower() in g]
topildi.append(any(g in korpus_ng[n] for g in ng))
topildi = np.array(topildi)
tp = (topildi & oqqan).sum()
nom = f"{n}-gram" + (" (kod bilan)" if faqat_kod else "")
print(f" {nom:<19} belgilandi {topildi.sum():>3}, aniqlik {tp / max(topildi.sum(), 1):.3f}, "
f"to'liqlik {tp / oqqan.sum():.3f} (aynan {topildi[oqqan & shakl].mean():.2f}, "
f"boshqa shakl {topildi[oqqan & ~shakl].mean():.2f})")
print(" uzun n-gram faqat aynan nusxani topadi; qisqa n-gram - noyob token bilan cheklansa")
print("\n=== 4. Aniqlash 2: model ehtimoli (a'zolik belgisi) ===")
lp = np.array([np.log(model.p(k.lower(), "hujjati", b)) for k, b in eval_el])
print(f" log P(javob | prompt): oqqan {lp[oqqan].mean():.2f}, toza {lp[~oqqan].mean():.2f}")
print(f" ROC AUC (oqqanmi?): {roc_auc_score(oqqan, lp):.3f}")
halol = togri[~oqqan].mean()
toza = togri[~oqqan]
se2 = np.sqrt(toza.var(ddof=1) / len(toza) + yangi_t.var(ddof=1) / len(yangi_t))
yaqin = abs(halol - yangi_t.mean()) <= 2 * se2
print(f" tozalangan baho (oqqanlar chiqarilgan): {halol:.3f}; yopiq to'plam {yangi_t.mean():.3f}; "
f"farq {halol - yangi_t.mean():+.3f} (SE {se2:.3f}) -> {'mos' if yaqin else 'mos emas'}")
print(" ⭐ E'lon qilingan eval o'rgatish ma'lumotiga oqishi mumkin: yopiq to'plam va tekshiruvlar kerak")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. Ma'lumot: eval to'plamining bir qismi o'rgatish korpusiga oqqan ===
eval 240 fakt ('<kod> hujjati qaysi bo'limga tegishli?'), korpus 5548 jumla
oqqan: 74 ta (31%); aynan shaklda 33, boshqa shaklda 41
model: so'z trigram, lug'at 3107 so'z; tasodifiy daraja 1/8 = 0.125
=== 2. Oshirilgan baho ===
e'lon qilingan eval: 0.400
oqqan qismi 1.000, toza qismi 0.133
yangi yopiq to'plam (120 fakt): 0.092
e'lon qilingan - yopiq = +0.308 (SE 0.041) -> oqish belgisi
=== 3. Aniqlash 1: n-gram mosligi korpus bilan ===
5-gram belgilandi 33, aniqlik 1.000, to'liqlik 0.446 (aynan 1.00, boshqa shakl 0.00)
3-gram belgilandi 240, aniqlik 0.308, to'liqlik 1.000 (aynan 1.00, boshqa shakl 1.00)
3-gram (kod bilan) belgilandi 74, aniqlik 1.000, to'liqlik 1.000 (aynan 1.00, boshqa shakl 1.00)
uzun n-gram faqat aynan nusxani topadi; qisqa n-gram - noyob token bilan cheklansa
=== 4. Aniqlash 2: model ehtimoli (a'zolik belgisi) ===
log P(javob | prompt): oqqan -0.32, toza -3.61
ROC AUC (oqqanmi?): 1.000
tozalangan baho (oqqanlar chiqarilgan): 0.133; yopiq to'plam 0.092; farq +0.041 (SE 0.037) -> mos
⭐ E'lon qilingan eval o'rgatish ma'lumotiga oqishi mumkin: yopiq to'plam va tekshiruvlar kerakNima ko'rsatdi: vazifa ataylab o'rganib bo'lmaydigan qilib qurilgan: har hujjat kodi tasodifiy bo'limga tegishli, shuning uchun halol model faqat tasodifiy darajada (1/8) javob bera oladi. Korpusga eval faktlarining 74 tasi (31%) "forumdan" oqqan: 33 tasi aynan shaklda, 41 tasi boshqa so'zlar bilan. Haqiqiy trigram model e'lon qilingan eval da 0.400 oldi — oqqan qismida 1.000, toza qismida 0.133; hech qayerda e'lon qilinmagan yangi yopiq to'plamda esa 0.092. Farq +0.308 (SE 0.041) — oqish belgisi. 3-bo'lim — n-gram mosligi: 5-gram faqat aynan nusxalarni topdi (to'liqlik 0.446, boshqa shakldagilarni 0.00); oddiy 3-gram umumiy ibora ("hujjati moliya bo'limiga") tufayli barcha 240 elementni belgiladi (aniqlik 0.308); faqat noyob token (kod) qatnashgan 3-gramlar esa 74 tasini ham, xatosiz topdi. 4-bo'lim — model ehtimoli: oqqan javoblarda o'rtacha log P -0.32, tozalarida -3.61, AUC 1.000. Bu yerda ajratish mukammal, chunki trigram model yodlagan faktni to'liq eslaydi; katta LLM larda bunday ehtimol signali ancha zaif. Oqqanlar chiqarilgandan keyingi baho (0.133) yopiq to'plamga (0.092) statistik mos. Bog'liq bo'lim: 2.9.
5. To'g'ri va noto'g'ri tushunishlar
| Noto'g'ri fikr | To'g'risi |
|---|---|
| "BLEU/ROUGE yuqori — javob to'g'ri" | 1-misolda noto'g'ri raqamli javob F1 0.803, to'g'ri parafraz 0.270 |
| "EM — eng ishonchli metrika" | Faqat aynan shaklni taniydi; to'g'ri qisqa va parafraz javoblarda 0.000 |
| "Vazifaga xos tekshiruv hammasini ushlaydi" | raqam_mos yolg'on qo'shimcha da'voni 30/30 o'tkazdi |
| "LLM-hakam — betaraf" | U ham model; tarafkashlikni o'lchang (2-misol usullari) |
| "Kelishuv 60% — yaxshi" | Kappa bilan tasodifni hisobga oling |
| "v2 aniqligi yuqori — v2 yaxshi" | 3-misolda +0.043, lekin CI [-0.007, +0.092] |
| "Umumiy yaxshilandi — ishga tushiramiz" | Xavfsizlikda -0.175, sezilarli; oltin testlar yiqildi |
| "Ochiq benchmarkdagi ball — qobiliyat" | 4-misolda e'lon qilingan 0.400, yopiq 0.092 |
| "Uzun n-gram mosligi oqishni to'liq topadi" | Boshqa shakldagi oqishni topmadi (to'liqlik 0.446) |
6. Keng tarqalgan xatolar va yechimlari
1. Normallashtirishsiz EM
togri = javob == etalon # ⚠️ "25 kun." != "25 kun"
togri = normal(javob) == normal(etalon) # ✅2. Hakamdan bitta tartibda so'rash
hukm = hakam(savol, yangi, eski) # ⚠️ yangi doim birinchi
h1, h2 = hakam(savol, yangi, eski), hakam(savol, eski, yangi) # ✅ ikki tartib3. Kelishuvni foizda o'lchash
kelishuv = np.mean(inson == hakam) # ⚠️ tasodifni hisobga olmaydi
kappa = cohen_kappa_score(inson, hakam) # ✅4. Juftlashmagan taqqoslash
farq = b[rng.integers(0, n, n)].mean() - a[rng.integers(0, n, n)].mean() # ⚠️
idx = rng.integers(0, n, n); farq = (b[idx] - a[idx]).mean() # ✅ bir xil savollar5. Faqat umumiy o'rtacha
if b.mean() > a.mean(): ishga_tushir() # ⚠️
if not sabablar(toifalar, oltin_testlar, umumiy_ci): ishga_tushir() # ✅ darvoza6. Versiyasiz natijalar
natija = {"model": "v2", "aniqlik": 0.708} # ⚠️
natija = {"model": "v2", "eval": versiya(el), "aniqlik": 0.708} # ✅7. Ochiq eval ni tekshirmasdan ishonish
print("aniqlik", baho(ochiq_benchmark)) # ⚠️
print(baho(ochiq_benchmark), baho(yopiq_toplam)) # ✅ + n-gram tekshiruvi7. Integratsiya — bu bilim qayerda kerak bo'ladi
- 11-qism (o'tilgan): bootstrap, ishonch intervallari, gipoteza testlari
- 18-qism (o'tilgan): juftlashgan taqqoslash, SE, oqib ketish va test to'plamini qulflash
- 25.5-dars (o'tilgan): strukturali chiqish — JSON sxema ham qat'iy tekshiruv; 25.9 — retrieval baholash (RAG ning birinchi qavati)
- Keyingi darslar: LLM fine-tuning — fine-tuning qilingan modelni aynan shu usullar bilan baholash va o'rgatish ma'lumotini eval bilan deduplikatsiya qilish; Agentlar va tool calling — ko'p qadamli vazifalarni baholash; LLM xavfsizligi — xavfsizlik eval to'plamlari; MLOps va deploy qismida — regressiya testlarini CI ga ulash
8. Eng yaxshi amaliyotlar
Eval to'plamini toifalar, oltin testlar va versiya (xesh) bilan yarating; har topilgan xatoni unga qo'shing.
Imkon bo'lgan joyda qat'iy va vazifaga xos tekshiruv ishlating; n-gram metrikalar — faqat qo'shimcha signal.
LLM-hakamni kichik inson belgili to'plamda Cohen kappa bilan tekshiring.
Juftlikni ikki tartibda so'rang; rubrika va etalon bering; uslub va uzunlik ta'sirini o'lchang.
Ikki versiyani bir xil savollarda juftlashgan bootstrap CI bilan solishtiring; shovqin darajasini biling.
Har o'zgarishda regressiya testini ishga tushiring: toifalar, oltin testlar, umumiy.
Eval to'plamini ochiq joyga qo'ymang; yopiq to'plam saqlang va oqishni tekshiring.
Har natija yonida model, prompt, eval versiyasi va sozlamalarni yozing.
9. Amaliy topshiriq
Vazifa 1: Bashorat qiling
1. # etalon "Yillik ta'til 25 kun.", javob "25 kun": EM va token F1?
2. # nega "26 kun" javobi F1 da to'g'ri parafrazdan yuqori ball oladi?
3. # AUC 0.5 dan past bo'lsa, metrika haqida nima deydi?
4. # BLEU dagi qisqalik jarimasi nima uchun kerak?
5. # hakam ikki tartibda 73% holatda bir xil hukm bersa - nimani bildiradi?
6. # kelishuv 0.6, tasodifiy kelishuv 0.4 - kappa?
7. # juftlashgan CI nega juftlashmagandan tor?
8. # farq CI si [-0.007, +0.092] - xulosa?
9. # 0.02 lik farqni sezish uchun kerakli savol soni formulasi?
10. # nega oltin testlar o'rtachaga qo'shilmay, alohida tekshiriladi?
11. # 5-gram mosligi oqishning qaysi turini topa olmaydi?
12. # e'lon qilingan eval 0.40, yopiq to'plam 0.09 - nima bo'lgan?Javoblar
- EM 0; F1: umumiy 2 token ("25", "kun"), P = 2/2, R = 2/4 → F1 = 0.667
- U etalon bilan deyarli barcha tokenlarni baham ko'radi — faqat bitta raqam farq qiladi
- Ball to'g'ri javoblarni emas, ko'proq noto'g'rilarini yuqori baholaydi — to'g'rilikni o'lchamaydi
- Juda qisqa javob (bir-ikki to'g'ri so'z) yuqori n-gram aniqlik olmasligi uchun
- 27% holatda hukm faqat tartibga bog'liq — pozitsiya tarafkashligi yoki noaniqlik
- (0.6 - 0.4) / (1 - 0.4) = 0.333
- Savol qiyinligi ikki versiyada umumiy — farqda qisqaradi
- 0 intervalga kiradi — yaxshilanish statistik jihatdan tasdiqlanmadi
- n ≈ (2 · sd(d) / 0.02)^2
- Ular kritik: bitta yiqilish ham qabul qilinmaydi, o'rtacha esa uni yashiradi
- Boshqa so'zlar bilan qayta yozilgan (parafraz qilingan) oqishni
- Eval o'rgatish ma'lumotiga oqqan — model javoblarni yodlagan
Vazifa 2: Xatolarni tuzating
1. em = np.mean([j == e for j, e in zip(javoblar, etalonlar)])
2. yutuq = np.mean([hakam(s, yangi[i], eski[i]) == "A" for i, s in enumerate(savollar)])
print("yangi yaxshi" if yutuq > 0.5 else "eski yaxshi")
3. print("hakam ishonchli" if np.mean(inson == hakam) > 0.6 else "yo'q")
4. if b.mean() > a.mean():
print("v2 ni ishga tushiramiz")
5. natijalar_jadvali.append({"prompt": "v3", "aniqlik": b.mean()})Javoblar
1. em = np.mean([normal(j) == normal(e) for j, e in zip(javoblar, etalonlar)])
2. h = []
for i, s in enumerate(savollar): # ikki tartib
h1 = hakam(s, yangi[i], eski[i]) # "A" = yangi
h2 = hakam(s, eski[i], yangi[i]) # "B" = yangi
h.append(1.0 if (h1, h2) == ("A", "B") else 0.0 if (h1, h2) == ("B", "A") else 0.5)
# + inson belgili kichik to'plamda kappa, bootstrap CI
3. print(f"kappa {cohen_kappa_score(inson, hakam):.3f}")
4. d = b - a
o = [d[rng.integers(0, n, n)].mean() for _ in range(2000)]
past = np.percentile(o, 2.5)
# + toifalar bo'yicha CI va oltin testlar (darvoza)
5. natijalar_jadvali.append({"prompt": "v3", "model": model_nomi,
"eval": versiya(el), "aniqlik": b.mean()})Vazifa 3: Metrikalar
Modellang:
- Normallashtirish, EM, token F1
- BLEU (n = 1..4, BP) va ROUGE-L noldan
- Javob turlari bo'yicha o'rtacha va AUC
- Vazifaga xos tekshiruv va uning ko'r nuqtasi
Vazifa 4: Hakam
Modellang:
- Juftliklar va inson belgilari
- Ikki tartibda so'rash, izchillik
- "Teng" juftliklarda uzunlik va uslub tahlili
- Cohen kappa noldan, sklearn bilan tekshirish
Vazifa 5: Versiyalarni solishtirish
Modellang:
- Eval xeshi
- Bootstrap CI va shovqin darajasi
- Juftlashgan va juftlashmagan CI
- Toifalar va oltin testlar bilan darvoza
Vazifa 6: Oqib ketish
Modellang:
- Korpusga eval ning bir qismini aynan va boshqa shaklda qo'shish
- E'lon qilingan va yopiq to'plam bahosi
- N-gram mosligi (uzun, qisqa, noyob tokenli)
- Ehtimol bo'yicha a'zolik belgisi
Vazifa 7: O'ylash
Mahsulot menejeri aytdi: "Yangi promptni LLM-hakam bilan eski promptga qarshi 200 ta savolda sinadik — yangisi 64% holatda yutdi. Hakam juda kuchli model, unga ishonsak bo'ladi. Ertaga ishga tushiramiz." Siz nima deysiz?
Javob
Qisqa javob: 64% — umid beruvchi signal, lekin ishga tushirish uchun yetarli dalil emas. Uchta savolga javob kerak: hakam betarafmi, farq shovqindan kattami va biror toifada yomonlashish yo'qmi.
1. Hakamni tekshirish. Yangi javoblar qaysi o'rinda ko'rsatilgan? Agar doim bir tomonda bo'lsa, pozitsiya tarafkashligi natijani sun'iy oshirishi mumkin — 2-misoldagi STUB hakamda birinchi o'rin 0.627 holatda tanlandi. Yangi prompt javoblarni uzunroq qildimi? Uzunlik tarafkashligi bo'lsa, "yutuq" uzunlikdan kelishi mumkin. 50-100 juftlikni inson belgilab, kappa hisoblash kerak.
2. Statistika. 200 juftlikda 64% ning bootstrap CI sini hisoblang; bir xil promptni ikki marta sinab, shovqin darajasini biling.
3. Toifalar va oltin testlar. 3-misolda umumiy farq +0.043 bo'lsa ham xavfsizlikda -0.175 edi. Xavfsizlik va boshqa kritik toifalar alohida tekshirilishi kerak.
4. Hakam va model oilasi. Agar yangi prompt hakam bilan bir oiladagi modelning uslubiga yaqinlashtirsa, o'z-o'zini afzal ko'rish ham rol o'ynashi mumkin.
Tavsiya:
# 1. har juftlik ikki tartibda; kelishmasa - "teng"
# 2. 100 juftlikda inson belgilari -> kappa; uzunlik va uslub ta'siri
# 3. bootstrap CI (juftlashgan), shovqin darajasi
# 4. toifalar va oltin testlar bilan darvoza; natijani eval versiyasi bilan yozishMenejerga javob: "Natija yaxshi ko'rinadi, lekin hakamni ikki tartibda qayta ishga tushiraylik va 100 ta juftlikni o'zimiz belgilab tekshiraylik. Xavfsizlik savollarini alohida ko'ramiz. Hammasi joyida bo'lsa, ertaga emas, indinga ishga tushiramiz — bir kunlik tekshiruv bir oylik muammodan arzon."
Nimani mustahkamlaydi: 2.3, 2.5, 2.6, 2.7, 2.8, 2.9-bo'limlar.
Xulosa
Bu darsda avtomatik metrikalarni noldan yozib, cheklovlarini o'lchadik, LLM-hakam tarafkashliklarini aniqlash usullarini ko'rdik, ikki prompt versiyasini juftlashgan bootstrap bilan solishtirib regressiya darvozasini qurdik va eval to'plamining oqib ketishini aniqladik.
Eng muhim uch fikr:
N-gram metrikalar so'z o'xshashligini o'lchaydi, to'g'rilikni emas. 1-misolda token F1 noto'g'ri raqamli javobga
0.803, to'g'ri parafrazga0.270berdi; AUC token F10.425, BLEU0.377— tasodifdan ham yomon. Vazifaga xosraqam_mosancha kuchli (AUC0.833), lekin yolg'on qo'shimcha da'volarni 30/30 o'tkazdi — qat'iy tekshiruv o'zi mo'ljallangan xatonigina ushlaydi.LLM-hakam — o'lchov asbobi, uni ham tekshirish kerak. 2-misoldagi STUB hakamda (tarafkashliklar ataylab qo'yilgan) tartibni almashtirish pozitsiya tarafkashligini (
0.627,SE 0.022), "teng" juftliklar tahlili uzunlik (0.731) va uslub (0.773) tarafkashligini aniqladi. Inson bilan kappa0.221dan ikki tartib bilan0.404ga, uslub belgisini olib tashlab0.635ga ko'tarildi. Haqiqiy hakamda aynan shu kod ishlatiladi.Ikki versiya — juftlashgan CI, toifalar va oltin testlar bilan; eval — yopiq va versiyali. 3-misolda umumiy farq
+0.043(CI[-0.007, +0.092]) "yaxshiroq ko'rindi", lekin xavfsizlikda-0.175sezilarli yomonlashish va 3 ta yiqilgan oltin test darvozani yopdi. 4-misolda oqqan eval haqiqiy trigram modelga0.400berdi, yopiq to'plam esa0.092— noyob tokenli n-gram tekshiruvi 74 ta oqishning hammasini topdi.
Keyingi darsda LLM fine-tuning: qachon fine-tuning, qachon prompt yoki RAG; SFT ma'lumoti formati, prompt tokenlarini niqoblash, LoRA va to'liq fine-tuning, katastrofik unutish va ma'lumot sifati — o'zimiz o'rgatgan kichik GPT da.
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!