Ugrás a tartalomra
17/3017/30. fejezet

Temperature, top-p és a determinizmus, ami nincs a kezedben

A temperature a softmax előtt osztja a logit értékeket: ez megöli a kreativitás-tárcsa mítoszát. Két azonos greedy hívás, két válasz.

Ezen az oldalon

Íme ugyanaz a kérés, ugyanannak a modellnek elküldve ötször. Ugyanazok a súlyok, ugyanaz a prompt, ugyanaz a gép, ugyanaz a random seed. Csak egyetlen szám változik.

TEXT
prompt: "Q: What is the capital of France?\nA:"

T = 0.0   " Paris\nWhat is the question and does the answer answer it? The
           question is: What is the capital of France?..."

T = 0.7   " Paris\nWhat is the question: Which city is the capital of
           France?..."

T = 1.0   " Paris\nWhat is a good geographical qualifier for describing
           Paris concerning its location?\nA: Near the Mediterranean Sea..."

T = 1.5   " Paris\nWhat clue from premise allows we to conclude that Godwin
           was &, He chose Healing Crimson Colour No:white flour Pure..."

T = 2.0   "安全感金华.ITEMT]]];\naims assume parental.st-importe.valtermination
           Screens قطر_Zeroหมายเลข-zA ('$ספטמבר..."

Semmi nem romlott el. Az utolsó sor minden token eleme szabályosan a modell saját, 151 936 elemű szótárára adott valószínűségi eloszlásából lett kihúzva. A megváltoztatott szám neve temperature; a legtöbb dokumentáció kreativitás-tárcsaként írja le, és ez a leírás olyan módon téves, amit ez a fejezet nem állítani, hanem megmutatni fog.

Ez az a fejezet is, ahol három korábbi ígéret esedékessé válik. A 4. fejezet definiálta a logit fogalmát, de igazán nem költötte el. A 2. fejezet lebegőpontos doboza egy utasítással zárult — emlékezz erre, amikor a 17. fejezet azt kérdezi, miért adhat ugyanaz a prompt, modell és seed különböző token értékeket. A 9. fejezet mixture-of-experts doboza pedig a nemdeterminizmus négy okának katalógusát ígérte. Mindhárom alább érkezik.

Az egyetlen sor, amelyen az egész fejezet függ

Link a szakaszhoz: Az egyetlen sor, amelyen az egész fejezet függ

A 4. fejezet a logit értéket normalizálatlan, valós számú pontszámként vezette be, osztályonként egyet. A 8. fejezet elérte, hogy egy nyelvi modell minden szótárelemhez ilyet állítson elő. A softmax ezt a z\mathbf{z} vektort valószínűségekké alakítja:

pi=ezijezjp_i = \frac{e^{z_i}}{\sum_j e^{z_j}}

A temperature itt lép be — a név a statisztikus fizikából származik, ahol ugyanez a paraméter szabályozza, milyen élesen koncentrálódik egy Boltzmann-eloszlás az alacsony energiájú állapotaira1 — és az exponenciálás előtt osztja el a logit értékeket:

pi(T)=ezi/Tjezj/Tp_i(T) = \frac{e^{z_i/T}}{\sum_j e^{z_j/T}}

Ez az elhelyezés a teljes mechanizmus, és két sornyi algebra megéri, hogy látszódjon, miért nem lehetne máshol. Tegyük fel, hogy a temperature értéket inkább a valószínűségekre próbálnád alkalmazni — megszoroznád őket 1/T1/T értékkel, majd újranormalizálnád. Ezt kapnád:

pi/Tjpj/T=pijpj=pi\frac{p_i/T}{\sum_j p_j/T} = \frac{p_i}{\sum_j p_j} = p_i

A konstans kiesik. A valószínűségek skálázása semmit nem csinál; az eloszlás változatlanul visszatér. A temperature csak azért hat, mert az exponensen működik: TT értékkel osztani az exponenciálás előtt ugyanaz, mint minden valószínűséget 1/T1/T hatványra emelni — ez egy nemlineáris átformálás, amely az elemek közötti arányokat változtatja meg, nem a közös skálájukat.

Ebből az elhelyezésből mindkét határérték minden további munka nélkül következik. Ahogy T0T \to 0, a legnagyobb logit elszökik a többitől, és pp rázuhan az egyetlen legmagasabb pontszámú token elemre: ez a greedy decoding. Ahogy TT nő, minden zi/Tz_i/T nullához tart, minden exponenciális tag 1-hez tart, és az eloszlás a teljes szótáron egyenleteshez lapul. Pontosan T=0T = 0 esetén a képlet nullával oszt, ezért minden implementáció külön kezeli, és az aritmetikai maximumra vált — beleértve az alábbi widgetet is, amely T0.001T \le 0.001 esetén argmaxra kapcsol.

Egy figyelmeztetés, mert a névütközés valódi zavart okoz. Van a gépi tanulásban egy másik, ettől független dolog is, amelyet temperature néven emlegetnek: temperature scaling, egy kalibrációs módszer, amely egy validációs halmazon illeszt egy értéket, hogy egy osztályozó magabiztossága megfeleljen a pontosságának.2 Ugyanaz a képlet, semmi köze a generáláshoz. Amikor cikkek „temperature” értéket mondanak, gyakran erre gondolnak; ez a fejezet soha nem.

Íme az eloszlás, az aritmetikával a szemed előtt. A logit értékek rögzítettek és hihetőek, így az alábbi próza számai ellenőrizhetők azzal, amit látsz:

  • ␣Paris96.9%
  • ␣the1.3%
  • ␣located0.8%
  • ␣a0.5%
  • ␣Lyon0.2%
  • ␣called0.1%
  • ␣home0.1%
  • ␣Marseille0.0%
  • ␣not0.0%
  • ␣banana0.0%

10 / 10 token éli túl a vágást, és osztozik a valószínűségen.

Adatok megtekintése táblázatként
TokenlogitA hőmérséklet utánA vágás után
␣Paris⁨9.4⁩96.90%96.90%
␣the⁨5.1⁩1.31%1.31%
␣located⁨4.6⁩0.80%0.80%
␣a⁨4.1⁩0.48%0.48%
␣Lyon⁨3.2⁩0.20%0.20%
␣called⁨2.9⁩0.15%0.15%
␣home⁨2.4⁩0.09%0.09%
␣Marseille⁨1.8⁩0.05%0.05%
␣not⁨1.1⁩0.02%0.02%
␣banana⁨-2.6⁩0.00%0.00%
Mintavétel: hőmérséklet, top-p és top-k

A The capital of France is tíz lehetséges folytatása, 1-es temperature mellett, vágás nélkül. ␣Paris tartja a tömeg 96,90 %-át; ␣banana, legalul, 2.6-2.6 logit értékkel, 0,00 %-ot kap. Húzd a temperature értéket 0-ra, és egyetlen token marad 100 %-kal. Húzd 2-re, és ␣Paris 69,81 %-ra esik, miközben ␣banana 0,17 %-ra mászik — a modell elutasított token eleme, amelynek valódi valószínűséget adott egy olvasó által elfordított gomb.

A ␣banana szám miniatűrben az egész érv: a temperature emelése nem adhat a modellnek olyan ötletet, amely korábban nem volt meg benne. A logit értékek már ki vannak számolva, a rangsor már rögzített, és a temperature pontosan megőrzi — semennyi hő nem emel egy alacsonyabb pontszámú token elemet egy magasabb pontszámú fölé. Csak újraosztja a tömeget a modell saját maga által létrehozott rangsorában lefelé. A magas temperature nem teszi találékonyabbá a modellt; csak valószínűbbé teszi, hogy olyan token értékeket adjon ki, amelyeket rossznak pontozott.

Valódi szótáron ez már nem érdekesség, hanem annak az oka, hogy a magas temperature kimenet használhatatlan. Qwen/Qwen2.5-0.5B-Instruct modellen mérve, egy forward pass, a fenti prompt mellett, azt számolva, hány token kell a valószínűségi tömeg adott részének összegyűjtéséhez:

temperaturetop-1 probabilityentropytokens holding 80 %90 %95 %99 %
0.599.98 %0.00 nats1111
0.799.65 %0.03 nats1111
1.096.01 %0.30 nats11114
1.288.20 %0.88 nats1213252
1.562.83 %3.07 nats293532,67226,787
2.016.62 %8.19 nats13,51632,96655,231101,205

Olvasd lassan az alsó sort. T=2T = 2 mellett, egy pontosan egy helyes válasszal rendelkező kérdésnél 32 966 különböző token osztozik a valószínűségi tömeg felső 90 %-án. Ez nem szélesebb kreatív tér. Ez egy modell, amelynek az aritmetika azt mondta, hogy egy koreai partikula és egy C++ azonosító is élő opció a A: utáni szóként. A nyitó blokk szemete ennek a közvetlen következménye, és nem hiba a modellben vagy a könyvtárban — pontosan ezt kérte a hívás.

A hasznos tartomány szűk, és a feladattól függ, nem ízléstől. Egy tényszerű kérdésnél a válasz egy token, és nagyjából 1,2 fölött minden hő csak hibát injektál a semmiért. Egy nyílt végűnél valóban több jó folytatás létezik, és némi hő olyan változatosságot vásárol, amely folyékony marad:

TEXT
"Write a two-sentence story about a lighthouse."

T = 0.0  "The lighthouse stood tall and proud, its beacon illuminating the
          night sky above. A lone sailor, his eyes fixed on the distant
          horizon..."

T = 0.7  "In the quiet, stormy waters of the sea, a lighthouse stood
          sentinel over the horizon, its golden dome casting a warm glow
          on the fog-shrouded streets below..."

T = 1.0  "In the quiet night, a lone lighthouse stood sentinel over the
          sea, its shining beacon a beacon of hope and solace for sailors
          and fishermen across the vast and endless ocean..."

T = 1.3  "In the gentle sunlight, now reflecting upon the opening of Jack's
          lighthouse, Jim Trahan, a small-time individual difficult to
          define in paperwork, wondered about a career where simplicity
          reigns..."

1,3-nál a modell kitalált egy tulajdonnevet és egy mondatot, amely nem parse-olható. Az „minden alkalommal azonos” és az „inkoherens” közti sáv ennél a modellnél, ezen a feladaton nagyjából 0,6 és 1,1 között van, és az őszinte tanács az, hogy a saját feladatodon méréssel találd meg, ne egy blogposztból másolj át egy számot.

Miért rossz szöveg a legvalószínűbb szöveg

Link a szakaszhoz: Miért rossz szöveg a legvalószínűbb szöveg

Egy nyilvánvaló kérdés bújik meg mindez alatt: ha a modellnek van valószínűségi eloszlása, és egy token a legvalószínűbb, miért ne vennénk mindig azt? A greedy decoding ingyenes, reprodukálható, és nem igényel paramétereket.

Mert az eredmény ez:

TEXT
prompt: "In a shocking finding, scientists discovered a herd of unicorns
         living in a remote valley."

greedy: " The unicorns were so rare that they were not even recognized by
         the local people. The unicorns were so rare that they were not
         even recognized by the local people. The unicorns were so rare
         that they were not even recognized by the local people. ..."

         repeated 4-grams: 87.6 %

Nyolc mondat, egy mondat. A négy-token ablakok közel kilencven százaléka már korábban is megjelent ugyanabban a kimenetben. Ez a neural text degeneration, amelyet Holtzman és szerzőtársai neveztek el és magyaráztak meg abban a cikkben, amely bevezette a top-p módszert.3 A modell nem romlott el; a szekvenciavalószínűség maximalizálása egyszerűen rossz célfüggvény nyílt végű szöveghez. Az emberi írás nem a szavak legvalószínűbb sorozata — hordoz meglepetést, a tokenenkénti valószínűsége vándorol, süllyed és helyreáll — miközben a maximális valószínűségű út egy fixpont, amelynek belépés után nincs oka kilépni.

Ezért létezik egyáltalán sampling. És ugyanakkor — ez az a rész, amely gyakran kimarad — ez nem univerzális törvény. A 12. fejezet kétlépéses szófeladatokon 24-ből 24 helyes választ mért egyszerű greedy decoding mellett, a 0,8-as temperature sampling pedig ezt 81 %-ra ejtette; a self-consistency ezután hatszor annyi token elköltésével mászott vissza oda, ahol a greedy már eleve volt. Mindkét tény egyszerre igaz:

Nyílt végű generálás. Nincs egyetlen helyes folytatás, ezért a legvalószínűbb egy csapda — loopol, és 87,6 %-át saját magából másolja. Sample.

Egy helyes válasszal rendelkező feladatok. Van egyetlen helyes folytatás, ezért bármi más kihúzása hiba kihúzása. A 12. fejezet 100 %-a pontosan emiatt lett 81 %. Ne sample-elj.

A legtöbb production prompt a második típus, mégis az elsőhöz hasonlóan konfigurálják, mert a temperature ott maradt azon, amit a példakód használt.

Kétféle vágás, és csak az egyik alkalmazkodik

Link a szakaszhoz: Kétféle vágás, és csak az egyik alkalmazkodik

A teljes eloszlásból samplingolni valójában senki nem szokott, mert a farok óriási és tele van értelmetlenséggel. Valamit le kell vágni. Két klasszikus válasz van, és egyetlen tekintetben különböznek, amely mindent eldönt.

Top-k fix számú jelöltet tart meg. Valószínűség szerint rendezz, tartsd meg az első kk elemet, dobd el a többit, normalizálj újra.4 Top-p, más néven nucleus sampling, fix mennyiségű tömeget tart meg: csökkenő sorrendben veszi a token értékeket, amíg az összesített valószínűség el nem éri pp értéket, majd megáll.3 Formálisan a nucleus a legkisebb VpV_p halmaz, amelyre

iVppip\sum_{i \in V_p} p_i \ge p

A különbség kozmetikainak hangzik, de nem az, mert két, ugyanabban a percben elküldött prompt teljesen különböző eloszlásalakot kaphat. Mindkettő ugyanaz a modell, 1-es temperature mellett:

Q: What is the capital of France?\nA:Once upon a time,
top-1 probability96.01 %25.39 %
tokens holding 90 % of the mass1467
top-k = 40 keeps99.61 % of the mass78.87 % of the mass
mass in ranks 2 to 403.61 %53.48 %
token at rank 40␣Av, 0.0093 %␣Dr, 0.128 %

Egy fix kk, két ellentétes irányú kudarc. A tényszerű prompt esetén k=40k = 40 beenged 39 token elemet, amelyek együtt 3,6 %-ot érnek — átengedi a szemetet, köztük egy ezredszázalékos nagyságrendű jelöltet, mert a szabály helyeket számol, nem bizonyítékot. A történetes prompt esetén ugyanaz a k=40k = 40 kidobja a tömeg 21 %-át, amelyet a modell valóban kiosztott, mert ott az igazi nucleus 467 token széles.

A top-p pontosan egy számmal végzi el mindkét feladatot. Állítsd be p=0.9p = 0.9 értékre, és az első promptnál 1 token marad, a másodiknál 467, mert az eloszlásról tesz fel kérdést, nem darabszámot kényszerít rá. Nézd meg közvetlenül ezt az alkalmazkodást — ugyanaz a vágás, négy temperature:

  • ␣Paris91.1%
  • ␣the5.2%
  • ␣located3.7%
  • ␣a0.0%
  • ␣Lyon0.0%
  • ␣called0.0%
  • ␣home0.0%
  • ␣Marseille0.0%
  • ␣not0.0%
  • ␣banana0.0%

3 / 10 token éli túl a vágást, és osztozik a valószínűségen.

Adatok megtekintése táblázatként
TokenlogitA hőmérséklet utánA vágás után
␣Paris⁨9.4⁩85.03%91.10%
␣the⁨5.1⁩4.84%5.18%
␣located⁨4.6⁩3.47%3.71%
␣a⁨4.1⁩2.48%
␣Lyon⁨3.2⁩1.36%
␣called⁨2.9⁩1.12%
␣home⁨2.4⁩0.80%
␣Marseille⁨1.8⁩0.54%
␣not⁨1.1⁩0.34%
␣banana⁨-2.6⁩0.03%
Mintavétel: hőmérséklet, top-p és top-k

Top-p 0,90 mellett, 1,5-ös temperature értékkel: a tíz token közül három marad életben és osztozik a tömegen, ␣Paris 91,10 %-ra újranormalizálva. Most csak a temperature értéket mozgasd. 0,7-nél ugyanaz a 0,90 egy túlélőt hagy — ennyire szűk nucleus esetén ez greedy decoding más néven. 2,0-nál ötöt hagy. A vágás nem mozdult; az alatta lévő alak igen.

Ez a widget egy olyan tévhitet is eldönt, amelyet érdemes néven nevezni, mert valódi pénzbe kerül. Magabiztos eloszlásnál top_p = 0.9 nem „egy kis változatosság”. Hanem greedy. 1-es temperature mellett a vezető token itt 96,90 %-ot tart, ami már 0,9 fölött van, ezért a nucleus egy token széles, és semmi más nem húzható ki. Csapatok top_p értékre állítják 0,9-et abban a hitben, hogy lazítottak valamin, aztán csodálkoznak, miért azonos minden válasz.

Ha ehelyett top-k értéket állítasz, az ellenkező kudarc ugyanilyen jól látható:

  • ␣Paris97.2%
  • ␣the1.3%
  • ␣located0.8%
  • ␣a0.5%
  • ␣Lyon0.2%
  • ␣called0.0%
  • ␣home0.0%
  • ␣Marseille0.0%
  • ␣not0.0%
  • ␣banana0.0%

5 / 10 token éli túl a vágást, és osztozik a valószínűségen.

Adatok megtekintése táblázatként
TokenlogitA hőmérséklet utánA vágás után
␣Paris⁨9.4⁩96.90%97.20%
␣the⁨5.1⁩1.31%1.32%
␣located⁨4.6⁩0.80%0.80%
␣a⁨4.1⁩0.48%0.49%
␣Lyon⁨3.2⁩0.20%0.20%
␣called⁨2.9⁩0.15%
␣home⁨2.4⁩0.09%
␣Marseille⁨1.8⁩0.05%
␣not⁨1.1⁩0.02%
␣banana⁨-2.6⁩0.00%
Mintavétel: hőmérséklet, top-p és top-k

Top-k 5-nél, top-p nélkül. Minden temperature mellett öt token marad, mert ötöt kértünk. 1-es temperature mellett, ahogy látszik, a ␣Paris alatti négy jelölt együtt 2,79 %-ot ér. Vidd le 0,7-re, és ugyanez a négy 0,38 %-ot ér — a vágás színház, a modell gyakorlatilag greedy. Emeld 2,0-ra, és 22,54 %-ot érnek. Azonos beállítás, azonos túlélőszám, három teljesen különböző viselkedés, és a kérésben semmi nem mondja meg, melyiket kapod.

A büntetések, képletekkel, mert összekeverésük népbetegség

Link a szakaszhoz: A büntetések, képletekkel, mert összekeverésük népbetegség

Három különböző mechanizmus utazik hasonló neveken, más dolgokat csinálnak, és a különbség mérhető. Legyen cic_i annak száma, hányszor jelent már meg a ii token.

ziziα1[ci>0]z_i \leftarrow z_i - \alpha \cdot \mathbb{1}[c_i > 0]

Vonj le egy konstanst minden olyan token értékből, amely egyáltalán megjelent. Egyszer megjelenni és negyvenszer megjelenni ugyanakkora büntetést kap. Ez kapcsoló, nem tárcsa.

ziziβciz_i \leftarrow z_i - \beta \, c_i

Vonj le a darabszámmal arányosan. Egy négyszer használt token négyszer akkora büntetést kap, mint egy egyszer használt token, és a nyomás a szöveg növekedésével halmozódik.

zi{zi/ρif zi>0ziρif zi0z_i \leftarrow \begin{cases} z_i / \rho & \text{if } z_i > 0 \\ z_i \cdot \rho & \text{if } z_i \le 0 \end{cases}

Az eredeti, a CTRL cikkből.7 Oszt, nem kivon; az előjelkezelés azért kell, mert egy negatív logit elosztása nagyobbá tenné. Erőssége ezért a logit nagyságától függ, ami azt jelenti, hogy ugyanaz a ρ\rho a mondat különböző pontjain másként üt.

Ugyanaz a korábbi degenerált folytatás, mindegyik alkalmazásával. A „megváltoztatott lépések” azt számolja, a 120 generálási lépésből hány választott más token elemet, mint amit a büntetés nélküli modell választott volna. A futás itt 120 lépés, szemben a fenti blokk 140 lépésével, ezért a büntetés nélküli baseline 87,6 % helyett 85,5 %-ot mutat:

settingrepeated 4-gramssteps altered
nothing85.5 %0 / 120
presence 0.565.0 %3 / 120
presence 1.03.4 %11 / 120
frequency 0.56.0 %12 / 120
frequency 1.00.0 %20 / 120
repetition 1.2 (CTRL)0.0 %35 / 120

Három dolog következik. A 0,5-ös presence 120-ból három döntést változtatott meg, és negyedével vágta le az ismétlést — a loopot néhány token tartotta össze. A 0,5-ös frequency négyszer annyi döntést változtatott meg, sokkal nagyobb hatással, mert a darabszám-szorzó tovább nő, a presence konstans viszont nem. A széles körben másolt 1,2-es CTRL penalty pedig 120-ból 35 döntést írt át, ami nem finom lökés; ez egy másik modell.

Ez az utolsó szám készíti elő azt a hibát, amelyre senki nem figyelmeztet.

Mit tesznek a büntetések azzal a szöveggel, amelynek ismétlődnie kell

Link a szakaszhoz: Mit tesznek a büntetések azzal a szöveggel, amelynek ismétlődnie kell

A kód ismétel. A táblák ismételnek. A listák ismételnek. A strukturált kimenet definíció szerint ismétel — ettől struktúra. Egy penalty nem tud különbséget tenni aközött, hogy a modell loopba ragadt, vagy helyesen kibocsátja egy tábla negyedik sorát, mert mindkettő úgy néz ki, mint egy token újbóli megjelenése.

Ugyanaz a három feladat, háromféleképpen generálva:

tasknothingfrequency 0.5repetition 1.2
markdown table, 6 rows0 / 56 steps altered0 / 562 / 62
Python function0 / 930 / 9310 / 110
bulleted list, 1 to 120 / 500 / 500 / 50

A 0,5-ös frequency penalty mindháromnál ártalmatlannak bizonyult, ami hasznos és kissé meglepő eredmény, és valami pontosat mond: mivel egyetlen döntés sem változott, a strukturális token elemeknek a pozíciójukban többel kellett nyerniük, mint amennyit a penalty levont, még öt-hat megjelenés után is. A CTRL penalty, amely viszont oszt, már kimozdítja őket, és ezt állította elő:

TEXT
repetition 1.2, markdown table:
  | n | 2^n |
  | --- | --- |
  | 0 | 1      |
  | 1 | 2       |
  | 2 | 4       |

Az igazítás szétesik: az egyes cellákon belüli kitöltés mennyisége sorról sorra változik, mert a záró pipe előtti szóközsorozat pontosan az a fajta ismétlés, amelyet a penalty szét akar törni. Kozmetikai hiba, és hat extra tokenbe került. A Python eset nem kozmetikai:

TEXT
nothing / frequency 0.5:
      total = 0
      for i in range(1, n + 1):
          total += i ** 2
      return total

repetition 1.2:
      # Initialize total_sum with 0
      total_sum = 0
      # Loop through numbers from 1 to n, incrementing by 2 each time
      for i in range(1, n + 1,

A penalty letolta a modellt total értékről — amelyet már használt a docstringben — total_sum értékre, kitalált kommentekkel tömte ki a kimenetet, hogy a költségkeretét fel nem használt token értékekre költse, majd besétált egy háromargumentumos range hívásba stride-dal. A komment azt mondja: incrementing by 2 each time, ami rossz 1-től nn-ig vett négyzetösszegre. Egy repetition penalty helytelen kódot állított elő egy promptból, amelyre nélküle helyes válasz született.

Az ebből következő szabály rövid: a büntetések nyílt végű prózához valók, és ki kell kapcsolni őket kódnál, strukturált kimenetnél, táblázatos adatnál és bárminél, aminek schema-ja van. A 18. fejezet pontosan erről a második kategóriáról szól.

Az alkalmazás sorrendje, és miért változtatja meg a választ

Link a szakaszhoz: Az alkalmazás sorrendje, és miért változtatja meg a választ

Minden valódi implementáció ezeket egy konkrét sorrendben alkalmazza:

penalties → temperature → top-k → top-p → sample

Ez nem önkényes könyvelés, és két lépés felcserélése ténylegesen más eloszlásokat eredményez. Két mérés, mindkettő a tényszerű prompton.

Vágás a temperature előtt vagy után. A nucleus azon az eloszláson számolódik, amelyet kap, és a temperature radikálisan megváltoztatja ezt az eloszlást:

top-p 0.9 after temperaturetop-p 0.9 before temperature
T=1.0T = 1.01 token1 token
T=1.5T = 1.5353 tokens1 token
T=2.0T = 2.032,966 tokens1 token

T=2T = 2 mellett ugyanaz a névleges beállítás 32 966-os vagy 1-es jelölthalmazt ad, kizárólag attól függően, melyik lépés fut előbb. Ha valaha elgondolkodtál, miért „nem csinál semmit” a temperature emelése az egyik provider esetén, és miért teszi tönkre a kimenetet egy másiknál ugyanazzal a két számmal, ez a táblázat hihető válasz.

Büntetés a temperature előtt vagy után. Ha levonsz egy α\alpha penalty értéket, majd osztasz TT értékkel, az effektív penalty α/T\alpha/T lesz; ha előbb osztasz, majd utána vonsz le, akkor α\alpha. A vezető token elemre alkalmazott 1,0-s presence penalty mellett:

temperaturepenalise, then tempertemper, then penalise
0.599.858 %99.948 %
1.089.839 %89.839 %
2.010.783 %6.830 %

T=1T = 1 mellett azonosak, ahogy annak lennie kell. T=2T = 2 mellett 1,58-szoros különbség. A „presence penalty 1.0” nem jól definiált büntetésmennyiség, hacsak azt is nem tudod, hol alkalmazzák a temperature értéket, és ezt egyetlen API sem dokumentálja.

Részletek megjelenítése

Opcionális: az egész pipeline a fenti sorrendben.

Tizenhat sor, és ebben benne van minden, amiről ez a fejezet szól. Ugyanaz a számítás, amelyet a widget végez, csak tíz fix szám helyett valódi logit vektoron.

sample.pyPYTHON
def sample(logits, counts, presence=0.0, frequency=0.0,
           temperature=1.0, top_k=0, top_p=1.0, generator=None):
    z = logits.clone()

    idx = torch.tensor(list(counts))                       # 1. penalties
    if len(idx):
        z[idx] -= presence
        z[idx] -= frequency * torch.tensor([float(c) for c in counts.values()])

    if temperature <= 0:                                   # 2. temperature
        return int(z.argmax())                             #    T=0 is argmax
    p = torch.softmax(z / temperature, -1)

    p, order = p.sort(descending=True)
    if top_k:                                              # 3. top-k
        p[top_k:] = 0
    p = p * ((p.cumsum(0) - p) < top_p)                     # 4. top-p

    p = p / p.sum()                                        # 5. renormalise
    return int(order[torch.multinomial(p, 1, generator=generator)])

A top-p sorban lévő cumsum(0) - p az összesített tömeg az aktuális token nélkül, és ettől kerül be a nucleusba az a token is, amely átlépi a küszöböt, nem áll meg közvetlenül előtte. Ha ezt eggyel elrontod, a top_p = 0.9 csendben kicsit szűkebb vágássá válik, mint minden más implementációban.

Ez a kurzus második felének kevés olyan pontja közé tartozik, ahol a Python a megfelelő nyelv, és az ok strukturális, nem stilisztikai: a fenti minden sorhoz a teljes logit vektornak a kezedben kell lennie, HTTP API felett pedig ez a vektor nem létezik. Elküldheted temperature és top_p értékeket egy providernek; nem implementálhatod őket, és nem láthatod, mit csináltak.

Minden provider ezeknek a vezérlőknek más részhalmazát fogadja, eltérő tartományokkal, és a többit csendben figyelmen kívül hagyja. Ez nem absztrakt panasz. Minden alkalmazásnak, amely modellválasztást kínál, valahol le kell írnia a különbségeket, és az a fájl, ahol ezt megteszi, az inkompatibilitás térképe. Íme, mit deklarál egy ilyen katalógus egyetlen paraméterre azon a kilenc szövegforráson át, amelyet támogat:

declared temperature rangesources
0 to 1Anthropic, Google, Meta, Cerebras, PaLM
0 to 1.5Mistral
0 to 2OpenAI, DeepSeek, xAI

A szó ugyanaz; a skála nem. Az „1-es temperature” az egyiknél a módosítatlan eloszlás, a másiknál a maximálisan engedélyezett hő, és a katalógus fele nem tudja kifejezni azt az értéket, amelyet a másik fele semleges-plusz-egy-kicsinek kezel. A többi gomb ugyanilyen egyenetlen: az OpenAI, DeepSeek és xAI bejegyzések presence és frequency penalty értékeket fogadnak, topK nélkül; a Google, Meta, Cerebras és PaLM bejegyzések topK értéket fogadnak, penalty nélkül; az Anthropic topK, topP és stop sequences értékeket fogad, penalty nélkül; és a kilencből pontosan egy — a Mistral — fogad seed értéket. Ha olyan paramétert küldesz, amelyet egy provider nem implementál, általában semmilyen hiba nem keletkezik: a kérés sikerül, a gomb nem csinál semmit, te pedig arra következtetsz, hogy a beállításnak nincs hatása.

És vedd észre, mi egy ilyen fájl: egy állítás valaki más API-járól, egy konkrét napon leírva, amelyet utólag semmi nem ellenőriz. Egy katalógus, amely 0-tól 1-ig tartományt mond egy olyan providerre, amely már 0-tól 2-ig fogad, csendben levág minden kérést.

Két további vezérlő ugyanabba a családba tartozik. logprobs, ahol elérhető, visszaadja a kiválasztott token log-valószínűségeit és gyakran a néhány legjobb alternatívát — ez az egyetlen ablakod arra az eloszlásra, amelyről ez a fejezet szól, és minden zárt modellre épített confidence heurisztika alapja. A maximum tokens és a stop sequences pedig a valószínűségtől teljesen függetlenül állítják meg a generálást: egy kemény plafon és egy string-illesztés. Mindkettő a 14. fejezet finish_reason értékeként jelenik meg, ahol length azt jelenti, hogy a válaszodat egy keret vágta félbe a mondat közepén, nem a modell fejezte be.

A seed és a determinizmus, ami nincs a kezedben

Link a szakaszhoz: A seed és a determinizmus, ami nincs a kezedben

Állíts be seed értéket, és a sampling reprodukálhatóvá válik. Ez a rész valódi, és könnyű ellenőrizni:

TEXT
seed = 1234  " Paris\nWhat is a good geographical qualifier for describing
               Paris concerning its location?\nA: Near the Mediterranean Sea"
seed = 1234  " Paris\nWhat is a good geographical qualifier for describing
               Paris concerning its location?\nA: Near the Mediterranean Sea"
seed = 7     " Paris is the capital of France. The appellation of Paris is
               \"Île de Paris\"."
seed = 7     " Paris is the capital of France. The appellation of Paris is
               \"Île de Paris\"."

Byte-ra azonos egy seed-en belül, különböző seed-ek között, pontosan ahogy hirdetik. Tehát amit a seed rögzít, az a sample function utolsó sorában lévő véletlen húzás — hogy egy adott eloszlásból melyik token kerül kiválasztásra.

Amit nem rögzít, az maga az eloszlás. És itt kezdődik a baj, mert a modell által előállított logit vektor nem matematikai objektum; milliárdnyi lebegőpontos összeadás kimenete, és ezeknek van sorrendjük.

A 2. fejezet készen hagyta ezt a kísérletet. Ugyanaz az egymillió float32 szám, különböző csoportosításokban összegezve:

TEXT
sequential          998.564270020    error vs float64: 6.393e-03
pairwise (numpy)    998.570556641    error vs float64: 1.061e-04
in 4 chunks         998.570495605    error vs float64: 1.672e-04
in 8 chunks         998.570556641    error vs float64: 1.061e-04
in 16 chunks        998.570678711    error vs float64: 1.594e-05

sequential == pairwise?  False
4 chunks == 8 chunks?    False

Nézd az utolsó sort. A chunkok száma megváltoztatja a választ. Ez nem numpy-érdekesség; ez a mechanizmus, mert amikor egy inference szerver több vagy kevesebb párhuzamos egységre bont egy redukciót, pontosan ezt csinálja. A szerver pedig aszerint bont, hány kérést szolgál ki.

Íme ugyanez a hatás magán a modellen. Ugyanaz a prompt, ugyanaz a forward pass, az egyetlen különbség az, hány más kérés került éppen a batchbe:

TEXT
20 identical forward passes, batch of 1:  20 / 20 bit-for-bit identical

the same prompt inside a batch of  2:  147,321 of 151,936 logits differ
the same prompt inside a batch of  4:  146,515 of 151,936 logits differ
the same prompt inside a batch of  8:  146,515 of 151,936 logits differ
the same prompt inside a batch of 16:  147,321 of 151,936 logits differ

largest change to any logit: 2.5e-05

Egyedül futtatva a modell tökéletesen determinisztikus — húsz pass, bitre azonos. Tedd ugyanazt a promptot egy batchbe nem kapcsolódó kérésekkel, és a logit értékeinek 97 %-a megváltozik. A te kérésedben semmi nem változott. Valaki más kérése megérkezett.

Most az őszinte rész, mert ezt általában úgy mesélik, mintha ez lenne a történet vége. Egy 2.5×1052.5 \times 10^{-5} nagyságú változás csak akkor módosítja a kimenetet, ha két jelölt token ennyire közel volt egymáshoz. Tizenkét prompt 717 generálási lépése során a két legfelső logit közti legkisebb rés 2.5×1032.5 \times 10^{-3} volt — százszor nagyobb, mint a perturbáció — és egy lépés sem volt elég közel a fliphez. Tehát ezen a modellen, float32-ben, laptopon, a batching minden logit értéket megmozdított, de egyetlen token elemet sem változtatott meg.

Ez kedvező feltételek leírása, nem megnyugtatás, és elég egyetlen feltételt megváltoztatni:

TEXT
same weights, same prompts, greedy decoding, no seed involved
float32 vs bfloat16:   6 of 8 answers diverge
                       first divergence at step 23, on average

  float32: "...it is scattered and dispersed into different colors,
            including blue. The blue light is scattered more than other
            colors, so it appears to come from the sky."

  bfloat16: "...it is scattered and scattered, causing the colors of the
             sun to be scattered and scattered, creating the appearance
             of a blue color."

A nyolc válaszból hat eltér, és az egyik erősen leromlik. A 2. fejezet táblázata megmondja, miért: a bfloat16 7 mantisszabitet tart meg, ezért 16-os logit nagyság közelében a reprezentálható értékek 0,125-re vannak egymástól — 16,0, aztán 16,125, aztán 16,25 — és a kerekítés akár 0,0625-tel is elmozdíthat egy logit értéket. Eközben a fent mért generálási lépések 4,7 %-ánál a felső két érték közti rés 0,1 alatt volt. Ez a teljes különbség a két kísérlet között: float32-ben a perturbáció százszor kisebb volt, mint a legközelebbi döntés, bfloat16-ban pedig azonos nagyságrendű. A production inference 16 biten fut, olyan hardveren, fused kernelekkel és redukciós sorrendekkel, amelyek megtartását senki nem ígéri. Az, hogy „a numerikus zaj elhanyagolható-e”, a precízióról és a hardverről szóló kérdés, nem a modellről.

Tehát a négy ok, ahogy a 9. fejezet ígérte:

A lebegőpontos összeadás nem asszociatív

Link a szakaszhoz: A lebegőpontos összeadás nem asszociatív

A 2. fejezet doboza. Egy összeg értéke változik az összeadás sorrendjével, ezért bármilyen változás abban, hogyan bontanak fel egy redukciót, megváltoztatja a logit értékeket. Ez az alapréteg; a másik három ennek a sorrendnek a megváltoztatási módja.

A dynamic batching idegenekével csoportosítja a kérésedet

Link a szakaszhoz: A dynamic batching idegenekével csoportosítja a kérésedet

A 13. fejezetből ismert continuous batching miatt megfizethető az inference — és ez azt jelenti, hogy azoknak a mátrixoknak az alakja, amelyeken a token értékeid átfolynak, a forgalomtól függ. Fent mérve: 147 321 logit mozdult el, mert változott a batch size.

A mixture-of-experts routing a batchtől függ

Link a szakaszhoz: A mixture-of-experts routing a batchtől függ

A 9. fejezet doboza már elmondta. A router diszkrét döntést hoz tokenenként és rétegenként, a batch felett számolt, szakértőnkénti kapacitáskorlátok mellett. Egy token, amely egyedül expert 7-hez ment volna, társaságban expert 12-höz megy. Ez nem kerekítési különbség; ez más súlykészlet.

Egy -latest típusú verzióstring pointer, és a pointereket átirányítják. A providerek a kiszolgáló stacket is frissítik fix verzióazonosító alatt. Egyiket sem olyan granularitással jelentik be, amelyből összeköthetnéd a saját kimeneted változásával.

Az OpenAI seed paramétere az egyetlen lehetséges módon őszinte erről: együtt érkezik egy system_fingerprint mezővel, amely a backend konfigurációját azonosítja, és a dokumentáció kimondja, hogy a determinizmus best-effort, és a megváltozott fingerprint azt jelenti, hogy az eredmények eltérhetnek. Olvasd ezt annak, ami: egy provider közli veled, hogy a fenti négy ok mindegyikét ő irányítja, te egyiket sem, és az egyetlen dolog, amit kínálni tud, hogy utólag megmondja, valami elmozdult.

Itt minden egy gombról és annak következményeiről szólt. Lépjünk egy szinttel hátrébb, és megjelenik a nehezebb probléma: az objektum, amelyet hangoltunk, valószínűségi eloszlás, a valószínűségi eloszlásoknak pedig nincs interfészük.

Egy function callnak van. Egy adatbázissorhoz van. Egy három kötelező mezős JSON body-t váró POST handlernek van, és minden mást elutasít. A modell és a rendszered minden más komponense között olyan szerződés ül, amelyről az egyik oldal nem tud ígéreteket tenni: a modell valamit elő fog állítani, egy általad formált, de nem rögzített eloszlásból húzva, a másik oldalon lévő kódnak pedig ismert típusú érték kell, különben hibát dob.

A két világ közötti híd ennek a fejezetnek az anyagából épül, nem parsingból és retry-ból. Ha egy token megtörné a szükséges struktúrát, nem sample-eled és reménykedsz — -\infty értékre állítod a logit értékét, mielőtt a softmax egyáltalán látná. A constrained decoding maszk ugyanazon a vektoron, amelyet ebben a fejezetben alakítgattunk, és a „kérlek, válaszolj JSON-ban” kérést garanciává változtatja.

A 18. fejezet ez a szerződés: tool calling, JSON Schema, strukturált kimenetek, és mi kell ahhoz, hogy egy valószínűségi rendszer tetején determinisztikus rendszert lehessen biztonságosan építeni.


A fejezet minden mérése Qwen/Qwen2.5-0.5B-Instruct modellen készült CPU-n, float32-ben, hacsak nincs másképp jelezve, a sampling pedig az opcionális szakaszban leírt módon lett implementálva, nem könyvtárra bízva. Ez egy kis modell, és a konkrét értékek az övéi; a mechanizmusok nem. Von Platen How to generate text with different decoding methods című írása (Hugging Face, 2020) az a cikk, amelyhez ez az anyag méri magát, és továbbra is a legjobb rövid bevezetés ugyanebbe a témába. A determinizmus szakaszhoz: a PyTorch reprodukálhatósági jegyzetei leírják, mit rögzít és mit nem egy seed egyetlen gépen, az OpenAI seed és system_fingerprint dokumentációja leírja, mit ígérhet és mit nem egy provider, a Thinking Machines 2025-ös írása a batch-invariant kernelekről pedig a legvilágosabb nyilvános magyarázat arra, miért lehetséges, de nem ingyenes ezt inference-server szinten kijavítani.

  1. Ackley, D. H., Hinton, G. E. and Sejnowski, T. J. A Learning Algorithm for Boltzmann Machines. Cognitive Science 9(1), pp. 147–169 (1985), ahol a softmax temperature értéke a statisztikus fizikából érkezik. Hinton, G., Vinyals, O. and Dean, J., Distilling the Knowledge in a Neural Network, arXiv:1503.02531 (2015), 2. szakasz: itt jelenik meg újra ugyanez a paraméter a modern deep learningben — egy tanár teljes eloszlásának láthatóvá tételére, ami a 13. fejezet soft labels témája, nem ennek a fejezetnek a samplingja.

  2. Guo, C., Pleiss, G., Sun, Y. and Weinberger, K. Q. On Calibration of Modern Neural Networks. arXiv:1706.04599 (2017). Ne keverd össze ezt a fejezet temperature értékével. A temperature scaling egy validációs halmazon illeszt egyetlen értéket, hogy a modell magabiztossága megfeleljen a pontosságának; ez egy post-hoc kalibrációs módszer, amelyet osztályozók kimenetére alkalmaznak. A temperature sampling futásidejű vezérlő arra, hogyan húz token értékeket egy generátor. Ugyanaz a képlet, más cél, közös érték nélkül.

  3. Holtzman, A., Buys, J., Du, L., Forbes, M. and Choi, Y. The Curious Case of Neural Text Degeneration. arXiv:1904.09751 (2019). Bevezeti a nucleus sampling módszert és azt a mérést, hogy a maximalizáláson alapuló decoding olyan szöveget állít elő, amelynek valószínűségi profilja egyáltalán nem hasonlít emberi szövegre. 2

  4. Fan, A., Lewis, M. and Dauphin, Y. Hierarchical Neural Story Generation. arXiv:1805.04833 (2018). A top-k samplingot népszerűsítő cikk.

  5. Nguyen, M. et al. Turning Up the Heat: Min-p Sampling for Creative and Coherent LLM Outputs. arXiv:2407.01082 (2024).

  6. Meister, C., Pimentel, T., Wiher, G. and Cotterell, R. Locally Typical Sampling. arXiv:2202.00666 (2022).

  7. Keskar, N. S., McCann, B., Varshney, L. R., Xiong, C. and Socher, R. CTRL: A Conditional Transformer Language Model for Controllable Generation. arXiv:1909.05858 (2019). A 4.1. szakasz az eredeti repetition penalty — az, amely oszt.


Készítette

David Vicente Campos

A NeuraLIA Labs alapítója és a MyRealFood társalapítója

Mérnökinformatikus vagyok, a Leóni Egyetemen végeztem. Társalapítottam a MyRealFoodot, ahol CTO-ként felépítettem azt az alkalmazást, amelyet emberek milliói használtak arra, hogy egészségesebben táplálkozzanak, és megalapítottam a NeuraLIA Labst, ahol AI-termékeket fejlesztek. Itt arról írok, amit menet közben meg kellett értenem, úgy, ahogy szerettem volna, hogy valaki elmagyarázza nekem.

Továbbiak a szerzőről

Közzétette a NeuraLIA Labs.

Kapj új bejegyzéseket a postaládádba

AI-hírek, útmutatók és termékfrissítések — rövid email, amikor valami igazán hasznosat publikálunk.

Kurzusindex

Abstract software decision engine with branching paths, probability nodes, and glowing gates.
jev11 perc olvasás

A Jev AI-modell döntésekre készült, nem prózára

A TypeSafe AI Jev modellje azért kap figyelmet, mert a szoftveres intelligenciát valószínűségi problémaként kezeli: válaszd ki a megfelelő ágat, rendelj hozzá bizalmi szintet, és ne fizess egy LLM-nek szövegírásért, amikor a kódnak döntésre van szüksége.

Abstract agent runtime sorting documents, memory blocks and pointer nodes inside a bounded context frame.
context-engineering11 perc olvasás

Kontextustervezés hosszú távú AI-ügynökökhöz

A hosszú ideig futó ügynökök nem csak azért vallanak kudarcot, mert kicsi az ablak. Akkor hibáznak, amikor a fájlok, eszközkimenetek és elavult előzmények kiszorítják azt a feladatot, amelyet az ügynöknek be kellett volna fejeznie.

Készen állsz, hogy a LIA válasszon helyetted?

Építs az összes AI-modellel egy helyen – kezdd el ma, ingyen.