Asosiy qismga o'tish

LoRA va Soup: run1 — o'qitilmagan birinchi model

18-bob 5 kod bloki 1414 so'z

Beshinchi qism

To'rtinchi qismda training ma'lumoti qanday yasalishini ko'rdik. Beshinchi qism — trainingning o'zi: har bir model, uning sozlamalari va natijasi. Lekin hikoyani halol boshlash kerak: birinchi rejalashtirilgan model — run1 — hech qachon o'qitilmagan. Bu bob — nega, va o'sha qaror keyingi hamma narsani qanday belgilagani haqida.

Avval toollar.

LoRA: modelning kichik bir qismini train qilish

4 milliard parametrli modelni to'liq training — har bir vaznni o'zgartirish — juda ko'p xotira va vaqt talab qiladi. LoRA (Low-Rank Adaptation) boshqa yo'l: asl model vaznlari muzlatiladi, va uning ba'zi qatlamlari yoniga kichik qo'shimcha matritsalar qo'yiladi. Training faqat shu qo'shimchalarni o'zgartiradi.

Qanchalik kichik? Tezning birinchi haqiqiy training logidan bitta qator:

python4 qator
log = (Path.home() / "tez_runs/pilot4b/train.log").read_text(encoding="utf-8", errors="replace").replace("\r", "\n")
for qator in log.splitlines():
    if "trainable" in qator or "LoRA:" in qator:
        print(qator.strip(" │"))
Chiqish
LoRA:    r=16, alpha=32
LoRA applied: 8,519,680 trainable / 4,214,270,976 total (0.20%)
Merge LoRA:  soup merge --adapter output

To'rt milliard parametrdan sakkiz yarim million — besh yuzdan biri. Shuning uchun training bitta videokartada sig'adi va soatlar ichida tugaydi. Yana bir qadam: asl model ham 4 bitga siqilgan holda yuklanadi (QLoRA) — xotira yana bir necha barobar kamayadi.

Training tugagach, LoRA qo'shimchalari asl modelga merge qilinadi (qo'shib yuboriladi), va natija — oddiy model fayli. Keyin 6-bobdagi kabi GGUF Q4_K_M ga aylantiriladi. Tahlilchining kompyuterida LoRA ham, training kutubxonalari ham kerak emas.

Soup

Trainingni boshqaradigan dastur — Soup (2-bobdagi tadqiqotda tanlangan). U bitta YAML fayl bilan ishlaydi. run1 uchun tayyorlangan fayl:

python1 qator
print((Path.home() / "tez_runs/run1/soup.yaml").read_text(encoding="utf-8"))
Chiqish
base: Qwen/Qwen3.5-2B
task: sft
modality: text
backend: transformers

data:
  train: ./data/train.jsonl
  format: chatml
  val_split: 0.05
  max_length: 4096
  train_on_responses_only: true

training:
  epochs: 2
  lr: 2e-4
  batch_size: auto
  gradient_accumulation_steps: 4
  warmup_ratio: 0.03
  quantization: 4bit
  save_steps: 200
  lora:
    r: 16
    alpha: 32
    dropout: 0.05
    target_modules: auto

output: ./output

Asosiy qatorlar:

  • base — asos model: Qwen3.5-2B.
  • format: chatml — 15-bobdagi qator shakli: tizim, foydalanuvchi, javob.
  • val_split: 0.05 — oxirgi 5 foiz tekshirish uchun (15-bobdagi tuzoq).
  • train_on_responses_only — loss (xato) faqat javob tokenlarida hisoblanadi. Model besh ming belgili tizim promptini yodlashga urinmaydi — u faqat to'g'ri javob yozishni o'rganadi.
  • quantization: 4bit — QLoRA.
  • lora: r 16, alpha 32 — qo'shimcha matritsalarning o'lchami va kuchi.
  • epochs: 2 — ma'lumot ikki marta ko'riladi.

run1 ning ma'lumoti

run1 uchun birinchi partiyadan training fayli yasaldi:

python5 qator
import json

qatorlar = [json.loads(q) for q in open(Path.home() / "tez_runs/run1/data/train.jsonl", encoding="utf-8")]
savollar = sum(q["messages"][-1]["content"].startswith('{"ask"') for q in qatorlar)
print(f"qatorlar: {len(qatorlar):,}, rejalar: {len(qatorlar) - savollar:,}, savollar: {savollar}")
Chiqish
qatorlar: 1,638, rejalar: 1,474, savollar: 164

Soup ning o'z tekshiruvi (soup doctor) muhit va fayl to'g'ri ekanini tasdiqladi. Hammasi tayyor edi. soup train buyrug'i esa hech qachon berilmadi.

Nega o'qitilmadi

Trainingdan oldin oxirgi o'lchov qilindi: 2B modelning o'zi qayerda turibdi, va undan kattaroq 4B qayerda. Ikkalasi ham o'qitilmagan, bir xil sharoitda, ikki to'plamda:

python8 qator
import pandas as pd

for toplam in ("transactions", "loans"):
    for fayl in ("round3", "round4", "round4b"):
        xom = pd.read_json(TEZ / f"results/{fayl}_{toplam}.jsonl", lines=True)
        for model, guruh in xom.groupby("model"):
            if model in ("qwen3.5-2b", "qwen3.5-4b"):
                print(f"{fayl:8s} {toplam:13s} {model:11s} {int(guruh['correct'].sum())}/{len(guruh)}")
Chiqish
round3   transactions  qwen3.5-2b  22/40
round3   transactions  qwen3.5-4b  37/40
round4   transactions  qwen3.5-2b  20/40
round4   transactions  qwen3.5-4b  36/40
round4b  transactions  qwen3.5-2b  20/40
round3   loans         qwen3.5-2b  25/40
round3   loans         qwen3.5-4b  30/40
round4   loans         qwen3.5-2b  25/40
round4   loans         qwen3.5-4b  37/40
round4b  loans         qwen3.5-2b  25/40

Qwen3.5-2B: 40 dan 20-25. Qwen3.5-4B: 30 dan 37 gacha — raundga qarab (raundlar orasida nima o'zgargani yozib qo'yilmagan). Va bu — trainingsiz.

O'sha kuni 2B ning xatolari alohida ko'rib chiqildi. Xulosa: 2B o'zbek tilini tushunadi — "filiallar bo'yicha", "olib tashla", "o'tgan oy" so'zlarini to'g'ri ushlaydi. U mantiqda xato qiladi: matnli ustunni jamlaydi, guruhlashni unutadi, ikkinchi filtrni tashlab ketadi. 4B esa xuddi shu o'zbekcha savollarda o'ndan to'qqiz-o'nni to'g'ri bajardi.

Ikki yo'l bor edi:

  • 2B ni train qilish — tez, kichik, kuchsiz noutbukka mos. Lekin 25 dan 37 gacha ko'tarilishi kerak, va bu ko'p ma'lumot va ko'p raund degani.
  • 4B ni train qilish — allaqachon 30-37 da. Training uning qolgan xatolarini tuzatadi.

Qarorni loyiha muallifi qildi, bitta jumla bilan: hamma modelni emas, bitta modelni mukammal darajaga olib chiqish kerak. Tanlov — Qwen3.5-4B. 2B va kuchsiz noutbuk uchun alohida model keyinga qoldirildi — va hozirgacha qaytilmagan.

Trainingdan oldin nima yetishmadi

4B tanlangandan keyin "trainingdan oldin nima yetishmaydi" degan ro'yxat tuzildi. U o'sha kuni yozilgan, va endi har bir bandiga — bir necha kundan keyin — halol baho berish mumkin:

# Yetishmagan narsa Bugungi holat
1 Tekshiruvchi o'qitiladigan model bilan bir xil — u faqat o'zi biladigan misollarni qoldiradi Asosiy tekshiruvchi Gemma bo'ldi (14-bob). Lekin qutqarishda yana o'quvchi modeli ishlatildi — muammo qisman qaytdi
2 Davomli suhbat yo'q Qo'shildi: "on" maydoni, suhbat ichidagi so'rovlar (8-bob)
3 Ko'p uchraydigan so'rovlar uchun tool yo'q Sana oralig'i, bir nechta qiymat, saralash, ulush — qo'shildi. Ikki faylni solishtirish — yo'q
4 Toza snake_case ustun nomlari Sarlavhalarni qayta nomlash qo'shildi (15-bob). Kod uslubidagi nomlar — bugun
5 Juda toza yozilgan so'rovlar Shovqin qo'shildi (15-bob). Qisqa so'rovlar — hali yetishmaydi (16-bob)
6 Uzun prompt sekin — o'qitilgan model qisqa promptda ishlashi mumkin Qilinmadi
7 Kattaroq, qattiqroq test va tahlilchining savollari Real jadvallar ustidagi 105 ta savol — qilindi. Tahlilchining savollari — yo'q

Ba'zi bandlarni hozirgi fayllar bilan tekshiramiz:

python11 qator
asboblar = {a["name"]: a for a in json.load(open(TEZ / "prompt/tools.json", encoding="utf-8"))}
filtr_amallari = asboblar["filter"]["args"]["op"]["enum"]
print("sana oralig'i asbobi:", "filter_dates" in asboblar)
print("bir nechta qiymat (in):", "in" in filtr_amallari)
print("saralash asbobi:", "sort" in asboblar)
print("ulush (share):", "share" in asboblar["group_and_total"]["args"])
print("ikki faylni solishtirish asbobi:", any("compare" in n or "match" in n for n in asboblar if n != "period_compare"))

tez8 = [json.loads(q) for q in open(Path.home() / "tez_runs/tez8/data/train.jsonl", encoding="utf-8")]
uzunlik = sorted(len(q["messages"][0]["content"]) for q in tez8)
print(f"tez8 tizim promptining medianasi: {uzunlik[len(uzunlik) // 2]:,} belgi")
Chiqish
sana oralig'i asbobi: True
bir nechta qiymat (in): True
saralash asbobi: True
ulush (share): True
ikki faylni solishtirish asbobi: False
tez8 tizim promptining medianasi: 5,608 belgi

Oltinchi band haqida alohida. Uzun prompt — 6-bobdagi sovuq javob vaqtining sababi. Fikr shunday edi: o'qitilgan model qoidalar va misollarni allaqachon o'rganib olgan, demak promptdan ularni olib tashlash mumkin. Bu hech qachon sinalmadi — prompt besh ming belgi atrofida qoldi. Sinab ko'rmaganimiz uchun foydali bo'lardimi — bilmaymiz.

run1 dan qolgan saboq

run1 o'qitilmagan bo'lsa ham, u eng arzon saboqni berdi: trainingdan oldin o'lchash. Bir necha soatlik test 2B ni train qilish va qayta o'lchashga ketadigan vaqtni tejadi va yo'nalishni o'zgartirdi. Va trainingdan oldingi "nima yetishmaydi" ro'yxati keyingi bir necha modelning planiga aylandi.

Keyingi bobda birinchi haqiqiy training: pilot4b, va undan keyingi tez3, tez4, tez5.

Xulosa

  • LoRA modelning kichik bir qismini o'qitadi: Tez da 4 milliarddan 8.5 million parametr (0.2 foiz). Asl model 4 bitda yuklanadi (QLoRA), natija asl modelga qo'shiladi va GGUF ga aylantiriladi.
  • Soup bitta YAML fayl bilan boshqariladi; loss faqat javob tokenlarida hisoblanadi.
  • run1 (Qwen3.5-2B, 1 638 qator) tayyorlandi, lekin o'qitilmadi: o'qitilmagan 4B 2B dan ancha kuchli chiqdi, va "bitta modelni mukammal qilish" qarori bilan 4B tanlandi.
  • Trainingdan oldingi yetti bandlik ro'yxatdan ko'pi bajarildi; ikki faylni solishtirish, qisqa prompt va tahlilchining savollari — hali yo'q.

Bu bobni bepul o'qidingiz.

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

Telegramda yozish Narxlar