搜尋課程與筆記

搜尋筆記

輸入主題、關鍵字或單元編號,例如 Flow Matching、U4。

    按 Esc 關閉 · ⌘ / Ctrl K 開啟搜尋

    L1.1 14 分鐘閱讀 2026年10月

    L1.1 十個房仲各看一百間房:Bias 與 Variance

    本篇重用3 篇

    十個房仲,同一間房

    台北有十位資深房仲,本領一樣、方法一樣。差別只在他們各自看過的一百間房子不同——同一個市場裡隨機抽的一百間。

    現在把同一間房子帶去給十個人估。你會得到十個數字。

    問題一:這十個數字散得多開? 如果從 2,700 萬到 3,100 萬,那表示「他看過哪一百間」對答案影響很大——換一份資料就換一個答案。

    問題二:這十個數字的平均,會偏嗎? 如果十個人平均起來是 2,880 萬而真實價值是 2,900 萬,那有一個 20 萬的系統性偏差——這個偏差不會因為找第十一個房仲而消失,因為它是「這套方法」本身的偏差,不是誰的運氣。

    兩個問題是獨立的。一個方法可以很穩定但一直偏(十個人都說 2,600 萬);也可以平均起來很準但每個人差很多(平均 2,900 但散佈 ±400 萬)。兩種都不好,但要修的東西完全不同。

    上一篇的分數提供了線索,但還沒有說清楚誤差怎麼來。若同一套方法換一批案例就換一個答案,我們要量的是「平均偏多少」,還是「每次變多少」? 我們先固定一間房子,把這兩種變動分開。

    十個房仲對同一間房的估價,會散得多開?
    平均起來會偏嗎?
    這兩個問題為什麼一定要分開問?

    課堂提問Q1

    「十個房仲」在數學上是什麼?期望是對什麼取的?把 E[(Y−f^(x))2]\mathbb E[(Y-\hat f(x))^2] 拆成三塊——每一塊分別對應上面的哪個問題?

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

    十個房仲 = 十份訓練資料。 訓練集 DD 本身是隨機的(從 pp 抽 nn 筆),所以 f^D\hat f_D 是一個隨機函數:換一份資料就換一個模型。房仲的「本領」是演算法(假設空間+損失+最佳化),十個人共用;不同的是餵給它的資料。

    期望對兩件事取。 固定一個查詢點 xx:YY 的隨機(同一個 xx 的實際成交價本來就有波動)與 DD 的隨機(抽到哪一百間)。兩者獨立。

    三項分解。 令 fˉ(x)=ED[f^D(x)]\bar f(x)=\mathbb E_D[\hat f_D(x)](十個房仲的平均答案,10→∞10\to\infty 的版本),f⋆(x)=E[Y∣x]f^\star(x)=\mathbb E[Y\mid x](M1.2 說的最佳答案):

    ED,Y[(Y−f^D(x))2]=Var(Y∣x)⏟不可約+(fˉ(x)−f⋆(x))2⏟bias2 :問題二+ED[(f^D(x)−fˉ(x))2]⏟variance:問題一.\mathbb E_{D,Y}\big[(Y-\hat f_D(x))^2\big] =\underbrace{\mathrm{Var}(Y\mid x)}_{\text{不可約}} +\underbrace{(\bar f(x)-f^\star(x))^2}_{\text{bias}^2\ \text{:問題二}} +\underbrace{\mathbb E_D\big[(\hat f_D(x)-\bar f(x))^2\big]}_{\text{variance:問題一}}.

    bias 是「平均起來偏多少」,variance 是「換一份資料會抖多少」,不可約是「同一個 xx 的 YY 本身就會變」。 三項都非負,所以每一項都是總誤差的下界之一——想要總誤差小,三項都得小。

    三塊,各由不同的設定控制

    • 不可約誤差 E[Var(Y∣X)]\mathbb E[\mathrm{Var}(Y\mid X)]:由問題本身決定。換模型沒用,加資料沒用。唯一能動它的方式是換問題——加入新的特徵,讓原本「隨機」的部分變成可預測的(房子的漏水史、賣方的急迫程度)。這一項在共用 toy 裡正好是 0.152=0.02250.15^2=0.0225。
    • bias²:整套學習方法在這個 nn 下的平均預測,離條件平均多遠。它受到模型、regularization、最佳化與有限資料影響,不只是 approximation error;增加資料也可能改變它。
    • variance:換一份訓練資料後,預測離平均預測多遠。它不是 estimation error 的另一個名字;兩者的基準不同。更多資料常能減少它,但一般演算法沒有單調保證。

    三個設定解釋了為什麼「模型不夠好」需要先診斷。同樣的症狀(測試誤差高),bias 主導時要加容量,variance 主導時要加資料或減容量,不可約主導時該做的是接受它並停止投入——很多專案在這一格燒掉幾個月。

    若十個房仲的誤差不完全同步,平均預測可以降低散佈;但若每個人都只會畫直線,平均仍是直線。這是 ensembling 的直覺。平均預測與平均參數不是同一件事:對非線性網路,一般有 f平均參數≠平均預測f_{\text{平均參數}}\ne\text{平均預測},不能直接把這個計算當成權重平均的保證。

    平均同分布模型的預測,保留它們的平均 bias;能壓多少 variance,還要看彼此的相關性。

    靶心圖與十條擬合曲線

    圖說: bias 是多次擬合的平均離真值多遠;variance 是每次擬合離那條平均曲線多遠。

    把總誤差拆成三塊,再算出 variance 的量級

    固定 xx,寫 f^=f^D(x)\hat f=\hat f_D(x)、fˉ=ED[f^]\bar f=\mathbb E_D[\hat f]、f⋆=E[Y∣x]f^\star=\mathbb E[Y\mid x]。把 Y−f^Y-\hat f 拆成三段:

    Y−f^=(Y−f⋆)⏟噪聲+(f⋆−fˉ)⏟常數+(fˉ−f^)⏟均值為 0.Y-\hat f=\underbrace{(Y-f^\star)}_{\text{噪聲}}+\underbrace{(f^\star-\bar f)}_{\text{常數}}+\underbrace{(\bar f-\hat f)}_{\text{均值為 }0}.

    平方後取期望。三個交叉項都是零:第一段對 YY 的條件期望為零且與 DD 獨立;第三段對 DD 的期望為零;第二段是常數。於是

    E[(Y−f^)2]=Var(Y∣x)+(fˉ−f⋆)2+VarD(f^).\mathbb E\big[(Y-\hat f)^2\big]=\mathrm{Var}(Y\mid x)+(\bar f-f^\star)^2+\mathrm{Var}_D(\hat f).

    這與 天氣預報該報幾度:MSE 的最小值是 Conditional Expectation 的三行證明是同一個技巧(拆成「均值為零的部分」加「常數部分」,交叉項消失),只是那裡對 YY 分解,這裡多了一層對 DD 的分解。

    線性模型有一個乾淨的量級公式。設計矩陣固定、噪聲變異數 σ2\sigma^2、參數個數 k=d+1k=d+1(本篇的 pp 一律留給分布),最小平方估計在訓練點上的平均 variance 是

    1n∑iVar(f^(xi))=σ2kn.\frac1n\sum_i \mathrm{Var}\big(\hat f(x_i)\big)=\frac{\sigma^2 k}{n}.

    兩個依賴一目了然:參數越多,variance 線性上升;資料越多,線性下降。 這是「nn 要跟 kk 一起長」這句老話的來源,也是下面實測會驗證的公式。

    注意這個分解只對平方損失這麼漂亮

    三項分解依賴平方損失的代數(交叉項為零)。換成 0–1 損失或 cross-entropy,「bias」與「variance」仍然可以定義(Domingos 2000 給了一個統一的框架),但它們不再單純相加:分類問題裡 variance 有時幫得上忙——一個平均起來偏向錯誤類別的預測,只要抖得夠厲害,仍然可能有一半的時間落在正確的那一邊。

    所以在分類任務上,請把 bias–variance 當成思考工具(是「方法本身偏了」還是「換份資料就變」)而不是可以逐項相加的帳。要量化,直接量你在意的那個指標在多次重抽下的平均與散佈——這也正是 同一個實驗跑三次結果都不同,該報哪一個? 要做的事。

    三種處方,與「加資料」的極限

    回到十個房仲。如果十個人的估價彼此差很多(高 variance):他們的方法對「看過哪一百間」太敏感。修法是讓每個人多看一些(加資料)、或讓方法更受限(減容量、加正則化),或把十個人的答案平均起來(ensembling)。

    如果十個人很一致但一起偏低(高 bias):多找一百個房仲、每人多看一千間,都不會改善。要換方法——加入他們現在沒在看的特徵,或允許更豐富的調整規則。

    如果十個人一致、也不偏,但每次的實際成交價本來就在 ±5% 之間跳(不可約):這是市場本身的隨機。此時該做的是改變目標——報一個區間而不是一個數字,或者去找能解釋那 5% 的新資訊。

    這一切依賴什麼。 一,十份資料真的是獨立同分佈抽的;若十個房仲其實共用一半的案例,variance 會被低估。二,這裡的 fˉ\bar f 是「無限多份資料的平均模型」,實務上只能用有限次重抽估計,重抽次數不夠時 bias 與 variance 的估計本身就有 variance。三,平方損失(見上面的 Details)。

    把三塊量出來

    固定 30 個位置(只重抽噪聲,這樣分解裡沒有「設計也在變」這個額外來源),每個 degree 重抽 300 份資料:

    import numpy as np, warnings; warnings.filterwarnings("ignore")
    from numpy.polynomial import Polynomial
    from ml_toy import truth, NOISE
    
    xs, ys = truth()
    x = np.linspace(0, 1, 30)                              # 固定的 30 個位置
    Y = np.sin(2*np.pi*x) + NOISE*np.random.default_rng(0).standard_normal((300, 30))
    
    for d in (1, 2, 3, 5, 7, 9, 12):
        P = np.array([Polynomial.fit(x, yy, d)(xs) for yy in Y])   # 300 條擬合曲線
        bias2 = ((P.mean(0) - ys)**2).mean()                        # 平均曲線離真值多遠
        var   = P.var(0).mean()                                     # 每條離平均曲線多遠
        print(f"degree {d:2d}   bias² {bias2:.4f}   variance {var:.4f}"
              f"   noise {NOISE**2:.4f}   總和 {bias2+var+NOISE**2:.4f}")
    degree  1   bias² 0.2004   variance 0.0016   noise 0.0225   總和 0.2245
    degree  2   bias² 0.2004   variance 0.0022   noise 0.0225   總和 0.2251
    degree  3   bias² 0.0048   variance 0.0028   noise 0.0225   總和 0.0301
    degree  5   bias² 0.0000   variance 0.0041   noise 0.0225   總和 0.0266
    degree  7   bias² 0.0000   variance 0.0053   noise 0.0225   總和 0.0278
    degree  9   bias² 0.0000   variance 0.0069   noise 0.0225   總和 0.0294
    degree 12   bias² 0.0000   variance 0.0095   noise 0.0225   總和 0.0320

    兩欄的方向完全相反,一如理論。 bias² 從 0.20040.2004 一路掉到 0.00000.0000(d≥5d\ge5 之後,多項式已經足以逼近 sin⁡\sin 到量測不出的程度);variance 從 0.00160.0016 單調爬到 0.00950.0095。總和的谷底在 d=5d=5(0.02660.0266),與上一篇 U 形的谷底一致——U 形不是一個經驗現象,它是這兩欄相加的結果。

    三個細節直接看這裡:

    • d=1d=1 與 d=2d=2 的 bias² 完全相同(0.20040.2004):二次項對 sin⁡(2πx)\sin(2\pi x) 在 [0,1][0,1] 上幫不上忙,所以「加容量」在這一步只買到 variance、沒買到 bias。加錯方向的容量比不加更糟。
    • d≥5d\ge5 之後 bias² 是 0.00000.0000:這時再減 degree 只會傷害,再加 degree 只買 variance。這一格的正確判斷是「停」,而不是繼續調。
    • 不可約誤差那一欄從頭到尾是 0.02250.0225:它不是被模型影響的量。總和永遠 >0.0225>0.0225——這條地板線在讀任何訓練曲線時都該先畫出來。

    驗證量級公式。 理論說 variance ≈σ2(d+1)/n\approx\sigma^2(d+1)/n。固定 d=9d=9,改變 nn:

    for n in (30, 100, 300):
        x = np.linspace(0, 1, n)
        Y = np.sin(2*np.pi*x) + NOISE*np.random.default_rng(0).standard_normal((300, n))
        P = np.array([Polynomial.fit(x, yy, 9)(xs) for yy in Y])
        print(f"degree 9, n={n:3d}:  variance {P.var(0).mean():.4f}"
              f"   (理論 σ²(d+1)/n = {NOISE**2*10/n:.4f})")
    degree 9, n= 30:  variance 0.0069   (理論 σ²(d+1)/n = 0.0075)
    degree 9, n=100:  variance 0.0021   (理論 σ²(d+1)/n = 0.0022)
    degree 9, n=300:  variance 0.0008   (理論 σ²(d+1)/n = 0.0007)

    這裡 dense grid 上的 variance 與訓練點平均公式量級接近,但不是同一個量。精確的 grid variance 是 σ2ϕ(x)⊤(V⊤V)−1ϕ(x)\sigma^2\phi(x)^\top(V^\top V)^{-1}\phi(x) 再對 grid 平均;只有在原訓練點平均,才直接等於 σ2k/n\sigma^2k/n。

    加資料會影響整個估計器;固定特徵與問題後,不可約誤差才是不隨樣本數改變的部分。

    刻意違反:把噪聲關掉。 令 σ=0\sigma=0,不可約誤差變 00、公式預測 variance 也變 00。但這個結論只在「資料位置固定」時成立——若每次重抽連 xx 的位置一起重抽(更接近真實的重新蒐集資料),高次多項式仍然抖得很厲害,因為設計本身的隨機也是 variance 的來源,而它不隨 σ\sigma 消失。這解釋了上一篇的觀察:噪聲為零時仍然可以過擬合。做這個分解時把「什麼在重抽」講清楚,比記住公式更重要。

    拖設定,看三塊怎麼此消彼長

    互動 demo:三塊各自由不同的設定控制:加資料壓 variance、換假設空間壓 bias、雜訊那塊誰也動不了。

    檢查理解

    想一想

    一個團隊把同一個架構用五個不同的隨機種子各訓一次,測試準確率是 71%71\%、83%83\%、76%76\%、85%85\%、74%74\%。他們決定回報最高的 85%85\%。除了誠實性以外,這組數字在診斷上告訴你什麼?

    想一想

    在表裡 d≥5d\ge5 之後 bias² 都是 0.00000.0000。有人主張「所以應該用 d=12d=12,反正 bias 已經最小」。最合適的評論是:

    想一想

    「加一倍資料」對三項的影響是:

    參考文獻

    1. Geman, S., Bienenstock, E., Doursat, R. Neural Networks and the Bias/Variance Dilemma. Neural Computation 1992.(把分解系統地用在學習演算法上的經典來源。)
    2. Hastie, T., Tibshirani, R., Friedman, J. The Elements of Statistical Learning, 2nd ed. Springer 2009, Ch. 7.3.(分解、線性模型的 σ2p/n\sigma^2p/n、以及它與模型選擇準則的關係。)
    3. Domingos, P. A Unified Bias-Variance Decomposition and its Applications. ICML 2000.(0–1 損失等非平方損失下的推廣,以及 variance 在分類裡為何可能有益。)