Lewati ke konten
17/30Bab 17 dari 30

Temperature, Top-p, dan Determinisme yang Sebenarnya Tidak Kamu Punya

Temperature membagi logits sebelum softmax—fakta kecil yang meruntuhkan ide “tombol kreativitas”.

Di halaman ini

Inilah request yang sama dikirim ke model yang sama lima kali. Bobot yang sama, prompt yang sama, mesin yang sama, random seed yang sama. Satu-satunya hal yang berubah hanyalah satu angka.

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

Tidak ada yang rusak. Setiap token di baris terakhir diambil secara sah dari distribusi probabilitas model itu sendiri atas kosakata berisi 151.936 entri. Angka yang berubah disebut temperature, di sebagian besar dokumentasi dijelaskan sebagai tombol kreativitas, dan deskripsi itu keliru dengan cara yang bisa bab ini demonstrasikan, bukan sekadar klaim.

Ini juga bab tempat tiga janji sebelumnya akhirnya dibayar. Bab 4 mendefinisikan logit dan belum benar-benar memakainya. Kotak floating-point di Bab 2 berakhir dengan instruksi — ingat ini saat Bab 17 bertanya mengapa prompt, model, dan seed yang sama bisa menghasilkan token berbeda. Dan kotak mixture-of-experts di Bab 9 menjanjikan katalog empat penyebab non-determinisme. Ketiganya muncul di bawah.

Bab 4 memperkenalkan logit sebagai skor bernilai riil yang belum dinormalisasi, satu per kelas. Bab 8 membuat language model menghasilkan satu skor per entri kosakata. softmax mengubah vektor z\mathbf{z} itu menjadi probabilitas:

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

Temperature masuk di sini — namanya dipinjam dari fisika statistik, tempat parameter yang sama mengontrol seberapa tajam distribusi Boltzmann berkonsentrasi pada state berenergi rendahnya1 — dan ia membagi logits sebelum eksponensial:

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

Penempatan itu adalah seluruh mekanismenya, dan dua baris aljabar cukup untuk melihat mengapa ia tidak mungkin berada di tempat lain. Misalkan kamu mencoba menerapkan temperature ke probabilitas saja — menskalakannya dengan 1/T1/T lalu menormalisasi ulang. Kamu akan mendapat

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

Konstantanya saling meniadakan. Menskalakan probabilitas tidak melakukan apa pun; distribusinya kembali tanpa berubah. Temperature hanya berpengaruh karena ia bekerja pada eksponen, tempat membagi dengan TT sebelum mengeksponensialkan sama dengan menaikkan setiap probabilitas ke pangkat 1/T1/T — pembentukan ulang nonlinier yang mengubah rasio antar-entri, bukan skala bersama mereka.

Dari penempatan itu, kedua batas langsung mengikuti tanpa kerja tambahan. Saat T0T \to 0, logit terbesar menjauh dari yang lain dan pp runtuh ke satu token dengan skor tertinggi: greedy decoding. Saat TT membesar, setiap zi/Tz_i/T menuju nol, setiap eksponensial menuju 1, dan distribusi merata menuju uniform atas seluruh kosakata. Tepat pada T=0T = 0, rumusnya membagi dengan nol, jadi setiap implementasi menanganinya secara khusus sebagai maksimum aritmetis — termasuk widget di bawah, yang beralih ke argmax pada T0.001T \le 0.001.

Satu peringatan, karena benturan nama ini menimbulkan kebingungan nyata. Ada hal kedua yang tidak terkait bernama temperature dalam machine learning: temperature scaling, metode kalibrasi yang menyesuaikan satu nilai pada validation set agar confidence classifier cocok dengan akurasinya.2 Rumusnya sama, tidak ada hubungannya dengan generation. Paper yang mengatakan “temperature” sering berarti yang itu; bab ini tidak pernah begitu.

Inilah distribusi itu, dengan aritmetikanya di depan matamu. Logits-nya tetap dan masuk akal, jadi angka-angka dalam prosa di bawah bisa kamu cocokkan dengan yang terlihat:

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

10 dari 10 token lolos pemotongan dan berbagi probabilitas.

Lihat data sebagai tabel
TokenlogitSetelah temperatureSetelah pemotongan
␣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%
Sampling: temperature, top-p, dan top-k

Sepuluh kandidat kelanjutan untuk The capital of France is, pada temperature 1 tanpa pemotongan. ␣Paris memegang 96,90 % mass; ␣banana, di posisi terbawah dengan logit 2.6-2.6, mendapat 0,00 %. Geser temperature ke 0 dan satu token bertahan dengan 100 %. Geser ke 2 dan ␣Paris turun ke 69,81 %, sementara ␣banana naik ke 0,17 % — token yang ditolak model, diberi probabilitas nyata oleh knob yang diputar pembaca.

Angka ␣banana adalah seluruh argumen dalam bentuk mini: menaikkan temperature tidak bisa memberi model ide yang tidak ia miliki. Logits sudah dihitung, ranking sudah tetap, dan temperature mempertahankannya persis — sepanas apa pun, token berskor lebih rendah tidak pernah berpindah ke atas token berskor lebih tinggi. Yang ia lakukan hanyalah mendistribusikan ulang mass ke bawah sepanjang ranking yang dihasilkan model itu sendiri. Temperature tinggi tidak membuat model lebih inventif; ia membuat model lebih mungkin mengeluarkan token yang ia nilai buruk.

Pada kosakata nyata, ini berhenti menjadi keanehan kecil dan menjadi alasan output temperature tinggi tidak bisa dipakai. Diukur pada Qwen/Qwen2.5-0.5B-Instruct, satu forward pass, prompt di atas, menghitung berapa banyak token yang dibutuhkan untuk mengakumulasi bagian tertentu dari probability mass:

temperatureprobabilitas top-1entropytoken yang memegang 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

Baca baris terbawah pelan-pelan. Pada T=2T = 2, untuk pertanyaan dengan tepat satu jawaban benar, 32.966 token berbeda berbagi 90 % teratas dari probability mass. Itu bukan ruang kreatif yang lebih luas. Itu model yang diberi tahu, oleh aritmetika, untuk memperlakukan partikel bahasa Korea dan identifier C++ sebagai opsi hidup untuk kata setelah A:. Sampah di blok pembuka adalah konsekuensi langsungnya, dan itu bukan bug di model atau library — itulah yang diminta request tersebut.

Rentang yang berguna sempit dan bergantung pada tugas, bukan selera. Pada pertanyaan faktual, jawabannya satu token dan panas apa pun di atas sekitar 1,2 menyuntikkan error tanpa manfaat. Pada pertanyaan terbuka, memang ada lebih dari satu kelanjutan yang baik, dan sedikit panas membeli variasi yang tetap lancar:

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

Pada 1,3 model sudah menciptakan nama diri dan kalimat yang tidak bisa diparse. Rentang antara “identik setiap kali” dan “tidak koheren” kira-kira 0,6 sampai 1,1 untuk model ini pada tugas ini, dan saran jujurnya adalah kamu menemukannya dengan mengukur pada tugas kamu, bukan menyalin angka dari blog post.

Mengapa teks yang paling mungkin adalah teks yang buruk

Tautan ke bagian: Mengapa teks yang paling mungkin adalah teks yang buruk

Ada pertanyaan jelas yang bersembunyi di balik semua ini: jika model punya distribusi probabilitas dan satu token paling mungkin, mengapa tidak selalu mengambilnya? Greedy decoding gratis, reproducible, dan tidak butuh parameter.

Karena hasilnya seperti ini:

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 %

Delapan kalimat, satu kalimat. Hampir sembilan dari sepuluh window empat token sudah muncul sebelumnya dalam output yang sama. Ini adalah neural text degeneration, dinamai dan dijelaskan oleh Holtzman et al. dalam paper yang memperkenalkan top-p.3 Modelnya tidak rusak; memaksimalkan probabilitas sekuens hanyalah objective yang salah untuk teks terbuka. Tulisan manusia bukanlah urutan kata yang paling mungkin — ia membawa kejutan, probabilitas per token-nya bergerak, turun, lalu pulih — sementara jalur probabilitas maksimum adalah fixed point yang, setelah dimasuki, tidak punya alasan untuk keluar.

Itulah alasan sampling ada. Ini juga, dan bagian ini sering ditinggalkan, bukan hukum universal. Bab 12 mengukur 24 dari 24 benar pada soal kata dua langkah dengan plain greedy decoding, dan sampling pada temperature 0,8 menurunkannya menjadi 81 %; self-consistency lalu menghabiskan enam kali token untuk naik kembali ke tempat greedy sudah berada. Kedua fakta ini sama-sama benar:

Open-ended generation. Tidak ada satu kelanjutan benar, jadi yang paling mungkin adalah jebakan — ia berulang, dan 87,6 % darinya disalin dari dirinya sendiri. Sample.

Tugas dengan satu jawaban benar. Memang ada satu kelanjutan benar, jadi mengambil apa pun selain itu berarti mengambil error. 100 % di Bab 12 menjadi 81 % persis karena alasan ini. Jangan sample.

Sebagian besar prompt production adalah jenis kedua tetapi dikonfigurasi seperti jenis pertama, karena temperature dibiarkan pada apa pun yang dipakai example code.

Dua cara memotong, dan hanya satu yang beradaptasi

Tautan ke bagian: Dua cara memotong, dan hanya satu yang beradaptasi

Sampling dari distribusi penuh bukanlah yang benar-benar dilakukan siapa pun, karena tail-nya sangat besar dan penuh omong kosong. Sesuatu harus dipotong. Ada dua jawaban klasik dan keduanya berbeda dalam satu hal yang menentukan segalanya.

Top-k mempertahankan jumlah kandidat tetap. Urutkan berdasarkan probabilitas, pertahankan kk pertama, buang sisanya, normalisasi ulang.4 Top-p, juga disebut nucleus sampling, mempertahankan jumlah mass tetap: ambil token dalam urutan menurun sampai probabilitas kumulatifnya mencapai pp, lalu berhenti.3 Secara formal, nucleus adalah set terkecil VpV_p dengan

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

Perbedaannya terdengar kosmetik, padahal tidak, karena dua prompt yang kamu kirim pada menit yang sama memiliki bentuk distribusi yang sama sekali berbeda. Keduanya adalah model yang sama pada temperature 1:

Q: What is the capital of France?\nA:Once upon a time,
probabilitas top-196,01 %25,39 %
token yang memegang 90 % mass1467
top-k = 40 mempertahankan99,61 % mass78,87 % mass
mass di ranking 2 sampai 403,61 %53,48 %
token di ranking 40␣Av, 0,0093 %␣Dr, 0,128 %

Satu kk tetap, dua kegagalan berlawanan arah. Pada prompt faktual, k=40k = 40 mengizinkan 39 token yang secara total bernilai 3,6 % — ia membiarkan sampah masuk, termasuk kandidat pada sembilan per seratus ribu persen, karena aturannya menghitung slot, bukan evidence. Pada prompt cerita, k=40k = 40 yang sama membuang 21 % mass yang benar-benar diberikan model, karena nucleus sebenarnya di sana selebar 467 token.

Top-p membuat satu angka melakukan kedua pekerjaan itu. Setel p=0.9p = 0.9 dan ia mempertahankan 1 token pada prompt pertama dan 467 pada prompt kedua, karena ia mengajukan pertanyaan tentang distribusi alih-alih memaksakan hitungan padanya. Lihat adaptasi itu langsung — pemotongan yang sama, empat temperature:

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

3 dari 10 token lolos pemotongan dan berbagi probabilitas.

Lihat data sebagai tabel
TokenlogitSetelah temperatureSetelah pemotongan
␣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%
Sampling: temperature, top-p, dan top-k

Top-p pada 0,90 dengan temperature di 1,5: tiga dari sepuluh token bertahan dan berbagi mass, ␣Paris dinormalisasi ulang menjadi 91,10 %. Sekarang ubah hanya temperature. Pada 0,7, 0,90 yang sama menyisakan satu penyintas — nucleus sesempit itu adalah greedy decoding dengan nama berbeda. Pada 2,0 ia menyisakan lima. Pemotongannya tidak pernah bergerak; bentuk di bawahnya yang berubah.

Widget itu juga meluruskan miskonsepsi yang perlu dinamai, karena biayanya uang sungguhan. Pada distribusi yang percaya diri, top_p = 0.9 bukan “sedikit variasi”. Itu greedy. Pada temperature 1, token terdepan di sini memegang 96,90 %, yang sudah di atas 0,9, jadi nucleus selebar satu token dan tidak ada yang lain yang bisa pernah diambil. Tim menyetel top_p ke 0,9 dengan keyakinan mereka sudah melonggarkan sesuatu lalu bingung mengapa setiap respons identik.

Setel top-k sebagai gantinya dan kegagalan sebaliknya sama terlihatnya:

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

5 dari 10 token lolos pemotongan dan berbagi probabilitas.

Lihat data sebagai tabel
TokenlogitSetelah temperatureSetelah pemotongan
␣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%
Sampling: temperature, top-p, dan top-k

Top-k pada 5, tanpa top-p. Lima token bertahan pada setiap temperature, karena lima itulah yang diminta. Pada temperature 1, seperti terlihat, empat kandidat di bawah ␣Paris secara total bernilai 2,79 %. Turunkan ke 0,7 dan empat yang sama bernilai 0,38 % — pemotongannya hanya teater, dan model efektifnya greedy. Naikkan ke 2,0 dan mereka bernilai 22,54 %. Setting identik, jumlah penyintas identik, tiga perilaku yang sama sekali berbeda, dan tidak ada apa pun dalam request yang memberitahumu mana yang kamu dapat.

Penalty, dengan rumusnya, karena kebingungan di sini endemik

Tautan ke bagian: Penalty, dengan rumusnya, karena kebingungan di sini endemik

Tiga mekanisme berbeda berjalan dengan nama yang mirip, mereka melakukan hal berbeda, dan perbedaannya bisa diukur. Misalkan cic_i adalah berapa kali token ii sudah muncul.

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

Kurangi konstanta dari token mana pun yang sudah pernah muncul. Muncul sekali dan muncul empat puluh kali dikenai penalty identik. Ini switch, bukan dial.

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

Kurangi sebanding dengan hitungan. Token yang dipakai empat kali dikenai penalty empat kali lebih keras daripada token yang dipakai sekali, dan tekanannya berlipat saat teks bertambah.

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}

Yang asli, dari paper CTRL.7 Ia membagi, bukan mengurangi, dengan kasus tanda yang diperlukan karena membagi logit negatif akan membuatnya lebih besar. Jadi kekuatannya bergantung pada magnitudo logit, yang berarti ρ\rho yang sama menghantam berbeda di titik berbeda dalam kalimat yang sama.

Kelanjutan degeneratif yang sama dari sebelumnya, dengan masing-masing diterapkan. “Steps altered” menghitung berapa dari 120 langkah generation yang memilih token berbeda dibanding yang akan dipilih model tanpa penalty. Run ini 120 langkah, dibanding 140 di blok di atas, itulah mengapa baseline tanpa penalty terbaca 85,5 %, bukan 87,6 %:

settingrepeated 4-gramssteps altered
tidak ada85,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

Tiga hal muncul. Presence pada 0,5 mengubah tiga keputusan dari 120 dan memangkas repetisi seperempat — loop itu ditahan oleh segelintir token. Frequency pada 0,5 mengubah keputusan empat kali lebih banyak untuk efek yang jauh lebih besar, karena pengali hitungan terus bertambah sementara konstanta presence tidak. Dan penalty CTRL pada nilai 1,2 yang banyak disalin menulis ulang 35 dari 120 keputusan, yang bukan dorongan kecil; itu model yang berbeda.

Angka terakhir itu adalah setup untuk kegagalan yang tidak diperingatkan siapa pun.

Apa yang dilakukan penalty pada teks yang memang seharusnya berulang

Tautan ke bagian: Apa yang dilakukan penalty pada teks yang memang seharusnya berulang

Code berulang. Tabel berulang. Daftar berulang. Structured output berulang menurut definisi — itulah yang disebut struktur. Penalty tidak bisa membedakan antara model yang terjebak dalam loop dan model yang benar mengeluarkan baris keempat sebuah tabel, karena keduanya terlihat seperti token muncul lagi.

Tiga tugas yang sama, dihasilkan dengan tiga cara:

tasktidak adafrequency 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

Frequency penalty pada 0,5 ternyata tidak berbahaya pada ketiganya, hasil yang berguna dan agak mengejutkan, dan ia mengatakan sesuatu yang presisi: karena tidak ada keputusan yang berubah, token struktural pasti memenangkan posisinya dengan margin lebih besar daripada penalty yang dikurangkan, bahkan setelah muncul lima dan enam kali. Penalty CTRL, yang membagi sebagai gantinya, memang menggeser mereka, dan inilah yang dihasilkannya:

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

Alignment-nya berantakan: jumlah padding di dalam setiap cell berubah dari baris ke baris, karena deretan spasi sebelum pipe penutup persis jenis repetisi yang ingin dipecah penalty. Kosmetik, dan biayanya enam token ekstra. Kasus Python bukan kosmetik:

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 mendorong model menjauh dari total — yang sudah dipakai dalam docstring — ke total_sum, mengisi output dengan komentar rekaan untuk menghabiskan budget pada token yang belum dipakai, lalu masuk ke range tiga argumen dengan stride. Komentarnya mengatakan incrementing by 2 each time, yang salah untuk jumlah kuadrat dari 1 sampai nn. Repetition penalty menghasilkan code yang salah dari prompt yang dijawab benar tanpanya.

Aturan berikutnya singkat: penalty untuk prosa terbuka, dan harus dimatikan untuk code, structured output, data tabular, dan apa pun dengan schema. Bab 18 membahas persis kategori kedua itu.

Urutan penerapan, dan mengapa ia mengubah jawaban

Tautan ke bagian: Urutan penerapan, dan mengapa ia mengubah jawaban

Setiap implementasi nyata menerapkan ini dalam satu urutan spesifik:

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

Ini bukan pembukuan arbitrer, dan menukar dua tahap menghasilkan distribusi yang benar-benar berbeda. Dua pengukuran, keduanya pada prompt faktual.

Memotong sebelum atau sesudah temperature. Nucleus dihitung pada distribusi apa pun yang diserahkan kepadanya, dan temperature mengubah distribusi itu secara radikal:

top-p 0.9 setelah temperaturetop-p 0.9 sebelum temperature
T=1.0T = 1.01 token1 token
T=1.5T = 1.5353 token1 token
T=2.0T = 2.032.966 token1 token

Pada T=2T = 2, setting nominal yang sama menghasilkan candidate set berisi 32.966 atau 1, murni tergantung tahap mana yang berjalan dulu. Jika kamu pernah bertanya-tanya mengapa menaikkan temperature “tidak melakukan apa-apa” pada satu provider dan menghancurkan output pada provider lain dengan dua angka yang sama, tabel ini adalah jawaban yang masuk akal.

Memberi penalty sebelum atau sesudah temperature. Mengurangkan penalty α\alpha lalu membaginya dengan TT menghasilkan penalty efektif α/T\alpha/T; membagi dulu lalu mengurangi menghasilkan α\alpha. Dengan presence penalty 1,0 diterapkan ke token terdepan:

temperatureberi penalty, lalu tempertemper, lalu beri penalty
0.599,858 %99,948 %
1.089,839 %89,839 %
2.010,783 %6,830 %

Identik pada T=1T = 1, sebagaimana harusnya. Berbeda faktor 1,58 pada T=2T = 2. “Presence penalty 1.0” bukan jumlah penalty yang terdefinisi dengan baik kecuali kamu juga tahu di mana temperature diterapkan, dan tidak ada API yang mendokumentasikan ini.

Tampilkan detail

Opsional: seluruh pipeline, dalam urutan di atas.

Enam belas baris, dan semua yang ada di bab ini ada di dalamnya. Ini komputasi yang sama dengan yang dilakukan widget, pada vektor logit nyata, bukan sepuluh angka tetap.

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

cumsum(0) - p pada baris top-p adalah mass kumulatif tanpa token saat ini, yang membuat nucleus menyertakan token yang melewati threshold, bukan berhenti tepat sebelumnya. Salah satu langkah dan top_p = 0.9 diam-diam menjadi pemotongan yang sedikit lebih ketat daripada setiap implementasi lain.

Ini salah satu dari sedikit tempat di paruh kedua kursus tempat Python adalah bahasa yang tepat, dan alasannya struktural, bukan gaya: setiap baris di atas membutuhkan seluruh vektor logits di tanganmu, dan melalui HTTP API vektor itu tidak ada. Kamu bisa mengirim temperature dan top_p ke provider; kamu tidak bisa mengimplementasikannya, dan kamu tidak bisa melihat apa yang mereka lakukan.

Setiap provider menerima subset berbeda dari kontrol ini, dengan rentang berbeda, dan mengabaikan sisanya diam-diam. Ini bukan keluhan abstrak. Aplikasi apa pun yang menawarkan pilihan model harus menuliskan perbedaan itu di suatu tempat, dan file tempat ia melakukannya adalah peta inkompatibilitas. Inilah yang dideklarasikan salah satu katalog seperti itu untuk satu parameter di sembilan sumber teks yang didukungnya:

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

Katanya sama; skalanya tidak. “Temperature 1” adalah distribusi yang tidak dimodifikasi pada satu tempat dan panas maksimum yang diizinkan pada tempat lain, dan separuh katalog tidak bisa mengekspresikan nilai yang diperlakukan separuh lainnya sebagai netral-plus-sedikit. Knob lainnya sama tidak ratanya: entri OpenAI, DeepSeek, dan xAI menerima presence dan frequency penalties dan tidak ada topK; entri Google, Meta, Cerebras, dan PaLM menerima topK dan tidak ada penalties; Anthropic menerima topK, topP, dan stop sequences serta tidak ada penalties; dan tepat satu dari sembilan — Mistral — menerima seed. Mengirim parameter yang tidak diimplementasikan provider umumnya tidak menghasilkan error sama sekali: request berhasil, knob tidak melakukan apa pun, dan kamu menyimpulkan setting itu tidak berpengaruh.

Dan perhatikan apa file seperti itu: sebuah klaim tentang API milik orang lain, ditulis pada satu hari tertentu, yang tidak diverifikasi lagi setelahnya. Katalog yang mengatakan 0 sampai 1 untuk provider yang sekarang menerima 0 sampai 2 akan diam-diam membatasi setiap request.

Dua kontrol lagi masuk keluarga yang sama. logprobs, jika ditawarkan, mengembalikan log-probabilities dari token yang dipilih dan sering beberapa alternatif teratas — satu-satunya jendela yang kamu punya ke distribusi yang dibahas bab ini, dan dasar setiap heuristic confidence yang dibangun di atas model tertutup. Dan maximum tokens plus stop sequences mengakhiri generation tanpa merujuk probabilitas sama sekali: hard cap dan pencocokan string. Keduanya muncul sebagai finish_reason dari Bab 14, tempat length berarti jawabanmu terpotong di tengah kalimat oleh budget, bukan selesai oleh model.

Seed, dan determinisme yang tidak kamu punya

Tautan ke bagian: Seed, dan determinisme yang tidak kamu punya

Setel seed dan sampling menjadi reproducible. Bagian itu nyata, dan mudah diverifikasi:

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-identical dalam satu seed, berbeda antar-seed, persis seperti yang diiklankan. Jadi yang diperbaiki seed adalah random draw di baris terakhir fungsi sample itu — token mana yang dipilih dari suatu distribusi.

Yang tidak ia perbaiki adalah distribusinya. Dan di situlah masalahnya, karena vektor logits yang dihasilkan modelmu bukan objek matematis; ia adalah output dari miliaran penjumlahan floating-point, dan penjumlahan itu punya urutan.

Bab 2 meninggalkan eksperimen ini siap pakai. Jutaan angka float32 yang sama, dijumlahkan dalam pengelompokan berbeda:

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

Lihat baris terakhir. Jumlah chunk mengubah jawabannya. Itu bukan keanehan tentang numpy; itu mekanismenya, karena ketika inference server membagi reduction ke lebih banyak atau lebih sedikit unit paralel, ia melakukan tepat ini. Dan server membagi berdasarkan berapa banyak request yang sedang dilayaninya.

Inilah efek itu pada modelnya sendiri. Prompt yang sama, forward pass yang sama, satu-satunya perbedaan adalah berapa banyak request lain yang kebetulan ada dalam batch:

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

Dijalankan sendiri, modelnya perfectly deterministic — dua puluh pass, identik hingga bit. Masukkan prompt identik ke batch bersama request yang tidak terkait dan 97 % logits-nya berubah. Tidak ada apa pun tentang request kamu yang berubah. Request orang lain tiba.

Sekarang bagian jujurnya, karena ini biasanya diceritakan seolah-olah itulah akhir cerita. Perubahan sebesar 2.5×1052.5 \times 10^{-5} hanya mengubah output jika dua candidate token berjarak sedekat itu satu sama lain. Dari 717 langkah generation di dua belas prompt, gap terkecil antara dua logits teratas adalah 2.5×1032.5 \times 10^{-3} — seratus kali lebih besar daripada perturbation — dan tidak ada langkah yang cukup dekat untuk flip. Jadi pada model ini, dalam float32, di laptop, batching menggerakkan setiap logit dan tidak mengubah satu token pun.

Itu deskripsi kondisi yang menguntungkan, bukan penenang, dan satu perubahan pada kondisi itu sudah cukup:

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

Enam dari delapan jawaban menyimpang, dan salah satunya memburuk parah. Tabel Bab 2 menjelaskan alasannya: bfloat16 menyimpan 7 bit mantissa, jadi dekat magnitudo logit 16, nilai yang bisa direpresentasikan berjarak 0,125 — 16,0, lalu 16,125, lalu 16,25 — dan rounding bisa menggeser logit hingga 0,0625. Sementara itu, 4,7 % dari langkah generation yang diukur di atas punya gap top-two di bawah 0,1. Itulah seluruh perbedaan antara kedua eksperimen: dalam float32, perturbation seratus kali lebih kecil daripada keputusan terdekat, dan dalam bfloat16 ukurannya sama. Production inference berjalan dalam 16-bit, pada hardware dengan fused kernels dan urutan reduction yang tidak dijanjikan siapa pun untuk tetap. Apakah “numerical noise bisa diabaikan” adalah pertanyaan tentang precision dan hardware, bukan tentang model.

Jadi, empat penyebabnya, dikatalogkan seperti yang dijanjikan Bab 9:

Penjumlahan floating-point tidak asosiatif

Tautan ke bagian: Penjumlahan floating-point tidak asosiatif

Kotak Bab 2. Urutan penjumlahan mengubah nilainya, jadi perubahan apa pun dalam cara reduction dibagi mengubah logits. Ini substratnya; tiga lainnya adalah cara mengubah urutan.

Dynamic batching mengelompokkan request kamu dengan milik orang asing

Tautan ke bagian: Dynamic batching mengelompokkan request kamu dengan milik orang asing

Continuous batching, dari Bab 13, adalah alasan inference terjangkau — dan itu berarti bentuk matriks yang dilalui token kamu bergantung pada traffic. Diukur di atas: 147.321 logits bergerak karena batch size berubah.

Mixture-of-experts routing bergantung pada batch

Tautan ke bagian: Mixture-of-experts routing bergantung pada batch

Kotak Bab 9 sudah mengatakannya. Router membuat pilihan diskret per token per layer, tunduk pada batas kapasitas per-expert yang dihitung atas batch. Token yang sendirian akan pergi ke expert 7, saat bersama yang lain pergi ke expert 12. Ini bukan perbedaan rounding; ini set bobot yang berbeda.

Version string seperti -latest adalah pointer, dan pointer bisa diarahkan ulang. Provider juga memperbarui serving stack di bawah identifier versi tetap. Tidak satu pun diumumkan pada granularitas yang memungkinkanmu mengorelasikannya dengan perubahan output milikmu sendiri.

Parameter seed milik OpenAI jujur tentang ini dengan satu-satunya cara yang bisa ia lakukan: ia dikirim bersama field system_fingerprint yang mengidentifikasi konfigurasi backend, dan dokumentasi menyatakan bahwa determinisme bersifat best-effort dan fingerprint yang berubah berarti hasil bisa berbeda. Bacalah apa adanya — provider memberi tahu kamu bahwa ia mengontrol keempat penyebab di atas, kamu tidak mengontrol satu pun, dan satu hal yang bisa ia tawarkan adalah memberi tahu kamu setelah fakta bahwa sesuatu bergerak.

Semua di sini membahas sebuah knob dan konsekuensinya. Mundur satu level dan masalah yang lebih sulit muncul: objek yang selama ini kita tuning adalah distribusi probabilitas, dan distribusi probabilitas tidak punya interface.

Function call punya. Database row punya. Handler POST yang mengharapkan JSON body dengan tiga field wajib punya, dan ia akan menolak apa pun selain itu. Di antara model dan setiap component lain dalam sistemmu ada kontrak yang salah satu sisinya tidak bisa berjanji: model akan menghasilkan sesuatu, diambil dari distribusi yang sudah kamu bentuk tetapi belum kamu tetapkan, dan code di sisi lain membutuhkan nilai dengan tipe yang diketahui atau ia throw.

Jembatan antara dua dunia itu dibangun dari materi bab ini, bukan dari parsing dan retry. Jika sebuah token akan merusak struktur yang diwajibkan, kamu tidak men-sample-nya lalu berharap — kamu menyetel logit-nya ke -\infty sebelum softmax pernah melihatnya. Constrained decoding adalah mask atas vektor yang sama yang sepanjang bab ini kita bentuk ulang, dan ia mengubah “tolong balas dalam JSON” dari request menjadi guarantee.

Bab 18 adalah kontrak itu: tool calling, JSON Schema, structured outputs, dan apa yang diperlukan untuk membuat sistem deterministic aman dibangun di atas sistem probabilistik.


Semua pengukuran dalam bab ini berasal dari Qwen/Qwen2.5-0.5B-Instruct pada CPU, float32 kecuali dinyatakan lain, dengan sampling diimplementasikan seperti tertulis di bagian opsional alih-alih didelegasikan ke library. Itu model kecil, dan nilai spesifiknya miliknya; mekanismenya bukan. Artikel Von Platen How to generate text with different decoding methods (Hugging Face, 2020) adalah artikel yang menjadi pembanding pengukuran tulisan ini dan masih merupakan pengantar singkat terbaik untuk materi yang sama. Untuk bagian determinisme: catatan reproducibility PyTorch menjelaskan apa yang diperbaiki dan tidak diperbaiki seed pada satu mesin, dokumentasi OpenAI tentang seed dan system_fingerprint menjelaskan apa yang bisa dan tidak bisa dijanjikan provider, dan diskusi Thinking Machines tahun 2025 tentang batch-invariant kernels adalah penjelasan publik paling jelas tentang mengapa memperbaiki ini di level inference-server mungkin dilakukan tetapi tidak gratis.

  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), tempat temperature dalam softmax berasal dari fisika statistik. Hinton, G., Vinyals, O. and Dean, J., Distilling the Knowledge in a Neural Network, arXiv:1503.02531 (2015), section 2, adalah tempat parameter yang sama muncul kembali dalam deep learning modern — sebagai cara membuka distribusi lengkap teacher, yaitu soft labels Bab 13, bukan sampling bab ini.

  2. Guo, C., Pleiss, G., Sun, Y. and Weinberger, K. Q. On Calibration of Modern Neural Networks. arXiv:1706.04599 (2017). Jangan bingungkan ini dengan temperature dalam bab ini. Temperature scaling menyesuaikan satu nilai pada validation set agar confidence model cocok dengan akurasinya; ini metode kalibrasi post-hoc yang diterapkan pada output classifier. Temperature sampling adalah kontrol runtime atas cara generator mengambil tokens. Rumus yang sama, tujuan berbeda, dan tidak ada nilai bersama.

  3. Holtzman, A., Buys, J., Du, L., Forbes, M. and Choi, Y. The Curious Case of Neural Text Degeneration. arXiv:1904.09751 (2019). Memperkenalkan nucleus sampling dan pengukuran bahwa decoding berbasis maksimisasi menghasilkan teks yang profil probabilitasnya sama sekali tidak seperti teks manusia. 2

  4. Fan, A., Lewis, M. and Dauphin, Y. Hierarchical Neural Story Generation. arXiv:1805.04833 (2018). Paper yang memopulerkan top-k sampling.

  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). Section 4.1 adalah repetition penalty asli — yang membagi.


Dibuat oleh

David Vicente Campos

Pendiri NeuraLIA Labs & salah satu pendiri MyRealFood

Saya seorang insinyur komputer lulusan Universitas León. Saya ikut mendirikan MyRealFood, tempat saya sebagai CTO membangun aplikasi yang telah digunakan jutaan orang untuk makan lebih sehat, dan saya mendirikan NeuraLIA Labs, tempat saya membangun produk AI. Di sini saya menulis tentang hal-hal yang harus saya pahami sepanjang perjalanan, sebagaimana dulu saya berharap ada yang menjelaskannya kepada saya.

Selengkapnya tentang penulis

Diterbitkan oleh NeuraLIA Labs.

Dapatkan postingan baru di inbox kamu

Berita AI, panduan, dan update produk — email singkat saat kami menerbitkan sesuatu yang layak kamu baca.

Indeks kursus

Abstract software decision engine with branching paths, probability nodes, and glowing gates.
jev11 menit baca

Model AI Jev dibuat untuk keputusan, bukan prosa

Jev dari TypeSafe AI menarik perhatian karena memperlakukan kecerdasan software sebagai persoalan probabilitas: pilih cabang yang tepat, sertakan keyakinan, dan hindari membayar LLM untuk menulis teks saat kode membutuhkan keputusan.

Abstract agent runtime sorting documents, memory blocks and pointer nodes inside a bounded context frame.
context-engineering11 menit baca

Rekayasa konteks untuk agen AI jangka panjang

Agen yang berjalan lama tidak gagal hanya karena window-nya kecil. Mereka gagal ketika file, output tool, dan riwayat lama menggeser tugas yang seharusnya diselesaikan agen.

Siap membiarkan LIA yang memilih?

Berkarya dengan semua model AI dalam satu tempat — mulai gratis hari ini.