Siirry sisältöön
17/30Luku 17/30

Temperature, top-p ja determinismi, jota sinulla ei ole

Temperature jakaa logits ennen softmaxia, ja se romuttaa ajatuksen luovuussäätimestä. Sama greedy-kutsu voi silti antaa kaksi vastausta.

Tällä sivulla

Tässä on sama pyyntö lähetettynä samalle mallille viisi kertaa. Samat weights, sama prompt, sama kone, sama satunnaissiemen. Vain yksi numero muuttuu.

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 ('$ספטמבר..."

Mikään ei mennyt rikki. Viimeisen rivin jokainen token arvottiin täysin oikein mallin omasta todennäköisyysjakaumasta sen 151 936 alkion sanaston yli. Muuttuvaa numeroa kutsutaan nimellä temperature, useimmissa dokumentaatioissa sitä kuvataan luovuussäätimeksi, ja se kuvaus on väärä tavalla, jonka tämä luku voi näyttää eikä vain väittää.

Tässä luvussa myös kolme aiempaa lupausta lunastetaan. Luku 4 määritteli logit-käsitteen eikä oikeastaan käyttänyt sitä loppuun. Luvun 2 liukulukuja käsittelevä laatikko päättyi ohjeeseen — muista tämä, kun luku 17 kysyy, miksi sama prompt, malli ja siemen voivat tuottaa eri tokenit. Ja luvun 9 mixture-of-experts-laatikko lupasi luettelon neljästä non-determinism-syystä. Kaikki kolme tulevat vastaan alla.

Yksi rivi, jonka varassa koko luku roikkuu

Linkki osioon: Yksi rivi, jonka varassa koko luku roikkuu

Luku 4 esitteli logit-arvon normalisoimattomana reaaliarvoisena pisteenä, yksi per luokka. Luku 8 sai kielimallin tuottamaan yhden jokaista sanaston alkiota kohti. softmax muuttaa tuon vektorin z\mathbf{z} todennäköisyyksiksi:

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

Temperature tulee mukaan tässä — nimi on lainattu tilastollisesta fysiikasta, jossa sama parametri ohjaa sitä, kuinka terävästi Boltzmann-jakauma keskittyy matalaenergisiin tiloihinsa1 — ja se jakaa logits ennen eksponenttia:

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

Tämä sijainti on koko mekanismi, ja kahden rivin algebra riittää näyttämään, miksei se voisi olla missään muualla. Oletetaan, että yrittäisit soveltaa temperature-arvoa sen sijaan todennäköisyyksiin — skaalata niitä arvolla 1/T1/T ja normalisoida uudelleen. Saisit

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

Vakio supistuu pois. Todennäköisyyksien skaalaaminen ei tee mitään; jakauma palaa ennalleen. Temperature vaikuttaa vain siksi, että se toimii eksponentissa, jossa jakaminen arvolla TT ennen eksponentointia on sama kuin kunkin todennäköisyyden korottaminen potenssiin 1/T1/T — epälineaarinen uudelleenmuotoilu, joka muuttaa alkioiden välisiä suhteita eikä niiden yhteistä skaalaa.

Tästä sijainnista seuraavat molemmat raja-arvot ilman lisätyötä. Kun T0T \to 0, suurin logit karkaa muista ja pp romahtaa yksittäiseen parhaiten pisteytettyyn tokeniin: greedy decoding. Kun TT kasvaa, jokainen zi/Tz_i/T lähestyy nollaa, jokainen eksponentti lähestyy yhtä, ja jakauma litistyy kohti tasaista jakaumaa koko sanaston yli. Täsmälleen kohdassa T=0T = 0 kaava jakaa nollalla, joten jokainen toteutus käsittelee sen erikoistapauksena aritmeettiseksi maksimiarvoksi — myös alla oleva widget, joka vaihtaa argmaxiin kohdassa T0.001T \le 0.001.

Yksi varoitus, koska nimien törmäys aiheuttaa oikeaa sekaannusta. Machine learningissä on toinen, tähän liittymätön asia nimeltä temperature: temperature scaling, kalibrointimenetelmä, joka sovittaa yhden arvon validointijoukolla niin, että luokittelijan luottamus vastaa sen tarkkuutta.2 Sama kaava, ei mitään tekemistä generoinnin kanssa. Paperit, joissa lukee "temperature", tarkoittavat usein sitä; tämä luku ei koskaan.

Tässä on tuo jakauma, aritmetiikka suoraan edessäsi. Logits ovat kiinteät ja uskottavat, joten alla olevan tekstin luvut voi tarkistaa siitä, mitä näet:

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

10/10 tokenia läpäisee rajauksen ja jakaa todennäköisyyden.

Näytä tiedot taulukkona
TokenlogitLämpötilan jälkeenRajauksen jälkeen
␣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%
Näytteistys: lämpötila, top-p ja top-k

Kymmenen ehdokasjatkoa lauseelle The capital of France is, temperature 1 ja ilman leikkausta. ␣Paris pitää hallussaan 96,90 % massasta; ␣banana, pohjalla logit-arvolla 2.6-2.6, saa 0,00 %. Vedä temperature nollaan, ja yksi token selviää 100 %:lla. Vedä se arvoon 2, ja ␣Paris putoaa 69,81 %:iin samalla kun ␣banana nousee 0,17 %:iin — mallin hylkäämä token saa todellista todennäköisyyttä säätimestä, jota lukija käänsi.

Temperature ei ole luovuussäädin

Linkki osioon: Temperature ei ole luovuussäädin

Numero ␣banana on koko argumentti pienoiskoossa: temperature-arvon nostaminen ei voi antaa mallille ideaa, jota sillä ei ollut. Logits on jo laskettu, järjestys on jo kiinteä, ja temperature säilyttää sen täsmälleen — mikään määrä lämpöä ei koskaan siirrä matalammin pisteytettyä tokenia korkeammin pisteytetyn yläpuolelle. Se vain jakaa massaa alemmas siinä järjestyksessä, jonka malli itse tuotti. Korkea temperature ei tee mallista kekseliäämpää; se tekee todennäköisemmäksi, että malli tuottaa tokenit, jotka se pisteytti huonoiksi.

Todellisessa sanastossa tämä lakkaa olemasta kuriositeetti ja muuttuu syyksi, miksi korkean temperature-arvon output on käyttökelvotonta. Mitattuna mallilla Qwen/Qwen2.5-0.5B-Instruct, yksi forward pass, yllä oleva prompt, laskien montako tokenia tarvitaan tietyn osuuden keräämiseksi todennäköisyysmassasta:

temperaturetop-1-todennäköisyysentropiatokenit, joissa 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

Lue alin rivi hitaasti. Kohdassa T=2T = 2, kysymyksessä johon on täsmälleen yksi oikea vastaus, 32 966 eri tokenia jakaa todennäköisyysmassan ylimmän 90 %:n. Se ei ole laajempi luova tila. Se on malli, jolle aritmetiikka on käskenyt kohdella korean partikkelia ja C++-tunnistetta elävinä vaihtoehtoina sanalle, joka tulee kohdan A: jälkeen. Avauslohkon roska on suora seuraus, eikä se ole bugi mallissa tai kirjastossa — se on se, mitä pyyntö pyysi.

Hyödyllinen alue on kapea ja riippuu tehtävästä eikä mausta. Faktakysymyksessä vastaus on yksi token, ja kaikki lämpö noin 1,2:n yläpuolella lisää virhettä ilman hyötyä. Avoimessa tehtävässä on todella useampi kuin yksi hyvä jatko, ja jonkin verran lämpöä ostaa vaihtelua, joka pysyy sujuvana:

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..."

Kohdassa 1,3 malli on keksinyt erisnimen ja lauseen, joka ei jäsenny. Kaista "aina identtinen" ja "epäkoherentti" välillä on tälle mallille tässä tehtävässä suunnilleen 0,6–1,1, ja rehellinen neuvo on, että löydät sen mittaamalla omalla tehtävälläsi, et kopioimalla numeroa blogipostauksesta.

Miksi todennäköisin teksti on huonoa tekstiä

Linkki osioon: Miksi todennäköisin teksti on huonoa tekstiä

Kaiken tämän alla piilee ilmeinen kysymys: jos mallilla on todennäköisyysjakauma ja yksi token on todennäköisin, miksei sitä aina valittaisi? Greedy decoding on ilmainen, toistettava eikä tarvitse parametreja.

Koska tulos on tämä:

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 %

Kahdeksan virkettä, yksi virke. Lähes yhdeksän kymmenestä neljän tokenin ikkunasta oli jo esiintynyt aiemmin samassa outputissa. Tämä on neural text degeneration, jonka Holtzman ym. nimesivät ja selittivät paperissa, joka esitteli top-p:n.3 Malli ei ole rikki; sekvenssitodennäköisyyden maksimointi on vain väärä tavoite avoimelle tekstille. Ihmisen kirjoitus ei ole todennäköisin sanajono — siinä on yllätystä, sen per-token-todennäköisyys vaeltelee, laskee ja palautuu — kun taas maksimitodennäköisyyden polku on kiintopiste, johon päästyään sillä ei ole syytä poistua.

Siksi sampling on olemassa ylipäätään. Ja, tämä osa usein jätetään pois, se ei ole universaali laki. Luku 12 mittasi 24/24 oikein kaksivaiheisissa sanatehtävissä pelkällä greedy decodingilla, ja sampling temperature 0,8:lla pudotti sen 81 %:iin; self-consistency käytti sitten kuusi kertaa enemmän tokeneita kiivetäkseen takaisin sinne, missä greedy jo oli. Molemmat faktat ovat yhtä aikaa totta:

Avoin generointi. Ei ole yhtä oikeaa jatkoa, joten todennäköisin on ansa — se alkaa loopata, ja 87,6 % siitä on kopioitu itsestään. Sample.

Tehtävät, joissa on yksi oikea vastaus. On olemassa yksi oikea jatko, joten minkä tahansa muun arpominen on virheen arpomista. Luvun 12 100 % muuttui 81 %:iin täsmälleen tästä syystä. Älä käytä samplingia.

Useimmat production promptit ovat toista tyyppiä ja konfiguroidaan ensimmäisen kaltaisiksi, koska temperature jätettiin siihen arvoon, jota esimerkkikoodi käytti.

Kaksi tapaa leikata, ja vain toinen mukautuu

Linkki osioon: Kaksi tapaa leikata, ja vain toinen mukautuu

Sampling koko jakaumasta ei ole sitä, mitä kukaan oikeasti tekee, koska häntä on valtava ja täynnä hölynpölyä. Jotain pitää leikata pois. Klassisia vastauksia on kaksi, ja ne eroavat yhdellä tavalla, joka ratkaisee kaiken.

Top-k pitää kiinteän määrän ehdokkaita. Lajittele todennäköisyyden mukaan, pidä ensimmäiset kk, hylkää loput, normalisoi uudelleen.4 Top-p, jota kutsutaan myös nucleus samplingiksi, pitää kiinteän määrän massaa: ota tokenit laskevassa järjestyksessä, kunnes niiden kumulatiivinen todennäköisyys saavuttaa pp, ja pysähdy.3 Muodollisesti nucleus on pienin joukko VpV_p, jolla

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

Ero kuulostaa kosmeettiselta eikä ole sitä, koska saman minuutin aikana lähettämilläsi kahdella promptilla on täysin erilaiset jakauman muodot. Molemmat näistä ovat sama malli temperature 1:llä:

Q: What is the capital of France?\nA:Once upon a time,
top-1-todennäköisyys96,01 %25,39 %
tokenit, joissa 90 % massasta1467
top-k = 40 pitää99,61 % massasta78,87 % massasta
massa sijoilla 2–403,61 %53,48 %
token sijalla 40␣Av, 0,0093 %␣Dr, 0,128 %

Yksi kiinteä kk, kaksi epäonnistumista vastakkaisiin suuntiin. Faktapromptilla k=40k = 40 päästää sisään 39 tokenia, jotka yhdessä ovat arvoltaan 3,6 % — se päästää roskaa läpi, mukaan lukien ehdokkaan yhdeksän tuhannesosan prosentin kohdalla, koska sääntö laskee paikkoja eikä evidenssiä. Tarinapromptilla sama k=40k = 40 heittää pois 21 % massasta, jonka malli aidosti antoi, koska todellinen nucleus on siellä 467 tokenia leveä.

Top-p saa täsmälleen yhden numeron tekemään molemmat työt. Aseta p=0.9p = 0.9, ja se pitää 1 tokenin ensimmäisellä promptilla ja 467 toisella, koska se kysyy jakaumasta eikä pakota siihen lukumäärää. Katso mukautuminen suoraan — sama leikkaus, neljä temperature-arvoa:

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

3/10 tokenia läpäisee rajauksen ja jakaa todennäköisyyden.

Näytä tiedot taulukkona
TokenlogitLämpötilan jälkeenRajauksen jälkeen
␣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%
Näytteistys: lämpötila, top-p ja top-k

Top-p 0,90 ja temperature 1,5: kolme kymmenestä tokenista selviää ja jakaa massan, ␣Paris uudelleennormalisoituna 91,10 %:iin. Siirrä nyt vain temperature-arvoa. Kohdassa 0,7 sama 0,90 jättää yhden selviytyjän — noin kapea nucleus on greedy decoding eri nimellä. Kohdassa 2,0 se jättää viisi. Leikkaus ei liikkunut; sen alla oleva muoto liikkui.

Tuo widget ratkaisee myös väärinkäsityksen, joka kannattaa nimetä, koska se maksaa ihmisille oikeaa rahaa. Varmassa jakaumassa top_p = 0.9 ei ole "hieman vaihtelua". Se on greedy. Temperature 1:llä johtava token pitää tässä 96,90 %, mikä on jo yli 0,9, joten nucleus on yhden tokenin levyinen eikä mitään muuta voida koskaan arpoa. Tiimit asettavat top_p arvoon 0,9 uskoen löysänneensä jotain ja ihmettelevät sitten, miksi jokainen vastaus on identtinen.

Aseta sen sijaan top-k, ja vastakkainen epäonnistuminen näkyy yhtä selvästi:

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

5/10 tokenia läpäisee rajauksen ja jakaa todennäköisyyden.

Näytä tiedot taulukkona
TokenlogitLämpötilan jälkeenRajauksen jälkeen
␣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%
Näytteistys: lämpötila, top-p ja top-k

Top-k 5, ei top-p:tä. Viisi tokenia selviää jokaisella temperature-arvolla, koska viisi pyydettiin. Temperature 1:llä, kuten kuvassa, neljä ehdokasta kohdan ␣Paris alla ovat yhteensä 2,79 %:n arvoisia. Pudota 0,7:ään ja samat neljä ovat 0,38 % — leikkaus on teatteria, ja malli on käytännössä greedy. Nosta 2,0:aan, ja ne ovat 22,54 %. Identtinen asetus, identtinen selviytyjien määrä, kolme täysin eri käyttäytymistä, eikä mikään pyynnössä kerro, minkä niistä saat.

Penalties, kaavoineen, koska niiden sekoittaminen on endeemistä

Linkki osioon: Penalties, kaavoineen, koska niiden sekoittaminen on endeemistä

Kolme eri mekanismia kulkee samankaltaisilla nimillä, ne tekevät eri asioita, ja ero on mitattava. Olkoon cic_i niiden kertojen määrä, joina token ii on jo esiintynyt.

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

Vähennä vakio jokaisesta tokenista, joka on esiintynyt lainkaan. Yksi esiintymä ja neljäkymmentä esiintymää saavat identtisen rangaistuksen. Se on kytkin, ei säädin.

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

Vähennä lukumäärän suhteessa. Neljä kertaa käytetty token saa neljä kertaa kovemman rangaistuksen kuin kerran käytetty token, ja paine kumuloituu tekstin kasvaessa.

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}

Alkuperäinen, CTRL-paperista.7 Se jakaa eikä vähennä, ja merkkitapaus tarvitaan, koska negatiivisen logit-arvon jakaminen tekisi siitä suuremman. Sen voimakkuus riippuu siis logit-arvon suuruudesta, mikä tarkoittaa, että sama ρ\rho osuu eri tavalla saman virkkeen eri kohdissa.

Sama degeneroitunut jatko aiemmalta, jokainen näistä sovellettuna. "Muutetut askeleet" laskee, montako 120 generointiaskeleesta valitsi eri tokenin kuin rankaisematon malli olisi valinnut. Ajo on tässä 120 askelta verrattuna yllä olevan lohkon 140:een, minkä vuoksi rankaisematon baseline näyttää 85,5 % eikä 87,6 %:

asetustoistetut 4-grammitmuutetut askeleet
ei mitään85,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

Tästä seuraa kolme asiaa. Presence 0,5 muutti kolme päätöstä 120:stä ja leikkasi toistoa neljänneksellä — loop pysyi kasassa kourallisella tokeneita. Frequency 0,5 muutti neljä kertaa enemmän päätöksiä ja vaikutti paljon enemmän, koska lukumääräkerroin kasvaa jatkuvasti, mutta presence-vakio ei. Ja CTRL penalty laajasti kopioidulla arvolla 1,2 kirjoitti uusiksi 35 päätöstä 120:stä, mikä ei ole pieni tönäisy; se on eri malli.

Tuo viimeinen luku alustaa epäonnistumisen, josta kukaan ei varoita.

Mitä penalties tekevät tekstille, jonka kuuluukin toistua

Linkki osioon: Mitä penalties tekevät tekstille, jonka kuuluukin toistua

Koodi toistaa. Taulukot toistavat. Listat toistavat. Rakenteinen output toistaa määritelmän mukaan — se on rakenne. Penalty ei osaa erottaa mallia, joka on jumissa loopissa, mallista, joka tuottaa oikein taulukon neljännen rivin, koska molemmat näyttävät siltä, että token esiintyy uudelleen.

Samat kolme tehtävää, generoitu kolmella tavalla:

tehtäväei mitäänfrequency 0,5repetition 1,2
markdown-taulukko, 6 riviä0 / 56 askelta muutettu0 / 562 / 62
Python-funktio0 / 930 / 9310 / 110
luettelomerkillinen lista, 1–120 / 500 / 500 / 50

Frequency penalty arvolla 0,5 osoittautui vaarattomaksi kaikissa kolmessa, mikä on hyödyllinen ja hieman yllättävä tulos, ja se kertoo jotain täsmällistä: koska yksikään päätös ei muuttunut, rakenteellisten tokenien on täytynyt voittaa paikkansa enemmän kuin penalty vähensi, jopa viiden ja kuuden esiintymän jälkeen. CTRL penalty, joka jakaa, onnistuu kuitenkin syrjäyttämään ne, ja tässä on mitä se tuotti:

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

Tasaus hajoaa: kunkin solun sisäinen padding muuttuu riviltä toiselle, koska välilyöntien jono ennen sulkevaa pystyviivaa on juuri sellainen toisto, jonka rikkomista varten penalty on olemassa. Kosmeettista, ja se maksoi kuusi ylimääräistä tokenia. Python-tapaus ei ole kosmeettinen:

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,

Penalty työnsi mallin pois kohteesta total — joka oli jo käytetty docstringissä — kohteeseen total_sum, täytti outputin keksityillä kommenteilla käyttääkseen budjettinsa käyttämättömiin tokeneihin, ja käveli sitten kolmiargumenttiseen range-kutsuun stride-arvon kanssa. Kommentti sanoo incrementing by 2 each time, mikä on väärin neliöiden summalle yhdestä arvoon nn. Repetition penalty tuotti virheellistä koodia promptista, johon vastattiin oikein ilman sitä.

Tästä seuraava sääntö on lyhyt: penalties ovat avointa proosaa varten, ja niiden pitäisi olla pois päältä koodissa, rakenteisessa outputissa, taulukkomuotoisessa datassa ja kaikessa, missä on schema. Luku 18 käsittelee juuri tuota toista kategoriaa.

Soveltamisjärjestys, ja miksi se muuttaa vastausta

Linkki osioon: Soveltamisjärjestys, ja miksi se muuttaa vastausta

Jokainen todellinen toteutus soveltaa näitä tietyssä järjestyksessä:

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

Tämä ei ole mielivaltaista kirjanpitoa, ja kahden vaiheen vaihtaminen tuottaa aidosti eri jakaumia. Kaksi mittausta, molemmat faktapromptilla.

Leikkaus ennen tai jälkeen temperature-arvon. Nucleus lasketaan siitä jakaumasta, joka sille annetaan, ja temperature muuttaa tuota jakaumaa radikaalisti:

top-p 0,9 temperature-arvon jälkeentop-p 0,9 ennen temperature-arvoa
T=1.0T = 1.01 token1 token
T=1.5T = 1.5353 tokenia1 token
T=2.0T = 2.032 966 tokenia1 token

Kohdassa T=2T = 2 sama nimellinen asetus tuottaa ehdokasjoukoksi 32 966 tai 1, pelkästään sen mukaan mikä vaihe ajetaan ensin. Jos olet joskus miettinyt, miksi temperature-arvon nostaminen "ei tee mitään" yhdellä providerilla ja tuhoaa outputin toisella samoilla kahdella numerolla, tämä taulukko on uskottava vastaus.

Rankaisu ennen tai jälkeen temperature-arvon. Penalty-arvon α\alpha vähentäminen ja sitten jakaminen arvolla TT antaa efektiiviseksi penalty-arvoksi α/T\alpha/T; ensin jakaminen ja sitten vähentäminen antaa α\alpha. Presence penalty 1,0 sovellettuna johtavaan tokeniin:

temperaturerankaise, sitten tempertemper, sitten rankaise
0,599,858 %99,948 %
1,089,839 %89,839 %
2,010,783 %6,830 %

Identtisiä kohdassa T=1T = 1, kuten niiden pitääkin olla. Eroa kertoimella 1,58 kohdassa T=2T = 2. "Presence penalty 1,0" ei ole hyvin määritelty määrä penaltyä, ellet myös tiedä, missä temperature sovelletaan, eikä mikään API dokumentoi tätä.

Näytä lisätiedot

Valinnainen: koko pipeline yllä olevassa järjestyksessä.

Kuusitoista riviä, ja kaikki tässä luvussa on niissä. Se on sama laskenta, jonka widget tekee, oikealla logit-vektorilla eikä kymmenellä kiinteällä numerolla.

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)])

Top-p-rivin cumsum(0) - p on kumulatiivinen massa pois lukien nykyinen token, mikä saa nucleuksen sisältämään kynnyksen ylittävän tokenin sen sijaan, että se pysähtyisi juuri ennen sitä. Tee tähän off-by-one-virhe, ja top_p = 0.9 muuttuu hiljaa hieman tiukemmaksi leikkaukseksi kuin joka muussa toteutuksessa.

Tämä on yksi niistä harvoista paikoista kurssin jälkipuoliskolla, joissa Python on oikea kieli, ja syy on rakenteellinen eikä tyylillinen: jokainen yllä oleva rivi tarvitsee koko logits-vektorin käsiisi, ja HTTP API:n yli sitä vektoria ei ole olemassa. Voit lähettää temperature ja top_p providerille; et voi toteuttaa niitä, etkä voi nähdä, mitä ne tekivät.

Universaalia sampling API:a ei ole

Linkki osioon: Universaalia sampling API:a ei ole

Jokainen provider hyväksyy eri osajoukon näistä säätimistä, eri vaihteluväleillä, ja jättää loput hiljaa huomiotta. Tämä ei ole abstrakti valitus. Jokaisen sovelluksen, joka tarjoaa mallivalinnan, täytyy kirjata erot jonnekin, ja tiedosto, jossa se tekee sen, on kartta yhteensopimattomuudesta. Tässä on, mitä yksi tällainen katalogi ilmoittaa yhdestä parametrista yhdeksässä tukemassaan tekstilähteessä:

ilmoitettu temperature-aluelähteet
0–1Anthropic, Google, Meta, Cerebras, PaLM
0–1,5Mistral
0–2OpenAI, DeepSeek, xAI

Sana on sama; skaala ei. "Temperature 1" on yhdellä muokkaamaton jakauma ja toisella suurin sallittu lämpö, eikä puolet katalogista pysty ilmaisemaan arvoa, jota toinen puoli pitää neutraalina plus pienenä lisänä. Muut knobs ovat yhtä epätasaisia: OpenAI-, DeepSeek- ja xAI-merkinnät ottavat presence ja frequency penalties eivätkä topK; Google-, Meta-, Cerebras- ja PaLM-merkinnät ottavat topK eivätkä penalties; Anthropic ottaa topK, topP ja stop sequences eikä penalties; ja täsmälleen yksi yhdeksästä — Mistral — ottaa siemenen. Parametrin lähettäminen providerille, joka ei toteuta sitä, ei yleensä tuota virhettä lainkaan: pyyntö onnistuu, säädin ei tee mitään, ja päättelet, ettei asetuksella ole vaikutusta.

Ja huomaa, mitä tällainen tiedosto on: väite jonkun muun API:sta, kirjoitettuna yhtenä tiettynä päivänä, eikä mikään tarkista sitä myöhemmin. Katalogi, joka sanoo 0–1 providerille, joka nykyään hyväksyy 0–2, leikkaa hiljaa jokaisen pyynnön.

Kaksi muuta säädintä kuuluu samaan perheeseen. logprobs, jos sitä tarjotaan, palauttaa valitun tokenin log-todennäköisyydet ja usein muutaman parhaan vaihtoehdon — ainoan ikkunan siihen jakaumaan, josta tämä luku kertoo, ja perustan jokaiselle confidence-heuristiikalle, joka rakennetaan suljetun mallin päälle. Ja maximum tokens sekä stop sequences päättävät generoinnin täysin ilman todennäköisyyttä: kova katto ja merkkijono-osuma. Molemmat näkyvät finish_reason-arvona luvusta 14, jossa length tarkoittaa, että vastauksesi leikattiin kesken virkkeen budjetin takia, ei että malli olisi saanut sen valmiiksi.

Siemen, ja determinismi, jota sinulla ei ole

Linkki osioon: Siemen, ja determinismi, jota sinulla ei ole

Aseta siemen, ja samplingista tulee toistettavaa. Se osa on totta, ja se on helppo todentaa:

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\"."

Tavutasolla identtinen saman siemenen sisällä, eri siementen välillä erilainen, juuri kuten luvattiin. Siemen siis lukitsee satunnaisarvonnan tuon sample-funktion viimeisellä rivillä — minkä tokenin valitaan annetusta jakaumasta.

Se ei lukitse jakaumaa. Ja siinä ongelma on, koska logits-vektori, jonka mallisi tuottaa, ei ole matemaattinen olio; se on miljardien liukulukuadditioiden output, ja niillä on järjestys.

Luku 2 jätti tämän kokeen valmiiksi. Sama miljoona float32-lukua, summattuna eri ryhmittelyillä:

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

Katso viimeistä riviä. Chunkien määrä muuttaa vastauksen. Se ei ole kuriositeetti numpysta; se on mekanismi, koska kun inference server jakaa reduktion useampaan tai harvempaan rinnakkaiseen yksikköön, se tekee täsmälleen tätä. Ja serveri jakaa sen sen mukaan, montako pyyntöä se palvelee.

Tässä on tuo vaikutus itse malliin. Sama prompt, sama forward pass, ainoa ero on se, montako muuta pyyntöä sattui olemaan batchissa:

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

Yksin ajettuna malli on täydellisen deterministinen — kaksikymmentä läpivientiä, bitilleen identtisiä. Laita identtinen prompt samaan batchiin asiaan liittymättömien pyyntöjen kanssa, ja 97 % sen logits muuttuu. Mikään sinun pyynnössäsi ei muuttunut. Jonkun muun pyyntö saapui.

Nyt rehellinen osa, koska tämä kerrotaan yleensä ikään kuin tarina päättyisi tähän. Muutos 2.5×1052.5 \times 10^{-5} muuttaa outputia vain, jos kaksi ehdokas-tokenia olivat niin lähellä toisiaan. 717 generointiaskeleen yli kahdessatoista promptissa pienin ero kahden ylimmän logit-arvon välillä oli 2.5×1032.5 \times 10^{-3} — sata kertaa suurempi kuin häiriö — eikä yksikään askel ollut riittävän lähellä kääntyäkseen. Tässä mallissa, float32:lla, läppärillä, batching siis liikutti jokaista logit-arvoa eikä muuttanut yhtään tokenia.

Se on kuvaus suotuisista olosuhteista, ei rauhoittelu, ja yksi muutos olosuhteisiin riittää:

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."

Kuusi kahdeksasta vastauksesta erkanee, ja yksi heikkenee pahasti. Luvun 2 taulukko kertoo miksi: bfloat16 säilyttää 7 mantissabittiä, joten logit-suuruuden 16 lähellä esitettävät arvot ovat 0,125:n välein — 16,0, sitten 16,125, sitten 16,25 — ja pyöristys voi siirtää logit-arvoa jopa 0,0625. Samaan aikaan yllä mitatuista generointiaskeleista 4,7 %:lla top-two-ero oli alle 0,1. Siinä on koko ero kahden kokeen välillä: float32:ssa häiriö oli sata kertaa pienempi kuin lähin päätös, ja bfloat16:ssa se on samaa kokoluokkaa. Production inference ajetaan 16-bittisenä, laitteistolla jossa on fused kernels ja reduktiojärjestykset, joita kukaan ei lupaa pitää samoina. Se, onko "numeerinen kohina merkityksetöntä", on kysymys tarkkuudesta ja laitteistosta, ei mallista.

Eli neljä syytä, luetteloituna kuten luku 9 lupasi:

Floating-point addition is not associative

Linkki osioon: Floating-point addition is not associative

Luvun 2 laatikko. Summan järjestys muuttaa sen arvoa, joten mikä tahansa muutos reduktion jakamisessa muuttaa logits. Tämä on alusta; muut kolme ovat tapoja muuttaa järjestystä.

Dynamic batching groups your request with strangers'

Linkki osioon: Dynamic batching groups your request with strangers'

Continuous batching, luvusta 13, on syy siihen, miksi inference on kohtuuhintaista — ja se tarkoittaa, että niiden matriisien muoto, joiden läpi tokenisi kulkevat, riippuu liikenteestä. Yllä mitattu: 147 321 logits liikkui, koska batch-koko muuttui.

Mixture-of-experts routing depends on the batch

Linkki osioon: Mixture-of-experts routing depends on the batch

Luvun 9 laatikko sanoi tämän jo. Router tekee diskreetin valinnan per token per layer, riippuen per-expert-kapasiteettirajoista, jotka lasketaan batchin yli. Token, joka olisi yksin mennyt expertille 7, menee seurassa expertille 12. Tämä ei ole pyöristysero; se on eri weights-joukko.

The model behind the name changes

Linkki osioon: The model behind the name changes

Versiomerkkijono kuten -latest on osoitin, ja osoittimia osoitetaan uudelleen. Providerit päivittävät myös serving stackia kiinteän versiotunnisteen alla. Kumpaakaan ei ilmoiteta sillä tarkkuudella, että voisit korreloida sen oman outputisi muuttumiseen.

OpenAI:n seed-parametri on tästä rehellinen ainoalla tavalla, jolla se voi olla: sen mukana tulee system_fingerprint-kenttä, joka tunnistaa backend-konfiguraation, ja dokumentaatio sanoo, että determinismi on best-effort ja että muuttunut fingerprint tarkoittaa, että tulokset voivat erota. Lue se sellaisena kuin se on — provider kertoo sinulle, että se hallitsee kaikkia neljää yllä olevaa syytä, sinä et hallitse niistä mitään, ja ainoa asia, jonka se voi tarjota, on kertoa sinulle jälkikäteen, että jokin liikkui.

Minne tästä mennään seuraavaksi

Linkki osioon: Minne tästä mennään seuraavaksi

Kaikki tässä on koskenut yhtä säädintä ja sen seurauksia. Astu yksi taso taaksepäin, ja vaikeampi ongelma ilmestyy: virittämämme olio on todennäköisyysjakauma, eikä todennäköisyysjakaumilla ole rajapintaa.

Function callilla on. Tietokantarivillä on. POST-handlerilla, joka odottaa JSON-bodya kolmella pakollisella kentällä, on, ja se hylkää kaiken muun. Mallin ja jokaisen muun järjestelmäsi komponentin välissä on sopimus, josta toinen osapuoli ei voi antaa lupauksia: malli tuottaa jotain, jakaumasta jota olet muotoillut mutta et lukinnut, ja toisella puolella oleva koodi tarvitsee tunnetun tyyppisen arvon tai se heittää virheen.

Silta näiden kahden maailman välillä rakennetaan tämän luvun materiaalista eikä parsingista ja retryistä. Jos token rikkoisi vaaditun rakenteen, et käytä samplingia ja toivo parasta — asetat sen logit-arvoksi -\infty ennen kuin softmax koskaan näkee sen. Constrained decoding on maski saman vektorin päällä, jota olemme koko tämän luvun muotoilleet, ja se muuttaa pyynnön "vastaa JSONilla" takuuksi.

Luku 18 on tuo sopimus: tool calling, JSON Schema, structured outputs ja mitä vaaditaan, jotta probabilistisen järjestelmän päälle voidaan rakentaa turvallisesti deterministinen järjestelmä.


Kaikki tämän luvun mittaukset tulevat mallista Qwen/Qwen2.5-0.5B-Instruct CPU:lla, float32 ellei toisin mainita, ja sampling toteutettiin valinnaisessa osiossa kirjoitetulla tavalla eikä delegoitu kirjastolle. Ne ovat pieni malli, ja tietyt arvot ovat sen; mekanismit eivät ole. Von Platenin How to generate text with different decoding methods (Hugging Face, 2020) on artikkeli, jota vasten tämä on mitattu, ja se on edelleen paras lyhyt johdanto samaan aiheeseen. Determinismi-osiosta: PyTorchin reproducibility notes kuvaavat, mitä siemen lukitsee ja ei lukitse yhdellä koneella, OpenAI:n dokumentaatio arvoista seed ja system_fingerprint kuvaa, mitä provider voi ja ei voi luvata, ja Thinking Machinesin vuoden 2025 keskustelu batch-invariant kernels -aiheesta on selkein julkinen selitys siitä, miksi tämän korjaaminen inference-server-tasolla on mahdollista mutta ei ilmaista.

  1. Ackley, D. H., Hinton, G. E. ja Sejnowski, T. J. A Learning Algorithm for Boltzmann Machines. Cognitive Science 9(1), s. 147–169 (1985), jossa softmaxin temperature tulee tilastollisesta fysiikasta. Hinton, G., Vinyals, O. ja Dean, J., Distilling the Knowledge in a Neural Network, arXiv:1503.02531 (2015), osio 2, on paikka, jossa sama parametri ilmestyy uudelleen modernissa deep learningissä — tapana paljastaa teacher-mallin koko jakauma, mikä on luvun 13 soft labels eikä tämän luvun sampling.

  2. Guo, C., Pleiss, G., Sun, Y. ja Weinberger, K. Q. On Calibration of Modern Neural Networks. arXiv:1706.04599 (2017). Älä sekoita tätä tämän luvun temperature-arvoon. Temperature scaling sovittaa yhden arvon validointijoukolla niin, että mallin luottamus vastaa sen tarkkuutta; se on post-hoc-kalibrointimenetelmä, jota sovelletaan luokittelijan outputeihin. Temperature sampling on ajonaikainen säädin sille, miten generaattori arpoo tokenit. Sama kaava, eri tarkoitus, eikä yhteistä arvoa.

  3. Holtzman, A., Buys, J., Du, L., Forbes, M. ja Choi, Y. The Curious Case of Neural Text Degeneration. arXiv:1904.09751 (2019). Esittelee nucleus samplingin ja mittauksen, jonka mukaan maksimointiin perustuva decoding tuottaa tekstiä, jonka todennäköisyysprofiili ei muistuta lainkaan ihmisen tekstiä. 2

  4. Fan, A., Lewis, M. ja Dauphin, Y. Hierarchical Neural Story Generation. arXiv:1805.04833 (2018). Paperi, joka popularisoi top-k samplingin.

  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. ja Cotterell, R. Locally Typical Sampling. arXiv:2202.00666 (2022).

  7. Keskar, N. S., McCann, B., Varshney, L. R., Xiong, C. ja Socher, R. CTRL: A Conditional Transformer Language Model for Controllable Generation. arXiv:1909.05858 (2019). Osio 4.1 on alkuperäinen repetition penalty — se, joka jakaa.


Tekijä

David Vicente Campos

NeuraLIA Labsin perustaja ja MyRealFoodin toinen perustaja

Olen valmistunut tietotekniikan insinööriksi Leónin yliopistosta. Olin mukana perustamassa MyRealFoodia, jossa teknologiajohtajana rakensin sovelluksen, jota miljoonat ihmiset ovat käyttäneet syödäkseen paremmin, ja perustin NeuraLIA Labsin, jossa rakennan tekoälytuotteita. Täällä kirjoitan siitä, mitä minun on pitänyt ymmärtää matkan varrella, niin kuin olisin toivonut jonkun selittävän asiat minulle.

Lisää kirjoittajasta

Julkaisija: NeuraLIA Labs.

Uudet julkaisut suoraan sähköpostiisi

AI-uutisia, oppaita ja tuoteuutisia — lyhyt sähköposti, kun julkaisemme jotain aikasi arvoista.

Kurssin hakemisto

Abstract software decision engine with branching paths, probability nodes, and glowing gates.
jev9 min lukuaikaa

Jev AI -malli on rakennettu päätöksiä, ei proosaa varten

TypeSafe AI:n Jev herättää huomiota, koska se käsittelee ohjelmistojen älykkyyttä todennäköisyysongelmana: valitse oikea haara, liitä mukaan varmuus ja vältä maksamasta LLM:lle tekstin kirjoittamisesta, kun koodi tarvitsee päätöksen.

Abstract agent runtime sorting documents, memory blocks and pointer nodes inside a bounded context frame.
context-engineering9 min lukuaikaa

Kontekstisuunnittelu pitkän aikavälin AI-agenteille

Pitkäkestoiset agentit eivät epäonnistu vain siksi, että ikkuna on pieni. Ne epäonnistuvat, kun tiedostot, työkalujen tulosteet ja vanhentunut historia syrjäyttävät tehtävän, joka agentin piti saada valmiiksi.

Valmis antamaan LIA:n valita puolestasi?

Rakenna kaikilla tekoälymalleilla yhdessä paikassa — aloita ilmaiseksi jo tänään.