Asosiy qismga o'tish

Keyingi qadamlar

29-bob 16 kod bloki 5643 so'z

Qayerdamiz

Kitob oxiriga yetdi, loyiha esa yo'q. Bu bob — Tez qayerda turgani va keyingi qadamlar qaysi tartibda qo'yilishi haqida. Va har bir qadamning sababi — o'lchangan raqam.

Avval bitta raqam — kitob davomida eng muhim bo'lgan raqam. 10-bobda Tez uchun hallucination (gallyutsinatsiya) ni aniqladik: noto'g'ri plan ("different result") va berilmagan savol ("guessed instead of asking") yig'indisi. Bugungi mahsulot modeli tez8 da bu ulush:

python10 qator
import json
import glob

TOZA = ["loans", "deposits", "cash_desk", "transactions", "realistic_loans", "realistic_deposits", "realistic_cash"]
GURUHLAR = {"toza": TOZA, "shovqinli": [f"noisy_{t}" for t in TOZA],
            "real": sorted(Path(f).parent.name for f in glob.glob(str(TEZ / "accuracy/suites/real_*/questions.json")))}
for guruh, toplamlar in GURUHLAR.items():
    javoblar = [json.loads(q) for t in toplamlar for q in open(TEZ / f"results/tez8g_cpu_{t}.jsonl", encoding="utf-8")]
    yolgon = sum(j["reason"] in ("different result", "guessed instead of asking") for j in javoblar)
    print(f"{guruh:10s} {len(javoblar):4d} savol: to'g'ri {sum(j['correct'] for j in javoblar):4d}, hallucination {yolgon:3d} ({yolgon / len(javoblar):.1%})")
Chiqish
toza        320 savol: to'g'ri  315, hallucination   5 (1.6%)
shovqinli   320 savol: to'g'ri  311, hallucination   8 (2.5%)
real        105 savol: to'g'ri   81, hallucination  24 (22.9%)

O'zimiz yasagan jadvallarda — juda past. Real jadvallarda — 22.9 foiz, deyarli to'rtta javobdan biri. Bu farq — keyingi ishlarning asosiy sababi.

Xatolar qayerdan keladi

tez8 ning real jadvallardagi har bir xatosi alohida tahlil qilingan va sababi bo'yicha guruhlangan. Tahlil loyihaning 13-why-the-model-falls-short.md faylida; uning ilovasidagi jadvalni o'qib, sabablarni sanaymiz:

python20 qator
from collections import Counter

tahlil = (TEZ.parent.parent / "13-why-the-model-falls-short.md").read_text(encoding="utf-8")
ilova = tahlil.split("## Appendix")[1]
sabablar = Counter()
for qator in ilova.splitlines():
    katak = [k.strip() for k in qator.strip().strip("|").split("|")]
    if len(katak) == 6 and katak[1].isdigit():
        sabab = katak[5]
        if sabab.startswith("wrong plan") or sabab.startswith("guessed"):
            sabablar["model xato qildi: noto'g'ri reja yoki taxmin"] += 1
        elif sabab.startswith("tool gap") or sabab.startswith("information not in table"):
            sabablar["asbob yo'q yoki ma'lumot jadvalda yo'q"] += 1
        elif sabab.startswith("arguable"):
            sabablar["test bahsli"] += 1
        else:
            sabablar["javob promptda ko'rinmagan"] += 1
for sabab, soni in sabablar.most_common():
    print(f"{soni:3d}  {sabab}")
print(f"jami: {sum(sabablar.values())}")
Chiqish
  9  javob promptda ko'rinmagan
  8  model xato qildi: noto'g'ri reja yoki taxmin
  6  asbob yo'q yoki ma'lumot jadvalda yo'q
  1  test bahsli
jami: 24

Bu jadval kitobning eng muhim xulosalaridan birini beradi: xatolarning kattaroq qismi modelning "aqli" muammosi emas. Javob promptda yo'q, yoki uni bajaradigan tool yo'q.

  • "Javob promptda ko'rinmagan" — masalan, valyuta jadvalida namunalarda faqat uchta valyuta ko'rinadi, va model dollar qaysi qatorda ekanini bilmaydi; yoki "qaytarilgan tovarlar" — bu jadvalda manfiy miqdor ekanini hech kim aytmagan. Model ko'rmagan narsani hech qanday training o'rgatmaydi. Bu — jadval tavsifi va ilova ishi.
  • "Tool yo'q" — nisbat, farq, bashorat. Bunga yo yangi tool kerak, yo "qila olmayman" deyish. Training modelga "qila olmayman" deyishni o'rgata oladi (17-bob), lekin to'g'ri javobni bera olmaydi.
  • Qolgan qismi — model haqiqatan noto'g'ri plan tuzgan yoki so'rash o'rniga taxmin qilgan holatlar — keyingi training ma'lumotining ishi.

Model atrofidagi qatlamlar

22-bob qayta trainingning chegarasini ko'rsatdi: har bir training tez8 ning ikkilangan javoblarini aralashtiradi. Shuning uchun keyingi qadamlar modelning og'irliklariga tegmaydi. Ular model atrofida ishlaydi: model nimani ko'rishini yaxshilaydi, uning planini bajarilgandan keyin tekshiradi, va ikkilanganda to'xtatadi. Har bir qatlam alohida o'lchandi.

1. Jadval tavsifi

Yuqoridagi jadvalda eng katta guruhlardan biri — "javob promptda ko'rinmagan". Masalan, valyuta jadvalida namunalar faqat uchta valyutani ko'rsatardi. Jadval tavsifchisi (11-bob) endi matn ustunining hamma qiymatlarini yozadi, agar ular birgalikda 600 belgiga sig'sa:

python6 qator
sozlama = json.loads((TEZ / "training/settings.json").read_text(encoding="utf-8"))
print("values_chars_limit:", sozlama["values_chars_limit"])
for t in ("real_fx_rates", "real_banks", "real_retail"):
    jadval = json.loads((TEZ / f"prompt/domains/{t}/table.json").read_text(encoding="utf-8"))
    toliq = [u["name"] for u in jadval["columns"] if "values" in u and u["type"] == "text"]
    print(f"{t:14s} hamma qiymatlari ko'rinadigan matn ustunlari: {toliq}")
Chiqish
values_chars_limit: 600
real_fx_rates  hamma qiymatlari ko'rinadigan matn ustunlari: ['G1', 'G2']
real_banks     hamma qiymatlari ko'rinadigan matn ustunlari: ['Banknomi']
real_retail    hamma qiymatlari ko'rinadigan matn ustunlari: ['Country']

Model o'sha-o'sha tez8. Real jadvallarda faqat tavsif o'zgargan holda:

python15 qator
HAMMASI = sum(GURUHLAR.values(), [])

def hukmlar(prefiks, toplamlar):
    return {(t, j["id"]): j for t in toplamlar for j in map(json.loads, open(TEZ / f"results/{prefiks}_cpu_{t}.jsonl", encoding="utf-8"))}

def matritsa(prefiks, toplamlar):
    sanoq = Counter(j["reason"] if not j["reason"].startswith("plan failed") else "plan failed"
                    for j in hukmlar(prefiks, toplamlar).values())
    javoblar = sum(v for k, v in sanoq.items() if k not in ("asked", "asked on a clear request"))
    return sanoq["same result"], javoblar, sanoq["asked"], sanoq["asked"] + sanoq["guessed instead of asking"]

def togrilar(prefiks, toplamlar):
    return sum(json.loads(q)["correct"] for t in toplamlar for q in open(TEZ / f"results/{prefiks}_cpu_{t}.jsonl", encoding="utf-8"))

print(f"real 105 savol: eski tavsif {togrilar('tez8g', GURUHLAR['real'])}, yangi tavsif {togrilar('tez8d', GURUHLAR['real'])}")
Chiqish
real 105 savol: eski tavsif 81, yangi tavsif 84

Bitta qo'shimcha tuzatish shu yerda qilindi. Bank nomlarida uch xil tutuq belgisi bor edi (O‘z, Oz,O'z), foydalanuvchi esa oddiy'yozadi. Grammar modelni ro'yxatdagi qiymatlardan birini tanlashga majbur qiladi (9-bob), va "O'zmilliybank" so'rovida model boshqa bankni tanlab qo'ygan edi. Endi ro'yxatdagi hamma tutuq belgilari bitta oddiy'` ga keltiriladi; engine esa (10-bob) qiymatlarni solishtirishda baribir tutuq belgilariga e'tibor bermaydi, shuning uchun haqiqiy ma'lumot bilan moslik buzilmaydi.

2. Validator

Model plani DuckDB da bajarilgandan keyin, natija foydalanuvchiga ko'rsatilishidan oldin, uni oddiy qoidalar tekshiradi — validator. Qoida shubhali natija topsa, Tez javob o'rniga savol beradi:

python5 qator
import ast
manba = (TEZ / "accuracy/validate.py").read_text(encoding="utf-8")
for tugun in ast.parse(manba).body:
    if isinstance(tugun, ast.FunctionDef) and tugun.name == "problems":
        print(ast.get_source_segment(manba, tugun))
Chiqish
def problems(steps, result, base_rows):
    found = []
    if not result["rows"]:
        found.append("empty result")
    if any(step["tool"] in FILTERS for step in steps) and len(result["rows"]) == base_rows:
        found.append("filter kept every row")
    if _grouped(steps) and len(result["rows"]) == base_rows:
        found.append("grouping changed nothing")
    if result["rows"] and _missing_previous(steps, result):
        found.append("comparison without previous data")
    return found

Har bir qoida bitta shart bilan qabul qilindi: saqlangan javoblarda u birorta to'g'ri javobga tegmasligi kerak. Uchta model (tez8, tez9, tez10) ning 20 to'plamdagi hamma rejalarida qoidalarni sinaymiz:

python30 qator
from accuracy.execute import effective_steps, run_plan
from accuracy.run import BASE, _earlier, load_json, open_data
from accuracy.tools import ToolError
from accuracy.validate import problems

FAYLLAR = {"loans": "loans", "deposits": "deposits", "cash_desk": "cash_desk", "transactions": "bank",
           "realistic_loans": "loans", "realistic_deposits": "deposits", "realistic_cash": "cash_desk"}

def fayl(toplam):
    nom = toplam.removeprefix("noisy_")
    return f"/mnt/d/Tez_spikes/data/{FAYLLAR.get(nom, nom)}.csv"

sozlama = load_json(TEZ / "accuracy/settings.json")
qoidalar = Counter()
for toplam in HAMMASI:
    savollar = {s["id"]: s for s in load_json(TEZ / f"accuracy/suites/{toplam}/questions.json")}
    baza = open_data(fayl(toplam))
    qatorlar = baza.execute(f"SELECT count(*) FROM {BASE}").fetchone()[0]
    for prefiks in ("tez8g", "tez9g", "tez10g"):
        for j in map(json.loads, open(TEZ / f"results/{prefiks}_cpu_{toplam}.jsonl", encoding="utf-8")):
            try:
                javob = json.loads(j["output"])
                qadamlar = effective_steps(_earlier(savollar[j["id"]]), javob)
                natija = run_plan(baza, BASE, qadamlar, sozlama)
            except (ValueError, KeyError, TypeError, ToolError):
                continue
            for qoida in problems(qadamlar, natija, qatorlar):
                qoidalar[(qoida, j["reason"] == "same result")] += 1
for qoida in sorted({k[0] for k in qoidalar}):
    print(f"{qoida:35s} noto'g'ri javoblarda {qoidalar[(qoida, False)]:3d}, to'g'ri javoblarda {qoidalar[(qoida, True)]}")
Chiqish
comparison without previous data    noto'g'ri javoblarda   3, to'g'ri javoblarda 0
empty result                        noto'g'ri javoblarda  15, to'g'ri javoblarda 0
filter kept every row               noto'g'ri javoblarda   8, to'g'ri javoblarda 0
grouping changed nothing            noto'g'ri javoblarda   3, to'g'ri javoblarda 0

To'rtta qoida ham faqat noto'g'ri javoblarda ishladi. Boshqa qoidalar ham sinalgan edi (masalan, "kodli ustun bo'yicha filtr, so'rovda raqam yo'q") — ular to'g'ri javoblarga ham tegdi va olib tashlandi.

3. Ishonch darvozasi

22-bobda tez8 ning ishonchi o'zgaradigan javoblarni oldindan ajratganini ko'rdik. Bu raqam qayerdan keladi? Model har bir token ni tanlaganda barcha mumkin bo'lgan token larga ehtimol beradi. llama-server so'rovda "logprobs": true bo'lsa, tanlangan har bir token ning ehtimol logarifmini qaytaradi. Undan ikki raqam chiqadi: eng past token ehtimoli va o'rtacha ehtimol (logarifmlar o'rtachasining eksponentasi):

python4 qator
manba = (TEZ / "accuracy/validate.py").read_text(encoding="utf-8")
for tugun in ast.parse(manba).body:
    if isinstance(tugun, ast.FunctionDef) and tugun.name == "confidence":
        print(ast.get_source_segment(manba, tugun))
Chiqish
def confidence(tokens):
    return math.exp(sum(token["logprob"] for token in tokens) / len(tokens)) if tokens else 0.0

Qaysi biri to'g'ri va noto'g'ri planlarni yaxshiroq ajratadi? O'lchov — AUC: tasodifiy olingan to'g'ri javobning ishonchi tasodifiy noto'g'ri javobnikidan yuqori bo'lish ehtimoli (0.5 — tanga, 1.0 — mukammal):

python16 qator
import math

def ishonchlar(toplamlar):
    javoblar = [json.loads(q) for t in toplamlar for q in open(TEZ / f"results/tez8c_cpu_{t}.jsonl", encoding="utf-8")]
    return [j for j in javoblar if j["output"].startswith('{"steps"')]

def auc(yaxshi, yomon):
    return sum((a > b) + 0.5 * (a == b) for a in yaxshi for b in yomon) / (len(yaxshi) * len(yomon))

SOZLASH = GURUHLAR["toza"] + GURUHLAR["shovqinli"]
for nom, toplamlar in (("toza+shovqinli", SOZLASH), ("real", GURUHLAR["real"])):
    javoblar = ishonchlar(toplamlar)
    for olchov, qiymat in (("eng past token", lambda j: j["min_prob"]), ("o'rtacha", lambda j: math.exp(j["mean_logprob"]))):
        yaxshi = [qiymat(j) for j in javoblar if j["correct"]]
        yomon = [qiymat(j) for j in javoblar if not j["correct"]]
        print(f"{nom:15s} {olchov:15s} AUC {auc(yaxshi, yomon):.3f}  ({len(yaxshi)} to'g'ri, {len(yomon)} noto'g'ri)")
Chiqish
toza+shovqinli  eng past token  AUC 0.836  (501 to'g'ri, 10 noto'g'ri)
toza+shovqinli  o'rtacha        AUC 0.875  (501 to'g'ri, 10 noto'g'ri)
real            eng past token  AUC 0.875  (69 to'g'ri, 23 noto'g'ri)
real            o'rtacha        AUC 0.904  (69 to'g'ri, 23 noto'g'ri)

O'rtacha ehtimol ikkala guruhda ham yaxshiroq. Darvoza oddiy: o'rtacha ishonch chegaradan past bo'lsa, Tez javob o'rniga savol beradi. Chegara faqat toza va shovqinli to'plamlarda tanlandi, aniq qoida bilan: aniq so'rovlarga savol berish bir foizdan oshmasin. Real to'plam chegarani tanlashda ishlatilmadi:

python1 qator
print("tanlangan chegara:", sozlama["confidence_threshold"])
Chiqish
tanlangan chegara: 0.94

4. Hammasi birga

Uchala qatlam (tavsif, validator ning dastlabki uchta qoidasi, darvoza) ishga tushiriladigan kodga ulandi va 745 savol jonli, boshidan oxirigacha qayta o'tkazildi. Har bir javob yozuvida endi modelning o'z chiqishi, ishonchi va validator sababi bor:

python8 qator
for guruh, toplamlar in GURUHLAR.items():
    a, b = hukmlar("tez8g", toplamlar), hukmlar("tez8s", toplamlar)
    togri, javoblar, topildi, savollar = matritsa("tez8s", toplamlar)
    yoqotildi = sum(a[k]["correct"] and not b[k]["correct"] for k in a)
    print(f"{guruh:10s} tez8 {sum(j['correct'] for j in a.values()):3d}, qatlamlar bilan {sum(j['correct'] for j in b.values()):3d};"
          f"  precision {togri}/{javoblar} = {togri / javoblar:.1%};  yo'qotilgan to'g'ri javob: {yoqotildi}")
to_xtatildi = Counter(j["held"] for j in hukmlar("tez8s", HAMMASI).values() if j["held"])
print("to'xtatilgan javoblar:", dict(to_xtatildi))
Chiqish
toza       tez8 315, qatlamlar bilan 313;  precision 284/289 = 98.3%;  yo'qotilgan to'g'ri javob: 2
shovqinli  tez8 311, qatlamlar bilan 309;  precision 280/287 = 97.6%;  yo'qotilgan to'g'ri javob: 3
real       tez8  81, qatlamlar bilan  90;  precision 79/89 = 88.8%;  yo'qotilgan to'g'ri javob: 0
to'xtatilgan javoblar: {'low confidence': 11, 'filter kept every row': 2, 'empty result': 1, 'comparison without previous data': 2}

Real jadvallarda precision 75.8 foizdan 88.8 foizga ko'tarildi, va bitta ham to'g'ri javob yo'qolmadi. Toza va shovqinli to'plamlarda darvoza bir nechta to'g'ri javobni savolga aylantirdi — oldindan o'lchangan, bir foizdan kam narx.

"To'qson foizga bir-ikki savol qoldi" — shunday ko'rindi.

Yangi savollar haqiqati

Lekin bu 105 savol endi halol hakam emas edi. Jadval tavsifi, tutuq belgisi tuzatishi va validator qoidalari — hammasi shu savollardagi xatolarni o'rganib tanlangan. Test ustida sozlangan narsa testda yaxshi ko'rinadi. Haqiqiy javob uchun hech kim ko'rmagan savollar kerak edi.

Oltita real jadval uchun 92 ta yangi savol yozildi (14 tasi savol berilishi kerak bo'lgan), har birining kutilgan javobi haqiqiy ma'lumotda tekshirildi, va savollar git da muzlatildi — hech qaysi model ularni ko'rishidan oldin. Keyin bitta jonli o'tish:

python18 qator
from accuracy.run import expected_results, judge
from runtime.client import parse_answer

xom, qatlam = Counter(), Counter()
for t in GURUHLAR["real"]:
    savollar = load_json(TEZ / f"accuracy/suites/{t}/fresh.json")
    lugat = {s["id"]: s for s in savollar}
    baza = open_data(fayl(t))
    kutilgan = expected_results(baza, savollar, sozlama)
    for j in map(json.loads, open(TEZ / f"results/fresh8s_cpu_{t}.jsonl", encoding="utf-8")):
        _, sabab = judge(baza, lugat[j["id"]], parse_answer(j["output"]), kutilgan, sozlama)
        xom[sabab if not sabab.startswith("plan failed") else "plan failed"] += 1
        qatlam[j["reason"] if not j["reason"].startswith("plan failed") else "plan failed"] += 1

for nom, sanoq in (("tez8 o'zi", xom), ("qatlamlar bilan", qatlam)):
    javoblar = sum(v for k, v in sanoq.items() if k not in ("asked", "asked on a clear request"))
    print(f"{nom:16s} precision {sanoq['same result']}/{javoblar} = {sanoq['same result'] / javoblar:.1%},  jim xato {sanoq['different result'] + sanoq['guessed instead of asking']},"
          f"  savol topildi {sanoq['asked']}/{sanoq['asked'] + sanoq['guessed instead of asking']}")
Chiqish
tez8 o'zi        precision 58/89 = 65.2%,  jim xato 31,  savol topildi 3/14
qatlamlar bilan  precision 57/78 = 73.1%,  jim xato 21,  savol topildi 6/14

Qatlamlar yangi savollarda ham yordam berdi — precision bir necha punktga oshdi, jim xatolar kamaydi. Lekin 88.8 foiz emas. Eski 105 savoldagi raqam test ustida sozlash bilan shishgan edi. Jurnalda — 25-raqam:

python4 qator
for qator in Path("/mnt/c/Users/Admin/Desktop/Offline/12-mistakes-and-lessons.md").read_text(encoding="utf-8").splitlines():
    if qator.startswith("| 25 |"):
        for ustun, matn in zip(("xato", "narxi", "qoida"), [q.strip() for q in qator.strip("|").split("|")][2:]):
            print(f"{ustun}: {matn}\n")
Chiqish
xato: Reported the stack as 88.8% precision, "1-2 questions from 90%", on the 105 real-table questions, although the descriptions, the apostrophe fix and the validator rules had all been chosen by looking at misses in those same questions.

narxi: On 92 fresh questions frozen before any run, the same stack scored 73.1% (57/78); the 105-question figure was inflated by tuning on the test.

qoida: Keep a frozen held-out set from the start; every fix is chosen on one set and the claim is made only on a set no fix has looked at.

Bu kitobdagi eng og'ir, lekin eng foydali raqam. Endi har bir tuzatish bitta to'plamda tanlanadi, va da'vo faqat hech qaysi tuzatish ko'rmagan to'plamda qilinadi.

Yangi savollardagi xatolar ham guruhlandi. Eng kattasi — bitta naqsh: foydalanuvchi bitta umumiy son so'raganda ("jami depozitlar", "o'rtacha yosh") model biror ustun bo'yicha guruhlab qo'yadi. Ikkinchisi — kodlarni taxmin qilish ("erkak mijozlar" uchun SEX = 2). Uchinchisi — bajarib bo'lmaydigan so'rovga (daromad, nisbat) taxminiy javob.

Birinchisi uchun ikki narsa sinaldi. Validator ga to'rtinchi qoida qo'shildi: guruhlash hech narsani o'zgartirmagan bo'lsa (har bir guruh — bitta qator), bu shubhali (yuqoridagi jadvalda — "grouping changed nothing"). Va tizim promptiga bitta qator: "guruhlashni faqat foydalanuvchi nima bo'yicha guruhlashni aytganda qil". Qator 260 ta toza savoldan keyin to'xtatildi: uchta to'g'ri javobni buzdi, birortasini tuzatmadi — "menejerlar bo'yicha jami" so'rovida model guruhlashni olib tashladi. Model aynan shu prompt matnida o'qitilgan; uni o'zgartirish — qayta trainingning kichik nusxasi, xuddi shu almashinuv bilan.

Javob o'zini tushuntiradi

To'rtta javobdan biri noto'g'ri bo'lsa, tahlilchi buni ko'rishi kerak. Tezning plani — oddiy, aniq qadamlar ro'yxati; uni foydalanuvchi tilida oddiy jumlalarga aylantirish mumkin. Bu kod 12-bobdagi o'qituvchi uchun yozilgan edi (faqat inglizcha); endi u o'zbekcha (lotin va kirill), ruscha va inglizcha gapiradi, ustun nomlari va qiymatlarni esa jadvaldagidek qoldiradi. Yangi savollardagi haqiqiy noto'g'ri javoblarda:

python10 qator
from training.describe import explain, load_texts

til = json.loads((TEZ / "training/explain.json").read_text(encoding="utf-8"))
matnlar = load_texts(TEZ / "training", til)
yozuv = json.loads((TEZ / "training/uzbek_script.json").read_text(encoding="utf-8"))
for t, raqam in (("real_regions", 8), ("real_credit_clients", 3), ("real_fx_rates", 8), ("real_credit_clients", 5)):
    savol = {s["id"]: s for s in load_json(TEZ / f"accuracy/suites/{t}/fresh.json")}[raqam]
    javob = {j["id"]: j for j in map(json.loads, open(TEZ / f"results/fresh8s_cpu_{t}.jsonl", encoding="utf-8"))}[raqam]
    print(f"[{savol['language']}] {savol['text']}")
    print(explain(json.loads(javob["output"]), savol["language"], matnlar, til, yozuv), end="\n\n")
Chiqish
[uz_latin] jami depozitlar summasi
1. Har bir Regions uchun Total deposits bo'yicha jami hisoblanadi.

[en] clients aged between 40 and 50
1. Keep only the rows where AGE is none of 40, 50.

[ru] курсы рубля и тенге
1. Оставить только строки, где G1 одно из: 'RUB', 'TJS'.

[uz_cyrillic] кейинги ойда тўлайдиганлар
1. Фақат default payment next month 1ga тенг бўлган қаторлар қолдирилади.

Har bir xato ko'rinib turibdi: "jami" so'ralgan — "har bir viloyat uchun" deyilgan; "40 dan 50 gacha" so'ralgan — "40, 50 dan hech biri emas"; rubl va tenge so'ralgan — TJS (somoniy) tanlangan. Bu son foizni oshirmaydi, lekin jim xatoni ko'rinadigan xatoga aylantiradi. Tahlilchi raqamni hisobotga qo'yishdan oldin planni o'qiydi.

Kodlar lug'ati

Kod taxmin qilish xatosini train qilish emas, ma'lumot tuzatadi. Bank jadvallarida kodlar lug'ati bo'ladi: SEX: 1 — erkak, 2 — ayol. Tezning promptida har bir jadval uchun lug'at joyi bor (8-bob), real jadvallar uchun esa u bo'sh edi. Tahlilchi bir marta yozadigan lug'at bilan sinov:

python9 qator
lugat = json.load(open(DATA / "kodlar/glossary.json", encoding="utf-8"))
for soz, ma_no in lugat.items():
    print(f"  {soz}: {ma_no}")
savollar = {s["id"]: s for s in json.load(open(DATA / "kodlar/questions.json", encoding="utf-8"))}
javoblar = [json.loads(q) for q in open(DATA / "kodlar/tez8_codes.jsonl", encoding="utf-8")]
print(f"\nqat'iy hakam: {sum(j['correct'] for j in javoblar)}/{len(javoblar)}")
for j in javoblar:
    if not j["correct"]:
        print(f"  {savollar[j['id']]['text']}: {j['output']}")
Chiqish
  erkak / мужчина / male: SEX = 1
  ayol / женщина / female: SEX = 2
  uylangan / женатый / married: MARRIAGE = 1
  bo'ydoq / холостой / single: MARRIAGE = 2
  magistratura / магистратура / graduate school: EDUCATION = 1
  oliy ta'lim / высшее образование / university: EDUCATION = 2
  o'rta maktab / средняя школа / high school: EDUCATION = 3
  to'lamaydi / неплательщик / default: default payment next month = 1

qat'iy hakam: 9/12
  мужчины старше 40 лет: {"steps":[{"tool":"filter","args":{"column":"SEX","op":"=","value":1}},{"tool":"filter","args":{"column":"AGE","op":">=","value":40}}]}
  average limit of women: {"steps":[{"tool":"filter","args":{"column":"SEX","op":"=","value":2}},{"tool":"group_and_total","args":{"group_by":["SEX"],"value_column":"LIMIT_BAL","agg":"avg"}}]}
  число неплательщиков среди женщин: {"steps":[{"tool":"filter","args":{"column":"SEX","op":"=","value":2}},{"tool":"filter","args":{"column":"default payment next month","op":"=","value":1}},{"tool":"group_and_total","args":{"group_by":["SEX"],"value_column":"default payment next month","agg":"count"}}]}

Kodlar hamma savolda to'g'ri ishlatildi. Uchta "xato"ning birortasi ham kod xatosi emas: "40 dan katta" o'rniga >=, va ikki marta ayollarni ajratgandan keyin ortiqcha jinsi bo'yicha guruhlash — son to'g'ri, yonida kod ustuni ortiqcha. Lug'atsiz tez8 xuddi shu turdagi savollarda kodni taxmin qilardi.

Uchta model, bir xil qatlamlar

Qatlamlar modelga bog'liq emas. Shuning uchun savol tug'ildi: 22-bobda yutqazgan tez10 va tez11a qatlamlar bilan yaxshiroq bo'lmaydimi? tez10 ko'proq savol beradi, darvoza esa aynan ishonchsiz javoblarni ushlaydi — ikkalasi birga nima beradi? Uchala model bir xil 92 ta yangi savolda, to'rt qoidali validator va darvoza bilan:

python24 qator
def hisob(qatorlar):
    javoblar = [q for q in qatorlar if not q["sorradi"]]
    togri = sum(q["togri"] for q in javoblar if not q["kerak"])
    return togri, len(javoblar), sum(q["sorradi"] for q in qatorlar if q["kerak"]), sum(q["kerak"] for q in qatorlar)

for model in ("tez8", "tez10", "tez11a"):
    xom, qatlam, yoqoldi = [], [], 0
    for t in GURUHLAR["real"]:
        savollar = load_json(TEZ / f"accuracy/suites/{t}/fresh.json")
        lugat = {s["id"]: s for s in savollar}
        baza = open_data(fayl(t))
        kutilgan = expected_results(baza, savollar, sozlama)
        for j in map(json.loads, open(TEZ / f"results/fresh{model}v_cpu_{t}.jsonl", encoding="utf-8")):
            javob = parse_answer(j["output"])
            togri, _ = judge(baza, lugat[j["id"]], javob, kutilgan, sozlama)
            kerak = lugat[j["id"]]["expect"] == "ask"
            xom.append({"togri": togri, "sorradi": "ask" in javob, "kerak": kerak})
            qatlam.append({"togri": j["correct"], "sorradi": j["reason"] in ("asked", "asked on a clear request"), "kerak": kerak})
            yoqoldi += togri and not kerak and not j["correct"]
    for nom, qatorlar in (("o'zi", xom), ("qatlamlar", qatlam)):
        togri, javoblar, topildi, kerak = hisob(qatorlar)
        print(f"{model:7s} {nom:10s} to'g'ri {togri:3d}   precision {togri}/{javoblar} = {togri / javoblar:.1%}"
              f"   jim xato {javoblar - togri:3d}   savol topildi {topildi}/{kerak}")
    print(f"{model:7s} qatlamlar yo'qotgan to'g'ri javob: {yoqoldi}\n")
Chiqish
tez8    o'zi       to'g'ri  58   precision 58/89 = 65.2%   jim xato  31   savol topildi 3/14
tez8    qatlamlar  to'g'ri  57   precision 57/73 = 78.1%   jim xato  16   savol topildi 8/14
tez8    qatlamlar yo'qotgan to'g'ri javob: 1

tez10   o'zi       to'g'ri  54   precision 54/81 = 66.7%   jim xato  27   savol topildi 9/14
tez10   qatlamlar  to'g'ri  52   precision 52/62 = 83.9%   jim xato  10   savol topildi 11/14
tez10   qatlamlar yo'qotgan to'g'ri javob: 2

tez11a  o'zi       to'g'ri  57   precision 57/83 = 68.7%   jim xato  26   savol topildi 8/14
tez11a  qatlamlar  to'g'ri  55   precision 55/72 = 76.4%   jim xato  17   savol topildi 10/14
tez11a  qatlamlar yo'qotgan to'g'ri javob: 2

tez8 qatoridagi "qatlamlar" yuqoridagidan yaxshiroq — farq faqat to'rtinchi qoida (guruhlash hech narsani o'zgartirmadi): u guruhlash xatolarining bir qismini ushladi. tez10 eng yuqori precision ga chiqdi, lekin bepul emas: u ko'proq savol beradi, shuning uchun to'g'ri javoblar soni ham eng kam. 22-bobda u toza savollarda ham tez8 dan orqada edi. tez11a o'zi eng yuqori precision ga ega edi, lekin qatlamlar bilan eng past precision ga tushdi: qatlamlar uning xatolarini kamroq ushladi.

Bu yerda tanlov qoidasi muhim. Bu 92 savol endi ham halol hakam emas — to'rtinchi qoida aynan shular ustida tanlangan. Shuning uchun qaror shu yerda, ikkinchi yangi to'plamni ko'rishdan oldin qabul qilindi: mahsulot modeli tez8 bo'lib qoladi (ko'proq to'g'ri javob, toza savollarda ham yaxshiroq), tez10 esa taqqoslash uchun o'lchanadi. Natijaga qarab keyin tanlash — 25-xatoni yana bir marta qilish bo'lardi.

Halol raqam

Ikkinchi yangi to'plam — yana 92 savol (13 tasi savol berilishi kerak bo'lgan), birinchisi kabi yozilgan, git da muzlatilgan, va hech qaysi tuzatish uni ko'rmagan. Bu kitobdagi yagona da'vo shu to'plamda qilinadi:

python19 qator
for model in ("tez8", "tez10"):
    xom, qatlam, yoqoldi = [], [], 0
    for t in GURUHLAR["real"]:
        savollar = load_json(TEZ / f"accuracy/suites/{t}/fresh2.json")
        lugat = {s["id"]: s for s in savollar}
        baza = open_data(fayl(t))
        kutilgan = expected_results(baza, savollar, sozlama)
        for j in map(json.loads, open(TEZ / f"results/fresh2{model}_cpu_{t}.jsonl", encoding="utf-8")):
            javob = parse_answer(j["output"])
            togri, _ = judge(baza, lugat[j["id"]], javob, kutilgan, sozlama)
            kerak = lugat[j["id"]]["expect"] == "ask"
            xom.append({"togri": togri, "sorradi": "ask" in javob, "kerak": kerak})
            qatlam.append({"togri": j["correct"], "sorradi": j["reason"] in ("asked", "asked on a clear request"), "kerak": kerak})
            yoqoldi += togri and not kerak and not j["correct"]
    for nom, qatorlar in (("o'zi", xom), ("qatlamlar", qatlam)):
        togri, javoblar, topildi, kerak = hisob(qatorlar)
        print(f"{model:7s} {nom:10s} to'g'ri {togri:3d}   precision {togri}/{javoblar} = {togri / javoblar:.1%}"
              f"   jim xato {javoblar - togri:3d}   savol topildi {topildi}/{kerak}")
    print(f"{model:7s} qatlamlar yo'qotgan to'g'ri javob: {yoqoldi}\n")
Chiqish
tez8    o'zi       to'g'ri  56   precision 56/89 = 62.9%   jim xato  33   savol topildi 3/13
tez8    qatlamlar  to'g'ri  56   precision 56/72 = 77.8%   jim xato  16   savol topildi 10/13
tez8    qatlamlar yo'qotgan to'g'ri javob: 0

tez10   o'zi       to'g'ri  54   precision 54/80 = 67.5%   jim xato  26   savol topildi 10/13
tez10   qatlamlar  to'g'ri  53   precision 53/63 = 84.1%   jim xato  10   savol topildi 12/13
tez10   qatlamlar yo'qotgan to'g'ri javob: 1

Mahsulot — tez8 va qatlamlar: ko'rilmagan savollarda 77.8 foiz precision. Birinchi yangi to'plamdagi raqamga deyarli teng — demak bu safar raqam sozlash bilan shishmagan. Qatlamlar jim xatolarni ikki barobar kamaytirdi, savol berilishi kerak bo'lgan so'rovlarni uchtadan o'ntaga ko'tardi, va bitta ham to'g'ri javobni olmadi.

To'qson foiz emas. Javoblarning 22 foizi (72 tadan 16 tasi) hali ham noto'g'ri — lekin endi u tahlilchiga oddiy jumlalar bilan tushuntiriladi, va u raqamni hisobotga qo'yishdan oldin planni o'qiy oladi.

tez10 ikkala yangi to'plamda ham bir xil manzarani berdi: precision olti punktga yuqori, to'g'ri javob uch-beshtaga kam. Ikki mustaqil to'plam rozi — bu tasodif emas. Qaysi biri yaxshiroq — bu texnik emas, mahsulot savoli: tahlilchi uchun kamroq noto'g'ri javob muhimmi yoki ko'proq javob? Bu savol foydalanuvchi bilan hal qilinadi, va undan oldin tez10 qatlamlar bilan toza va shovqinli savollarda ham o'lchanishi kerak.

Tartib

Shu natijalardan keyingi qadamlar tartibi chiqadi:

1. Tahlilchining haqiqiy savollari. Hamma narsadan muhim. Ikkala yangi to'plam ham — hali bizning tasavvurimiz. Tahlilchidan o'ttiz-yuzta yozilgan savol va fayllarining ustun nomlari hamda kodlar lug'ati (qatorlar emas) — eng halol test to'plami bo'ladi.

2. tez8 yoki tez10. tez10 ni qatlamlar bilan hamma 745 savolda o'lchash, keyin tahlilchi bilan tanlash.

3. Hisoblangan ustun tooli. Ikki ustundan nisbat, farq yoki foiz — real xatolarning bir qismi aynan shu tool yo'qligidan. U schema ni o'zgartiradi, demak qayta training va hamma modellarni qayta sinash kerak; va 22-bobdagi saboq bo'yicha natija faqat yangi, muzlatilgan to'plamda baholanadi.

4. "Qila olmayman" o'rniga "shuni nazarda tutdingizmi?". Savol berish o'rniga model eng ehtimolli planni taklif qiladi va tushuntirishni ko'rsatadi; tahlilchi bitta bosish bilan tasdiqlaydi. Bu darvoza ushlagan javoblarning bir qismini qaytaradi — xavfsiz holda.

5. Haqiqiy 8 GB kompyuter. Tez ning o'z xotirasi o'lchandi (26-bob); Windows bilan birga va kuchsiz protsessorda — hali yo'q.

6. Ilova. Oyna, fayl tashlash, oldindan ko'rish va bekor qilish, grafik va Excelga saqlash, model serverini himoyalash (27-bob), fayl xeshini tekshirish (28-bob), ikki faylni solishtirish.

7. Kattaroq model. 9B model xatolarning "model xato qildi" qismini kamaytirishi mumkin. Uning xotirasi o'lchanmagan, lekin 4B ning o'zi 8 GB ning yarmidan ko'pini oladi (26-bob). Bu ofis serveri bilan birga ko'rib chiqiladi.

Har bir qadam uchun ikki qoida amal qiladi: har bir modelda bitta o'zgarish, va da'vo faqat hech qaysi tuzatish ko'rmagan to'plamda qilinadi.

Bu kitob qanday davom etadi

Bu kitob "kundalik" sifatida yozilgan (1-bob), va u loyiha bilan birga o'zgaradi. Bir nechta bob aniq qayta yoziladi: 26-bob — haqiqiy 8 GB kompyuterda sinovdan keyin; 27-bob — model serveri himoyalangandan keyin; shu bob — tahlilchining haqiqiy savollari kelganda.

Bitta narsa o'zgarmaydi: har bir raqam o'lchanadi, har bir xato yoziladi, va "bilmaymiz" degan joyda "bilmaymiz" deb yoziladi. Bu bobning o'zi bunga misol: 88.8 foiz deb yozilgan raqam yangi savollarda 77.8 foiz bo'lib chiqdi, va ikkalasi ham kitobda qoldi.

Xulosa

  • tez8 ning hallucination ulushi: o'zimizning jadvallarda bir-ikki foiz, real jadvallarda 22.9 foiz.
  • Real xatolarning kattaroq qismi — training muammosi emas: javob promptda ko'rinmagan yoki tool yo'q. Shuning uchun model atrofiga qatlamlar qurildi: jadval tavsifi, validator, ishonch darvozasi va tushuntirish.
  • Sozlangan savollarda qatlamlar 88.8 foiz ko'rsatdi; hech kim ko'rmagan savollarda — 77.8 foiz precision, jim xatolar ikki barobar kam, birorta to'g'ri javob yo'qolmadi. Halol raqam — ikkinchisi.
  • Har qanday qayta training yoki prompt o'zgarishi javoblarning oltidan birini o'zgartiradi — aynan model ishonchsiz bo'lganlarini. Shuning uchun o'qitilgan prompt matni muzlatilgan.
  • tez10 qatlamlar bilan aniqroq, lekin kamroq javob beradi; tanlov — tahlilchi bilan.
  • Tartib: tahlilchining savollari, tez8 yoki tez10, hisoblangan ustun, tasdiqlash oynasi, haqiqiy 8 GB kompyuter, ilova, kattaroq model.

Bu bobni bepul o'qidingiz.

Kitob o'rgatadi, lekin sizning kodingiz nega ishlamaganini ayta olmaydi. Kursda uy vazifangiz tekshiriladi.

Telegramda yozish Narxlar