IlmHamroh
Data Science va sun'iy intellekt/Katta til modellari3/14-dars44 daqiqa
Mundarija (22)

25.3-dars: Generatsiya parametrlari

25-QISM — KATTA TIL MODELLARI · 3-dars


1. Kirish va motivatsiya

24.9-darsda generatsiya strategiyalarini noldan yozgan edik: greedy, temperature, top-k, top-p. LLM API sida xuddi shu tugmalar so'rov parametrlari sifatida keladi — temperature, top_p, top_k, max_tokens, stop_sequences — va javob bilan birga stop_reason (javob nima uchun tugadi) hamda usage (nechta token sarflandi) qaytadi. Bu darsda o'sha mexanizmlarni takrorlamaymiz, balki ularga API foydalanuvchisi ko'zi bilan qaraymiz: qaysi parametr nimani o'zgartiradi, qaysi biri narxga ta'sir qiladi, qaysi biri javobni jimgina buzadi va nega temperature=0 ham ba'zan boshqa javob beradi.

Real vaziyat. Jamoa mahsulot tavsiflarini avtomatik yozuvchi xizmat qurdi. Ishlab chiqishda hammasi yaxshi edi; ishga tushgach uchta shikoyat keldi. Birinchisi: tavsiflarning bir qismi jumla o'rtasida uzilib qolgan — max_tokens kichik edi, kod esa stop_reason ni tekshirmasdan matnni saytga chiqargan. Ikkinchisi: takror so'zlarni kamaytirish uchun "chastota jarimasi" yoqildi — takror kamaydi, lekin tavsiflar sezilarli qisqardi, chunki jarima vergul va nuqtani ham "takror" deb jazoladi. Uchinchisi: sinov uchun temperature=0 qo'yilgan edi, lekin bir xil so'rov ikki marta turli javob qaytardi va regression testlar "tasodifan" yiqila boshladi. Bu darsning to'rt misoli aynan shu uch holatni kichik modelda o'lchaydi.

Bu darsda API uslubidagi yarat() funksiyasini o'zimiz o'rgatgan kichik modelga quramiz, parametrlar to'rini juftlashgan taqqoslash bilan o'lchaymiz, takror jarimalarining yon ta'sirini ko'rsatamiz, float yig'indi tartibi determinizmni qanday buzishini ko'ramiz va kesilgan javoblarni qayta ishlash strategiyalarini narx bilan solishtiramiz.

Bu darsda:

  • API parametrlari: 24.9 dagi mexanizmlarning nomlari
  • temperature, top_p, top_k — birga ishlatish
  • max_tokens, stop ketma-ketliklari va stop_reason
  • Chastota va mavjudlik jarimalari
  • Determinizm: temperature=0 nega har doim bir xil emas
  • Kesilgan javobni qayta ishlash
  • Vazifa turiga qarab parametr tanlash
  • Tuzoqlar

ℹ Misollar real torch/numpy bilan (Python 3.14, torch 2.14 CPU). "LLM" o'rnida o'zimiz o'rgatgan so'z darajasidagi kichik GPT; uning ustida API ga o'xshash Mijoz.yarat() interfeysi quriladi. Bu interfeys parametr nomlari va javob tuzilishini takrorlaydi, lekin katta modellarning xulqi haqida empirik da'vo emas.


2. Nazariya — chuqur tushuntirish

2.1. API parametrlari: 24.9 dagi mexanizmlar

text
API PARAMETRI      24.9 DAGI MEXANIZM                    NIMANI BOSHQARADI
temperature        logit / T, keyin softmax              tekislik (0 -> greedy ga yaqin)
top_p              nucleus: massasi >= p eng kichik to'plam   dumni kesish (moslashuvchan)
top_k              eng katta k ta token                  dumni kesish (qat'iy)
max_tokens         sikl qadamlari soni (yuqori chegara)  javob uzunligi, kechikish
stop_sequences     shu matn chiqsa, to'xtash             format chegarasi
(ba'zi API larda)
frequency_penalty  logit -= alfa * soni                  takrorni kamaytirish
presence_penalty   logit -= beta * [soni > 0]            yangi mavzuga undash
seed               torch.Generator urug'i                takrorlanuvchanlik (kafolatsiz)

JAVOBDA:
  content       - matn (yoki tool chaqiruvi, 25.12)
  stop_reason   - "end_turn" | "max_tokens" | "stop_sequence" | "tool_use"
  usage         - input_tokens, output_tokens (narx, 25.2)

Muhim farq: API da biz logitlarni ko'rmaymiz. 24.9 da top-p yadrosi hajmini, entropiyani va ehtimollarni to'g'ridan-to'g'ri o'lchadik; API da faqat natija matni va stop_reason bor. Shuning uchun parametr tanlash — tashqaridan o'lchash masalasi: bir nechta sozlamada 100-200 so'rov, to'g'rilik va xilma-xillik o'lchovi, juftlashgan taqqoslash.

API parametrlari — 24.9 dagi dekodlash tugmalarining o'zi; farqi shundaki, ichkarini ko'rmaysiz va faqat natijani o'lchaysiz.

2.2. temperature, top_p va top_k birga

text
1-MISOL (ro'yxat yozuvchi model, 200 so'rov):
  sozlama               to'g'ri  takror   noyob  uzunlik
  temperature=0           0.0%  100.0%    2.0%   15.5    <- greedy siklga tushdi
  temperature=0.5        35.0%   65.0%  100.0%   13.1
  temperature=1.0        43.5%   54.5%  100.0%   11.3
  temperature=1.5        34.0%   51.5%   99.5%   10.7
  T=1.0, top_p=0.9       50.5%   49.5%  100.0%   11.4
  T=1.0, top_k=3         45.0%   55.0%   95.0%   11.7
  T=1.5, top_p=0.9       48.0%   52.0%   99.0%   10.3

JUFTLASHGAN FARQLAR (to'g'rilik):
  T=1.5 + top_p=0.9  -  T=1.5  : +0.140, SE 0.027  sezilarli
  T=1.0 + top_p=0.9  -  T=1.0  : +0.070, SE 0.023  sezilarli
  T=0.5              -  T=1.0  : -0.085, SE 0.036  sezilarli (!)

Ikki kuzatuv. Birinchisi: top_p yuqori haroratning zararini qopladi — T=1.5 da dumdagi xato tokenlar tanlanadi, top_p ularni kesadi (+0.140). Bu 24.9 dagi natijaning API ko'rinishi. Ikkinchisi — kutilmagan: bu vazifada past harorat yomonroq (T=0.5 — T=1.0 dan 0.085 past). Sabab — takror: past T da model eng ehtimolli elementlarni qayta-qayta tanlaydi, T=0 da esa 50 ta so'rovga aynan bir xil, takrorli ro'yxat beradi. "Aniqlik uchun temperatura past bo'lsin" degan qoida faqat bitta to'g'ri javobli vazifalarda to'g'ri; ro'yxat, g'oya, variantlar kerak bo'lganda u zarar keltirishi mumkin.

text
AMALIY QOIDALAR:
  odatda BITTA tugmani o'zgartiring: temperature YOKI top_p
  (ba'zi provayderlar ikkalasini birga o'zgartirishni tavsiya etmaydi
   yoki cheklaydi - model hujjatini tekshiring)
  top_k - kamdan-kam kerak; ko'pincha top_p yetarli
  default qiymatlardan boshlang va faqat o'lchov ko'rsatsa o'zgartiring

Harorat — vazifaga bog'liq: yagona javobli vazifada past, ro'yxat va xilma-xillik kerak bo'lganda — past harorat takrorga olib kelishi mumkin; har doim o'lchang.

2.3. max_tokens, stop ketma-ketliklari va stop_reason

text
MAX_TOKENS:
  javobning YUQORI CHEGARASI, "buyurtma" emas
  model javobni erta tugatsa - kamroq token to'lanadi
  chegaraga yetsa - javob ChALA, stop_reason = "max_tokens"

1-MISOL (T=0.5, 200 so'rov):
  max_tokens=6   end_turn   0.0%, max_tokens 100.0%
  max_tokens=12  end_turn  30.0%, max_tokens  70.0%
  max_tokens=30  end_turn 100.0%, max_tokens   0.0%

STOP KETMA-KETLIKLARI:
  shu matn paydo bo'lsa - generatsiya to'xtaydi, stop matni javobga KIRMAYDI
  stop=[","]  ->  "anjir"   stop_reason = "stop_sequence"
  foydali: "faqat birinchi qatorni", shablon chegarasi (masalan, "</javob>")

STOP_REASON QIYMATLARI (Anthropic API):
  "end_turn"      - model o'zi tugatdi (normal)
  "max_tokens"    - chegaraga yetdi: javob chala bo'lishi mumkin
  "stop_sequence" - stop matnlaridan biri chiqdi
  "tool_use"      - model vosita chaqirmoqchi (25.12-dars)

stop_reason ni har bir javobda tekshiring: "max_tokens" — chala javob, uni foydalanuvchiga yoki keyingi bosqichga (JSON parser, 25.5) uzatmang.

2.4. Chastota va mavjudlik jarimalari

text
FORMULALAR (ba'zi provayderlarda mavjud):
  logit[t] -= frequency_penalty * soni[t]         # necha marta chiqqan
  logit[t] -= presence_penalty  * [soni[t] > 0]   # umuman chiqqanmi
  soni - SHU javobda allaqachon generatsiya qilingan tokenlar

YON TA'SIR - STRUKTURA TOKENLARI:
  vergul, nuqta, qator oxiri, JSON qavslari ham "takrorlanadi"
  ularni jazolash -> ro'yxat qisqaradi yoki format buziladi

2-MISOL (T=0.5, 200 so'rov):
  sozlama                       to'g'ri  takror  elementlar
  jarimasiz                      35.0%   65.0%     6.0
  frequency 1.5                  99.5%    0.5%     3.0   <- ro'yxat 2 barobar qisqa
  presence 1.5, tinish ozod      88.0%   12.0%     6.0
  presence 5.0, tinish ozod     100.0%    0.0%     6.0

Bu misolda format buzilmadi, lekin tinish belgilarini jazolash boshqa yo'l bilan "yashirin" zarar keltirdi: model vergulni takrorlashdan qochib, ro'yxatni erta tugatdi — o'rtacha 3.0 element, o'quv ma'lumotida esa 3-8 (o'rtacha 5.5). "To'g'ri" ulushi 99.5% — lekin foydalanuvchi so'ragan narsani (to'liq ro'yxat) olmadi. Tinish belgilari jarimadan ozod qilinganda uzunlik o'z joyiga qaytdi (6.0), takror esa presence 5.0 bilan butunlay yo'qoldi. Ba'zi API larda bunday "ozod" ro'yxat yo'q — u holda jarimani kichik qiymatdan boshlab, uzunlik va format ni ham o'lchab tanlash kerak.

Jarima faqat takrorni emas, hamma takrorlanuvchi tokenni jazolaydi; ta'sirini to'g'rilik, uzunlik va format bilan birga o'lchang.

2.5. Determinizm: temperature=0 nega har doim bir xil emas

text
NAZARIYADA:
  temperature=0 -> har qadamda argmax -> bir xil kirish = bir xil chiqish

AMALDA - FLOAT YIG'INDI TARTIBI:
  float32 da (a + b) + c != a + (b + c)
  3-misol: (1e8 + (-1e8)) + 1 = 1.0,  1e8 + ((-1e8) + 1) = 0.0
  100 000 son yig'indisi: oldinga, teskari, bo'laklab - uch xil natija
  GPU da matmul/attention yig'indisini parallel bo'laklarga bo'ladi;
  bo'linish batch hajmi, apparat va yadro tanlovi bilan o'zgaradi
  server so'rovingizni har safar boshqa batch ga qo'shadi

3-MISOL (40 prompt, greedy, 20 token = 800 qadam):
  eng yaqin ikki logit farqi: mediana 0.530, eng kichigi 2.38e-04
  usul            maks |dlogit|   argmax o'zgargan qadam   javob o'zgardi
  tartib boshqa     4.77e-06           0.00%                  0.0%
  bfloat16          3.89e-02           0.88%                 15.0%
  yolg'iz va 40 talik batch: maks |dlogit| 2.38e-06 (CPU da ham 0 emas!)

ZANJIR REAKSIYASI:
  bitta qadamda argmax ag'darilsa - keyingi kontekst boshqa -
  butun davom boshqa (qadamlarning 0.88% i javoblarning 15% ini o'zgartirdi)

Bizning kichik modelda float32 tartib shovqini (~5e-6) 800 qadamda birorta tanlovni ag'darmadi — eng yaqin ikki logit orasidagi farq 2.38e-04 edi. Katta modellarda lug'at yuz minglab token, javoblar minglab token, shuning uchun "deyarli teng" qadamlar ko'p uchraydi va bitlar darajasidagi farq ham ba'zan tanlovni ag'daradi. Past aniqlikdagi hisob (bfloat16 — katta modellarni ishga tushirishda keng tarqalgan) esa shovqinni ming barobar oshiradi va bizning kichik modelda ham javoblarning 15% ini o'zgartirdi.

text
AMALIY OQIBATLAR:
  "temperature=0 -> bir xil javob" ga tayanadigan test mo'rt
  seed parametri bo'lsa ham - odatda "iloji boricha", kafolat emas
  YECHIMLAR:
    testlarda aniq matn emas, XUSUSIYATLAR tekshiriladi
    (format, kerakli maydonlar, faktlar - 25.5, 25.10)
    kerakli bo'lsa, javobni keshlash yoki saqlash (audit uchun)
    baholashda bir necha namuna va o'rtacha

temperature=0 — "eng ehtimolli token" degani, "doim bir xil javob" emas; hisob yo'li o'zgarsa, deyarli teng tanlovlar ag'dariladi va butun davom o'zgaradi.

2.6. Kesilgan javobni qayta ishlash

text
4-MISOL (40 prompt, greedy; NAMUNA narxlar 3 $ / 12 $):
  strategiya                  to'liq  chaqiruv  kirish  chiqish  narx/1000 so'rov
  e'tiborsiz (8)                0.0%     1.00     8.0     8.0     0.1200 $
  qayta urinish (8->16->32)   100.0%     2.00    16.0    21.2     0.3024 $
  davom ettirish (8 dan)      100.0%     2.00    24.0    13.2     0.2304 $
  yetarli max_tokens (32)     100.0%     1.00     8.0    13.2     0.1824 $

XULOSALAR:
  max_tokens ni yetarli qo'yish - eng arzon: faqat yozilgan token to'lanadi
  qayta urinish - chala javobning tokenlari BEHUDA ketadi
  davom ettirish - chiqish tejaladi, lekin prompt har safar QAYTA to'lanadi
  greedy da davom ettirish bir martalik javob bilan 100% bir xil

Davom ettirish (javobning boshini qaytarib, "davom et" deb so'rash) model imkoniyatidan uzun javoblar uchun kerak — masalan, modelning maksimal chiqish chegarasidan uzun hujjat. Oddiy holatda esa yechim oddiy: max_tokens ni javob uzunligi taqsimotining dumiga (masalan, 99-persentil) moslang va stop_reason ni tekshiring. Matnga qarab "kesilganmi?" deb taxmin qilish (4-misol, 4-bo'lim) bu formatda ishladi, lekin JSON yoki erkin matnda ishonchli emas — stop_reason bor ekan, uni ishlating.

max_tokens — shift, narx emas: uni yetarli qo'ying va stop_reason == "max_tokens" ni xato holat sifatida qayta ishlang.

2.7. Vazifa turiga qarab parametr tanlash

text
VAZIFA                          TEMPERATURE    TOP_P      MAX_TOKENS       BOSHQA
tasniflash, ma'lumot ajratish   0 - 0.2        default    kichik, aniq     strukturali chiqish 25.5-bob
savol-javob (RAG)               0 - 0.3        default    o'rtacha         "bilmayman" ruxsat
kod yozish                      0 - 0.3        default    katta            testlar bilan tekshirish
xulosa, tarjima                 0.2 - 0.5      default    manba x nisbat   uzunlik ko'rsatmasi
g'oyalar, variantlar, ro'yxat   0.7 - 1.0      0.9 - 1.0  o'rtacha         takrorni o'lchang
ijodiy matn                     0.8 - 1.0      0.9 - 1.0  katta            bir nechta namuna

HAMMA HOLATDA:
  stop_reason ni tekshirish
  jadval - boshlang'ich nuqta; yakuniy qiymat - o'z baho to'plamingizda o'lchov
  (25.10-dars; qaror qoidasi: "eng yaxshisidan sezilarli yomon bo'lmagan eng sodda")

Parametrlar jadvali — boshlang'ich taxmin; yakuniy tanlov o'z vazifangizda juftlashgan o'lchov bilan qilinadi.

2.8. Tuzoqlar

Asosiy tuzoqlar: stop_reason ni tekshirmay chala javobni ishlatish; max_tokens ni "narxni cheklash" uchun juda kichik qo'yish; max_tokens ni "kerakli uzunlik" deb o'ylash (model undan oldin tugatishi mumkin — uzunlikni ko'rsatmada ayting); temperature va top_p ni bir vaqtda ko'r-ko'rona o'zgartirish; "aniqlik uchun temperature=0" ni har vazifaga qo'llash (ro'yxat va variantlarda takrorga olib keladi); jarimani struktura tokenlariga ham qo'llab, formatni yoki uzunlikni buzish; temperature=0 ga tayanib aniq matnni tekshiruvchi testlar yozish; seed ni kafolat deb bilish; kesilgan javobni "qayta urinish" bilan tuzatib, chala tokenlar uchun ikki marta to'lash; stop ketma-ketligi javobga kirmasligini unutish; parametrni bitta namunaga qarab tanlash.


3. Tez ma'lumotnoma

python
import anthropic

client = anthropic.Anthropic()                   # ANTHROPIC_API_KEY muhitdan

javob = client.messages.create(
    model="claude-sonnet-5",
    max_tokens=1024,                              # yuqori chegara, faqat yozilgani to'lanadi
    temperature=0.2,                              # vazifaga qarab (2.7-jadval)
    stop_sequences=["</javob>"],                  # format chegarasi
    messages=[{"role": "user", "content": "..."}],
)

if javob.stop_reason == "max_tokens":             # chala javob - xato holat
    raise RuntimeError("javob kesildi: max_tokens ni oshiring yoki davom ettiring")
matn = javob.content[0].text
print(javob.usage.input_tokens, javob.usage.output_tokens)

# jarimalar (ba'zi provayderlarda), tinish belgilari ozod
logit = logit - (alfa * soni + beta * (soni > 0)) * niqob     # niqob[tinish] = 0

# determinizm: aniq matn emas, xususiyatlarni tekshiring
assert javob_json["holat"] in {"tasdiqlandi", "rad etildi"}

Generatsiya parametrlari xulosasi

temperature / top_p / top_k - 24.9 dagi dekodlash tugmalari, tashqaridan o'lchanadi
past T - yagona javobda yaxshi, ro'yxatda takrorga olib kelishi mumkin
max_tokens - shift; stop_reason == "max_tokens" -> chala javob
jarimalar struktura tokenlarini ham jazolaydi
temperature=0 != doim bir xil: float tartib, batch, aniqlik
parametr = o'z baho to'plamingizda juftlashgan o'lchov

4. Batafsil misollar

Misollar real torch/numpy bilan (Python 3.14, torch 2.14 CPU). Model — ro'yxat yozishga o'rgatilgan kichik so'z darajasidagi GPT; Mijoz.yarat() API parametrlari va javob tuzilishini takrorlaydi.

Misol 1 — API uslubidagi parametrlar to'ri

python
"""API uslubidagi generatsiya: temperature, top_p, top_k, max_tokens, stop va stop_reason."""

import math

import numpy as np
import torch
import torch.nn as nn
import torch.nn.functional as F

TOIFALAR = {
    "meva": "olma nok uzum anor shaftoli o'rik gilos behi xurmo anjir".split(),
    "sabzavot": "sabzi piyoz kartoshka karam bodring pomidor lavlagi turp qalampir baqlajon".split(),
    "ichimlik": "choy qahva sut kompot sharbat ayron kefir suv limonad kakao".split(),
    "shirinlik": "halva pishiriq tort murabbo novvot parvarda asal konfet shokolad pechenye".split(),
}
L = 32


def royxat(rng):
    t = str(rng.choice(list(TOIFALAR)))
    n = int(rng.integers(3, 9))
    elementlar = [str(x) for x in rng.choice(TOIFALAR[t], n, replace=False)]
    return f"<d> ro'yxat : {t} javob : " + " , ".join(elementlar) + " . <end>"


class Blok(nn.Module):
    def __init__(self, d, boshlar):
        super().__init__()
        self.boshlar = boshlar
        self.ln1, self.ln2 = nn.LayerNorm(d), nn.LayerNorm(d)
        self.qkv = nn.Linear(d, 3 * d)
        self.proj = nn.Linear(d, d)
        self.ffn = nn.Sequential(nn.Linear(d, 4 * d), nn.GELU(), nn.Linear(4 * d, d))

    def forward(self, x):
        B, T, d = x.shape
        q, k, v = self.qkv(self.ln1(x)).split(d, dim=2)
        q, k, v = [t.view(B, T, self.boshlar, -1).transpose(1, 2) for t in (q, k, v)]
        o = F.scaled_dot_product_attention(q, k, v, is_causal=True)
        x = x + self.proj(o.transpose(1, 2).reshape(B, T, d))
        return x + self.ffn(self.ln2(x))


class GPT(nn.Module):
    def __init__(self, V, d=48, boshlar=4, qatlamlar=2):
        super().__init__()
        self.emb = nn.Embedding(V, d)
        self.poz = nn.Embedding(L, d)
        self.bloklar = nn.Sequential(*[Blok(d, boshlar) for _ in range(qatlamlar)])
        self.ln = nn.LayerNorm(d)
        self.chiqish = nn.Linear(d, V)

    def forward(self, x):
        x = x[:, -L:]
        h = self.emb(x) + self.poz(torch.arange(x.shape[1]))
        return self.chiqish(self.ln(self.bloklar(h)))


def orgat(T, V, seed=0, qadamlar=250, B=32):
    torch.manual_seed(seed)
    model = GPT(V)
    opt = torch.optim.AdamW(model.parameters(), lr=5e-3, weight_decay=0.01)
    g = torch.Generator().manual_seed(seed)
    for _ in range(qadamlar):
        bosh = torch.randint(0, len(T) - L - 1, (B,), generator=g)
        w = torch.stack([T[i:i + L + 1] for i in bosh.tolist()])
        loss = F.cross_entropy(model(w[:, :-1]).reshape(-1, V), w[:, 1:].reshape(-1))
        opt.zero_grad()
        loss.backward()
        opt.step()
    model.eval()
    return model


class Mijoz:
    """API ga o'xshash interfeys: parametrlar nomi va javob tuzilishi LLM API laridagidek."""

    def __init__(self, model, lugat):
        self.model, self.lugat = model, lugat
        self.s2i = {w: i for i, w in enumerate(lugat)}

    @torch.no_grad()
    def yarat(self, promptlar, max_tokens=30, temperature=1.0, top_p=1.0, top_k=None,
              stop=None, seed=0):
        """Promptlar ro'yxati -> [{"text", "stop_reason", "usage"}], batch bilan."""
        x = torch.tensor([[self.s2i[w] for w in p.split()] for p in promptlar])
        n0 = x.shape[1]
        g = torch.Generator().manual_seed(seed)
        for _ in range(max_tokens):
            logit = self.model(x)[:, -1]
            if temperature == 0:
                keyingi = logit.argmax(-1)
            else:
                logit = logit / temperature
                if top_k is not None:
                    chegara = logit.topk(top_k, dim=-1).values[:, -1:]
                    logit = logit.masked_fill(logit < chegara, float("-inf"))
                if top_p < 1.0:
                    tartib, idx = logit.sort(dim=-1, descending=True)
                    p = torch.softmax(tartib, -1)
                    tartib = tartib.masked_fill(p.cumsum(-1) - p >= top_p, float("-inf"))
                    logit = torch.full_like(logit, float("-inf")).scatter(-1, idx, tartib)
                keyingi = torch.multinomial(torch.softmax(logit, -1), 1, generator=g)[:, 0]
            x = torch.cat([x, keyingi[:, None]], 1)
        javoblar = []
        for qator in x[:, n0:].tolist():
            sozlar, sabab = [], "max_tokens"
            for i in qator:
                w = self.lugat[i]
                if w == "<end>":
                    sabab = "end_turn"
                    break
                sozlar.append(w)
                matn = " ".join(sozlar)
                topilgan = [matn.index(s) for s in (stop or []) if s in matn]
                if topilgan:                               # stop matni javobga kirmaydi
                    sozlar = matn[:min(topilgan)].split()
                    sabab = "stop_sequence"
                    break
            chiq = len(sozlar) + (1 if sabab != "max_tokens" else 0)
            javoblar.append({"text": " ".join(sozlar), "stop_reason": sabab,
                             "usage": {"input_tokens": n0, "output_tokens": chiq}})
        return javoblar


def tahlil(javob, toifa):
    """Ro'yxat to'g'rimi: hamma element shu toifadan, takror yo'q, nuqta bilan tugagan."""
    matn = javob["text"]
    toza = matn.rstrip(" .")
    el = [w for w in toza.split(" , ")] if toza else []
    togri_el = all(e in TOIFALAR[toifa] for e in el) and len(el) > 0
    takror = len(el) != len(set(el))
    return togri_el and not takror and matn.endswith("."), takror, " ".join(el)


def main() -> None:
    torch.set_num_threads(1)
    rng = np.random.default_rng(0)
    matn = " ".join(royxat(rng) for _ in range(3000))
    lugat = sorted(set(matn.split()))
    s2i = {w: i for i, w in enumerate(lugat)}
    mijoz = Mijoz(orgat(torch.tensor([s2i[w] for w in matn.split()]), len(lugat)), lugat)
    toifalar = list(TOIFALAR)
    promptlar = [f"<d> ro'yxat : {t} javob :" for t in toifalar for _ in range(50)]
    toifa_q = [t for t in toifalar for _ in range(50)]

    print("=== 1. Bitta so'rov: javob tuzilishi ===")
    j = mijoz.yarat(promptlar[:1], temperature=0)[0]
    print(f"  {j}")

    print("\n=== 2. Parametrlar to'ri (200 so'rov: 4 toifa x 50) ===")
    print("  sozlama                 to'g'ri  takror  noyob  o'rt. uzunlik  end_turn")
    sozlamalar = [("temperature=0", {"temperature": 0}),
                  ("temperature=0.5", {"temperature": 0.5}),
                  ("temperature=1.0", {}),
                  ("temperature=1.5", {"temperature": 1.5}),
                  ("T=1.0, top_p=0.9", {"top_p": 0.9}),
                  ("T=1.0, top_k=3", {"top_k": 3}),
                  ("T=1.5, top_p=0.9", {"temperature": 1.5, "top_p": 0.9})]
    togri = {}
    for nom, s in sozlamalar:
        javoblar = mijoz.yarat(promptlar, seed=1, **s)
        t = [tahlil(jv, tq) for jv, tq in zip(javoblar, toifa_q)]
        togri[nom] = np.array([x[0] for x in t], dtype=float)
        noyob = len({x[2] for x in t}) / len(t)
        uz = np.mean([jv["usage"]["output_tokens"] for jv in javoblar])
        tugadi = np.mean([jv["stop_reason"] == "end_turn" for jv in javoblar])
        print(f"  {nom:<22} {togri[nom].mean():>7.1%} {np.mean([x[1] for x in t]):>7.1%} "
              f"{noyob:>6.1%} {uz:>14.1f} {tugadi:>9.1%}")

    print("\n=== 3. Juftlashgan farq: to'g'rilik (200 so'rov) ===")
    for a, b in (("T=1.5, top_p=0.9", "temperature=1.5"), ("T=1.0, top_p=0.9", "temperature=1.0"),
                 ("temperature=0.5", "temperature=1.0")):
        d = togri[a] - togri[b]
        se = d.std(ddof=1) / math.sqrt(len(d))
        print(f"  {a} - {b}: {d.mean():+.3f}, SE {se:.3f} -> "
              f"{'sezilarli' if abs(d.mean()) > 2 * se else 'sezilarli emas'}")

    print("\n=== 4. max_tokens va stop ketma-ketligi ===")
    for mt in (6, 12, 30):
        javoblar = mijoz.yarat(promptlar, max_tokens=mt, temperature=0.5, seed=1)
        sabablar = {s: np.mean([jv["stop_reason"] == s for jv in javoblar])
                    for s in ("end_turn", "max_tokens")}
        print(f"  max_tokens={mt:<3}: end_turn {sabablar['end_turn']:>6.1%}, "
              f"max_tokens {sabablar['max_tokens']:>6.1%}")
    javoblar = mijoz.yarat(promptlar[:3], temperature=0.5, stop=[","], seed=1)
    for jv in javoblar:
        print(f"  stop=[',']: {jv['text']!r:<10} stop_reason={jv['stop_reason']}, chiqish {jv['usage']['output_tokens']} token")
    print("  ⭐ stop_reason ni har doim tekshiring: max_tokens - javob chala")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. Bitta so'rov: javob tuzilishi ===
  {'text': 'gilos , anjir , olma , behi , anor , anjir , nok .', 'stop_reason': 'end_turn', 'usage': {'input_tokens': 6, 'output_tokens': 15}}

=== 2. Parametrlar to'ri (200 so'rov: 4 toifa x 50) ===
  sozlama                 to'g'ri  takror  noyob  o'rt. uzunlik  end_turn
  temperature=0             0.0%  100.0%   2.0%           15.5    100.0%
  temperature=0.5          35.0%   65.0% 100.0%           13.1    100.0%
  temperature=1.0          43.5%   54.5% 100.0%           11.3    100.0%
  temperature=1.5          34.0%   51.5%  99.5%           10.7    100.0%
  T=1.0, top_p=0.9         50.5%   49.5% 100.0%           11.4    100.0%
  T=1.0, top_k=3           45.0%   55.0%  95.0%           11.7    100.0%
  T=1.5, top_p=0.9         48.0%   52.0%  99.0%           10.3    100.0%

=== 3. Juftlashgan farq: to'g'rilik (200 so'rov) ===
  T=1.5, top_p=0.9 - temperature=1.5: +0.140, SE 0.027 -> sezilarli
  T=1.0, top_p=0.9 - temperature=1.0: +0.070, SE 0.023 -> sezilarli
  temperature=0.5 - temperature=1.0: -0.085, SE 0.036 -> sezilarli

=== 4. max_tokens va stop ketma-ketligi ===
  max_tokens=6  : end_turn   0.0%, max_tokens 100.0%
  max_tokens=12 : end_turn  30.0%, max_tokens  70.0%
  max_tokens=30 : end_turn 100.0%, max_tokens   0.0%
  stop=[',']: 'anjir'    stop_reason=stop_sequence, chiqish 2 token
  stop=[',']: "o'rik"    stop_reason=stop_sequence, chiqish 2 token
  stop=[',']: 'gilos'    stop_reason=stop_sequence, chiqish 2 token
  ⭐ stop_reason ni har doim tekshiring: max_tokens - javob chala

Nima ko'rsatdi: model 3000 ta ro'yxatda o'rgatildi: to'rt toifa (meva, sabzavot, ichimlik, shirinlik), har ro'yxatda 3-8 ta takrorsiz element. yarat() API javobiga o'xshash lug'at qaytaradi: text, stop_reason, usage. Birinchi javobning o'zi muammoni ko'rsatdi: greedy (temperature=0) anjir ni ikki marta yozdi. 2-bo'lim: greedy 200 so'rovga atigi 4 xil ro'yxat berdi (noyob 2.0%), hammasi takrorli — to'g'rilik 0.0%. Harorat oshgan sari takror kamaydi (65.0% → 51.5%), lekin T=1.5 da noto'g'ri toifa elementlari ko'paydi va to'g'rilik 34.0% ga tushdi. Eng yaxshisi T=1.0, top_p=0.9 (50.5%). Juftlashgan farqlar: top_p T=1.5 da +0.140 (SE 0.027), T=1.0 da +0.070 (SE 0.023) — ikkalasi sezilarli; T=0.5 esa T=1.0 dan sezilarli yomon (-0.085, SE 0.036) — past harorat bu vazifada takrorni kuchaytiradi. Umumiy to'g'rilik pastligi kichik modelning cheklovi: u qaysi elementlarni yozib bo'lganini yaxshi "eslamaydi" (2-misolda jarimalar buni tuzatadi). 4-bo'lim: max_tokens=6 da hamma javob kesildi, 12 da 70%, 30 da hech biri. stop=[","] birinchi elementdan keyin to'xtatdi va vergul javobga kirmadi. Bog'liq bo'limlar: 2.1, 2.2, 2.3.

Misol 2 — Takror jarimalari va ularning yon ta'siri

python
"""Chastota va mavjudlik jarimalari: takrorni kamaytirish va formatni buzmaslik."""

import math

import numpy as np
import torch
import torch.nn as nn
import torch.nn.functional as F

TOIFALAR = {
    "meva": "olma nok uzum anor shaftoli o'rik gilos behi xurmo anjir".split(),
    "sabzavot": "sabzi piyoz kartoshka karam bodring pomidor lavlagi turp qalampir baqlajon".split(),
    "ichimlik": "choy qahva sut kompot sharbat ayron kefir suv limonad kakao".split(),
    "shirinlik": "halva pishiriq tort murabbo novvot parvarda asal konfet shokolad pechenye".split(),
}
L = 32


def royxat(rng):
    t = str(rng.choice(list(TOIFALAR)))
    n = int(rng.integers(3, 9))
    elementlar = [str(x) for x in rng.choice(TOIFALAR[t], n, replace=False)]
    return f"<d> ro'yxat : {t} javob : " + " , ".join(elementlar) + " . <end>"


class Blok(nn.Module):
    def __init__(self, d, boshlar):
        super().__init__()
        self.boshlar = boshlar
        self.ln1, self.ln2 = nn.LayerNorm(d), nn.LayerNorm(d)
        self.qkv = nn.Linear(d, 3 * d)
        self.proj = nn.Linear(d, d)
        self.ffn = nn.Sequential(nn.Linear(d, 4 * d), nn.GELU(), nn.Linear(4 * d, d))

    def forward(self, x):
        B, T, d = x.shape
        q, k, v = self.qkv(self.ln1(x)).split(d, dim=2)
        q, k, v = [t.view(B, T, self.boshlar, -1).transpose(1, 2) for t in (q, k, v)]
        o = F.scaled_dot_product_attention(q, k, v, is_causal=True)
        x = x + self.proj(o.transpose(1, 2).reshape(B, T, d))
        return x + self.ffn(self.ln2(x))


class GPT(nn.Module):
    def __init__(self, V, d=48, boshlar=4, qatlamlar=2):
        super().__init__()
        self.emb = nn.Embedding(V, d)
        self.poz = nn.Embedding(L, d)
        self.bloklar = nn.Sequential(*[Blok(d, boshlar) for _ in range(qatlamlar)])
        self.ln = nn.LayerNorm(d)
        self.chiqish = nn.Linear(d, V)

    def forward(self, x):
        x = x[:, -L:]
        h = self.emb(x) + self.poz(torch.arange(x.shape[1]))
        return self.chiqish(self.ln(self.bloklar(h)))


def orgat(T, V, seed=0, qadamlar=250, B=32):
    torch.manual_seed(seed)
    model = GPT(V)
    opt = torch.optim.AdamW(model.parameters(), lr=5e-3, weight_decay=0.01)
    g = torch.Generator().manual_seed(seed)
    for _ in range(qadamlar):
        bosh = torch.randint(0, len(T) - L - 1, (B,), generator=g)
        w = torch.stack([T[i:i + L + 1] for i in bosh.tolist()])
        loss = F.cross_entropy(model(w[:, :-1]).reshape(-1, V), w[:, 1:].reshape(-1))
        opt.zero_grad()
        loss.backward()
        opt.step()
    model.eval()
    return model



class Mijoz:
    """API uslubidagi mijoz + chastota va mavjudlik jarimalari."""

    def __init__(self, model, lugat):
        self.model, self.lugat = model, lugat
        self.s2i = {w: i for i, w in enumerate(lugat)}

    @torch.no_grad()
    def yarat(self, promptlar, max_tokens=30, temperature=1.0, frequency_penalty=0.0,
              presence_penalty=0.0, ozod=(), seed=0):
        """logit -= frequency_penalty * soni + presence_penalty * [soni > 0].
        ozod - jarimadan ozod tokenlar (masalan, tinish belgilari)."""
        x = torch.tensor([[self.s2i[w] for w in p.split()] for p in promptlar])
        n0, V = x.shape[1], len(self.lugat)
        soni = torch.zeros(len(promptlar), V)
        niqob = torch.ones(V)
        for w in ozod:
            niqob[self.s2i[w]] = 0.0
        g = torch.Generator().manual_seed(seed)
        for _ in range(max_tokens):
            logit = self.model(x)[:, -1]
            logit = logit - (frequency_penalty * soni + presence_penalty * (soni > 0)) * niqob
            if temperature == 0:
                keyingi = logit.argmax(-1)
            else:
                keyingi = torch.multinomial(torch.softmax(logit / temperature, -1), 1,
                                            generator=g)[:, 0]
            soni[torch.arange(len(promptlar)), keyingi] += 1
            x = torch.cat([x, keyingi[:, None]], 1)
        javoblar = []
        for qator in x[:, n0:].tolist():
            sozlar, sabab = [], "max_tokens"
            for i in qator:
                if self.lugat[i] == "<end>":
                    sabab = "end_turn"
                    break
                sozlar.append(self.lugat[i])
            javoblar.append({"text": " ".join(sozlar), "stop_reason": sabab,
                             "usage": {"input_tokens": n0, "output_tokens": len(sozlar)}})
        return javoblar


def tahlil(javob, toifa):
    """(to'g'ri ro'yxatmi, takror bormi, format buzilganmi, elementlar soni)."""
    matn = javob["text"]
    format_ok = matn.endswith(" .") and javob["stop_reason"] == "end_turn"
    tanalar = matn.rstrip(" .").split(" , ") if matn else []
    format_ok = format_ok and all(len(t.split()) == 1 for t in tanalar)
    el = [t for t in tanalar if t]
    takror = len(el) != len(set(el))
    togri = format_ok and not takror and all(e in TOIFALAR[toifa] for e in el)
    return togri, takror, not format_ok, len(el)


def main() -> None:
    torch.set_num_threads(1)
    rng = np.random.default_rng(0)
    matn = " ".join(royxat(rng) for _ in range(3000))
    lugat = sorted(set(matn.split()))
    s2i = {w: i for i, w in enumerate(lugat)}
    mijoz = Mijoz(orgat(torch.tensor([s2i[w] for w in matn.split()]), len(lugat)), lugat)
    toifalar = list(TOIFALAR)
    promptlar = [f"<d> ro'yxat : {t} javob :" for t in toifalar for _ in range(50)]
    toifa_q = [t for t in toifalar for _ in range(50)]
    tinish = (",", ".", "<end>")

    print("=== 1. Muammo: past temperaturada takror ===")
    for jv in mijoz.yarat(promptlar[::50], temperature=0):
        print(f"  {jv['text'][:70]}")

    print("\n=== 2. Jarimalar (T=0.5, 200 so'rov) ===")
    print("  sozlama                        to'g'ri  takror  format buzuq  elementlar")
    sozlamalar = [("jarimasiz", {}),
                  ("frequency 0.5", {"frequency_penalty": 0.5}),
                  ("frequency 1.5", {"frequency_penalty": 1.5}),
                  ("presence 1.5", {"presence_penalty": 1.5}),
                  ("frequency 1.5, tinish ozod", {"frequency_penalty": 1.5, "ozod": tinish}),
                  ("presence 1.5, tinish ozod", {"presence_penalty": 1.5, "ozod": tinish}),
                  ("presence 5.0, tinish ozod", {"presence_penalty": 5.0, "ozod": tinish})]
    natija = {}
    for nom, s in sozlamalar:
        javoblar = mijoz.yarat(promptlar, temperature=0.5, seed=1, **s)
        t = np.array([tahlil(jv, tq) for jv, tq in zip(javoblar, toifa_q)], dtype=float)
        natija[nom] = t
        print(f"  {nom:<30} {t[:, 0].mean():>7.1%} {t[:, 1].mean():>7.1%} "
              f"{t[:, 2].mean():>13.1%} {t[:, 3].mean():>11.1f}")
    buzuq = [jv["text"] for jv in mijoz.yarat(promptlar[:4], temperature=0.5, seed=1,
                                               frequency_penalty=1.5)]
    print(f"  namuna (frequency 1.5, tinish jarimada): {buzuq[0][:60]!r}")

    print("\n=== 3. Juftlashgan farq: to'g'rilik (200 so'rov) ===")
    asos = natija["jarimasiz"][:, 0]
    for nom in ("frequency 1.5", "presence 1.5, tinish ozod", "presence 5.0, tinish ozod"):
        d = natija[nom][:, 0] - asos
        se = d.std(ddof=1) / math.sqrt(len(d))
        print(f"  {nom:<27} - jarimasiz: {d.mean():+.3f}, SE {se:.3f} -> "
              f"{'sezilarli' if abs(d.mean()) > 2 * se else 'sezilarli emas'}")

    print("\n=== 4. Greedy + jarima (temperature=0) ===")
    for nom, s in (("greedy", {}), ("greedy + presence 5.0, ozod",
                                    {"presence_penalty": 5.0, "ozod": tinish})):
        javoblar = mijoz.yarat(promptlar[::50], temperature=0, **s)
        t = np.array([tahlil(jv, tq) for jv, tq in zip(javoblar, toifalar)], dtype=float)
        print(f"  {nom:<28} to'g'ri {int(t[:, 0].sum())}/4, takror {int(t[:, 1].sum())}/4: "
              f"{javoblar[0]['text'][:48]}")
    print("  ⭐ Jarima struktura tokenlariga tegmasin; ta'sirini o'lchab tanlang")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. Muammo: past temperaturada takror ===
  gilos , anjir , olma , behi , anor , anjir , nok .
  sabzi , baqlajon , turp , lavlagi , bodring , qalampir , bodring , sab
  kakao , suv , qahva , suv , sharbat , kompot .
  tort , murabbo , asal , tort , pishiriq , tort , konfet , pishiriq .

=== 2. Jarimalar (T=0.5, 200 so'rov) ===
  sozlama                        to'g'ri  takror  format buzuq  elementlar
  jarimasiz                        35.0%   65.0%          0.0%         6.0
  frequency 0.5                    86.0%   14.0%          0.0%         3.9
  frequency 1.5                    99.5%    0.5%          0.0%         3.0
  presence 1.5                     99.5%    0.5%          0.0%         3.5
  frequency 1.5, tinish ozod       88.0%   12.0%          0.0%         6.0
  presence 1.5, tinish ozod        88.0%   12.0%          0.0%         6.0
  presence 5.0, tinish ozod       100.0%    0.0%          0.0%         6.0
  namuna (frequency 1.5, tinish jarimada): 'anjir , shaftoli .'

=== 3. Juftlashgan farq: to'g'rilik (200 so'rov) ===
  frequency 1.5               - jarimasiz: +0.645, SE 0.034 -> sezilarli
  presence 1.5, tinish ozod   - jarimasiz: +0.530, SE 0.035 -> sezilarli
  presence 5.0, tinish ozod   - jarimasiz: +0.650, SE 0.034 -> sezilarli

=== 4. Greedy + jarima (temperature=0) ===
  greedy                       to'g'ri 0/4, takror 4/4: gilos , anjir , olma , behi , anor , anjir , nok
  greedy + presence 5.0, ozod  to'g'ri 4/4, takror 0/4: gilos , anjir , olma , behi , anor , shaftoli .
  ⭐ Jarima struktura tokenlariga tegmasin; ta'sirini o'lchab tanlang

Nima ko'rsatdi: 1-bo'limda greedy to'rt toifaning hammasida takror yozdi (anjir, bodring, suv, tort ikki-uch marta). 2-bo'lim, T=0.5: jarimasiz to'g'rilik 35.0%, takror 65.0%. Chastota jarimasi 1.5 takrorni 0.5% ga tushirdi, to'g'rilik 99.5% — lekin ro'yxat o'rtacha 6.0 dan 3.0 elementga qisqardi: vergul ham jazolandi va model ro'yxatni erta yopdi (namuna: 'anjir , shaftoli .'). Format buzilmadi (0.0%), zarar uzunlikda yashiringan. Tinish belgilari ozod qilinganda uzunlik 6.0 ga qaytdi; presence 1.5 takrorni 12.0% gacha kamaytirdi, presence 5.0 esa butunlay yo'qotdi (100.0% to'g'ri). Juftlashgan farqlar jarimasizga nisbatan hammasi sezilarli (+0.530 dan +0.650 gacha, SE ~0.035). 4-bo'lim: greedy ham jarima bilan to'g'ri ro'yxat berdi (4/4) — takrorlangan anjir o'rniga shaftoli keldi. Bog'liq bo'lim: 2.4.

Misol 3 — Determinizm: float tartibi, batch va aniqlik

python
"""Determinizm: temperature=0 ham hisob yo'li o'zgarsa boshqa javob berishi mumkin."""

import math

import numpy as np
import torch
import torch.nn as nn
import torch.nn.functional as F

TOIFALAR = {
    "meva": "olma nok uzum anor shaftoli o'rik gilos behi xurmo anjir".split(),
    "sabzavot": "sabzi piyoz kartoshka karam bodring pomidor lavlagi turp qalampir baqlajon".split(),
    "ichimlik": "choy qahva sut kompot sharbat ayron kefir suv limonad kakao".split(),
    "shirinlik": "halva pishiriq tort murabbo novvot parvarda asal konfet shokolad pechenye".split(),
}
L = 32


def royxat(rng):
    t = str(rng.choice(list(TOIFALAR)))
    n = int(rng.integers(3, 9))
    elementlar = [str(x) for x in rng.choice(TOIFALAR[t], n, replace=False)]
    return f"<d> ro'yxat : {t} javob : " + " , ".join(elementlar) + " . <end>"


class Blok(nn.Module):
    def __init__(self, d, boshlar):
        super().__init__()
        self.boshlar = boshlar
        self.ln1, self.ln2 = nn.LayerNorm(d), nn.LayerNorm(d)
        self.qkv = nn.Linear(d, 3 * d)
        self.proj = nn.Linear(d, d)
        self.ffn = nn.Sequential(nn.Linear(d, 4 * d), nn.GELU(), nn.Linear(4 * d, d))

    def forward(self, x):
        B, T, d = x.shape
        q, k, v = self.qkv(self.ln1(x)).split(d, dim=2)
        q, k, v = [t.view(B, T, self.boshlar, -1).transpose(1, 2) for t in (q, k, v)]
        o = F.scaled_dot_product_attention(q, k, v, is_causal=True)
        x = x + self.proj(o.transpose(1, 2).reshape(B, T, d))
        return x + self.ffn(self.ln2(x))


class GPT(nn.Module):
    def __init__(self, V, d=48, boshlar=4, qatlamlar=2):
        super().__init__()
        self.emb = nn.Embedding(V, d)
        self.poz = nn.Embedding(L, d)
        self.bloklar = nn.Sequential(*[Blok(d, boshlar) for _ in range(qatlamlar)])
        self.ln = nn.LayerNorm(d)
        self.chiqish = nn.Linear(d, V)

    def forward(self, x):
        x = x[:, -L:]
        h = self.emb(x) + self.poz(torch.arange(x.shape[1]))
        return self.chiqish(self.ln(self.bloklar(h)))


def orgat(T, V, seed=0, qadamlar=250, B=32):
    torch.manual_seed(seed)
    model = GPT(V)
    opt = torch.optim.AdamW(model.parameters(), lr=5e-3, weight_decay=0.01)
    g = torch.Generator().manual_seed(seed)
    for _ in range(qadamlar):
        bosh = torch.randint(0, len(T) - L - 1, (B,), generator=g)
        w = torch.stack([T[i:i + L + 1] for i in bosh.tolist()])
        loss = F.cross_entropy(model(w[:, :-1]).reshape(-1, V), w[:, 1:].reshape(-1))
        opt.zero_grad()
        loss.backward()
        opt.step()
    model.eval()
    return model



@torch.no_grad()
def yashirin(model, x):
    x = x[:, -L:]
    h = model.emb(x) + model.poz(torch.arange(x.shape[1]))
    return model.ln(model.bloklar(h))[:, -1]


@torch.no_grad()
def logit_usul(model, h, usul):
    """Bir xil matematik ifoda, turli hisoblash yo'li."""
    W, b = model.chiqish.weight, model.chiqish.bias
    if usul == "float32":
        return h @ W.T + b
    if usul == "tartib boshqa":                       # yig'indi ikki bo'lakda, teskari tartibda
        k = h.shape[1] // 2
        return (h[:, k:] @ W[:, k:].T + h[:, :k] @ W[:, :k].T) + b
    if usul == "bfloat16":                            # boshqa apparat / aniqlik yo'li
        return (h.bfloat16() @ W.bfloat16().T).float() + b
    raise ValueError(usul)


@torch.no_grad()
def greedy(model, x, usul, n=20):
    for _ in range(n):
        keyingi = logit_usul(model, yashirin(model, x), usul).argmax(-1)
        x = torch.cat([x, keyingi[:, None]], 1)
    return x


def main() -> None:
    torch.set_num_threads(1)

    print("=== 1. Float yig'indi tartibi ===")
    a, b, c = (torch.tensor(v, dtype=torch.float32) for v in (1e8, -1e8, 1.0))
    print(f"  (1e8 + (-1e8)) + 1 = {((a + b) + c).item():.1f}")
    print(f"  1e8 + ((-1e8) + 1) = {(a + (b + c)).item():.1f}   (float32 da 1e8 - 1 = -1e8)")
    g = torch.Generator().manual_seed(0)
    v = torch.randn(100000, generator=g)
    oldinga = v.sum().item()
    orqaga = v.flip(0).sum().item()
    boladi = sum(q.sum().item() for q in v.split(1000))
    aniq = v.double().sum().item()
    print(f"  100000 son yig'indisi: oldinga {oldinga:.6f}, teskari {orqaga:.6f}, "
          f"bo'laklab {boladi:.6f}")
    print(f"  float64 dagi qiymat {aniq:.6f}; float32 farqlari 0 emas: "
          f"{abs(oldinga - aniq):.1e}, {abs(orqaga - aniq):.1e}, {abs(boladi - aniq):.1e}")

    print("\n=== 2. Model: bir xil so'rov, turli hisoblash yo'li ===")
    rng = np.random.default_rng(0)
    matn = " ".join(royxat(rng) for _ in range(3000))
    lugat = sorted(set(matn.split()))
    s2i = {w: i for i, w in enumerate(lugat)}
    model = orgat(torch.tensor([s2i[w] for w in matn.split()]), len(lugat))
    promptlar = [f"<d> ro'yxat : {t} javob : {e} ," for t, el in TOIFALAR.items() for e in el]
    x = torch.tensor([[s2i[w] for w in p.split()] for p in promptlar])
    asos = greedy(model, x, "float32")
    print(f"  {len(promptlar)} ta prompt, greedy (temperature=0), 20 token")
    h_hammasi, qadam_logit = [], []
    for t in range(x.shape[1], asos.shape[1]):
        h = yashirin(model, asos[:, :t])
        h_hammasi.append(h)
        qadam_logit.append(logit_usul(model, h, "float32"))
    lg = torch.cat(qadam_logit)
    top2 = lg.topk(2, -1).values
    oraliq = (top2[:, 0] - top2[:, 1]).numpy()
    print(f"  {len(oraliq)} qadam: eng yaqin ikki logit orasidagi farq - "
          f"mediana {np.median(oraliq):.3f}, eng kichigi {oraliq.min():.2e}")
    print("  usul            maks |dlogit|   qadamda argmax o'zgardi   javob o'zgardi")
    ozgarish = {}
    for usul in ("tartib boshqa", "bfloat16"):
        boshqa = torch.cat([logit_usul(model, h, usul) for h in h_hammasi])
        farq = (boshqa - lg).abs().max().item()
        almashdi = (boshqa.argmax(-1) != lg.argmax(-1)).float().mean().item()
        javob = greedy(model, x, usul)
        ozgardi = (javob != asos).any(1).float().mean().item()
        ozgarish[usul] = ozgardi
        print(f"  {usul:<15} {farq:>13.2e} {almashdi:>25.2%} {ozgardi:>16.1%}")

    print("\n=== 3. Batch tarkibi: yolg'iz va 40 talik batch ichida ===")
    yolgiz = torch.cat([logit_usul(model, yashirin(model, x[i:i + 1]), "float32")
                        for i in range(len(x))])
    batch = logit_usul(model, yashirin(model, x), "float32")
    bf = (yolgiz - batch).abs().max().item()
    print(f"  maks |dlogit| = {bf:.2e}")
    if bf > 0:
        print("  hatto CPU da ham: batch hajmi boshqa -> boshqa yadro yo'li -> bitlar farq qiladi")
    print("  GPU serverlarda batch hajmi va parallel bo'linish so'rovdan so'rovga o'zgaradi")

    print("\n=== 4. Xulosa (natijadan) ===")
    kichik = (oraliq < 0.01).mean()
    print(f"  qadamlarning {kichik:.1%} ida ikki eng yaxshi token farqi 0.01 dan kichik")
    if ozgarish["tartib boshqa"] == 0:
        print("  float32 tartib shovqini (~1e-6) bu 800 qadamda birorta tanlovni ag'darmadi")
    if ozgarish["bfloat16"] > 0:
        print(f"  bfloat16 shovqini (~1e-2) javoblarning {ozgarish['bfloat16']:.0%} ini o'zgartirdi:"
              " bitta ag'darish butun davomni o'zgartiradi")
    print("  ⭐ temperature=0 - 'eng ehtimolli token', lekin hisob yo'li o'zgarsa, javob ham o'zgaradi")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. Float yig'indi tartibi ===
  (1e8 + (-1e8)) + 1 = 1.0
  1e8 + ((-1e8) + 1) = 0.0   (float32 da 1e8 - 1 = -1e8)
  100000 son yig'indisi: oldinga -244.559769, teskari -244.559723, bo'laklab -244.559819
  float64 dagi qiymat -244.559764; float32 farqlari 0 emas: 4.9e-06, 4.1e-05, 5.6e-05

=== 2. Model: bir xil so'rov, turli hisoblash yo'li ===
  40 ta prompt, greedy (temperature=0), 20 token
  800 qadam: eng yaqin ikki logit orasidagi farq - mediana 0.530, eng kichigi 2.38e-04
  usul            maks |dlogit|   qadamda argmax o'zgardi   javob o'zgardi
  tartib boshqa        4.77e-06                     0.00%             0.0%
  bfloat16             3.89e-02                     0.88%            15.0%

=== 3. Batch tarkibi: yolg'iz va 40 talik batch ichida ===
  maks |dlogit| = 2.38e-06
  hatto CPU da ham: batch hajmi boshqa -> boshqa yadro yo'li -> bitlar farq qiladi
  GPU serverlarda batch hajmi va parallel bo'linish so'rovdan so'rovga o'zgaradi

=== 4. Xulosa (natijadan) ===
  qadamlarning 1.6% ida ikki eng yaxshi token farqi 0.01 dan kichik
  float32 tartib shovqini (~1e-6) bu 800 qadamda birorta tanlovni ag'darmadi
  bfloat16 shovqini (~1e-2) javoblarning 15% ini o'zgartirdi: bitta ag'darish butun davomni o'zgartiradi
  ⭐ temperature=0 - 'eng ehtimolli token', lekin hisob yo'li o'zgarsa, javob ham o'zgaradi

Nima ko'rsatdi: float32 da qo'shish assotsiativ emas: (1e8 + (-1e8)) + 1 = 1.0, 1e8 + ((-1e8) + 1) = 0.0 — chunki float32 da -1e8 + 1 yana -1e8 ga yaxlitlanadi. 100 000 ta son yig'indisi oldinga, teskari va bo'laklab uch xil chiqdi (float64 qiymatidan 4.9e-06 — 5.6e-05 farq). 2-bo'lim bir xil model va bir xil kirishda chiqish qatlamini uch yo'l bilan hisobladi. Tartib boshqa bo'lganda logitlar 4.77e-06 gacha farq qildi, lekin 800 qadamning birortasida ham argmax o'zgarmadi — bu modelda eng yaqin ikki logit farqi ham 2.38e-04, ya'ni shovqindan 50 barobar katta. bfloat16 da farq 3.89e-02: qadamlarning atigi 0.88% ida tanlov ag'darildi, lekin javoblarning 15.0% i o'zgardi — bitta ag'darilgan token keyingi butun kontekstni o'zgartiradi. 3-bo'lim — kutilmagan natija: hatto CPU da, bitta ipda, bir xil prompt yolg'iz va 40 talik batch ichida bitlar darajasida farqli logit berdi (2.38e-06) — batch hajmi yadro yo'lini o'zgartiradi. API serverlarida so'rovingiz har safar boshqa batch ga tushadi. Bog'liq bo'lim: 2.5.

Misol 4 — stop_reason: kesilgan javobni qayta ishlash

python
"""stop_reason: max_tokens bilan kesilgan javobni aniqlash va qayta ishlash strategiyalari."""

import math

import numpy as np
import torch
import torch.nn as nn
import torch.nn.functional as F

TOIFALAR = {
    "meva": "olma nok uzum anor shaftoli o'rik gilos behi xurmo anjir".split(),
    "sabzavot": "sabzi piyoz kartoshka karam bodring pomidor lavlagi turp qalampir baqlajon".split(),
    "ichimlik": "choy qahva sut kompot sharbat ayron kefir suv limonad kakao".split(),
    "shirinlik": "halva pishiriq tort murabbo novvot parvarda asal konfet shokolad pechenye".split(),
}
L = 32


def royxat(rng):
    t = str(rng.choice(list(TOIFALAR)))
    n = int(rng.integers(3, 9))
    elementlar = [str(x) for x in rng.choice(TOIFALAR[t], n, replace=False)]
    return f"<d> ro'yxat : {t} javob : " + " , ".join(elementlar) + " . <end>"


class Blok(nn.Module):
    def __init__(self, d, boshlar):
        super().__init__()
        self.boshlar = boshlar
        self.ln1, self.ln2 = nn.LayerNorm(d), nn.LayerNorm(d)
        self.qkv = nn.Linear(d, 3 * d)
        self.proj = nn.Linear(d, d)
        self.ffn = nn.Sequential(nn.Linear(d, 4 * d), nn.GELU(), nn.Linear(4 * d, d))

    def forward(self, x):
        B, T, d = x.shape
        q, k, v = self.qkv(self.ln1(x)).split(d, dim=2)
        q, k, v = [t.view(B, T, self.boshlar, -1).transpose(1, 2) for t in (q, k, v)]
        o = F.scaled_dot_product_attention(q, k, v, is_causal=True)
        x = x + self.proj(o.transpose(1, 2).reshape(B, T, d))
        return x + self.ffn(self.ln2(x))


class GPT(nn.Module):
    def __init__(self, V, d=48, boshlar=4, qatlamlar=2):
        super().__init__()
        self.emb = nn.Embedding(V, d)
        self.poz = nn.Embedding(L, d)
        self.bloklar = nn.Sequential(*[Blok(d, boshlar) for _ in range(qatlamlar)])
        self.ln = nn.LayerNorm(d)
        self.chiqish = nn.Linear(d, V)

    def forward(self, x):
        x = x[:, -L:]
        h = self.emb(x) + self.poz(torch.arange(x.shape[1]))
        return self.chiqish(self.ln(self.bloklar(h)))


def orgat(T, V, seed=0, qadamlar=250, B=32):
    torch.manual_seed(seed)
    model = GPT(V)
    opt = torch.optim.AdamW(model.parameters(), lr=5e-3, weight_decay=0.01)
    g = torch.Generator().manual_seed(seed)
    for _ in range(qadamlar):
        bosh = torch.randint(0, len(T) - L - 1, (B,), generator=g)
        w = torch.stack([T[i:i + L + 1] for i in bosh.tolist()])
        loss = F.cross_entropy(model(w[:, :-1]).reshape(-1, V), w[:, 1:].reshape(-1))
        opt.zero_grad()
        loss.backward()
        opt.step()
    model.eval()
    return model


class Mijoz:
    """API ga o'xshash interfeys: parametrlar nomi va javob tuzilishi LLM API laridagidek."""

    def __init__(self, model, lugat):
        self.model, self.lugat = model, lugat
        self.s2i = {w: i for i, w in enumerate(lugat)}

    @torch.no_grad()
    def yarat(self, promptlar, max_tokens=30, temperature=1.0, top_p=1.0, top_k=None,
              stop=None, seed=0):
        """Promptlar ro'yxati -> [{"text", "stop_reason", "usage"}], batch bilan."""
        x = torch.tensor([[self.s2i[w] for w in p.split()] for p in promptlar])
        n0 = x.shape[1]
        g = torch.Generator().manual_seed(seed)
        for _ in range(max_tokens):
            logit = self.model(x)[:, -1]
            if temperature == 0:
                keyingi = logit.argmax(-1)
            else:
                logit = logit / temperature
                if top_k is not None:
                    chegara = logit.topk(top_k, dim=-1).values[:, -1:]
                    logit = logit.masked_fill(logit < chegara, float("-inf"))
                if top_p < 1.0:
                    tartib, idx = logit.sort(dim=-1, descending=True)
                    p = torch.softmax(tartib, -1)
                    tartib = tartib.masked_fill(p.cumsum(-1) - p >= top_p, float("-inf"))
                    logit = torch.full_like(logit, float("-inf")).scatter(-1, idx, tartib)
                keyingi = torch.multinomial(torch.softmax(logit, -1), 1, generator=g)[:, 0]
            x = torch.cat([x, keyingi[:, None]], 1)
        javoblar = []
        for qator in x[:, n0:].tolist():
            sozlar, sabab = [], "max_tokens"
            for i in qator:
                w = self.lugat[i]
                if w == "<end>":
                    sabab = "end_turn"
                    break
                sozlar.append(w)
                matn = " ".join(sozlar)
                topilgan = [matn.index(s) for s in (stop or []) if s in matn]
                if topilgan:                               # stop matni javobga kirmaydi
                    sozlar = matn[:min(topilgan)].split()
                    sabab = "stop_sequence"
                    break
            chiq = len(sozlar) + (1 if sabab != "max_tokens" else 0)
            javoblar.append({"text": " ".join(sozlar), "stop_reason": sabab,
                             "usage": {"input_tokens": n0, "output_tokens": chiq}})
        return javoblar


def tahlil(javob, toifa):
    """Ro'yxat to'g'rimi: hamma element shu toifadan, takror yo'q, nuqta bilan tugagan."""
    matn = javob["text"]
    toza = matn.rstrip(" .")
    el = [w for w in toza.split(" , ")] if toza else []
    togri_el = all(e in TOIFALAR[toifa] for e in el) and len(el) > 0
    takror = len(el) != len(set(el))
    return togri_el and not takror and matn.endswith("."), takror, " ".join(el)



# NAMUNA narxlar (FARAZIY), $ / 1M token
N_KIRISH, N_CHIQISH = 3.0, 12.0


def strategiya(mijoz, promptlar, nom, seed=1):
    """Har prompt uchun: (yakuniy javob, chaqiruvlar, kirish tokenlari, chiqish tokenlari)."""
    natija = []
    for i, p in enumerate(promptlar):
        chaqiruv = kirish = chiqish = 0
        if nom == "e'tiborsiz (8)":
            j = mijoz.yarat([p], max_tokens=8, temperature=0, seed=seed + i)[0]
            chaqiruv, kirish, chiqish = 1, j["usage"]["input_tokens"], j["usage"]["output_tokens"]
            yakun = j
        elif nom == "qayta urinish (8->16->32)":
            for mt in (8, 16, 32):
                j = mijoz.yarat([p], max_tokens=mt, temperature=0, seed=seed + i)[0]
                chaqiruv += 1
                kirish += j["usage"]["input_tokens"]
                chiqish += j["usage"]["output_tokens"]
                if j["stop_reason"] != "max_tokens":
                    break
            yakun = j
        elif nom == "davom ettirish (8 dan)":
            matn = ""
            for _ in range(6):
                j = mijoz.yarat([f"{p} {matn}".strip()], max_tokens=8, temperature=0,
                                seed=seed + i)[0]
                chaqiruv += 1
                kirish += j["usage"]["input_tokens"]
                chiqish += j["usage"]["output_tokens"]
                matn = f"{matn} {j['text']}".strip()
                if j["stop_reason"] != "max_tokens":
                    break
            yakun = {"text": matn, "stop_reason": j["stop_reason"]}
        else:                                        # "yetarli max_tokens (32)"
            j = mijoz.yarat([p], max_tokens=32, temperature=0, seed=seed + i)[0]
            chaqiruv, kirish, chiqish = 1, j["usage"]["input_tokens"], j["usage"]["output_tokens"]
            yakun = j
        natija.append((yakun, chaqiruv, kirish, chiqish))
    return natija


def main() -> None:
    torch.set_num_threads(1)
    rng = np.random.default_rng(0)
    matn = " ".join(royxat(rng) for _ in range(3000))
    lugat = sorted(set(matn.split()))
    s2i = {w: i for i, w in enumerate(lugat)}
    mijoz = Mijoz(orgat(torch.tensor([s2i[w] for w in matn.split()]), len(lugat)), lugat)
    promptlar = [f"<d> ro'yxat : {t} javob : {e} ," for t, el in TOIFALAR.items() for e in el]

    print("=== 1. Kesilgan javob qanday ko'rinadi (max_tokens=8) ===")
    j = mijoz.yarat(promptlar[:1], max_tokens=8, temperature=0)[0]
    print(f"  text={j['text']!r}")
    print(f"  stop_reason={j['stop_reason']!r}, output_tokens={j['usage']['output_tokens']}")

    print("\n=== 2. To'rt strategiya (40 prompt, greedy) ===")
    print("  strategiya                   to'liq  chaqiruv  kirish tok  chiqish tok  narx/1000 $")
    toliq_yakun = {}
    for nom in ("e'tiborsiz (8)", "qayta urinish (8->16->32)", "davom ettirish (8 dan)",
                "yetarli max_tokens (32)"):
        r = strategiya(mijoz, promptlar, nom)
        toliq = np.mean([y["stop_reason"] == "end_turn" for y, *_ in r])
        ch, ki, cq = (np.mean([x[k] for x in r]) for k in (1, 2, 3))
        narx = (ki * N_KIRISH + cq * N_CHIQISH) / 1e6 * 1000
        toliq_yakun[nom] = [y["text"] for y, *_ in r]
        print(f"  {nom:<27} {toliq:>7.1%} {ch:>9.2f} {ki:>11.1f} {cq:>12.1f} {narx:>12.4f}")

    print("\n=== 3. Davom ettirish bir martalik javob bilan bir xilmi? ===")
    a, b = toliq_yakun["davom ettirish (8 dan)"], toliq_yakun["yetarli max_tokens (32)"]
    teng = np.mean([x == y for x, y in zip(a, b)])
    print(f"  aynan bir xil matn: {teng:.1%} (greedy: kontekst bir xil -> davom bir xil)")

    print("\n=== 4. stop_reason o'rniga matnga qarab aniqlash ===")
    javoblar = [jv for mt in (6, 9, 32)
                for jv in mijoz.yarat(promptlar, max_tokens=mt, temperature=0)]
    haqiqiy = np.array([jv["stop_reason"] == "max_tokens" for jv in javoblar])
    taxmin = np.array([not jv["text"].endswith(".") for jv in javoblar])
    print(f"  {len(javoblar)} javob, kesilgani {haqiqiy.mean():.1%}")
    print(f"  'nuqta bilan tugamagan' qoidasi: to'g'ri aniqlash {np.mean(taxmin == haqiqiy):.1%}")
    ikkala = np.mean(haqiqiy & ~taxmin)
    if ikkala > 0:
        print(f"  {ikkala:.1%} javob nuqta bilan tugagan, lekin baribir kesilgan")
    else:
        print("  bu formatda qoida ishladi - lekin JSON, kod yoki erkin matnda bunday oddiy belgi yo'q")
    print("  ⭐ max_tokens - shift, narx emas: faqat haqiqatan yozilgan tokenlar to'lanadi")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. Kesilgan javob qanday ko'rinadi (max_tokens=8) ===
  text='gilos , anjir , behi , anor ,'
  stop_reason='max_tokens', output_tokens=8

=== 2. To'rt strategiya (40 prompt, greedy) ===
  strategiya                   to'liq  chaqiruv  kirish tok  chiqish tok  narx/1000 $
  e'tiborsiz (8)                 0.0%      1.00         8.0          8.0       0.1200
  qayta urinish (8->16->32)    100.0%      2.00        16.0         21.2       0.3024
  davom ettirish (8 dan)       100.0%      2.00        24.0         13.2       0.2304
  yetarli max_tokens (32)      100.0%      1.00         8.0         13.2       0.1824

=== 3. Davom ettirish bir martalik javob bilan bir xilmi? ===
  aynan bir xil matn: 100.0% (greedy: kontekst bir xil -> davom bir xil)

=== 4. stop_reason o'rniga matnga qarab aniqlash ===
  120 javob, kesilgani 65.8%
  'nuqta bilan tugamagan' qoidasi: to'g'ri aniqlash 100.0%
  bu formatda qoida ishladi - lekin JSON, kod yoki erkin matnda bunday oddiy belgi yo'q
  ⭐ max_tokens - shift, narx emas: faqat haqiqatan yozilgan tokenlar to'lanadi

Nima ko'rsatdi: max_tokens=8 da javob vergul bilan uzildi ('gilos , anjir , behi , anor ,'), stop_reason='max_tokens'. 2-bo'limda to'rt strategiya: e'tiborsiz qoldirish eng arzon (0.1200 $ / 1000 so'rov), lekin birorta ham to'liq javob yo'q. Qayta urinish 100% to'liq, ammo eng qimmat (0.3024 $): kesilgan birinchi urinishning 8 tokeni behuda ketdi va prompt ikki marta yuborildi (chiqish 21.2 token, kerakligi 13.2). Davom ettirish chiqishni tejadi (13.2), lekin prompt va avvalgi qism qayta yuborildi (kirish 24.0) — 0.2304 $. Eng arzon to'liq yechim — boshidan yetarli max_tokens=32: 0.1824 $, chunki model 13 token atrofida o'zi tugatadi va 32 ning qolgani to'lanmaydi. 3-bo'lim: greedy da davom ettirish bir martalik javob bilan 100.0% bir xil — kauzal model uchun "oldingi qism + davom" va "bir martada" bir xil kontekst. 4-bo'lim: 120 javobning 65.8% i kesilgan; bu formatda "nuqta bilan tugamagan" qoidasi 100.0% to'g'ri aniqladi, lekin bu ro'yxat formatining xususiyati — stop_reason esa har qanday formatda ishlaydi. Bog'liq bo'lim: 2.6.


5. To'g'ri va noto'g'ri tushunishlar

Noto'g'ri fikr To'g'risi
"Past temperatura — har doim aniqroq" 1-misolda T=0.5 T=1.0 dan sezilarli yomon (-0.085); T=0 da to'g'rilik 0.0%
"top_p va temperature — bir xil narsa" T=1.5 da top_p to'g'rilikni +0.140 oshirdi
"max_tokens — javob uzunligi" Yuqori chegara; model ~13 tokenda o'zi tugatdi
"Katta max_tokens — qimmat" Faqat yozilgan tokenlar to'lanadi: 0.1824 $ — eng arzon to'liq yechim
"Kesilsa, qayta so'raymiz" Qayta urinish eng qimmat (0.3024 $) — chala tokenlar behuda
"Chastota jarimasi faqat takrorni kamaytiradi" Ro'yxat 6.0 dan 3.0 ga qisqardi — vergul ham jazolandi
"temperature=0 — doim bir xil javob" bfloat16 shovqini javoblarning 15% ini o'zgartirdi; batch ham logitni o'zgartiradi
"Float yig'indisi tartibga bog'liq emas" (1e8 - 1e8) + 1 = 1, 1e8 + (-1e8 + 1) = 0
"Stop ketma-ketligi javobda qoladi" Stop matni javobga kirmaydi
"Chala javobni matndan bilib olamiz" Formatga bog'liq; stop_reason — ishonchli manba

6. Keng tarqalgan xatolar va yechimlari

1. stop_reason tekshirilmaydi

python
saytga_chiqar(javob.content[0].text)                                # ⚠️
if javob.stop_reason == "max_tokens":                               # ✅
    raise ChalaJavob(javob.usage.output_tokens)
saytga_chiqar(javob.content[0].text)

2. Narxni kichik max_tokens bilan cheklash

python
javob = client.messages.create(..., max_tokens=100)                 # ⚠️ chala javoblar
javob = client.messages.create(..., max_tokens=uzunlik_p99)         # ✅ + ko'rsatmada uzunlik

3. Ro'yxat vazifasida temperature=0

python
g_oyalar = yarat(prompt, temperature=0)                             # ⚠️ takror, bir xil
g_oyalar = yarat(prompt, temperature=1.0, top_p=0.9)                # ✅ + takror o'lchovi

4. Jarima struktura tokenlariga ham

python
logit -= alfa * soni                                                # ⚠️ vergul ham
logit -= alfa * soni * niqob                                        # ✅ niqob[tinish] = 0

5. temperature=0 ga tayangan test

python
assert yarat(prompt, temperature=0) == KUTILGAN_MATN                # ⚠️ mo'rt
d = json.loads(yarat(prompt, temperature=0))                        # ✅ xususiyatlar
assert d["toifa"] in TOIFALAR and d["summa"] > 0

6. Kesilganda boshidan qayta so'rash

python
while j.stop_reason == "max_tokens":                                # ⚠️ chala tokenlar behuda
    j = yarat(prompt, max_tokens=2 * mt)
j = yarat(prompt, max_tokens=yetarli)                               # ✅ bir chaqiruv

7. Temperature va top_p ni birga ko'r-ko'rona

python
yarat(prompt, temperature=0.3, top_p=0.5, top_k=5)                  # ⚠️ nima ishladi?
yarat(prompt, temperature=0.3)                                      # ✅ bitta tugma, o'lchov bilan

7. Integratsiya — bu bilim qayerda kerak bo'ladi

  • 24.9-dars (o'tilgan): greedy, temperature, top-k, top-p, torch.Generator — bu darsdagi parametrlarning mexanizmi
  • 24.11-dars (o'tilgan): aralash aniqlik (bfloat16) — determinizm buzilishining bir sababi
  • 25.2-dars (o'tilgan): usage va narx — max_tokens strategiyalari narxi
  • 18-qism (o'tilgan): juftlashgan taqqoslash — parametr tanlash
  • Keyingi darslar: prompt tuzilishi 25.4-bob, strukturali chiqish — kesilgan JSON xavfi 25.5-bob, retry va xatolarni qayta ishlash 25.6-bob, baho to'plamida parametr tanlash 25.10-bob, stop_reason == "tool_use" (25.12)

8. Eng yaxshi amaliyotlar

  1. Har javobda stop_reason ni tekshiring; "max_tokens" ni xato holat deb qayta ishlang.

  2. max_tokens ni javob uzunligi taqsimotining dumiga moslang; uzunlikni ko'rsatmada ayting.

  3. Bitta tugmani o'zgartiring (temperature yoki top_p) va o'lchang.

  4. Harorat tanlashda vazifa turini hisobga oling: yagona javob — past, variantlar — o'rtacha.

  5. Jarimalarni kichik qiymatdan boshlang; to'g'rilik, uzunlik va formatni birga o'lchang.

  6. temperature=0 ga tayanadigan testlar o'rniga xususiyatlarni tekshiring.

  7. Parametrlarni 100-200 so'rovlik to'plamda juftlashgan taqqoslash bilan tanlang.

  8. Javoblarni (kerak bo'lsa) saqlang — takrorlanuvchanlik uchun yagona ishonchli yo'l.


9. Amaliy topshiriq

Vazifa 1: Bashorat qiling

python
1.  # temperature=0 da namuna olish nimaga aylanadi?
2.  # max_tokens=500, model 120 tokenda tugatdi - nechta chiqish tokeni to'lanadi?
3.  # stop_reason = "max_tokens" nimani bildiradi?
4.  # stop=["\n\n"] bilan javob matnida "\n\n" bo'ladimi?
5.  # frequency_penalty vergulga qanday ta'sir qiladi?
6.  # 1-misolda nega T=0.5 T=1.0 dan yomon?
7.  # float32 da (1e8 + (-1e8)) + 1 va 1e8 + ((-1e8) + 1)?
8.  # bitta qadamda argmax ag'darilsa, qolgan javob nima bo'ladi?
9.  # kesilgan javobni "qayta urinish" nega qimmat?
10. # davom ettirishda qaysi tokenlar qayta to'lanadi?
11. # ma'lumot ajratish vazifasi uchun taxminiy temperature?
12. # temperature=0 bilan yozilgan regression test nega mo'rt?
Javoblar
  1. Greedy ga (argmax)
  2. 120 ta
  3. Model chegaraga yetdi — javob chala bo'lishi mumkin
  4. Yo'q — stop matni javobga kirmaydi
  5. Vergul har safar chiqqanda jarimasi oshadi — ro'yxat qisqaradi yoki format buziladi (2-misol: 6.0 → 3.0)
  6. Past harorat eng ehtimolli elementlarni qayta-qayta tanlaydi — takror oshadi
  7. 1.0 va 0.0
  8. Kontekst o'zgaradi — davom butunlay boshqacha bo'lishi mumkin (0.88% qadam → 15% javob)
  9. Chala birinchi urinishning chiqish tokenlari va prompt qayta to'lanadi
  10. Prompt va avvalgi qism (kirish sifatida)
  11. 0 - 0.2
  12. Float tartibi, batch va aniqlik tufayli bir xil so'rov boshqa javob berishi mumkin

Vazifa 2: Xatolarni tuzating

python
1.  javob = client.messages.create(model=m, max_tokens=50, messages=xabarlar)
    return json.loads(javob.content[0].text)

2.  variantlar = [yarat(prompt, temperature=0) for _ in range(5)]

3.  logit = logit - 1.5 * soni                      # takrorga qarshi

4.  assert yarat("2+2?", temperature=0) == "Javob: 4."

5.  while javob.stop_reason == "max_tokens":
        javob = yarat(prompt, max_tokens=javob.usage.output_tokens * 2)
Javoblar
python
1.  javob = client.messages.create(model=m, max_tokens=1024, messages=xabarlar)
    if javob.stop_reason == "max_tokens":
        raise ChalaJavob("JSON kesilgan bo'lishi mumkin")
    return json.loads(javob.content[0].text)          # + validatsiya (25.5)

2.  variantlar = [yarat(prompt, temperature=1.0, top_p=0.9, seed=s) for s in range(5)]
    # yoki bitta so'rovda "5 ta turli variant" deb so'rash

3.  logit = logit - 1.5 * soni * niqob                # niqob[tinish] = 0
    # va uzunlik/formatni o'lchash

4.  javob = yarat("2+2?", temperature=0)
    assert "4" in javob                               # xususiyat, aniq matn emas

5.  javob = yarat(prompt, max_tokens=yetarli)          # boshidan yetarli chegara
    if javob.stop_reason == "max_tokens":             # juda uzun bo'lsa - davom ettirish
        javob = davom_ettir(prompt, javob)

Vazifa 3: Parametrlar to'ri

Modellang:

  1. API uslubidagi yarat() (temperature, top_p, top_k, max_tokens, stop)
  2. 200 so'rov: to'g'rilik, takror, noyob, uzunlik
  3. Juftlashgan farqlar
  4. max_tokens bo'yicha stop_reason taqsimoti

Vazifa 4: Jarimalar

Modellang:

  1. Chastota va mavjudlik jarimasi
  2. Tinish belgilari ozod / ozod emas
  3. To'g'rilik, takror, uzunlik, format
  4. Jarimaning eng kichik yetarli qiymatini toping

Vazifa 5: Determinizm

Modellang:

  1. Float yig'indi tartibi
  2. Chiqish qatlamini uch yo'l bilan hisoblash
  3. Eng yaqin ikki logit taqsimoti
  4. Batch hajmi 1, 8, 64 da logit farqi

Vazifa 6: Kesilgan javob

Modellang:

  1. To'rt strategiya: e'tiborsiz, qayta urinish, davom ettirish, yetarli chegara
  2. Chaqiruvlar, kirish/chiqish tokenlari va narx
  3. Davom ettirish natijasining bir martalik bilan mosligi (greedy va T=0.7 da)
  4. stop_reason va matn qoidasining aniqligi

Vazifa 7: O'ylash

QA muhandisi aytdi: "Biz LLM ni temperature=0 bilan chaqiramiz, demak u deterministik. 300 ta regression test yozdim — har biri aniq kutilgan matn bilan solishtiradi. Test yiqilsa, demak model yoki prompt buzilgan." Siz nima deysiz?

Javob

Qisqa javob: temperature=0 deterministiklik kafolati emas, shuning uchun aniq matnni solishtiradigan testlar "tasodifan" yiqiladi va jamoa ularga ishonmay qo'yadi. Testlar javobning xususiyatlarini tekshirishi kerak.

1. Nega bir xil emas. 3-misolda float yig'indi tartibi, batch hajmi va hisob aniqligi logitlarni o'zgartirdi. Bizning kichik modelda float32 shovqini tanlovni ag'darmadi, lekin bfloat16 shovqini qadamlarning 0.88% ida ag'darib, javoblarning 15% ini o'zgartirdi. Katta modelda deyarli teng tanlovlar ko'proq, server esa so'rovni har safar boshqa batch ga qo'shadi.

2. Nima tekshiriladi. Strukturali chiqish: JSON sxemaga mosmi, kerakli maydonlar bormi 25.5-bob. Faktlar: javobda to'g'ri raqam/nom bormi. Taqiqlar: shaxsiy ma'lumot yoki taqiqlangan so'z yo'qmi. Format: uzunlik chegarasi, til. Erkin matn uchun — baholovchi (qoidaga asoslangan yoki boshqa model, 25.10).

3. Statistik yondashuv. Muhim testlarda bitta chaqiruv emas, 3-5 chaqiruv va "hammasi o'tdi" yoki "kamida 4/5" mezoni. Prompt o'zgarishini esa butun baho to'plamida juftlashgan taqqoslash bilan baholash.

4. Qachon aniq matn kerak. Agar audit uchun aynan bir xil javob kerak bo'lsa — javobni saqlash va qayta ishlatish; qayta generatsiya qilmaslik.

Tavsiya:

python
# 1. assert javob == KUTILGAN  ->  assert xususiyatlar(javob)
# 2. JSON: sxema validatsiyasi (25.5)
# 3. muhim holatlar: 5 chaqiruv, >= 4/5 o'tishi
# 4. stop_reason == "end_turn" ham test sharti

Muhandisga javob: "temperature=0 'eng ehtimolli token' degani, 'bir xil javob' emas — float tartibi va server batchlari tufayli matn ba'zan o'zgaradi. Testlarni aniq matndan xususiyatlarga (sxema, faktlar, taqiqlar) o'tkazaylik, shunda yiqilgan test haqiqiy muammoni ko'rsatadi."

Nimani mustahkamlaydi: 2.2, 2.3, 2.4, 2.5, 2.6-bo'limlar.


Xulosa

Bu darsda 24.9 dagi dekodlash tugmalariga API foydalanuvchisi ko'zi bilan qaradik: API uslubidagi yarat() qurdik, parametrlar to'rini, takror jarimalarini, determinizm chegaralarini va kesilgan javoblarni qayta ishlashni o'lchadik.

Eng muhim uch fikr:

  1. Parametrlar vazifaga bog'liq va o'lchab tanlanadi. 1-misolda ro'yxat vazifasida greedy 200 so'rovga 4 xil takrorli ro'yxat berdi (to'g'rilik 0.0%), T=0.5 esa T=1.0 dan sezilarli yomon (-0.085, SE 0.036) — past harorat takrorni kuchaytirdi. top_p yuqori haroratda to'g'rilikni +0.140 oshirdi. 2-misolda chastota jarimasi takrorni yo'qotdi, lekin vergulni ham jazolab ro'yxatni 6.0 dan 3.0 elementga qisqartirdi; tinish belgilari ozod qilinganda uzunlik tiklandi.

  2. stop_reason va max_tokens — javob to'liqligining nazorati. max_tokens=12 da javoblarning 70% i kesildi. 4-misolda kesilgan javobni e'tiborsiz qoldirish 0% to'liq natija berdi; qayta urinish eng qimmat (0.3024 $), eng arzon to'liq yechim — yetarli max_tokens (0.1824 $), chunki faqat yozilgan tokenlar to'lanadi.

  3. temperature=0 — doim bir xil javob emas. 3-misolda float32 da qo'shish tartibi natijani o'zgartirdi, CPU da ham yolg'iz va batch ichidagi logitlar bitlar darajasida farq qildi (2.38e-06), bfloat16 shovqini esa qadamlarning 0.88% ida tanlovni ag'darib, javoblarning 15% ini o'zgartirdi. Testlar aniq matnni emas, xususiyatlarni tekshirishi kerak.

Keyingi darsda prompt engineering asoslari: tizim prompti, aniq ko'rsatma, XML teglar bilan tuzilish, few-shot misollarni tanlash, chain-of-thought va uning narxi, prompt shablonlarining xavfsizligi va versiyalash — "sehrli so'zlar" o'rniga o'lchov bilan.

Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
25.3-dars: Generatsiya parametrlari — IlmHamroh