Birinchi modellar: pilot4b dan tez5 gacha
To'rtta model, bitta sozlama
18-bobda Qwen3.5-4B tanlandi. Bu bobda u bilan o'qitilgan birinchi to'rtta model: pilot4b, tez3, tez4 va tez5. Ularning hammasi bir xil Soup sozlamasi bilan o'qitilgan — farq faqat ma'lumotda. Bu tasodif emas: sozlama o'zgarmasa, natijadagi farqni ma'lumotga bog'lash mumkin.
Har bir model haqida saqlangan narsalar — training fayli va training logi — ~/tez_runs papkasida.
Ulardan jadval yasaymiz:
import json import re import pandas as pd def log_qiymatlari(model): log = (Path.home() / f"tez_runs/{model}/train.log").read_text(encoding="utf-8", errors="replace").replace("\r", "\n") yoqotish = re.findall(r"'eval_loss': '([0-9.]+)'", log) vaqt = re.findall(r"'train_runtime': '([0-9.]+)'", log) return float(yoqotish[-1]) if yoqotish else "yozilmagan", round(float(vaqt[-1]) / 3600, 1) if vaqt else "yozilmagan" qatorlar = [] for model in ("pilot4b", "tez3", "tez4", "tez5"): soni = sum(1 for _ in open(Path.home() / f"tez_runs/{model}/data/train.jsonl", encoding="utf-8")) yoqotish, soat = log_qiymatlari(model) qatorlar.append({"model": model, "o'qitish qatorlari": soni, "oxirgi eval_loss": yoqotish, "o'qitish, soat": soat}) show(pd.DataFrame(qatorlar)) sozlamalar = {m: (Path.home() / f"tez_runs/{m}/soup.yaml").read_text(encoding="utf-8") for m in ("pilot4b", "tez3", "tez4", "tez5")} print("to'rtala sozlama bir xilmi:", len(set(sozlamalar.values())) == 1)
to'rtala sozlama bir xilmi: True
| model | o'qitish qatorlari | oxirgi eval_loss | o'qitish, soat |
|---|---|---|---|
| pilot4b | 1 610 | 0.063 | 1 |
| tez3 | 5 274 | 0.025 | yozilmagan |
| tez4 | 5 466 | 0.033 | yozilmagan |
| tez5 | 5 466 | 0.032 | yozilmagan |
Uchta logda training vaqti yozilmagan — Soup ning o'sha versiyasi uni har doim ham chiqarmagan. Va bir narsa allaqachon ko'rinib turibdi: eval_loss (tekshirish qismidagi xato) tez3 dan keyin kamaymaydi, hatto biroz oshadi. Bu yomon belgimi? Keyinroq ko'ramiz.
Test: 200 savol
Bu bosqichda Tez to'rtta "toza" test to'plamiga ega edi: tranzaksiyalar va kreditlar (40 tadan), depozitlar va kassa (60 tadan). Kassa jadvali trainingda umuman bo'lmagan. Har bir model shu 200 savolda sinalgan; o'qitilmagan Qwen3.5-4B ham. Saqlangan hukmlar:
TOPLAMLAR = ("transactions", "loans", "deposits", "cash_desk") def natija(prefiks): jami = {} for toplam in TOPLAMLAR: javoblar = [json.loads(q) for q in open(TEZ / f"results/{prefiks}_{toplam}.jsonl", encoding="utf-8")] jami[toplam] = sum(j["correct"] for j in javoblar) jami["jami (200)"] = sum(jami.values()) return jami jadval = pd.DataFrame({izoh: natija(p) for p, izoh in (("ab_A", "o'qitilmagan 4B"), ("pilot4b", "pilot4b"), ("tez3", "tez3"), ("tez4", "tez4"), ("tez5", "tez5"))}).T show(jadval.reset_index().rename(columns={"index": "model"}))
| model | transactions | loans | deposits | cash_desk | jami (200) |
|---|---|---|---|---|---|
| o'qitilmagan 4B | 35 | 37 | 42 | 50 | 164 |
| pilot4b | 31 | 34 | 39 | 34 | 138 |
| tez3 | 39 | 38 | 51 | 55 | 183 |
| tez4 | 37 | 37 | 50 | 59 | 183 |
| tez5 | 38 | 37 | 53 | 55 | 183 |
Ikki narsa darhol ko'rinadi. Birinchisi — yomon: pilot4b o'qitilmagan modeldan yomonroq. Ikkinchisi — g'alati: tez3, tez4 va tez5 — uchalasi ham aynan 183.
Bu hukmlar o'sha paytdagi engine bilan chiqarilgan. Keyinchalik engine va grammar o'zgargan (9-bob), shuning uchun bu jadvalni keyingi boblardagi raqamlar bilan to'g'ridan-to'g'ri solishtirib bo'lmaydi. Lekin bu to'rtta model o'zaro — bir xil sharoitda.
pilot4b: training modelni yomonlashtirdi
Birinchi o'qitilgan model o'qitilmaganidan 26 savolga yomonroq chiqdi. Eng yomoni — kassa jadvalida, ya'ni train qilishda ko'rilmagan jadvalda.
Sabab o'sha kuni topildi va 12-bobdagi "dangasa o'qituvchi" bilan bog'liq: birinchi partiyada so'rovlarning ko'pchiligida xom ustun nomlari bor edi — "summa_uzs bo'yicha jamla". Model foydalanuvchi so'rovidagi so'zni ustun nomi sifatida ko'chirishni o'rgandi. Kassa jadvalida esa ustun nomlari boshqacha edi, va model noto'g'ri — matnli — ustunni tanlab, uni jamlashga urindi.
Har bir modelning training faylida nechta so'rov o'z jadvalining pastki chiziqli ustun nomini o'z ichiga olishini sanaymiz:
ustun = re.compile(r"^- (.+?) \(\w+\), (?:all values|samples): ", re.M) def xom_nom_ulushi(model): jami = topildi = 0 for qator in open(Path.home() / f"tez_runs/{model}/data/train.jsonl", encoding="utf-8"): q = json.loads(qator) nomlar = [n for n in ustun.findall(q["messages"][0]["content"]) if "_" in n] sorov = [m for m in q["messages"] if m["role"] == "user"][-1]["content"].lower() jami += 1 topildi += any(re.search(rf"(?<!\w){re.escape(n.lower())}(?!\w)", sorov) for n in nomlar) return topildi, jami for model in ("run1", "pilot4b", "tez3", "tez4", "tez5"): topildi, jami = xom_nom_ulushi(model) print(f"{model:8s} {topildi:5,} / {jami:,} = {topildi / jami:.0%}")
run1 887 / 1,638 = 54% pilot4b 884 / 1,610 = 55% tez3 267 / 5,274 = 5% tez4 339 / 5,466 = 6% tez5 339 / 5,466 = 6%
pilot4b ning so'rovlarining yarmidan ko'pida xom ustun nomi bor. O'sha kuni yozilgan hisobotda bu ulush "75 foiz" deb aytilgan — u boshqacha sanash bilan olingan edi; yuqoridagi son aniq qoida bilan: so'rovda shu qatorning o'z jadvalidagi pastki chiziqli nom bormi. Qaysi sanash bo'lmasin, xulosa bir xil.
Tuzatish ikki qismli edi: 12-bobdagi leaked tekshiruvi (xom nomli matn qayta yoziladi yoki tashlanadi)
va 15-bobdagi sarlavhalarni qayta nomlash (model bitta jadvalni har xil nomlar bilan ko'radi va nomni
ko'chirish o'rniga ma'noni tushunishga majbur bo'ladi). tez3 da ulush yigirmadan birga tushdi — nol emas:
ba'zi so'rovlar ustun nomini qiymat sifatida haqli ravishda ishlatadi.
tez3: birinchi yaxshi model
tez3 — 5 274 qator, uch baravardan ko'p ma'lumot, xom nomlarsiz va qayta nomlangan sarlavhalar bilan. Natija: 200 dan 183, o'qitilmagan modeldan 19 savol yaxshi. Kassa — trainingda ko'rilmagan jadval — 55 dan 60.
Qolgan 17 xatoning sababi tahlil qilindi, va asosiy topilma 14-bobdagi tekshiruv bilan bog'liq edi: o'sha paytda training ma'lumotini Gemma tekshirardi va faqat Gemma tushungan matnlar qolardi. Gemma xato tushunadigan, lekin to'g'ri matnlar tashlanardi — va aynan o'sha holatlar modelning zaif joylari bo'lib qoldi. Shundan keyin "qutqarish" bosqichi qo'shildi (14-bob).
tez4 va tez5: bir xil ball, har xil savollar
tez4 tez3 ning aniq xatolarini nishonga oldi: suhbatda "boshidan boshla" ("on": "table") uchun 149 ta
aniq qator, noaniq davom so'rovlari uchun 92 ta savol qatori, allaqachon jamlangan natija ustida grafik
uchun 146 qator, va filtr qiymatlari faqat jadvaldagi ro'yxatdan. tez5 esa suhbatdagi "on" maydonini
javobning boshiga qo'ydi.
Ikkalasi ham — 183. Lekin bir xil 183 mi? Uchta modelning javoblarini savolma-savol solishtiramiz:
def hukmlar(prefiks): return {(toplam, j["id"]): j["correct"] for toplam in TOPLAMLAR for j in map(json.loads, open(TEZ / f"results/{prefiks}_{toplam}.jsonl", encoding="utf-8"))} t3, t4, t5 = hukmlar("tez3"), hukmlar("tez4"), hukmlar("tez5") for nom, oldin, keyin in (("tez3 -> tez4", t3, t4), ("tez4 -> tez5", t4, t5), ("tez3 -> tez5", t3, t5)): tuzaldi = sum(1 for k in oldin if not oldin[k] and keyin[k]) buzildi = sum(1 for k in oldin if oldin[k] and not keyin[k]) print(f"{nom}: tuzaldi {tuzaldi}, buzildi {buzildi}, ball {sum(oldin.values())} -> {sum(keyin.values())}") uchalasi_togri = sum(1 for k in t3 if t3[k] and t4[k] and t5[k]) kamida_bittasi_xato = sum(1 for k in t3 if not (t3[k] and t4[k] and t5[k])) print(f"uchala model ham to'g'ri topgan savollar: {uchalasi_togri}, kamida bittasi xato qilgan: {kamida_bittasi_xato}")
tez3 -> tez4: tuzaldi 6, buzildi 6, ball 183 -> 183 tez4 -> tez5: tuzaldi 5, buzildi 5, ball 183 -> 183 tez3 -> tez5: tuzaldi 7, buzildi 7, ball 183 -> 183 uchala model ham to'g'ri topgan savollar: 173, kamida bittasi xato qilgan: 27
Har bir yangi model nishonga olingan xatolarni tuzatdi — va shuncha boshqa savolni buzdi. Ball joyida turdi, lekin javoblar almashdi.
Bu bobning eng muhim saboqi shu yerda: 200 savollik testda modellar orasida bir necha savollik "shovqin" bor. Har bir training tasodifiy son bilan boshlanadi, ma'lumot biroz farq qiladi, va chegarada turgan savollar u yoqqa ham, bu yoqqa ham og'adi. O'sha kuni yozilgan xulosa: bu test modellar orasidagi besh savollik farqni ajrata olmaydi.
Bu saboq keyinchalik ikki narsaga aylandi. Birinchi: training qatorlarining o'zida ma'lum turdagi holatlar qanchalik to'g'ri ekanini o'lchash (masalan, tez5 da "boshidan boshla" 65 foizdan 90 foizga ko'tarilgan — 200 savollik ball buni ko'rsatmagan). Ikkinchi: testlarni kattalashtirish — keyinroq 745 ta savol va real jadvallar (6-qism), va eng oxirida ishonch oralig'i (14-model-dasturida).
eval_loss nima demaydi
Jadvaldagi eval_loss ga qaytamiz. tez3 — 0.025, tez4 — 0.033, tez5 — 0.032. Xato oshdi, lekin test ball bir xil qoldi. Nega?
Chunki har bir modelning tekshirish qismi — o'z faylining oxirgi 5 foizi — boshqa qatorlar. tez4 ning ma'lumotiga qiyinroq qatorlar qo'shilgan (suhbatlar, savollar), va uning tekshirish qismi ham qiyinroq. Shuning uchun turli modellarning eval_loss ini solishtirib bo'lmaydi — u bitta modelning training jarayonini kuzatish uchun (xato kamayyaptimi, qayta o'sib ketmayaptimi), modellarni solishtirish uchun emas.
Bu saboq kitobda yana qaytadi: tez8 va tez9 da ham eval_loss va real test natijasi bir-biriga to'g'ri kelmagan.
Xulosa
- pilot4b, tez3, tez4, tez5 — bir xil sozlama, faqat ma'lumot farq qiladi.
- pilot4b o'qitilmagan modeldan 26 savolga yomon chiqdi: so'rovlarning yarmidan ko'pida xom ustun nomi bor edi, va model nomni ko'chirishni o'rgandi. Tuzatish — xom nom tekshiruvi va sarlavhalarni qayta nomlash.
- tez3 — birinchi yaxshi model: 200 dan 183, o'qitilmagan modeldan 19 savol yaxshi.
- tez4 va tez5 nishonga olingan xatolarni tuzatdi, lekin shuncha savolni buzdi — ball 183 da qoldi. 200 savollik test bir necha savollik farqni ajrata olmaydi.
- eval_loss turli modellarni solishtirish uchun emas: har birining tekshirish qatorlari boshqa.
Keyingi bobda bu saboqlardan keyingi uchta model: tez6, tez7 va hozirgacha eng yaxshisi — tez8.
Bu bobni bepul o'qidingiz.
Kitob o'rgatadi, lekin sizning kodingiz nega ishlamaganini ayta olmaydi. Kursda uy vazifangiz tekshiriladi.