現(xiàn)DNN回歸預(yù)測(cè)與SHAP可解釋分析完整方案)
簡(jiǎn)介這是一份基于MATLAB平臺(tái)的DNN-SHAP多變量回歸預(yù)測(cè)完整項(xiàng)目實(shí)例面向具備一定編程基礎(chǔ)、希望掌握深度學(xué)習(xí)與模型可解釋性結(jié)合的研發(fā)人員。資料以項(xiàng)目文檔形式呈現(xiàn)從背景、目標(biāo)、挑戰(zhàn)到解決方案系統(tǒng)梳理了數(shù)據(jù)預(yù)處理、DNN回歸模型構(gòu)建、SHAP解釋模塊及結(jié)果輸出四大模塊并配有詳細(xì)代碼步驟與GUI設(shè)計(jì)說明便于讀者在智能制造、金融風(fēng)險(xiǎn)、環(huán)境監(jiān)測(cè)等場(chǎng)景中直接遷移應(yīng)用。壓縮包僅含1個(gè)docx文件大小73KB內(nèi)容緊湊但覆蓋全流程尤其適合需要兼顧預(yù)測(cè)精度和決策透明度的實(shí)踐者。目前已有521人學(xué)習(xí)下載。閱讀后可深入理解DNN與SHAP的融合方式、超參數(shù)調(diào)優(yōu)技巧以及如何利用SHAP值解析模型決策具有較強(qiáng)的工程參考價(jià)值。1. DNN-SHAP 這個(gè)組合解決的是多變量回歸預(yù)測(cè)里最讓人心虛的問題模型把數(shù)算對(duì)了但說不出是哪幾個(gè)變量、以什么方式把結(jié)果推出來(lái)的。用 MATLAB 把這套流程串起來(lái)——訓(xùn)練一個(gè) DNN 做多變量回歸預(yù)測(cè)再用 SHAP 值把每個(gè)特征的貢獻(xiàn)拆開最后用 GUI 讓不懂代碼的人也能重復(fù)這個(gè)過程是我這邊最常見的落地樣板。輸入是十來(lái)個(gè)數(shù)值列的表格數(shù)據(jù)輸出是一個(gè)連續(xù)值你對(duì)“預(yù)測(cè)完之后還要解釋”有硬需求這套方案就正好卡在這個(gè)位置上。數(shù)據(jù)工程師拿它應(yīng)付業(yè)務(wù)追問研究生拿它給畢業(yè)論文加解釋性亮點(diǎn)都是常見用途。2. 先把 DNN 回歸跑通網(wǎng)絡(luò)結(jié)構(gòu)、數(shù)據(jù)劃分與訓(xùn)練參數(shù)怎么定SHAP 是附在預(yù)測(cè)模型上的解釋層模型本身不靠譜解釋就是給錯(cuò)誤結(jié)論化妝。所以第一步不是急著寫 SHAP 函數(shù)而是把 DNN 回歸這件事做得經(jīng)得起檢驗(yàn)。這個(gè)章節(jié)圍繞一張多變量表格把從數(shù)據(jù)預(yù)處理到網(wǎng)絡(luò)訓(xùn)練再到驗(yàn)證指標(biāo)的全過程拆開講。2.1 輸入輸出與歸一化多變量表格的預(yù)處理不能偷懶拿到數(shù)據(jù)先別急著喂網(wǎng)絡(luò)。表格里每一列的量綱可能差著幾個(gè)數(shù)量級(jí)比如一列是百分比0~100另一列是溫度-20~40。DNN 對(duì)輸入尺度非常敏感權(quán)重初始化、梯度更新的步長(zhǎng)都默認(rèn)輸入是零均值、單位方差的分布直接把原始數(shù)據(jù)丟進(jìn)去前期訓(xùn)練會(huì)像無(wú)頭蒼蠅一樣亂撞。常見做法是對(duì)輸入 X 做 zscore 歸一化輸出 y 也可以做但我一般只歸輸入。輸出保持原始尺度后面算 SHAP 時(shí)得到的貢獻(xiàn)值就和 y 同單位解釋起來(lái)直接說“這個(gè)特征讓預(yù)測(cè)值高了多少”不用再做逆變換。歸一化參數(shù)只用訓(xùn)練集的均值和標(biāo)準(zhǔn)差驗(yàn)證集和測(cè)試集都復(fù)用這一套參數(shù)不能用全量數(shù)據(jù)的統(tǒng)計(jì)量否則會(huì)引入未來(lái)信息。數(shù)據(jù)劃分用隨機(jī)打亂70% 訓(xùn)練、15% 驗(yàn)證、15% 測(cè)試。時(shí)間序列場(chǎng)景不能隨機(jī)打亂要保持時(shí)間順序這個(gè)項(xiàng)目定位一般就是截面表格數(shù)據(jù)隨機(jī)劃分沒問題。劃分前要固定隨機(jī)種子保證同一個(gè)項(xiàng)目換人復(fù)現(xiàn)時(shí)結(jié)果對(duì)得上。rng(42); n size(X, 1); idx randperm(n); nTrain round(0.7 * n); nVal round(0.15 * n); XTrain X(idx(1:nTrain), :); YTrain y(idx(1:nTrain)); XVal X(idx(nTrain1:nTrainnVal), :); YVal y(idx(nTrain1:nTrainnVal)); XTest X(idx(nTrainnVal1:end), :); YTest y(idx(nTrainnVal1:end)); % 只用訓(xùn)練集計(jì)算均值和標(biāo)準(zhǔn)差 [XTrainN, mu, sigma] zscore(XTrain); XValN (XVal - mu) ./ sigma; XTestN (XTest - mu) ./ sigma;這段代碼把歸一化參數(shù) mu 和 sigma 留在了工作區(qū)它們是后面所有環(huán)節(jié)的公共依賴包括 GUI 里的預(yù)測(cè)新樣本以及 SHAP 計(jì)算時(shí)的特征擾動(dòng)。zscore 按列計(jì)算所以 mu 是 1×M 的向量sigma 同尺寸X 里必須沒有 NaN否則 mu 和 sigma 會(huì)出現(xiàn) NaN后續(xù)全部白算。2.2 用 featureInputLayer 搭回歸網(wǎng)絡(luò)結(jié)構(gòu)選擇的依據(jù)回歸任務(wù)里DNN 的深度不需要追求極限。多變量表格數(shù)據(jù)的特征維度通常在 5~20 之間樣本量在幾百到幾萬(wàn)之間隱藏層做到三層以上意義不大反而容易過擬合。我常用的結(jié)構(gòu)是輸入層 兩個(gè)全連接層64、32 ReLU 輸出層1 個(gè)神經(jīng)元 回歸損失層。隱藏層寬度按特征數(shù)的 2~4 倍起步。特征數(shù)是 10第一層 64 就足夠?qū)捥卣鲾?shù)是 30第一層可以放到 128。太寬會(huì)讓訓(xùn)練變慢且容易過擬合太窄則擬合不了特征交互。對(duì)回歸問題輸出層不要加激活函數(shù)linear 輸出才能預(yù)測(cè)任意范圍的連續(xù)值。numFeatures size(X, 2); layers [ featureInputLayer(numFeatures, Name, input) % R2020b 之后可用 fullyConnectedLayer(64, Name, fc1) reluLayer(Name, relu1) fullyConnectedLayer(32, Name, fc2) reluLayer(Name, relu2) fullyConnectedLayer(1, Name, output) regressionLayer(Name, regout)];如果你用的 MATLAB 版本較老沒有 featureInputLayer就把它刪掉讓第一個(gè) fullyConnectedLayer 直接讀入矩陣輸入效果基本一致。這段結(jié)構(gòu)里有兩個(gè)關(guān)鍵點(diǎn)一是 reluLayer 放在每個(gè)全連接層后面給網(wǎng)絡(luò)引入非線性二是最后接 regressionLayer它對(duì)應(yīng)的是均方誤差損失多變量回歸預(yù)測(cè)的默認(rèn)選擇。分類問題這里就換 classificationLayer但本項(xiàng)目的落點(diǎn)是連續(xù)值輸出回歸層不能動(dòng)。2.3 訓(xùn)練參數(shù)學(xué)習(xí)率、批次、早停和驗(yàn)證集訓(xùn)練參數(shù)的設(shè)置決定了網(wǎng)絡(luò)是收斂還是震蕩。adam 優(yōu)化器是默認(rèn)選擇它對(duì)學(xué)習(xí)率不那么敏感但還是有邊界。初始學(xué)習(xí)率 1e-3 通常能跑通大多數(shù)表格回歸任務(wù)如果 loss 曲線震蕩降到 5e-4 或 1e-4如果下降太慢可以試 2e-3但不要一上來(lái)就 1e-2很容易發(fā)散。批次大小 32 在表格數(shù)據(jù)上是平衡點(diǎn)樣本少就 16。L2 正則化給 1e-4對(duì) DNN 是有效的防過擬合手段比 dropout 更省事。早停用 ValidationPatience 參數(shù)控制驗(yàn)證損失連續(xù) 12 輪不下降就停不會(huì)讓訓(xùn)練白白跑滿 200 輪。options trainingOptions(adam, ... MaxEpochs, 200, ... InitialLearnRate, 1e-3, ... MiniBatchSize, 32, ... L2Regularization, 1e-4, ... ValidationData, {XValN, YVal}, ... ValidationFrequency, 10, ... ValidationPatience, 12, ... Shuffle, every-epoch, ... Verbose, 0, ... Plots, none); net trainNetwork(XTrainN, YTrain, layers, options); YPred predict(net, XTestN); RMSE sqrt(mean((YPred - YTest).^2)); R2 1 - sum((YPred - YTest).^2) / sum((YTest - mean(YTest)).^2); fprintf(RMSE %.4f, R2 %.4f\n, RMSE, R2);ValidationFrequency 設(shè) 10意思是每 10 輪算一次驗(yàn)證損失ValidationPatience 12 表示驗(yàn)證損失連續(xù) 12 次不改善就終止訓(xùn)練。Plots 設(shè)為 none 是因?yàn)楹竺嬉阉哆M(jìn) GUI訓(xùn)練過程中彈出一個(gè)大訓(xùn)練曲線窗口會(huì)把界面設(shè)計(jì)搞亂。這里的 R2 是回歸任務(wù)里業(yè)務(wù)方最常問的指標(biāo)如果 R2 不到 0.7建議先回頭查數(shù)據(jù)處理和特征選擇別急著上 SHAP。3. SHAP 值怎么算從 Shapley 原理到 MATLAB 可運(yùn)行實(shí)現(xiàn)SHAP 的核心是 Shapley 值它來(lái)自博弈論的合作分配問題后來(lái)被引入機(jī)器學(xué)習(xí)做特征歸因。搞清楚原理和 MATLAB 實(shí)現(xiàn)之間的差距才能調(diào)試出可信的結(jié)果。這一章把原理、代碼、結(jié)果解讀三段串起來(lái)。3.1 Shapley 值的回歸語(yǔ)義效率和加性對(duì)做預(yù)測(cè)意味著什么Shapley 值解決的問題是M 個(gè)特征共同協(xié)作產(chǎn)生了一個(gè)預(yù)測(cè)值每個(gè)特征應(yīng)該分到多少貢獻(xiàn)。嚴(yán)格定義是遍歷所有不包含特征 i 的特征子集 S計(jì)算加入 i 前后的預(yù)測(cè)變化再按子集大小的組合數(shù)加權(quán)平均。公式寫成φ_i Σ_{S?N{i}} [ |S|! (M-|S|-1)! / M! ] × [ f(S∪{i}) - f(S) ]這個(gè)公式有兩個(gè)對(duì)回歸預(yù)測(cè)極其重要的性質(zhì)。效率性所有特征的 Shapley 值加起來(lái)等于這個(gè)樣本的預(yù)測(cè)值減去基線預(yù)測(cè)值基線一般取背景數(shù)據(jù)的平均預(yù)測(cè)。加性每個(gè)特征對(duì)單個(gè)預(yù)測(cè)的貢獻(xiàn)是獨(dú)立的可以畫條形圖直接比較大小。難點(diǎn)在于 f(S) 怎么算DNN 只吃完整的特征向量你沒法把“缺少某幾個(gè)特征”的樣本直接丟進(jìn)去預(yù)測(cè)。SHAP 的工程處理辦法是用背景數(shù)據(jù)集里的真實(shí)值去填充缺失特征再對(duì)多個(gè)背景樣本取平均來(lái)逼近“特征子集 S 條件下的期望預(yù)測(cè)”。這就是為什么背景數(shù)據(jù)集的選擇會(huì)直接影響解釋結(jié)果的可靠性后面避坑章節(jié)會(huì)專門展開。3.2 一個(gè)可直接抄的 kernelSHAP 實(shí)現(xiàn)純 MATLABMATLAB 沒有官方 SHAP 工具箱常見做法是自己實(shí)現(xiàn) kernelSHAP 的采樣近似?;玖鞒淌巧呻S機(jī)掩碼每個(gè)掩碼的 0/1 表示該特征用被解釋樣本的值還是背景樣本的值用掩碼構(gòu)造一批擾動(dòng)樣本送進(jìn) DNN 預(yù)測(cè)再用加權(quán)線性回歸解出每個(gè)特征的 Shapley 值。function shap kernel_shap_dnn(net, x, Xb, mu, sigma, nSamples) % net 訓(xùn)練好的 DNN % x 1 x M 原始尺度的被解釋樣本 % Xb 背景樣本集原始尺度建議 50~200 行 % mu, sigma 訓(xùn)練時(shí)的歸一化參數(shù) % nSamples 掩碼采樣次數(shù)建議 1000~5000 M numel(x); x0 (x - mu) ./ sigma; Z0 (Xb - mu) ./ sigma; f0 mean(predict(net, Z0)); % 基線預(yù)測(cè) Z double(rand(nSamples, M) 0.5); % 隨機(jī)掩碼 Z(1, :) 1; % 全特征可見 Z(end, :) 0; % 全特征缺失 bgIdx randi(size(Z0, 1), nSamples, 1); Xm repmat(x0, nSamples, 1); for j 1:M hit (Z(:, j) 0); Xm(hit, j) Z0(bgIdx(hit), j); % 用背景值替換 end y predict(net, Xm) - f0; w zeros(nSamples, 1); for i 1:nSamples k sum(Z(i, :)); if k 0 || k M w(i) 1e6; % 理論權(quán)重?zé)o窮大近似處理 else w(i) (M - 1) / (nchoosek(M, k) * k * (M - k)); end end A [Z, ones(nSamples, 1)]; wvec sqrt(w(:)); % 加權(quán)最小二乘的平方根權(quán)重 B A .* wvec; yw y .* wvec; coef (B * B) \ (B * yw); shap coef(1:M); end這段代碼有四個(gè)關(guān)鍵參數(shù)。nSamples 是采樣次數(shù)1000 是最低可接受值3000 左右能讓結(jié)果平穩(wěn)Xb 背景集一般用訓(xùn)練集的子集后面會(huì)講怎么挑w 是 kernelSHAP 權(quán)重不同掩碼對(duì) Shapley 估計(jì)的貢獻(xiàn)權(quán)重不同全 1 和全 0 的掩碼在理論上是無(wú)窮權(quán)重代碼里用 1e6 近似最后的加權(quán)線性回歸解出系數(shù)前 M 個(gè)系數(shù)就是各特征的 SHAP 值最后一個(gè)是 bias 項(xiàng)。這個(gè)實(shí)現(xiàn)是基于邊緣采樣的近似沒有顯式建模特征相關(guān)性所以解釋結(jié)果的正負(fù)方向和業(yè)務(wù)直覺對(duì)不上時(shí)優(yōu)先懷疑特征聯(lián)動(dòng)而不是急著改網(wǎng)絡(luò)。3.3 結(jié)果怎么看全局重要性和單樣本力度的區(qū)別SHAP 算完是一堆逐樣本的數(shù)值矩陣每個(gè)樣本一行每一列對(duì)應(yīng)一個(gè)特征??慈种匾园衙總€(gè)特征在所有樣本上的絕對(duì) SHAP 值取平均排序后畫條形圖這是業(yè)務(wù)方最常要的“哪個(gè)變量最重要”的答案??磫蝹€(gè)樣本用 barh 畫橫向條形圖正值表示該特征把預(yù)測(cè)值往上推負(fù)值往下壓??刺卣鞯姆较蛐杂绊懹蒙Ⅻc(diǎn)圖橫軸是特征原始值縱軸是該特征對(duì)應(yīng)的 SHAP 值。能看出單調(diào)關(guān)系還是 U 形關(guān)系比如溫度對(duì)能耗預(yù)測(cè)的影響可能是先降后升這種信息 R2 給不了只有解釋層能給。一個(gè)容易被忽略的點(diǎn)SHAP 值的單位就是預(yù)測(cè)目標(biāo) y 的單位不是歸一化后的無(wú)量綱數(shù)。我在 GUI 里展示 SHAP 值時(shí)坐標(biāo)軸標(biāo)題直接寫“特征貢獻(xiàn)與預(yù)測(cè)值同單位”業(yè)務(wù)方不用再做單位換算了。4. 把訓(xùn)練和解釋裝進(jìn) GUIApp Designer 結(jié)構(gòu)、回調(diào)與進(jìn)度反饋?lái)?xiàng)目標(biāo)題里的重要部分是 GUI 設(shè)計(jì)。你給我一個(gè)能跑的訓(xùn)練腳本業(yè)務(wù)方用不了給我一個(gè)點(diǎn)按鈕就能完成全流程的界面業(yè)務(wù)方才愿意每天用。這一章講怎么用 App Designer 把前面兩步封裝成一個(gè)完整的桌面工具。4.1 三塊功能區(qū)訓(xùn)練、預(yù)測(cè)、解釋各負(fù)責(zé)什么GUI 不要貪多三個(gè)功能區(qū)足夠數(shù)據(jù)加載、訓(xùn)練、解釋。數(shù)據(jù)加載負(fù)責(zé)選文件、預(yù)覽表格、自動(dòng)拆分訓(xùn)練集和驗(yàn)證集訓(xùn)練區(qū)負(fù)責(zé)啟動(dòng)訓(xùn)練、顯示 RMSE 和 R2、把訓(xùn)練好的網(wǎng)絡(luò)和歸一化參數(shù)存進(jìn) GUI 的屬性解釋區(qū)負(fù)責(zé)選擇要解釋的樣本、算 SHAP、畫全局重要性和依賴圖。數(shù)據(jù)格式約定要寫死在界面說明里第一行是列名最后一列是目標(biāo) y前面的列全是輸入特征。常見做法是讓用戶選 Excel 或 CSV 文件用 readmatrix 讀數(shù)值用 readtable 讀列名。列名在畫圖時(shí)用來(lái)標(biāo)特征名這一步不能省否則 SHAP 圖畫出來(lái)是一堆 X1、X2業(yè)務(wù)方根本看不懂。function onLoad(app, ~) [file, path] uigetfile({*.xlsx;*.csv, 數(shù)據(jù)文件}); if isequal(file, 0) return; end data readmatrix(fullfile(path, file)); app.X data(:, 1:end-1); app.y data(:, end); app.LogText.Value sprintf(數(shù)據(jù)讀取完成%d 行 %d 個(gè)特征, ... size(app.X, 1), size(app.X, 2)); end這段代碼里用 app.X 和 app.y 存數(shù)據(jù)是 App Designer 屬性緩存的標(biāo)準(zhǔn)寫法。注意 readmatrix 對(duì) CSV 里的文本列會(huì)報(bào)錯(cuò)所以數(shù)據(jù)文件必須是純數(shù)值列名用 readtable 讀取后單獨(dú)存成 cell 數(shù)組。我在實(shí)際項(xiàng)目中遇到過用戶把“編號(hào)”列一起拖進(jìn)來(lái)這種列對(duì)回歸沒有任何意義反而會(huì)讓 SHAP 解釋出奇怪的噪聲所以 GUI 里要加一個(gè)“剔除無(wú)關(guān)列”的選擇框。4.2 回調(diào)函數(shù)怎么寫異步進(jìn)度條、參數(shù)傳遞和句柄重用App Designer 的核心是回調(diào)函數(shù)。每個(gè)按鈕的回調(diào)里做一件事不要在一個(gè)回調(diào)里又訓(xùn)練又解釋又畫圖界面會(huì)卡成一團(tuán)黑色。訓(xùn)練按鈕的回調(diào)只負(fù)責(zé)調(diào) trainNetwork把結(jié)果存到 app.net、app.mu、app.sigma解釋按鈕的回調(diào)只負(fù)責(zé)調(diào) kernel_shap_dnn把結(jié)果畫到坐標(biāo)軸。訓(xùn)練是同步阻塞的trainNetwork 跑起來(lái)之后界面會(huì)無(wú)響應(yīng)這是 MATLAB GUI 的常態(tài)。我一般會(huì)在訓(xùn)練前把按鈕設(shè)為禁用用 try/catch 包住訓(xùn)練過程結(jié)束后再啟用。要真正的異步必須用 parfeval但協(xié)調(diào)起來(lái)復(fù)雜對(duì)大多數(shù)內(nèi)部工具沒有必要寫日志讓用戶知道正在跑就行。function onTrain(app, ~) app.TrainButton.Enable off; app.LogText.Value 開始訓(xùn)練請(qǐng)稍候…; drawnow; try [net, mu, sigma] train_regression_model(app.X, app.y); app.net net; app.mu mu; app.sigma sigma; app.LogText.Value 訓(xùn)練完成模型已保存到當(dāng)前界面; catch ME app.LogText.Value [訓(xùn)練失敗 ME.message]; end app.TrainButton.Enable on; endtrain_regression_model 是一個(gè)獨(dú)立函數(shù)封裝了第二章里從數(shù)據(jù)劃分到 trainingOptions 的全部邏輯返回值里必須包含 mu 和 sigma。這樣 GUI 回調(diào)里不堆積細(xì)節(jié)出問題時(shí)也能單獨(dú)在命令行測(cè)試這個(gè)函數(shù)。drawnow 的調(diào)用很關(guān)鍵它強(qiáng)制 MATLAB 刷新界面否則日志文字要等訓(xùn)練結(jié)束才會(huì)顯示。回調(diào)里用 app. 前綴訪問屬性是 App Designer 的屬性傳遞機(jī)制不用全局變量。4.3 給別人用數(shù)據(jù)格式約定和 MATLAB Runtime 打包做完 GUI 版方案后下一步是把它交到同事手里。最常見做法是用 Compiler 打包成獨(dú)立桌面應(yīng)用目標(biāo)機(jī)器不需要裝完整 MATLAB但要裝對(duì)應(yīng)版本的 MATLAB Runtime。這里有個(gè)容易踩坑的地方用 R2023a 編譯的程序Runtime 也必須裝 R2023a跨小版本會(huì)出現(xiàn)加載失敗的彈窗。打包時(shí)注意兩點(diǎn)。第一把讀數(shù)據(jù)函數(shù)用到的所有依賴文件放在同一個(gè)工程目錄里用 compiler.build.app 指定主文件和附加文件。第二Runtime 體積很大安裝包分發(fā)要提前給用戶說明不要等裝到一半才解釋。另外如果目標(biāo)機(jī)器上的 MATLAB Runtime 不是 2026b 這類你實(shí)際編譯的版本兼容性最容易出問題交付時(shí)寫清楚版本號(hào)是最省事的做法。% 在編譯前先把依賴列清楚 appFile DNNSHAPApp.mlapp; dataFile read_input_data.m; trainFile train_regression_model.m; shapFile kernel_shap_dnn.m; compiler.build.app(appFile, ... AdditionalFiles, {dataFile, trainFile, shapFile}, ... OutputDir, build);這段代碼把四個(gè)源文件打包進(jìn)一個(gè)應(yīng)用運(yùn)行時(shí)用戶只需要一個(gè) exe 和一份 CSV。中文注釋在舊版 MATLAB 里容易亂碼我習(xí)慣在交付前把源文件里的中文注釋統(tǒng)一改成英文R2023a 之后中文注釋亂碼問題基本消失穩(wěn)妥起見還是建議編譯前檢查一遍顯示效果。5. DNN-SHAP 的避坑手冊(cè)五個(gè)讓結(jié)果翻車的細(xì)節(jié)做這個(gè)項(xiàng)目踩過的坑不少大部分不在網(wǎng)絡(luò)結(jié)構(gòu)上而是在數(shù)據(jù)處理的邊角處。這一章按現(xiàn)象、原因、解決的順序?qū)懬宄恳粭l都是我在項(xiàng)目里實(shí)際遇到過的。5.1 歸一化參數(shù)用錯(cuò)了地方SHAP 值直接不可讀現(xiàn)象訓(xùn)練時(shí) R2 很好但 GUI 里對(duì)單條新樣本預(yù)測(cè)時(shí)數(shù)值偏到離譜SHAP 圖上所有特征的貢獻(xiàn)加起來(lái)與預(yù)測(cè)差值對(duì)不上。原因預(yù)測(cè)新樣本時(shí)用了全量數(shù)據(jù)的 zscore 統(tǒng)計(jì)量或者是用測(cè)試集重新算了一套 mu 和 sigma。zscore 是不穩(wěn)定的mu 和 sigma 必須來(lái)自訓(xùn)練集換了數(shù)據(jù)集重算特征分布就變了DNN 的輸入分布和訓(xùn)練時(shí)不一致輸出自然亂掉。解決把 mu 和 sigma 作為模型的一部分保存用 save 存成 mat 文件預(yù)測(cè)和解釋時(shí)只加載這一份。save(norm_params.mat, mu, sigma); % 預(yù)測(cè)時(shí) loaded load(norm_params.mat); xNorm (newSample - loaded.mu) ./ loaded.sigma;5.2 DNN 隨機(jī)性讓 SHAP 結(jié)果抖動(dòng)先定種子再談解釋現(xiàn)象同樣一份數(shù)據(jù)、同一個(gè)腳本兩天后重跑特征重要性排名變了有的特征從第 1 掉到第 4。原因trainNetwork 默認(rèn)隨機(jī)初始化權(quán)重mini-batch 的 shuffle 也隨機(jī)。DNN 本身是個(gè)隨機(jī)算法SHAP 是對(duì)這個(gè)隨機(jī)模型的解釋模型換了解釋跟著換。解決訓(xùn)練前固定 rng(42)并且把隨機(jī)種子也存進(jìn)模型文件。如果樣本量小、模型不穩(wěn)定就訓(xùn)練 5 次對(duì)預(yù)測(cè)取平均再用平均后的預(yù)測(cè)算 SHAP。解釋層不能承受模型每跑一次都變一套說辭否則業(yè)務(wù)方會(huì)直接否定整個(gè)方案。5.3 背景數(shù)據(jù)集選得太大或太偏采樣參數(shù)怎么設(shè)現(xiàn)象同一個(gè)樣本的 SHAP 值連續(xù)算兩次差異超過 20%特征重要性圖上長(zhǎng)條順序來(lái)回跳。原因nSamples 太低或者背景集 Xb 取了全量訓(xùn)練集導(dǎo)致噪聲過大或者 Xb 里某類樣本占絕大多數(shù)基線預(yù)測(cè) f0 嚴(yán)重偏向那一類。解決背景集用 kmeans 從訓(xùn)練集里選 100 個(gè)代表點(diǎn)覆蓋特征空間的主要分布nSamples 提到 3000 以上。以下代碼把訓(xùn)練集壓縮到 100 個(gè)中心點(diǎn)作為背景集。rng(42); [~, C] kmeans(XTrainN, 100, MaxIter, 500); Xb C .* sigma mu; % 還原到原始尺度5.4 逐列替換特征破壞了變量相關(guān)性掩碼采樣別省這一步現(xiàn)象SHAP 畫出來(lái)面積這個(gè)特征的貢獻(xiàn)是負(fù)的業(yè)務(wù)方說不可能面積越大房?jī)r(jià)越高模型預(yù)測(cè)也確實(shí)是越高。原因我在 3.2 節(jié)給的簡(jiǎn)化實(shí)現(xiàn)里掩碼為 0 的特征是逐列隨機(jī)挑背景值替換的。這會(huì)讓“面積小但房間數(shù)多”這種現(xiàn)實(shí)中不存在的樣本組合出現(xiàn)DNN 在這種樣本上的預(yù)測(cè)行為是外推不能反映真實(shí)邊際貢獻(xiàn)。解決對(duì)掩碼為 0 的所有位置整行使用同一條背景樣本而不是每列獨(dú)立替換。把 3.2 節(jié)的循環(huán)改成按行處理——先抽背景行索引掩碼為 0 的列全部取該行的對(duì)應(yīng)值。這樣既快又能保留特征間相關(guān)性。對(duì)于特征之間強(qiáng)相關(guān)的場(chǎng)景這是必須修改的一步。5.5 GUI 里畫圖句柄打架cla、hold 和 drawnow 的配合現(xiàn)象在解釋按鈕上點(diǎn)第二遍坐標(biāo)軸里疊了第一次和第二次的全部散點(diǎn)圖像糊成一團(tuán)。原因plot 不會(huì)自動(dòng)清空坐標(biāo)軸App Designer 的 UIAxes 也不會(huì)。每次畫 SHAP 圖之前沒有執(zhí)行 cla舊圖層和新圖層疊在一起。解決畫圖前先 cla 清空當(dāng)前坐標(biāo)軸再畫新圖如果依賴圖要疊加參考線用 hold on 前確認(rèn)上一個(gè) hold off 已經(jīng)執(zhí)行畫完加 drawnow 強(qiáng)制刷新。cla(app.GlobAx); barh(app.GlobAx, fnames, meanAbsShap); drawnow;6. 驗(yàn)證 SHAP 可靠性的三個(gè)習(xí)慣效率性、穩(wěn)定性與業(yè)務(wù)一致性SHAP 結(jié)果不是算出來(lái)就能交付的。三個(gè)驗(yàn)證習(xí)慣我每次都會(huì)做缺一個(gè)都不放心把報(bào)告發(fā)出去。效率性驗(yàn)證是第一個(gè)。對(duì)任意一個(gè)被解釋樣本所有特征的 SHAP 值求和加上基線預(yù)測(cè)值應(yīng)該等于 DNN 對(duì)該樣本的預(yù)測(cè)值。誤差在 1e-3 以內(nèi)說明 kernelSHAP 的采樣近似足夠好如果差得遠(yuǎn)優(yōu)先查掩碼權(quán)重有沒有寫錯(cuò)再查背景集是不是太偏。baseline mean(predict(net, Z0)); check (predict(net, x0) - baseline) - sum(shap);穩(wěn)定性驗(yàn)證是第二個(gè)。同一個(gè)樣本、同一個(gè)網(wǎng)絡(luò)用不同隨機(jī)種子算 10 次 SHAP看每個(gè)特征的標(biāo)準(zhǔn)差。標(biāo)準(zhǔn)差超過該特征平均絕對(duì)值的 10%說明采樣次數(shù)不夠把 nSamples 從 1000 提到 5000 再試。這個(gè)驗(yàn)證結(jié)果也可以寫進(jìn)交付文檔業(yè)務(wù)方對(duì)“可復(fù)現(xiàn)”的信任度很高。業(yè)務(wù)一致性是第三個(gè)也是我最看重的一個(gè)。把依賴圖導(dǎo)出發(fā)給業(yè)務(wù)方之前先自己看一遍溫度對(duì)能耗的影響是不是和實(shí)際規(guī)律一致面積對(duì)房?jī)r(jià)的貢獻(xiàn)是不是單調(diào)上升如果依賴圖呈現(xiàn)的趨勢(shì)和業(yè)務(wù)經(jīng)驗(yàn)矛盾先排查數(shù)據(jù)質(zhì)量問題再看特征相關(guān)性而不是強(qiáng)行解釋。這個(gè)項(xiàng)目給我最大的教訓(xùn)是SHAP 是放大鏡模型和數(shù)據(jù)里的臟東西也會(huì)被放大。交付前跑完這三個(gè)檢查再把報(bào)告發(fā)出去能省掉大量來(lái)回扯皮。這組檢查習(xí)慣后來(lái)成了我固定的交付清單效率性誤差、穩(wěn)定性標(biāo)準(zhǔn)差、依賴圖趨勢(shì)。每次都跑一遍已經(jīng)成了肌肉記憶。希望幫到你。本文還有配套的精品資源點(diǎn)擊獲取