「好」到底是什麼意思?
一個模型帶著一句很有自信的話送到你桌上:「它有 95% 的準確率。」在你開心之前,先問這整個學習軌道都圍繞著的問題——好,是「對什麼而言」好?95% 這個數字拿來整理度假照片也許很夠用,但拿來篩檢醫療影像可能是場災難,因為它弄錯的那 5% 也許正好就是腫瘤。同一個數字也許能可靠地解鎖你的手機,卻也可能讓一個陌生人長驅直入。這個頭條數字沒有對你說謊,但它也沒有把整件事說清楚。學會讀懂它背後的東西是一項真正的技能,而不是模型訓練完之後隨手補上的小註腳。
一張循環圖:收集資料、訓練模型、評估,再循環回去改進,其中評估階段被特別標示。
讓我們把一切都固定在一個具體例子上,整篇指南都會重複用到它:一個二元分類器,看一張圖片,然後說「貓」或「不是貓」。我們永遠用測試集——它在學習時從沒看過的圖片——來評斷它,因為用它背下來的訓練集打分,對於它在新照片上的表現一點都說明不了(這個切分你在前面的階梯已經學過,這裡只是借用一下)。最簡單的分數就是 準確率:它正確標記的測試圖片所佔的比例。它感覺像是衡量「好」最理所當然的方式。讀完這篇指南,你會清楚看到它在什麼時候值得你信任、又在什麼時候悄悄背叛你。
混淆矩陣:用四個格子解釋一切
你會遇到的幾乎每一個指標——準確率、精確率、召回率、ROC 曲線——都是從一張叫做 混淆矩陣的小表格算出來的。如果你真的理解這張表,其餘的不過是建立在它之上的算術而已。對我們這個兩類別的貓偵測器來說,它是一個 2×2 的格子,交叉對照兩件事:模型「說了」什麼,以及實際上「是」什麼。每一張測試圖片都恰好落進這四個格子的其中一個。
這四個格子的名字聽起來嚇人,但其實遵循一條很整齊的規則。「陽性(positive)」或「陰性(negative)」描述的是「模型說了」什麼(陽性=「貓」,陰性=「不是貓」);「真(true)」或「偽(false)」描述的是模型「對了」沒有。所以:真陽性(TP)是一隻被模型叫做貓的真貓;偽陽性(FP)是一個被模型錯叫成貓的非貓(誤報);真陰性(TN)是一個被正確叫做不是貓的非貓;偽陰性(FN)是一隻模型漏掉、叫成不是貓的真貓。記憶口訣:看「後面」那個字知道模型主張了什麼,看「前面」那個字知道該不該相信它。
一個 2×2 的格子,標示著真陽性、偽陽性、偽陰性、真陰性,一軸是真實情況,另一軸是預測。
- 從 100 張測試圖片開始。假設其中 20 張真的是貓,80 張真的不是貓——這是真實標準(ground truth),在模型開口之前就固定了。
- 跑模型,把它每一次的判斷拿來和真實情況比對。在 20 隻真貓裡,它正確標出 16 隻 → TP = 16,漏掉 4 隻 → FN = 4(有 4 隻貓溜走了,被標成不是貓)。
- 在 80 個真正的非貓裡,它對其中 10 個錯喊「貓!」 → FP = 10(十次誤報),對 70 個正確地說不是貓 → TN = 70。
- 檢查一下這個格子是否合理:TP + FN = 16 + 4 = 20 隻真貓,FP + TN = 10 + 70 = 80 個真非貓,加起來剛好 100。每一張圖片都恰好被算到一次。
準確率與它隱藏的陷阱
現在我們可以精確地定義準確率,而不是含糊帶過。準確率不過就是預測正確的比例——兩個「答對」的格子(TP 和 TN)除以全部四個格子。它很直觀,也常常很有用。但它藏著一個陷阱,常見又危險到,能看出它正是這整篇指南最重要的一課。
準確率=正確判斷數除以全部判斷數。
一項一項地讀。分子 TP + TN 數的是模型答對的每一張圖片——真貓被叫做貓,加上真非貓被叫做不是貓。分母 TP + TN + FP + FN 不過是測試圖片的總數(四個格子相加)。所以準確率就是「在所有東西裡,我們對了幾個」。用我們一直在用的矩陣算:(TP + TN) / 總數 = (16 + 70) / (16 + 70 + 10 + 4) = 86 / 100 = 0.86,也就是 86% 的準確率。到目前為止,都還算合理。
現在看著這個陷阱啟動。想像一個不同的、不平衡的測試集,貓很罕見:在 1,000 張圖片裡,只有 10 張是貓(1%),990 張不是。打造一個最懶的「模型」——它完全無視圖片,永遠說「不是貓」。它從不產生任何一個陽性,所以 TP = 0、FP = 0;它把全部 990 個非貓都標對(TN = 990),並漏掉全部 10 隻貓(FN = 10)。
把這些代進公式:準確率 = (0 + 990) / (0 + 990 + 0 + 10) = 990 / 1000 = 0.99。一個從來沒認出過一隻貓的無用模型拿到了 99%——在頭條數字上贏過我們那個真的有在運作、86% 的偵測器!這個騙局來自分母:它被 990 個容易的陰性主宰,所以把罕見的陽性完全搞錯幾乎不會影響分數。回頭看混淆矩陣,騙局就一目了然——TP = 0 代表模型完全沒有能力找出我們真正在乎的東西,而準確率這個數字卻笑嘻嘻地把這件事藏了起來。
精確率與召回率:兩個誠實的問題
解開準確率陷阱的藥方,是不要再把所有東西平均在一起,而是針對陽性類別問兩個更銳利、更誠實的問題。這就是精確率與召回率。精確率問的是:「當模型喊『貓』的時候,它有多常是真的對的?」——這關乎模型警報的可信度。召回率問的是:「在外面所有的真貓裡,模型實際抓到了幾隻?」——這關乎涵蓋率,也就是它讓多少東西溜走。之前那個永遠說不是貓的懶模型從不喊貓,所以它根本談不上精確率、召回率也是零——立刻就被揭穿了。
精確率、召回率,以及平衡兩者的 F1 分數。
讓我們在矩陣上拆解每一塊(TP = 16、FP = 10、FN = 4)。精確率 = TP / (TP + FP),把它答對的貓除以「它叫做貓的全部東西」(不管對錯):16 / (16 + 10) = 16/26 ≈ 0.62。所以這個模型每次喊「貓」,大約只有 62% 的時候是對的。召回率 = TP / (TP + FN),把它答對的貓除以「真正存在的全部貓」:16 / (16 + 4) = 16/20 = 0.80。所以它找到了 80% 的真貓。注意分子上坐著的都是同一個 TP,但分母不同——精確率被誤報(FP)拉低,召回率被漏抓(FN)拉低。接著 F1 把這些擠成一個數字:2 · (0.62 · 0.80) / (0.62 + 0.80) = 2 · 0.492 / 1.415 ≈ 0.70。
一張圖顯示兩個重疊的集合——預測為陽性與實際為陽性——它們的交集是真陽性,用來說明精確率與召回率。
# Counts read straight off the 2x2 confusion matrix
TP, FP, FN, TN = 16, 10, 4, 70
accuracy = (TP + TN) / (TP + TN + FP + FN) # 0.860
precision = TP / (TP + FP) # 0.615
recall = TP / (TP + FN) # 0.800
f1 = 2 * precision * recall / (precision + recall) # 0.696
print(f"accuracy={accuracy:.3f} precision={precision:.3f} "
f"recall={recall:.3f} f1={f1:.3f}")
# accuracy=0.860 precision=0.615 recall=0.800 f1=0.696F1 為什麼用「調和平均數」而不是普通平均?因為調和平均數會懲罰一面倒的分數。想像一個垃圾郵件過濾器,為了不讓任何垃圾信通過,把「幾乎所有東西」都標成垃圾信:它達到接近 100% 的召回率(抓到所有垃圾信),但精確率慘不忍睹(它也把你的真信件全丟了)。比方說召回率 1.0 和精確率 0.1 的普通平均會給出一個讓人安心的 0.55——但 F1 = 2·(1.0·0.1)/(1.0+0.1) ≈ 0.18,拒絕被好的那一半騙過去。這一課是:沒有放諸四海皆準的「最好」指標。如果漏掉一隻貓才是代價高昂的錯誤(腫瘤、詐騙),就偏重召回率;如果誤報代價高(把一筆無辜的交易標記起來),就偏重精確率;當兩者都重要時,F1 是誠實的折衷。
閾值、ROC 曲線與 AUC
這裡有一個藏在前面一切之下的秘密:分類器其實不會直接吐出一個非黑即白的「貓/不是貓」。它在內部產生一個分數——像是 0.92 代表「蠻確定是貓」,或 0.13 代表「大概不是」。我們透過選一個閾值把這個分數變成決定:比方說,分數高於 0.5 就叫它貓。滑動那個閾值,整個畫面就會跟著變。把它調低,模型就更急著說「貓」——你抓到更多真貓(召回率上升),但也製造更多誤報(精確率下降)。把它調高,模型就變得吝嗇——誤報變少,但漏抓變多。並不存在唯一一個操作點;而是有一整條由它們構成的曲線,而這個取捨正是上一節精確率與召回率之間的拉鋸,現在變成連續的了。
為了一次看見整段閾值範圍,我們畫出 ROC 曲線——這是 ROC 曲線與 AUC的核心。當我們把閾值從嚴格掃到寬鬆時,它把兩個比率彼此對畫。在公式之前,先掌握你會需要的直覺:每一個閾值給模型一組(誤報率、真抓率),也就是圖上的一個點,而隨著閾值滑動把所有這些點串起來,就描出了這條曲線。
ROC 曲線的兩個座標軸,以及作為其下方面積的 AUC。
拆解這兩個比率。TPR(真陽性率)= TP / (TP + FN) 其實就是換了名字的召回率——在所有真貓裡被抓到的比例;它是縱軸,我們希望它高。FPR(偽陽性率)= FP / (FP + TN) 是真非貓裡被錯誤標記的比例;它是橫軸,我們希望它低。在我們算過的矩陣上,TPR = 16/(16+4) = 0.80,而 FPR——小心,FP+TN = 10+70 = 80,所以 FPR = 10/80 = 0.125。這單一一個閾值給出 ROC 圖上的點 (0.125, 0.80)。把閾值滑到一個新的值,你就得到一個新的 (FPR, TPR) 點;把它們全部收集起來就是那條曲線。
一張圖,橫軸是偽陽性率、縱軸是真陽性率;一條曲線在對角線上方朝左上角彎曲,下方陰影面積標示為 AUC。
現在來看 AUC——也就是那條 ROC 曲線下方的面積——以及初學者總是忽略的詮釋。AUC 有一個漂亮的白話意義:它是「模型給隨機挑出的一隻真貓的分數,高於隨機挑出的一個非貓」的機率。AUC = 1.0 代表模型「永遠」把任何一隻貓排在任何一個非貓之上(完美區分);AUC = 0.5 代表它不比擲硬幣好(那條對角線)。它是一個不依賴閾值的摘要,衡量分數把陽性排在陰性之上的能力有多好。有一個直接呼應準確率陷阱的警告:在嚴重不平衡的資料上,FPR 的分母裡有那一大池陰性,所以就算有很多誤報也幾乎推不動它——ROC/AUC 可能看起來好得討喜,而精確率卻慘不忍睹。當陽性很罕見時,請改用 精確率–召回率曲線,它讓罕見的那個類別始終留在舞台中央。
第一個暗示:信心也會說謊
退一步,注意這篇指南裡每一個工具測量的是什麼:模型選了「哪一個類別」,以及那個選擇有多常是對的。混淆矩陣、準確率、精確率、召回率、ROC——它們全都在評斷模型的決定。但它們沒有一個問過另一個更狡猾的問題:當模型替一個決定附上一個信心值——「我有 0.92 的把握這是貓」——那個 0.92 到底「代表」了什麼意義嗎?
那個問題就是「校準(calibration)」,也是 模型校準的主題。先在這裡種下一個直覺,借自天氣預報:想想預報員說「70% 機率下雨」的所有日子。如果這位預報員是「校準良好的」,那麼這些日子裡實際上應該大約有 70% 真的下雨——不多也不少。一個模型可以是出色的排序者(高 AUC、選對類別),卻嚴重過度自信,對只有 70% 時候是對的猜測硬貼上 0.99。對於手機解鎖或醫療決定來說,宣稱的信心與實際的信心之間的這道落差關係重大——而它對我們目前建立的每一個指標來說都是隱形的。
那就是通往這個學習軌道其餘部分的門。指南 2 會推進到準確率之外,進入針對偵測、分割、生成的更豐富指標,以及正是這個信心/校準的問題。後面的指南會問:當像素被刻意動手腳時(對抗樣本)模型撐不撐得住,當它部署時遇到的世界偏離了訓練資料時(分布偏移)會怎樣,以及它是否夠公平、夠可解釋到值得信任。這第一篇指南,是它們全部所立足的地基。