分類模型的最後一層是配方題:幾個類別 → 開幾個輸出單元;標籤長什麼樣 → 選哪個 loss。本頁把四個選項全部真的下水訓練:正解 B 準確率 0.970、輸出機率每列加總恰好=1;A 竟然跑得動——但損失一路鑽到 -17.75(交叉熵不可能是負的,數學已經壞掉);C 當場 Incompatible shapes;D 少一個座位、當場被拒。一份配方+三張錯誤現場,一次記牢。
Keras 要處理三類互斥、單標籤分類,y_train 為 0、1、2 的整數。下列模型設定何者最合適?
import numpy as np # 拿出陣列工具 y_train = np.array([0, 2, 1, 0, 2]) # 標籤:整數 0/1/2,一筆一個 # 請選擇合適的輸出層與 loss # 題目要你配的就是這兩件事
想像路口的紅綠燈:紅、黃、綠三盞燈,同一時刻只亮一盞——這就是「三類互斥、單標籤」:每筆資料屬於三類之一,不能同時屬於兩類。模型的輸出層就是那排燈座:三類就要三個燈座(Dense 的 3),每個燈座給一個「亮度」;softmax 把三個亮度換算成加總=100% 的機率——最亮的那盞就是預測(argmax)。
loss 那一半看的是標籤的長相:題目的 y_train 是 [0, 2, 1, 0, 2]——一筆一個整數。整數標籤直接配 sparse_categorical_crossentropy;若標籤已改成 one-hot([1,0,0] 這種),才配 categorical_crossentropy——兩者算的是同一個數學(本站實跑同值),差別只在「標籤怎麼寫」。
點擊後出現漸進式說明:白話說明 → 說清楚一點 → 常見錯誤與考點。
點擊後出現漸進式說明。
題目只給三行——但配方要的兩個線索(幾類?標籤長怎樣?)都藏在第 2 行。右上角的「看位置」可以把這一行放回完整程式裡看。
import numpy as np # 整箱搬進來,取小名 np
老朋友了。這次它只做一件事:把標籤清單變成 numpy 陣列——Keras 的 fit 吃陣列最順。
y_train = np.array([0, 2, 1, 0, 2]) # 一筆一個整數:0、1、2 三種
讀出兩個配方線索:① 取值有 0、1、2 三種 → 三類 → 輸出層要 3 個單元(Dense 的第一個數字)。② 每筆只有「一個整數」——不是 [1,0,0] 那種一排 0/1 → 標籤是整數形式 → loss 選 sparse_categorical_crossentropy(sparse 就是「標籤用整數寫」的記號)。
# 請選擇合適的輸出層與 loss # 兩個空格:輸出層(幾個單元+什麼 activation)與 loss
註解就是考題本體:要你填「輸出層」與「loss」這對必須成套的組合。填法是一條決策鏈:任務(三類互斥單標籤)→ 輸出層(Dense(3, softmax))→ 標籤長相(整數)→ loss(sparse_categorical_crossentropy)。接下來四個實驗室把這條鏈的每一環都實跑給你看。
輸出層的三個單元先各算出一個分數(logits,可正可負),softmax 再把它們換算成機率:
\[ p_i \;=\; \frac{e^{z_i}}{\sum_{j=1}^{3} e^{z_j}} \]
loss 名字裡的 sparse 不是另一種數學——它只是在說「我的標籤用整數寫」。同一份 y_train,兩種寫法對照:
SparseCategoricalCrossentropy、one-hot 標籤餵 CategoricalCrossentropy——損失都是 0.102425,小數點後六位一樣。兩個 loss 是同一個數學、兩種標籤介面——考題考的就是「你會不會看標籤長相選介面」。本站造了 300 筆三群資料(每類 100 筆),四個選項真的各訓練一次。結局分三種——最值得記的又是那個跑得動的錯:
把本題放進完整的地圖——分類任務只有三種基本款,每款一份固定配方:
這一題的三個錯誤選項,在真實工作裡對應三種你遲早會遇到的畫面。實跑原文貼給你,配讀法:
| 現場 | 實跑訊息(原文) | 讀法與反應 |
|---|---|---|
| D+sparse (少一個座位) | Received a label value of 2 which is outside the valid range of [0, 2) | 標籤出現 2,但輸出只有 2 個單元(合法範圍 0~1)——把 Dense 的單元數改成類別數。看到這句幾乎都是座位開少了。 |
| D+BCE (形狀不合) | Arguments target and output must have the same rank (ndim). Received: target.shape=(None,), output.shape=(None, 2) | binary_crossentropy 期待標籤跟輸出同形狀——整數標籤配它就對不上。換 sparse 家族,或檢查任務是不是真的二元。 |
| C+MAE (回歸錯棚) | Incompatible shapes: [32] vs. [32,3] | 一個 batch 的 32 個整數標籤,撞上 32×3 的輸出——回歸 loss 沒有「類別」概念。分類任務回到交叉熵家族。 |
| A+BCE (不報錯!) | Epoch 60/60 — loss: -17.75 - accuracy: 0.637 | 沒有錯誤訊息,只有壞掉的數字:交叉熵出現負值=標籤超出該 loss 的合法範圍。防身術:訓練前 assert y.max() < 輸出單元數、開訓後看一眼 loss 的正負。 |
另外把 C 的概念錯也說完:就算形狀對得上,用回歸距離量類別也毫無意義——類別 2 跟類別 0「差 2」、類別 1「差 1」是假距離(0/1/2 只是名字,不是數量);而 relu 輸出是任意非負數、不會加總成 1,不是機率,連「信心」都讀不出來。
這是二類的配方——一個 sigmoid 開關只能表達「是/不是」,裝不下三個互斥類別。實跑硬餵 0/1/2:訓練照跑不報錯,但 y=2 代進二元公式讓損失一路鑽到 -17.75——合法設定下交叉熵恆 ≥ 0,負值就是配方壞掉的警報;準確率卡在 0.637,第三類根本無處安放。
配方兩環全對:三類 → 3 個輸出單元+softmax(輸出變成加總=1 的機率分布,互斥的數學表達);整數標籤 → sparse 版交叉熵直接吃 0/1/2。實跑:準確率 0.970、每列機率加總恰為 1、argmax 就是預測類別。標籤若改 one-hot,換 categorical_crossentropy——實跑兩者損失同值 0.102425。
兩個都錯:relu 輸出是任意非負數、不加總成 1——不是機率;MAE 是回歸的尺,量的是「數值差多少」——但 0/1/2 是類別名字不是數量,「類別 2 跟 0 差 2」是假距離。實跑當場炸:Incompatible shapes: [32] vs. [32,3]——連形狀都對不上。
三類只開兩個座位——類別 2 沒有位置。實跑配 binary_crossentropy 當場 rank 錯誤(target (None,) vs output (None, 2));就算改配 sparse,也立刻拋出經典的 Received a label value of 2 which is outside the valid range of [0, 2)。輸出單元數必須等於類別數——這是配方的第一環。
再看一次同一段程式。這次你知道第 2 行藏著兩個配方線索了。
Keras 要處理三類互斥、單標籤分類,y_train 為 0、1、2 的整數。下列模型設定何者最合適?
y_train = np.array([0, 2, 1, 0, 2]) # 三種取值 → 3 個座位;一筆一個整數 → sparse
八題,全部都是本題的延伸。答錯會直接告訴你錯在哪。
Received a label value of 2 which is outside the valid range of [0, 2)。Incompatible shapes: [32] vs. [32,3]。argmax(axis=1) 挑最大機率的類別;最大機率本身可當信心分數。assert y_train.max() < 輸出單元數;開訓後看一眼 loss——分類任務的交叉熵不該是負的。「輸出層×loss 配方」是中級科目三深度學習的必考題型,而且幾乎年年換皮出。最常見的六種問法:① 給任務與標籤形式問配方(本題這種——順決策鏈:類別數 → 單元數、互斥 → softmax、整數 → sparse);② 整數標籤 vs one-hot 標籤各配哪個 loss(sparse vs categorical——同數學、不同介面);③ 二類任務的配方(Dense(1, sigmoid)+binary_crossentropy——A 選項的正當場合);④ 多標籤任務的配方(Dense(K, sigmoid)+binary_crossentropy——每類獨立開關);⑤ softmax 輸出的性質(0~1、加總=1、argmax 讀預測);⑥ 錯誤配方的症狀(label out of range、形狀不合、負的交叉熵)。一句口訣:幾類幾座位;互斥用 softmax、可複選用 sigmoid;整數配 sparse、one-hot 配 categorical。
就三款,背熟受用十年。① 二類、單標籤(垃圾信/正常信):Dense(1, sigmoid)+binary_crossentropy——一個 0~1 的開關,過 0.5 算正類。② 多類互斥、單標籤(本題;紅/黃/綠燈):Dense(K, softmax)+sparse_categorical_crossentropy(整數標籤)或 categorical_crossentropy(one-hot 標籤)——K 個座位、機率加總=1、argmax 挑一個。③ 多標籤、可複選(一部電影同時是動作+喜劇):Dense(K, sigmoid)+binary_crossentropy——K 個獨立開關,各自 0~1、不必加總 1,過門檻的都算。記憶鉤子:互斥=分蛋糕(softmax,總量固定 1);可複選=開關牆(sigmoid,各開各的)。
差在「標籤的介面」,不差在數學。兩者都是交叉熵 −log(p正確類):sparse 版收整數標籤(y=[0,2,1],直接當索引去挑機率);categorical 版收 one-hot 標籤(y=[[1,0,0],[0,0,1],[0,1,0]],內積挑出同一格機率)。本站實跑鐵證:同一組預測機率,兩種標籤各餵各的 loss,損失都是 0.102425——小數點後六位相同。實務上整數標籤省空間(一筆 1 格 vs K 格)、免轉換,所以 sparse 版最常用;已經 to_categorical 過的資料就用 categorical 版。考題兩個方向都出:「整數標籤配哪個」與「one-hot 配哪個」。
兩個正當場合。① 二類、單標籤:Dense(1, sigmoid) 輸出一個 0~1 的數,讀作「是正類的機率」——貓狗、垃圾信、離職預測全是它。② 多標籤:Dense(K, sigmoid)——K 個獨立開關,每類各自判「有沒有」,機率不必加總 1(一部電影可以同時 0.9 動作、0.8 喜劇)。它不能用的場合就是本題:三類互斥時,一個開關裝不下三個選項、K 個獨立開關又表達不了「只能選一個」——互斥要靠 softmax 的「加總=1」來實現。考題陷阱幾乎都是把①的配方搬到互斥多類上。
因為 binary_crossentropy 不檢查標籤範圍——它的公式 −[y·log(p) + (1−y)·log(1−p)] 只假設 y 是 0 或 1,你餵 2 它照算:y=2 時式子變成 −2log(p)+log(1−p),把 p 推向 1 可以讓損失無下限地變小——本站實跑損失從 0.38 一路鑽到 -17.75(epoch 1→60:0.38、-0.39、-1.21、-5.60、-17.75),模型「認真地最佳化一個壞掉的目標」。讀法:合法設定下交叉熵恆 ≥ 0(−log 機率,機率 ≤ 1)——看到負的交叉熵,第一反應是查標籤範圍與 loss 配對,不是高興損失變低。這是本系列「不報錯的錯」家族第三員(第 9 頁 shape、第 10 頁虛高分數、本頁負損失)。
這是 sparse_categorical_crossentropy 的範圍檢查在說話:標籤出現了 2,但輸出層只有 2 個單元——合法索引是 0 和 1(數學記號 [0, 2) = 含 0 不含 2)。翻譯成人話:你的座位開少了。修法一行:把 Dense(2) 改成 Dense(3)——單元數必須 ≥ 類別數(正好等於最乾淨)。這句訊息在實務上出現率極高(常見成因:某個罕見類別只在測試集出現、或標籤從 1 開始編而不是 0),看得懂就能秒修。
三層錯。① 輸出不是機率:relu 給任意非負數(可以是 [3.7, 0, 12.1]),不加總成 1,讀不出「信心」。② 假距離:MAE 量「數值差多少」,但類別 0/1/2 只是名字——「類別 2 跟 0 差 2、跟 1 差 1」暗示 1 是 0 與 2 的「中間類」,這個順序關係根本不存在(把類別重新編號,答案就變了——合理的 loss 不該怕重新編號)。③ 形狀也對不上:實跑當場 Incompatible shapes: [32] vs. [32,3]——一個 batch 的 32 個整數標籤撞上 32×3 的輸出。分類就用交叉熵家族;MAE/MSE 留給真正的數值預測(迴歸)。
兩步。① argmax:probs.argmax(axis=1) 挑每列最大機率的位置——實跑範例 [0.988, 0.012, 0.000] → 預測類別 0。② 信心讀法:最大的那個機率本身就是信心分數——0.988 是「非常確定」、0.361 是「猶豫」(實跑第二筆 [0.361, 0.638, 0.001],模型在 0 與 1 之間搖擺、最後選 1)。實務加碼:需要「不確定就拒答」時,可設信心門檻(如最大機率 < 0.6 交人工);需要校準的機率(例如醫療)時,softmax 的原始輸出可能過度自信,還會再做 calibration——但考證層級記到 argmax+信心讀法就足夠。