分類訓(xùn)了三天,loss狂跌上線指標(biāo)崩了:補(bǔ)完人工智能基礎(chǔ)才止血)
回歸當(dāng)分類訓(xùn)了三天,loss狂跌上線指標(biāo)崩了:補(bǔ)完人工智能基礎(chǔ)才止血發(fā)版前兩天,業(yè)務(wù)方直接把電話打到我工位上:「你們那個房價預(yù)測模型,昨天估出來的三居室比市場價高了150萬,客戶在簽約室當(dāng)場摔了合同?!刮掖蜷_監(jiān)控一看,訓(xùn)練loss曲線優(yōu)雅地下滑到了0.008,但線上的平均絕對誤差(MAE)直接飆到287萬。那一刻我才意識到,自己把整個問題從頭定義錯了。這事的起因說出來慚愧--我當(dāng)時剛接手一個二手房估價項目,數(shù)據(jù)結(jié)構(gòu)是一堆特征(面積、樓層、學(xué)區(qū))和對應(yīng)的成交價。我下意識就把它當(dāng)成了一個多分類問題:把價格分桶,讓模型去預(yù)測屬于哪個區(qū)間。于是順手搭了個三層全連接,輸出10個類別,損失函數(shù)選了CrossEntropyLoss。訓(xùn)練的時候看著loss一直往下掉,心里還挺美,以為這個「人工智能」項目能提前交付。如果你也正在用人工智能入門課程里的例子做真實項目,很容易像我一樣掉進(jìn)這個坑--把回歸硬套成分類,直到線上數(shù)據(jù)打臉才明白任務(wù)類型的選擇有多致命。為什么我會覺得「loss在降就對了」剛開始搞機(jī)器學(xué)習(xí)那陣子,我對評估的理解特別粗暴:loss往下走模型在變好。那門「機(jī)器學(xué)習(xí)入門」的教程里確實講過,訓(xùn)練過程中的損失函數(shù)值反映了模型預(yù)測與真實標(biāo)簽的差距,但沒人告訴我,當(dāng)任務(wù)類型選錯的時候,loss完全可以變成一張騙人的面具。我當(dāng)時的想法:把價格離散化成分段區(qū)間,輸出10個類別的概率,最后取argmax作為預(yù)測區(qū)間,再去映射回中位價,不也挺合理嗎?連續(xù)值被強(qiáng)行切碎之后我把500萬以內(nèi)的成交價切成10段,每段50萬。模型在訓(xùn)練集上的「準(zhǔn)確率」達(dá)到了92%,但那個準(zhǔn)確率是:只要預(yù)測區(qū)間與實際價格落在同一段就算對??蓪嶋H業(yè)務(wù)要的是精確數(shù)字,不是「差不多在200到250萬之間」這種含糊結(jié)果。特征工程這一步我也偷了懶。面積用原始值、樓層用樓層總數(shù)做歸一化,但學(xué)區(qū)被我用one-hot編碼成了20維稀疏向量,根本沒考慮不同學(xué)區(qū)之間的價格梯度信息。后來看「機(jī)器學(xué)習(xí)基礎(chǔ)」課程里專門有一節(jié)講連續(xù)特征的處理與分桶陷阱,我才明白自己把關(guān)鍵信息全扔掉了。如果你在做特征工程時對連續(xù)值、類別值的處理模棱兩可,那門課程里從特征存儲到數(shù)據(jù)預(yù)處理的完整管線真的能幫你避開這種災(zāi)難性設(shè)計。損失函數(shù)那張底牌被我完全忽略CrossEntropyLoss在意的是類別概率分布的對數(shù)似然,它根本不在乎預(yù)測值離真實價格有多遠(yuǎn)。舉個例子,真實價格是320萬,模型預(yù)測出「300-350萬」區(qū)間的概率是0.8,即使最終映射出的中位價325萬還算接近,但如果這個區(qū)間里所有點都映射到同一個值,loss的計算只關(guān)心那個0.8的置信度,完全看不出價格偏移。這就像你去醫(yī)院看病,醫(yī)生說你「大概率沒得癌癥」,但你其實得的是輕微胃炎--置信度很高,診斷方向全錯。我后來在「人工智能入門」中學(xué)到一個特別關(guān)鍵的概念:評估指標(biāo)必須與業(yè)務(wù)目標(biāo)一致?;貧w問題就要用MAE、MSE、RMSE這些能反映數(shù)值偏差的指標(biāo);分類問題才看準(zhǔn)確率、精確率、召回率。如果你連這個都沒搞清楚就上手訓(xùn)練,哪怕用了最先進(jìn)的深度學(xué)習(xí)框架也是白搭。那門課用極其直觀的圖表對比了不同指標(biāo)在典型場景下的表現(xiàn),學(xué)完之后我再也沒犯過把「準(zhǔn)確率」貼在回歸任務(wù)上的蠢事。修復(fù)過程:拆掉重來,從「管道」做起出問題當(dāng)天下午,我把之前的訓(xùn)練腳本全部作廢,重新梳理了整套機(jī)器學(xué)習(xí)管道。正好之前斷斷續(xù)續(xù)看過「亞馬遜云科技機(jī)器學(xué)習(xí)」的一些文檔,知道做項目不是上來就搭網(wǎng)絡(luò),而是數(shù)據(jù)預(yù)處理 → 特征工程 → 模型選擇 → 訓(xùn)練 → 評估 → 上線監(jiān)控六步缺一不可。第一步:重新定義輸入輸出我把價格恢復(fù)為連續(xù)數(shù)值,輸出層改成1個神經(jīng)元,激活函數(shù)用linear。損失函數(shù)換成HuberLoss,因為它對離群值不那么敏感--二手房數(shù)據(jù)里有不少上億的別墅,用MSE會讓模型過分討好那些極端值。import torch import torch.nn as nn # 錯誤的分類頭(棄用) # self.classifier nn.Linear(128, 10) # loss_fn nn.CrossEntropyLoss() # 正確的回歸頭 self.regressor nn.Sequential( nn.Linear(128, 64), nn.ReLU(), nn.Dropout(0.2), nn.Linear(64, 1) # 輸出連續(xù)價格 ) loss_fn nn.HuberLoss(delta50.0) # 50萬以內(nèi)的誤差線性,之外的平方第二步:特征工程重做學(xué)區(qū)不再是one-hot,而是用對應(yīng)學(xué)區(qū)近三個月歷史成交均價作為連續(xù)特征;面積做了對數(shù)變換緩解右偏;樓層改為「樓層與總樓層比」并和朝向做了一個組合特征。這些手段都是我在「機(jī)器學(xué)習(xí)基礎(chǔ)」里學(xué)到的,那門課把數(shù)據(jù)預(yù)處理、特征存儲、數(shù)據(jù)漂移這些概念串成了一條線,看完之后感覺自己之前一直在盲人摸象。第三步:評估指標(biāo)換成MAE和R2訓(xùn)練時每個epoch結(jié)束后都在驗證集上計算MAE,不再看那個欺騙性的loss數(shù)字。真正讓我服氣的是,我把同樣的數(shù)據(jù)用回歸模型跑了一晚,次日的MAE降到了18.7萬--比之前那個分類的偽92%準(zhǔn)確率靠譜得多。from sklearn.metrics import mean_absolute_error, r2_score def evaluate(model, loader): model.eval() preds, trues [], [] with torch.no_grad(): for X, y in loader: out model(X) preds.append(out.cpu().numpy()) trues.append(y.cpu().numpy()) preds np.concatenate(preds) trues np.concatenate(trues) mae mean_absolute_error(trues, preds) r2 r2_score(trues, preds) print(fMAE: {mae:.2f}萬, R2: {r2:.3f}) return mae, r2我從「混淆矩陣」里發(fā)現(xiàn)的第二個大坑雖然問題已經(jīng)定位到任務(wù)類型,但排查過程中還碰到了一個更隱蔽的坑:混淆矩陣。我用原來那套分桶方案的預(yù)測結(jié)果和真實桶畫了一個10×10的混淆矩陣,對角線上的數(shù)值確實很高,但不在對角線上的那些誤分類,對應(yīng)的價格偏差都是幾十上百萬。比如真實是「200-250萬」區(qū)間,被誤判到「300-350萬」,這一個跳躍就是100萬的誤差,但混淆矩陣只會把那一個格子標(biāo)記為1,不會告訴你偏差幅度。這就是為什么混淆矩陣對回歸問題毫無意義--它只在乎類別是否一致,不在乎偏離的程度。那門「人工智能」課程里專門有一章叫「模型評估與診斷」,把過擬合、欠擬合、混淆矩陣、ROC曲線、回歸指標(biāo)等概念掰開揉碎講了一遍。我以前總覺得這些指標(biāo)是面試八股文,真正被業(yè)務(wù)方指著鼻子罵的時候才意識到,不懂這些連為什么錯都解釋不清楚。如果你想系統(tǒng)建立人工智能項目的評估思維習(xí)慣,這門課非常適合花一個周末通讀,學(xué)完你會發(fā)現(xiàn)調(diào)試模型的時間至少縮短一半?,F(xiàn)在回看:如果早一點把「基礎(chǔ)」補(bǔ)牢如果我能在做這個項目之前,先把「人工智能入門」和「機(jī)器學(xué)習(xí)基礎(chǔ)」兩門課老老實實過一遍,至少能避開三個致命錯誤:任務(wù)類型判斷:看到數(shù)值型目標(biāo)先問自己,是連續(xù)預(yù)測還是離散判別?損失函數(shù)選擇:回歸至少試MSE、MAE、Huber;分類才考慮交叉熵。評估指標(biāo)與業(yè)務(wù)對齊:賣房子要的是價格誤差,不是分類命中率?!窤WS機(jī)器學(xué)習(xí)」的學(xué)習(xí)路徑設(shè)計得很有層次:先從「人工智能入門」建立對整個領(lǐng)域的概念地圖,再通過「機(jī)器學(xué)習(xí)入門」掌握建模全流程,最后才是「深度學(xué)習(xí)入門」去搞復(fù)雜的神經(jīng)網(wǎng)絡(luò)。我之前就是跳過前兩步直接干到第三步,結(jié)果連機(jī)器學(xué)習(xí)管道的正規(guī)流程都沒搞清楚,上線就翻車。# 訓(xùn)練腳本中的檢查點監(jiān)控,避免再次被loss迷惑 for epoch in range(epochs): model.train() for Xb, yb in train_loader: pred model(Xb) loss loss_fn(pred, yb) optimizer.zero_grad() loss.backward() optimizer.step() # 每個epoch后必須同時看驗證集的業(yè)務(wù)指標(biāo) train_mae, _ evaluate(model, train_loader) val_mae, val_r2 evaluate(model, val_loader) print(fEpoch {epoch}: train_mae{train_mae:.2f}, val_mae{val_mae:.2f}, val_r2{val_r2:.3f}) # 如果驗證MAE連續(xù)3輪不降,提前終止 if early_stop(val_mae): break給同樣在「回歸還分類」上翻過車的人接到新需求先畫目標(biāo)變量分布圖:是連續(xù)的就按回歸走,別自作聰明分桶?!溉斯ぶ悄苋腴T」這門課里有張任務(wù)類型決策樹,把回歸、分類、聚類、推薦分別對應(yīng)到典型業(yè)務(wù)場景,我后來把它打印出來貼在工位上,每次新項目都先過一遍--值得點進(jìn)去看看原圖。評估指標(biāo)不能只盯著一個:回歸至少看MAE、R2、殘差分布;分類不能只看準(zhǔn)確率,尤其樣本不平衡時要加上精確率、召回率。這些在「機(jī)器學(xué)習(xí)基礎(chǔ)」里講得特別透徹。特征工程不要敷衍:one-hot不是萬能藥,連續(xù)值分桶要先做相關(guān)性分析;「AWS基礎(chǔ)知識」那門課里介紹了特征存儲的概念,能把特征復(fù)用和版本管理做起來,而不是每次都重新寫腳本。上線前必須用獨立測試集跑一遍業(yè)務(wù)指標(biāo),而不是看訓(xùn)練loss。如果你的老板問你「人工智能項目為啥效果這么差」,別像我當(dāng)初一樣支支吾吾,帶著這套檢查清單去對答。那次房價預(yù)測翻車之后,我花了兩周把「人工智能」和「機(jī)器學(xué)習(xí)基礎(chǔ)」兩門課的系統(tǒng)學(xué)習(xí)路徑走了一遍,最大的感受是:理論不是用來面試的,是真的能在你掉進(jìn)數(shù)據(jù)沼澤時扔過來一根繩子?,F(xiàn)在再接到一個AI需求,我已經(jīng)能下意識地判斷該走回歸還是分類、選什么損失函數(shù)、用哪些指標(biāo)向上匯報。這感覺,比起當(dāng)初看著loss傻樂,踏實太多了。