L3.3 16 分鐘閱讀 2026年9月

L3.3 同一個實驗跑三次結果都不同,該報哪一個?

本篇重用M1.0兩台體重計:Gaussian 的線性組合

起點:三次結果都不一樣

你把同一份程式跑了三次,只換了 random seed。測試準確率是 0.8310.8310.8470.8470.8220.822

該報哪一個?

「報最好的 0.8470.847」聽起來有點心虛但很常見——畢竟那確實是你跑出來的。「報平均 0.8330.833」比較誠實。「三個都報」看起來很囉唆。

而真正的問題還在後面:你的同事用 baseline 跑了三次,得到 0.8180.8180.8350.8350.8090.809,報了 0.8350.835你比他好 1.21.2 個百分點。這代表什麼?

看那六個數字就知道:兩組的範圍幾乎完全重疊。1.21.2 個百分點的「優勢」小於任何一組自己的散佈。

這一篇要把這件事變成兩張可以直接使用的表:取最好的那一次能無中生有多大的差距,以及要幾個種子才分得出一個真實的差距

同一個實驗跑三次結果都不同,該報哪一個?
如果兩個方法其實一樣好,
「各跑三次、各報最好」會讓贏家看起來好多少?

課堂提問Q1

把「該報哪一個」翻成統計問題:你在估的是什麼?「取最好的 kk 次」與「取中位數」各是那個量的什麼估計?以及,為什麼兩個方法各自kk 次再比最好的,會系統性地製造差距?

先想一想,再展開看整理後的答案

在估什麼。 一次實驗的結果 XX 是一個隨機變數,隨機性來自初始化、minibatch 順序、資料增強的抽樣、以及非確定性的 GPU 運算。你真正想知道的是這個方法的典型表現——也就是 XX 的分布的一個中心位置(平均或中位數)。

兩種報法估的不是同一個東西。

  • 中位數(或平均)是那個中心位置的無偏(或接近無偏)估計。kk 個樣本的中位數,其抖動隨 kk1/k1/\sqrt k 縮小(兩台體重計:Gaussian 的線性組合:獨立樣本的平均,變異數除以 kk)。
  • 最好的那一次估的是分布的極值,不是中心。而且它隨 kk 系統性地往好的方向漂kk 越大,max\max 越大。它不是「比較樂觀的中心估計」,它根本不是中心的估計。

為什麼各自取最好會製造差距。 這是 從一百個學生裡挑最好的,他下次會考得更好嗎? 的 winner’s curse 再來一次,只是換了一個隨機性的來源。兩個方法都做「kk 個樣本取極值」,兩個極值各自往上漂了差不多的量;但兩者的漂移是獨立的,所以它們的是一個均值為零、但散佈被放大的隨機量。

於是「贏家」一定存在——只要有兩個數字,其中一個就比較大。問題不是「誰贏」,而是贏多少才算有意義。而那個門檻由那個差的散佈決定,下一節把它量出來。

先量抖動本身

任何關於「差多少才有意義」的判斷,都要先知道單一次實驗的抖動有多大。

沿用 同一張地圖從不同地方出發:損失曲面與初始化 那組設定(1323211\to32\to32\to1tanh\tanh 網路、Adam η=0.01\eta=0.01、4000 步、共用 toy),200 個 seed 的最終訓練 MSE:

中位數 0.0034   標準差 0.0010   範圍 [0.0023, 0.0085]

標準差是中位數的 29%29\% 這個比例是後面每一個判斷的基礎——它告訴你「一次實驗」這個量測工具的解析度有多粗。

真實任務上這個比例差異很大:影像分類的準確率可能只有 0.3%0.3\% 的抖動,強化學習可能超過 50%50\%所以這個數字要在自己的專案上量一次,它比任何通用的建議都有用,而且只要跑五到十個 seed 就估得出來。

第一張表:取最好的能無中生有多少

模擬:兩個方法的結果從那 200 個 seed 的分布裡抽,也就是它們真實品質完全相同。各抽 kk 個,各取自己最好的那一個,看「贏家」比「輸家」好多少(相對值)。重複兩萬次:

  k=  1  「贏家」比「輸家」好的幅度  中位數 16.9%   90 百分位 70.1%
  k=  3  「贏家」比「輸家」好的幅度  中位數 10.5%   90 百分位 26.8%
  k=  5  「贏家」比「輸家」好的幅度  中位數  8.9%   90 百分位 23.3%
  k= 10  「贏家」比「輸家」好的幅度  中位數  6.9%   90 百分位 19.1%

k=3k=3 那一列是最該記住的:兩個一模一樣的方法,各跑三次、各報最好的那一次,贏家平均看起來好 10.5%10.5\%,而且十次裡有一次好超過 26.8%26.8\%

「我們的方法比 baseline 好 10%」在三個種子加上取最好的報法下,正是純噪聲會產生的東西。

還有一個容易被誤讀的地方:這個假差距隨 kk 變小,但降得很慢16.910.58.96.916.9\to10.5\to8.9\to6.9)。跑十次再取最好,仍然會無中生有 6.9%6.9\%。原因是「取最好」本身就是在估極值——增加 kk 只會讓極值更極端,它不會收斂到任何東西

所以問題不在種子數,在報法。 換成中位數之後,kk 增加就真的在買精度(1/k1/\sqrt k),這是下一張表的前提。

注意隨機性的來源不只有 seed,而且有些不在你的控制裡

上面模擬的隨機性來自初始化與訓練過程。真實實驗還有幾層:

  • 資料切分的隨機:換一個 train/val 切法,結果會變(只有三十筆資料:交叉驗證 量過單次留出的估計標準差是 0.40690.4069 而 5-fold 是 0.03040.0304)。這一層常常比 seed 更大,卻更少被重複。
  • 資料增強、dropout、shuffle 的抽樣:通常和 seed 綁在一起。
  • 非確定性的硬體運算:GPU 上的浮點加法順序不固定,所以同一個 seed 也可能給不同的結果。這一層無法用固定 seed 消除,只能用確定性模式(通常更慢)或接受它。

實務上的建議是:重複的時候把能重抽的都重抽(seed 與資料切分一起換),因為你要估的是「這整套流程的表現」,不是「在這個特定切分上的表現」。只固定切分而換 seed,會系統性地低估抖動。

第二張表:要幾個種子

換成誠實的報法(每個方法跑 kk 次,比較中位數),並且做配對比較(兩個方法用同一組 seed 與同一組資料切分)。問:一個真實存在的差距 δ\delta,要幾個種子才能在 80%80\% 的把握下正確分辨?

  真實差距   2%  →  k=100 仍只有 77%
  真實差距   5%  →  k≈20(正確判斷 83%)
  真實差距  10%  →  k≈5 (正確判斷 84%)
  真實差距  20%  →  k≈1 (正確判斷 83%)

這張表可以在做實驗之前就用。 流程是:先跑五個 seed 估出抖動(上面那個 29%29\%),再問「我這個改動預期會帶來多大的改善」,然後查表看需要幾個種子。

  • 預期改善 20%20\%:一次就看得出來,不必多跑。
  • 預期改善 5%5\%:需要約 20 個種子。如果一次訓練要八小時,那是一個要排程的決定。
  • 預期改善 2%2\%在這個抖動水準下量不出來——100 個種子仍然只有 77%77\% 的把握。

最後一列值得停一下。它不是說「2%2\% 的改善不重要」,而是說在這個實驗設定下,你沒有能力偵測它。這時的選項是:降低抖動(加大驗證集、用交叉驗證、把訓練變得更穩定),或者接受你無法用這個實驗回答這個問題。

在花掉算力之前,先問自己這個實驗有沒有能力回答我要問的問題。

配對比較為什麼省種子。 如果兩個方法各自用不同的 seed,你比的是兩個獨立的隨機量,差的變異數是兩者相加。用同一組 seed 與同一組切分,兩邊共同的隨機成分(這次的切分剛好比較難、這個初始化剛好比較好)會在相減時抵消掉,剩下的只有「方法造成的差」。實務上這常常把所需的種子數減半以上,而成本是零——只要記得把 seed 也當成一個要對齊的東西。

回到情境:該報什麼

把前面兩張表合成一組可以直接照做的規則:

  1. 報中位數與範圍(或四分位距),加上種子數。0.8330.833(5 seeds,範圍 0.8220.8220.8470.847)」比「0.8470.847」誠實,而且資訊量更大——讀者可以自己判斷一個差距有沒有意義。
  2. 做配對比較:兩個方法共用同一組 seed 與同一組資料切分,報差值的分布而不是兩個分布。
  3. mm:你總共比較過幾組設定(從一百個學生裡挑最好的,他下次會考得更好嗎? 的那個數字)。它和種子數是兩件不同的事,而且兩個都影響該怎麼讀你的數字。
  4. 不要用「取最好的」當成績,除非你明確說明那是最好的一次、並同時報中位數。
  5. 測試集只讀一次,而且是在所有種子都跑完、決定都做完之後。

這一切依賴什麼。 一,上面兩張表的數字是在這個 toy 的抖動水準(標準差是中位數的 29%29\%)下算的;換一個任務要重新量。二,第二張表假設配對比較與中位數;用平均或不配對,需要的種子數更多。三,「80%80\% 的把握」是一個選擇——要更高的把握,種子數還要往上加。

回到情境:把那個 29%29\% 量成自己的數字

上面每一個結論都掛在同一個量上:單次實驗的相對抖動。所以最有價值的一步不是記住這兩張表,而是把那個數字量成自己的。

做法只要五到十次重複:

res = [run_everything(seed=s) for s in range(8)]     # seed 與資料切分一起換
med = np.median(res); spread = np.std(res)
print(f"中位數 {med:.4f}   標準差 {spread:.4f}   相對抖動 {spread/med*100:.0f}%")

拿到那個百分比之後,兩張表都可以重算——它們的形狀不變,只有刻度會隨那個比例縮放。而這八次重複本身就有回報:它讓你看得出來自己的量測工具有多粗,而那決定了接下來每一個「A 比 B 好」的判斷該不該相信。

一個推論值得單獨寫下來:如果相對抖動是 29%29\%,那麼任何小於 10%10\% 的改善都需要十幾二十次重複才讀得出來。而這表示「多跑幾次」常常比「再想一個新點子」更能推進專案——因為在沒有足夠重複的情況下,你根本不知道上一個點子有沒有效。

兩張表,一個抖動旋鈕

互動 demo:兩個一模一樣的方法各跑 k 次各報最好,k=3 的假優勢中位數就有 7%。

先消化一下

想一想

一篇報告寫「我們的方法達到 0.8470.847,優於 baseline 的 0.8350.835」,兩者各跑了三次並各報最好的一次。根據本篇的模擬(相對抖動 29%29\%),最合適的評論是:

想一想

在第一張表裡,假優勢從 k=1k=116.9%16.9\% 只降到 k=10k=106.9%6.9\%。為什麼增加種子數對它幫助這麼小?

想一想

一個團隊的相對抖動是 29%29\%,他們想驗證一個預期帶來 2%2\% 改善的想法。根據第二張表,最合理的決定是:

想一想

下列哪一句不對

參考文獻

  1. Dodge, J. et al. Show Your Work: Improved Reporting of Experimental Results. EMNLP 2019.(把「調了多少、跑了幾次」當成結果的一部分報告,並給出一個隨預算變化的表現曲線。)
  2. Bouthillier, X. et al. Accounting for Variance in Machine Learning Benchmarks. MLSys 2021.(系統性地拆開各層隨機性的貢獻,並指出只換 seed 會低估抖動。)
  3. Henderson, P. et al. Deep Reinforcement Learning that Matters. AAAI 2018.(在抖動特別大的領域裡,把「取最好的幾次」造成的假結論量出來。)