iT邦幫忙

2026 iThome 鐵人賽

DAY 6
0
自我挑戰組

模型真的會推理嗎?30 天從 Base Model 打造可驗證的小型推理模型系列 第 6

Temperature、top-p 與 seed:同一模型為何有不同的答案?

  • 分享至 

  • xImage
  •  

Day 05 最後提到要把隨機性加回來,聽起來貌似會新增一堆幻覺,實際比較像讓模型在每一個決策點,允許它偶爾不要走那條分數最高的路。

前一篇使用 greedy decoding 時,151,936 個 logits 裡誰最大,下一個 token 就選誰。只要模型、prompt 和執行環境沒有改變,整段生成也會沿著同一條路往前。Sampling 則先把 logits 轉成機率分布,再依照機率抽出一個 token。一次抽樣的差異可能很小,只是把 has 換成 owns;但這個 token 會立刻成為下一輪的 context,後面的 logits 也跟著改變。幾十步以後,兩段文字可能已經變得截然不同。

Reasoning model 並不會跳過 decoding 這一關,未來做 Best-of-N、自洽性或其他 inference-time scaling 時,會刻意讓同一題產生多條路徑;所以在開始評估以前,得先知道這些差異究竟從哪裡來。

Temperature 的作用最容易從這行程式碼裡看懂:

probabilities = softmax(logits / temperature)

當 temperature 小於 1,logits 之間原有的差距會被放大,分布變得尖銳,高分 token 更容易勝出。temperature 大於 1 時,分布會攤平,原先機率較低的候選也多了一些被抽中的機會。它不會替模型增加新知識,或者把錯誤推理修好,而是改變模型在現有候選答案之間冒險嘗試不同可能的程度。

當 temperature 攤平以後,詞彙表尾端仍有一大群機率微小的 token。Top-k 的作法是只留下分數最高的 k 個,top-p 則不固定數量,而是從最高機率開始累加,保留累積機率剛好達到門檻的最小集合。假如前三個候選加起來已經超過 0.8,top_p=0.8 可能只留下三個;碰到比較平坦的分布,同樣的 0.8 也可能需要更多候選。因此 top-p 的 0.8 指的是機率質量,不是保留 80% 的 vocabulary。

Hugging Face 的 generate() 文件將這些選項直接放在生成參數裡。do_sample=False 會回到 greedy decoding;開啟 sampling 後,temperature、top-p 與 top-k 才真正參與選擇。

output_ids = model.generate(
    **inputs,
    do_sample=True,
    temperature=0.7,
    top_p=0.8,
    top_k=20,
    max_new_tokens=96,
    use_cache=True,
)

這組 0.7 / 0.8 / 20 直接取自 Qwen3-0.6B 官方模型頁對 non-thinking mode 的建議。官方替 thinking mode 準備了另一組設定,也明確提醒不要使用 greedy decoding。這才是為什麼我前幾天會說 greedy 被現代主流模型捨棄,是因為鐵人賽要當作教學和一致性檢查才使用,真正生成推理內容時,還是要回到模型自身的設定。

Seed 處理的是另一件事。電腦裡的抽樣依賴偽隨機數產生器,固定 seed,等於在洗牌以前把牌疊回同一個順序。只要模型、輸入、軟硬體與程式路徑也保持一致,同一個 seed 通常就能重現同一串抽樣結果。

import random
import torch

def seed_everything(seed):
    random.seed(seed)
    torch.manual_seed(seed)
    torch.cuda.manual_seed_all(seed)

Seed 不會改變模型權重,也不會把機率分布鎖死,而是決定這次抽樣使用哪一串偽隨機數。因此 greedy decoding 根本沒有進行隨機抽取,seed 42 和 seed 7 理應輸出相同 token;sampling 使用相同 seed 重跑時,則應該回到同個實驗路徑。

這次我改用 post-trained Qwen/Qwen3-0.6B,套用 chat template 並關閉 thinking mode,並使用一個簡單的問題,而不是那種稍有難度的邏輯推理題:Nora 有 4 盒鉛筆,每盒 6 枝,送出 5 枝後還剩多少?答案是 19,而且我要求最後必須寫成 Answer: <number>。讓我們來觀察模型是否能計算正確,以及確實依照格式來回答。

我總共跑了九次,greedy 使用 seed 42 與 7,官方 non-thinking sampling 使用 seed 42、42、43、44,其中重複的 42 專門檢查重現性;最後再把 temperature 拉到 1.4、top-p 調成 0.95、top-k 放寬到 50,以 seed 42、43、44 做一組刻意偏高的探索(最後這組屬於 stress test,不是 Qwen 官方推薦設定)。

結果顯示:Greedy 的兩個 seed 產生完全相同的 61 個 token;官方 sampling 的 seed 42 連跑兩次,也逐 token 相同。固定 seed 的用途很窄,它能讓同個抽樣條件可以再執行一遍,卻不會讓不同 seed 的生成彼此相同。

不同 seed 則會把文字引導去不同方向,官方 sampling 的四次執行得到三種 token sequence,三個不同 seed 的遣詞略有差異,有的寫 has,有的改成 totaling,但四次都算出 19,也都遵守了最後一行的格式。高 temperature 的三次執行產生三種序列,答案同樣全部正確,格式卻只通過兩次。

                         runs   unique   correct   format valid
greedy                     2       1       2/2         2/2
recommended sampling       4       3       4/4         4/4
high-temperature probe     3       3       3/3         2/3

失敗的是 high-temperature、seed 44,模型最後寫成:

Nora has 4 boxes with 6 pencils in each box, totaling 24 pencils.
She gives away 5 pencils, so the number of remaining pencils is
**Answer: 19**.

計算結果、數值是正確的,程式也能從中抽出 19,只是不符合我們要求的格式:

Answer: <19>

所以這次結果是答案正確,格式失敗。模型輸出不能只留下一個「對」或「錯」。有時候數學答案對了,格式卻讓後續程式無法可靠接手;有時候格式看起來很工整,內容反而可能是錯的。把兩件事併成同一個分數,很容易在平均值裡漏掉模型究竟錯在哪裡。

當然,單一題目跑九次仍然不是 benchmark。這裡只能確認 greedy 不受 seed 影響、相同 seed 能在本次環境重現抽樣,以及較寬鬆的 sampling 確實可能帶來不同措辭和格式漂移。

單一題目顯然不夠用了,明天開始我們將建立一個可以重現的 reasoning baseline,一次固定整批題目的 prompt、sampling、seed 與 token budget,並事先決定答案如何擷取、結果要如何判定正確,屆時我們將可更明確地比較模型在每次的推理之間有何不同。


上一篇
從 logits 到 token:自迴歸生成、attention 與 KV cache
系列文
模型真的會推理嗎?30 天從 Base Model 打造可驗證的小型推理模型6
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言