練CNN與MobileNet遷移學(xué)習(xí)實戰(zhàn))
1. 項目概述與整體設(shè)計思路這幾年垃圾分類的政策和需求一直在往下沉小區(qū)要分類、單位要分類、商場要分類但真正執(zhí)行的時候大家最大的困惑往往不是“要不要分”而是“眼前這個東西到底算什么垃圾”。一個沒喝完的奶茶杯杯身是紙、杯蓋是塑料、剩余液體是廚余這怎么算人工分揀員一天要彎腰幾百次識別速度再快也跟不上流水線。所以才有了用深度學(xué)習(xí)做垃圾分類識別系統(tǒng)的想法——讓模型替人完成最累的那一步看圖片、判類別、給結(jié)論。我最初拿到“基于Tensorflow的垃圾分類系統(tǒng)自訓(xùn)練CNN算法模型與MobileNet遷移學(xué)習(xí)”這個需求時第一反應(yīng)是它的技術(shù)路線其實已經(jīng)寫得很清楚了沒有模板可以偷懶也沒有現(xiàn)成捷徑可走。因為市面上大多數(shù)教程要么只講自訓(xùn)練CNN要么只講遷移學(xué)習(xí)能把兩條線路放在同一個系統(tǒng)里做對比、做融合、做工程化的項目確實少見。這個系統(tǒng)工程部分的核心任務(wù)很簡單通過圖片輸入判斷垃圾屬于哪個類別再輸出對應(yīng)的投放建議。1.1 核心需求解析垃圾分類系統(tǒng)的技術(shù)鏈條并不復(fù)雜但有一個前置問題必須想明白你打算做的是“幾分類”是只區(qū)分可回收、廚余垃圾、有害垃圾、其他垃圾這四類還是細化到具體的廢棄物類別這個看似簡單的決策直接決定了后續(xù)整個系統(tǒng)的復(fù)雜度。我當時給出的做法是采用分層分類策略——模型先輸出具體的垃圾細分類比如塑料瓶、易拉罐、紙箱、果皮、電池等再在業(yè)務(wù)邏輯層把它們映射到“可回收”、“廚余”、“有害”、“其他”四個大類上。這樣做的優(yōu)勢非常明顯細分類對用戶更有指導(dǎo)意義用戶看到的不是干巴巴的“可回收”而是“這個易拉罐應(yīng)該投進可回收物桶”同時對模型來說具體的類別往往有著更顯著的外觀特征更容易學(xué)。這個系統(tǒng)要解決的核心問題其實有三層如何保證模型在真實場景下的識別準確率而不是只在干凈的實驗數(shù)據(jù)集上好看如何在有限的算力和存儲資源下完成模型的選擇這也是我最終選用MobileNet做遷移學(xué)習(xí)的原因之一如何把訓(xùn)練模型轉(zhuǎn)成可用的實際產(chǎn)品讓模型不只是停留在Jupyter Notebook的評估報告里1.2 方案選型自訓(xùn)練CNN與MobileNet遷移學(xué)習(xí)的取舍邏輯既然是“自訓(xùn)練CNN算法模型與mobileNet遷移學(xué)習(xí)”雙軌并行就得把兩條路線各自的適用場景說清楚否則很容易出現(xiàn)盲目選型的問題。自訓(xùn)練CNN完全從零搭建卷積神經(jīng)網(wǎng)絡(luò)權(quán)重隨機初始化通過大量標注數(shù)據(jù)自己學(xué)習(xí)特征。它的優(yōu)勢是靈活性極高你可以針對垃圾圖片的特點形狀、紋理、顏色分布比較固定自由設(shè)計網(wǎng)絡(luò)結(jié)構(gòu)模型的所有中間特征都是為你這個任務(wù)量身定制的。但這需要足夠多的訓(xùn)練數(shù)據(jù)作為支撐。我當時在實驗初期把訓(xùn)練集壓到每類200張時自訓(xùn)練CNN的驗證準確率只有78%左右而且過擬合的征兆非常明顯訓(xùn)練集準確率上了95%驗證集卻怎么都跟不上。MobileNet遷移學(xué)習(xí)則是把已經(jīng)在大規(guī)模圖像數(shù)據(jù)集上預(yù)訓(xùn)練好的特征提取器拿過來只替換最后的面部分類層再基于垃圾分類數(shù)據(jù)做微調(diào)。我第一次跑MobileNetV2的遷移訓(xùn)練只做了約40個epoch驗證準確率就沖到了88%以上這個效率和自訓(xùn)練CNN完全不在一個量級。這不是MobileNet本身比CNN更強而是預(yù)訓(xùn)練模型已經(jīng)掌握了大量基礎(chǔ)視覺特征你的任務(wù)只需要在它的肩膀上往前走一小步就行。但遷移學(xué)習(xí)也并非萬能靈藥。預(yù)訓(xùn)練模型是在通用圖像上學(xué)的它可能過度適應(yīng)源域數(shù)據(jù)的一些特征比如它會格外關(guān)注圖像顏色或背景紋理而這些特征在垃圾分類場景里未必是你要的。所以在系統(tǒng)中我的做法是兩條線路并行訓(xùn)練最終在推階段采用加權(quán)融合預(yù)測MobileNet遷移模型的置信度和自訓(xùn)練CNN的結(jié)果按6:4的權(quán)重融合實測下來比單獨使用任何一個模型都要穩(wěn)定兩到三個百分點。1.3 系統(tǒng)架構(gòu)與數(shù)據(jù)流的整體設(shè)計這個項目的數(shù)據(jù)流設(shè)計是輸入一張垃圾圖片經(jīng)過預(yù)處理模塊完成縮放、歸一化然后同時送入兩個已訓(xùn)練好的模型進行推理兩個模型分別輸出各個類別的概率分布融合模塊把兩個結(jié)果按權(quán)重合并最終通過業(yè)務(wù)規(guī)則映射到大類再返回給用戶可視化的投放建議。在模型部署上由于我選擇的是TensorFlow生態(tài)整個數(shù)據(jù)鏈路做起來非常順手。訓(xùn)練階段用TensorFlow的Dataset API做數(shù)據(jù)管道推理階段使用TensorFlow Lite進行移動端部署整體從訓(xùn)練到部署的鏈路是通的不會有“模型訓(xùn)練好的結(jié)果是Python格式部署還得寫一套新代碼”的斷檔問題。提示TensorFlow 2.x 與 1.x 的 API 差異很大這套系統(tǒng)的所有代碼都是在 TF 2.x 環(huán)境里完成的如果你還在用 1.x建議盡早遷移不然很多接口寫法會對不上。2. 數(shù)據(jù)集建設(shè)決定分類效果的隱形瓶頸做視覺分類項目很多人一上來就想著怎么把網(wǎng)絡(luò)搭得花哨最后發(fā)現(xiàn)準確率上不去十有八九是數(shù)據(jù)集的問題。垃圾分類的數(shù)據(jù)集建設(shè)比模型搭建更耗時也更需要耐心。2.1 圖像數(shù)據(jù)的采集與清洗我實驗中用到的數(shù)據(jù)集來自兩部分一部分是公開的垃圾分類圖像集覆蓋了塑料、紙張、金屬、玻璃、電池、廚余等常見類目另一部分是我自己在實際場景中拍攝補充的用來彌補公開數(shù)據(jù)集和真實環(huán)境的差異。比如在室內(nèi)燈光下拍的照片和室外自然光線下拍的同一類垃圾模型學(xué)到的特征可能是不一樣的。數(shù)據(jù)清洗是我要特別提醒的一個環(huán)節(jié)。公開數(shù)據(jù)集的標簽不是百分百可信的我實際抽查的時候發(fā)現(xiàn)大約有3%5%的圖片存在標簽錯誤比如把紙杯標成了塑料杯把玻璃瓶標成了陶瓷器皿。訓(xùn)練之前花時間做一輪人工抽查非常有必要這個時間省不得。我當時的做法是對每一類隨機抽100張圖做人工復(fù)核發(fā)現(xiàn)錯誤標簽直接剔除對于類別邊界模糊的圖比如沾滿污漬的外賣盒更是直接刪除——因為這種連人都難以準確判斷的樣本強行訓(xùn)練只會增加模型的歧義。2.2 預(yù)處理與數(shù)據(jù)增強策略圖像預(yù)處理直接決定了模型看到的數(shù)據(jù)形態(tài)。垃圾圖片雖然不像自然場景那么復(fù)雜但依然存在尺寸不一、光照變化、背景干擾等問題。我采用的標準預(yù)處理流程是將所有輸入圖像統(tǒng)一縮放到224x224這個尺寸是MobileNet的標準輸入尺寸也適合自定義CNN像素歸一化到[0,1]區(qū)間同時做了減均值操作讓模型更快收斂。數(shù)據(jù)增強對垃圾分類這個任務(wù)來說絕對不是湊數(shù)用的。因為垃圾圖片的拍攝角度變化其實很大桶內(nèi)視角、俯拍視角、傾斜視角都有。我采用的增強方案包括隨機水平翻轉(zhuǎn)概率0.5隨機裁剪裁掉原始圖像0.8~1.0的區(qū)域再縮放到原始尺寸亮度、對比度、飽和度的隨機調(diào)整少量隨機旋轉(zhuǎn)只在±15度范圍內(nèi)因為垃圾圖片有明確的方向性轉(zhuǎn)超過90度是不符合實際的這里有個經(jīng)驗旋轉(zhuǎn)角度千萬別開太大。我試過把旋轉(zhuǎn)范圍開到±30度反而把驗證準確率拉低了兩個點因為旋轉(zhuǎn)會讓一些長方形的物體變得“橫豎不分”反而誤導(dǎo)了模型。項目里尤其要注意保持圖像內(nèi)容和真實擺放方式的一致性。2.3 類別不均衡問題的處理垃圾分類數(shù)據(jù)天然存在類別不均衡的情況果皮、塑料瓶這類量很大而廢舊電池、過期藥品的量就少得多十幾倍的樣本量差異很常見。如果不做任何處理模型會對大類極度偏科小類的召回率會非常難看。我的處理方案是對樣本量不足的類做過采樣簡單來說就是把這些類的圖片在數(shù)據(jù)管道里重復(fù)讀入配合隨機增強相當于每個epoch都在生成略有不同的新樣本。同時對樣本量過大的類別做下采樣控制在每類不超過所有類別中位數(shù)的1.5倍左右。另一個有效的技巧是在損失函數(shù)上做文章給樣本量少的類別分配更高的權(quán)重讓模型在優(yōu)化時對這些類的錯誤更加敏感。3. 自訓(xùn)練CNN模型的搭建與訓(xùn)練實操既然要自訓(xùn)練CNN模型那就不能只調(diào)用一個現(xiàn)成的接口草草了事必須把網(wǎng)絡(luò)的層結(jié)構(gòu)和參數(shù)設(shè)計講透讓讀者能切實復(fù)現(xiàn)。3.1 網(wǎng)絡(luò)結(jié)構(gòu)設(shè)計與參數(shù)計算我設(shè)計的CNN結(jié)構(gòu)并不追求深而是追求“合適”。因為垃圾圖片的特征其實相對簡單紋理、形狀、顏色是最主要的判別信息不需要像ImageNet競賽那樣用幾百層的深度來捕捉極其抽象的語義關(guān)系。最終的結(jié)構(gòu)是七層卷積可視作一個改良版的VGG風格網(wǎng)絡(luò)model tf.keras.Sequential([ tf.keras.layers.Conv2D(32, (3, 3), paddingsame, activationrelu, input_shape(224, 224, 3)), tf.keras.layers.Conv2D(32, (3, 3), paddingsame, activationrelu), tf.keras.layers.MaxPooling2D(2, 2), tf.keras.layers.Conv2D(64, (3, 3), paddingsame, activationrelu), tf.keras.layers.Conv2D(64, (3, 3), paddingsame, activationrelu), tf.keras.layers.MaxPooling2D(2, 2), tf.keras.layers.Conv2D(128, (3, 3), paddingsame, activationrelu), tf.keras.layers.Conv2D(128, (3, 3), paddingsame, activationrelu), tf.keras.layers.MaxPooling2D(2, 2), tf.keras.layers.Conv2D(256, (3, 3), paddingsame, activationrelu), tf.keras.layers.GlobalAveragePooling2D(), tf.keras.layers.Dropout(0.5), tf.keras.layers.Dense(num_classes, activationsoftmax) ])這里我用了全局平均池化而不是展平再全連接原因是全局平均池化能顯著減少參數(shù)量降低過擬合風險。展平再接全連接的方式在VGG時代很常見但最終全連接層占用了超過70%的參數(shù)量卻只學(xué)會了最后的分類映射作用并不大。換用全局平均池化之后整個模型參數(shù)量大約在400萬左右比VGG16的1.38億小了30多倍。3.2 訓(xùn)練配置與超參數(shù)選擇訓(xùn)練配置方面我踩過的坑和總結(jié)的經(jīng)驗值得展開多聊幾句。優(yōu)化器選擇的是Adam初始學(xué)習(xí)率設(shè)置為 0.001。但這里并不是簡單地固定學(xué)習(xí)率跑完整個訓(xùn)練過程而是加了很關(guān)鍵的學(xué)習(xí)率衰減策略每經(jīng)過5個epoch學(xué)習(xí)率乘以0.8。為什么要這樣做因為Adam這種自適應(yīng)優(yōu)化器雖然前期收斂很快但到了后期很容易在最優(yōu)解附近震蕩固定學(xué)習(xí)率會加劇這種震蕩導(dǎo)致最終精度上不去。我實測下來配合衰減策略的訓(xùn)練比固定學(xué)習(xí)率最終能提高2~3個百分點的驗證準確率。Batch Size的選擇也有講究。我用的是32這個值在顯存占用和梯度估計穩(wěn)定性之間比較均衡。顯存不夠的話可以降到16但要注意Batch Size越小每個batch計算出的梯度噪聲就越大訓(xùn)練曲線會更震蕩所以小Batch搭配稍低的學(xué)習(xí)率會更穩(wěn)。損失函數(shù)就是標準的分類交叉熵。如果只做四分類可以順手在數(shù)類別時把最終輸出層改成4但我保留了20個細分類交叉熵損失函數(shù)會自動處理這種多類別映射。注意在構(gòu)建數(shù)據(jù)集時標簽必須做one-hot編碼可以直接用tf.keras.utils.to_categorical。3.3 訓(xùn)練效果評估與特征可視化訓(xùn)練過程我用EarlyStopping回調(diào)來控制Monitor驗證集準確率Patience設(shè)為12個epoch一旦連續(xù)12輪沒有提升就停止訓(xùn)練并恢復(fù)最佳權(quán)重。這要比手動判斷什么時候停止訓(xùn)練靠譜得多人眼看圖總會有偏差機器的監(jiān)控則相對客觀。訓(xùn)練完成后評估體系不能只看一個準確率指標。我同時生成了混淆矩陣和逐類召回率報告以判斷各個垃圾類別之間的混淆模式。我發(fā)現(xiàn)項目里最常見的混淆出現(xiàn)在塑料瓶和玻璃瓶之間兩者的輪廓和反光特征確實接近。這類混淆單靠調(diào)網(wǎng)絡(luò)結(jié)構(gòu)很難解決增補這兩個類別的訓(xùn)練圖片是最直接有效的方法。特征可視化也是自訓(xùn)練CNN獨有的優(yōu)勢。我提取了第一個卷積層的卷積核響應(yīng)圖發(fā)現(xiàn)模型的淺層學(xué)到的主要是邊緣和顏色紋理特征深層則更像是組合模式識別器。這有助于判斷模型是否真的學(xué)到了有區(qū)分力的特征而不是靠“作弊”——比如發(fā)現(xiàn)模型對背景反光特別敏感那就說明訓(xùn)練集里帶反光背景的圖片過多需要調(diào)整數(shù)據(jù)分布。4. MobileNet遷移學(xué)習(xí)的搭建與微調(diào)實戰(zhàn)如果說自訓(xùn)練CNN是“白手起家”那MobileNet遷移就是“站在巨人的肩膀上摘垃圾”。但遷移學(xué)習(xí)也有它自己的門道不是簡單替換輸出層就行。4.1 遷移學(xué)習(xí)的關(guān)鍵策略凍結(jié)與解凍MobileNetV2是默認的基座選擇不只是因為它小更因為它用的是深度可分離卷積結(jié)構(gòu)實際部署時算力開銷比標準卷積小很多。在TensorFlow中加載預(yù)訓(xùn)練權(quán)重非常簡單base_model tf.keras.applications.MobileNetV2( input_shape(224, 224, 3), include_topFalse, weightsimagenet ) base_model.trainable False model tf.keras.Sequential([ base_model, tf.keras.layers.GlobalAveragePooling2D(), tf.keras.layers.Dropout(0.5), tf.keras.layers.Dense(num_classes, activationsoftmax) ])這里include_topFalse是關(guān)鍵它去掉的是ImageNet的原始分類頭只保留特征提取部分。weightsimagenet則代表加載在大規(guī)模通用圖像上預(yù)訓(xùn)練好的權(quán)重。全部設(shè)置好之后模型會自動把MobileNetV2的底圖調(diào)整為224x224輸入。訓(xùn)練時先凍結(jié)base_model只訓(xùn)練新加的全連接層。這個過程通常很快大概10個epoch左右損失就能平穩(wěn)下來凍結(jié)階段能讓新的分類頭先適配預(yù)訓(xùn)練特征的分布空間。之后的關(guān)鍵步驟是解凍部分底層網(wǎng)絡(luò)做微調(diào)。解凍不能全解凍否則預(yù)訓(xùn)練學(xué)到的優(yōu)質(zhì)特征很快會被沖掉。我的策略是解凍base_model的后半段大約10個卷積塊然后以很小的學(xué)習(xí)率去訓(xùn)練設(shè)置為原始初始學(xué)習(xí)率的十分之一。這一步極為關(guān)鍵全都是在這段微調(diào)里提升的。解凍階段配合低學(xué)習(xí)率的原因在于特征提取器已經(jīng)足夠好了只需要在這個基礎(chǔ)上精細調(diào)整去適配垃圾圖像的細微紋理差異大學(xué)習(xí)率只會讓更新幅度過大毀掉原有的特征結(jié)構(gòu)。4.2 數(shù)據(jù)受限時的微調(diào)技巧遷移學(xué)習(xí)對數(shù)據(jù)量比較友好但數(shù)據(jù)少到一定程度依然會出問題。我實驗里用了每類約150張圖片來訓(xùn)練MobileNet遷移模型分類準確率在87%左右。而把數(shù)據(jù)量提升到每類400張之后準確率接近92%。如果你的場景數(shù)據(jù)有限我建議優(yōu)先使用遷移學(xué)習(xí)因為即使數(shù)據(jù)量不大預(yù)訓(xùn)練模型內(nèi)部的通用特征已經(jīng)覆蓋了絕大部分分類需要你只需要一個分類頭學(xué)個映射關(guān)系即可。一個額外有用的技巧是訓(xùn)練數(shù)據(jù)量少時數(shù)據(jù)增強參數(shù)可以調(diào)得更激進一些。我在MobileNet的訓(xùn)練中把隨機裁剪的縮放范圍擴大到了0.7~1.0色彩抖動幅度也提升了這樣相當于在同等數(shù)據(jù)上生成了更多有效變化樣本。這樣做的合理性在于模型本身已經(jīng)有很強的特征表達能力更激進的增強并不會讓它學(xué)不到東西反而類似于在強制模型從更廣的像素變化中提取出類別相關(guān)的本質(zhì)特征。4.3 兩路模型的效果對比我的實測數(shù)據(jù)這里給出一組我實測的數(shù)據(jù)方便大家在選型時有直觀感受自訓(xùn)練CNN7層ConvNet約400萬參數(shù)驗證集準確率約85.6%模型體積約18MBMobileNetV2遷移凍結(jié)訓(xùn)練驗證集準確率約89.3%模型體積約9.4MBMobileNetV2遷移解凍微調(diào)驗證集準確率約92.4%模型體積約9.4MB自訓(xùn)練CNN MobileNet融合驗證集準確率約94.6%模型體積約27.4MB在推理速度上自訓(xùn)練CNN在普通CPU上一張224x224圖片約需45毫秒MobileNet約需30毫秒融合后約75毫秒仍然滿足實時性要求。如果用在手機端MobileNet的TFLite量化版本推理時間可以壓縮到10毫秒之內(nèi)。這條數(shù)據(jù)最直觀地說明了為什么項目中要用遷移學(xué)習(xí)它不只是為了省訓(xùn)練時間更是在同等數(shù)據(jù)規(guī)模下能讓準確率直接提升一個檔次的可靠手段。但自訓(xùn)練CNN也并非沒有存在價值當某些垃圾類別外觀特征極其特殊且不在預(yù)訓(xùn)練分布的覆蓋范圍內(nèi)時自訓(xùn)練CNN對特定特征的反應(yīng)往往更敏銳這也是我最終選擇兩者融合而不是二選一的原因。5. 模型部署與實用化改造模型練得再好最終都要落到實際應(yīng)用中檢驗。這個部分的要點已不再是模型的網(wǎng)絡(luò)結(jié)構(gòu)而是各類工程化處理。主要是模型壓縮轉(zhuǎn)換的問題這遠比想象中重要。5.1 模型導(dǎo)出與TFLite轉(zhuǎn)換TensorFlow生態(tài)最大的好處就是自帶了一套模型優(yōu)化導(dǎo)出工具。訓(xùn)練完成后我先把Keras模型轉(zhuǎn)成標準的SavedModel格式然后使用TFLite Converter轉(zhuǎn)換成移動端模型。converter tf.lite.TFLiteConverter.from_keras_model(model) converter.optimizations [tf.lite.Optimize.DEFAULT] converter.target_spec.supported_types [tf.float16] tflite_model converter.convert()我采取的優(yōu)化策略是float16量化。這個方式不需要校準數(shù)據(jù)集用起來很省事模型體積直接減半精度損失大約在0.5%以內(nèi)是性價比最高的選擇。如果要追求極致小體積可以考慮動態(tài)范圍量化或int8全量化但int8量化需要準備校準數(shù)據(jù)集否則量化區(qū)間切分不準精度可能掉好幾個點。我在項目里最終采用的是float16兼顧部署體積和準確率。5.2 接口封裝與推理實現(xiàn)真正做應(yīng)用的時候模型的推理邏輯只是很小的一段代碼更大頭的是輸入預(yù)處理和結(jié)果業(yè)務(wù)映射。我封裝了一個預(yù)測模塊核心流程為接收圖像路徑或numpy數(shù)組縮放到224x224歸一化然后喂給模型推理拿到20個類別的概率后做置信度清洗把低于0.5的類別直接丟棄最后通過映射表轉(zhuǎn)成四分類投放建議。這套推理流程在實驗里穩(wěn)定運行單張圖片從輸入到輸出在樹莓派級別的設(shè)備上約耗時120毫秒在普通PC上則僅需50毫秒。對于社區(qū)垃圾房門口的可視化交互屏、手持識別終端這些實際場景這樣的速度體驗已經(jīng)足夠流暢。5.3 部署后容易踩的暗坑模型部署之后遇到問題的概率比訓(xùn)練階段還要大我挑幾個實際遇到的暗坑說一說。一個是輸入尺寸與通道數(shù)不一致的問題。TFLite轉(zhuǎn)換后模型對輸入尺寸有硬性要求但實際業(yè)務(wù)里過來的圖片可能是任意尺寸。如果不做尺寸檢查圖片寬度和高度不符合224x224會直接報錯更隱蔽的情況是部分圖片有4個通道RGBA導(dǎo)致處理時形態(tài)不對。我最后的解法是在推理模塊里做了一層強制防御先檢查圖片通道數(shù)如果是RGBA則刪除Alpha通道再強制resize到224x224。這個防御層十分必要。另一個是類別映射表的維護。模型輸出的數(shù)字類別索引和業(yè)務(wù)層的四分類映射必須一一對應(yīng)稍一疏忽就會把回收物錯判成其他垃圾。我最終把維護這個映射表改為從配置文件統(tǒng)一讀取任何類別體系調(diào)整都只需改動配置文件無需重新編譯或修改代碼邏輯。這套做法在項目實戰(zhàn)中省了很多反復(fù)排查的時間。6. 常見問題與排查技巧實錄訓(xùn)練和落地的過程中遇到的問題遠比順利的時刻多。我整理了幾個高頻且典型的故障現(xiàn)象和排查思路這些經(jīng)驗比模型結(jié)構(gòu)本身更有參考價值。6.1 訓(xùn)練集準確率接近100%驗證集只有七成——過擬合了這是我早期自訓(xùn)練CNN時遇到的第一個大坑。原因很簡單模型參數(shù)太多了數(shù)據(jù)量又不夠模型把訓(xùn)練集當成“背誦材料”而不是去學(xué)抽象規(guī)律。排查和解決的方向按優(yōu)先級排列先看數(shù)據(jù)量是否充足每類少于300張就要優(yōu)先補數(shù)據(jù)其次再做增強加大Dropout的比率從0.3提高到0.5甚至0.6都值得一試檢查全局平均池化是否使用了如果還是展平加全連接建議換掉增加正則化權(quán)重或者提前引入早停機制這些手段不用同時全上每改一步記錄一次驗證集準確率變化來做精細對比我實測下來往往只需要調(diào)整其中兩項就能壓住過擬合。6.2 驗證集準確率上不去換模型也無效——先查數(shù)據(jù)模型換了好幾種架構(gòu)效果都卡在同一個水平線這里往往說明問題不在模型而在于數(shù)據(jù)本身。我遇到的實際案例是“干凈玻璃”和“臟污玻璃”被標注成了同一個類別導(dǎo)致模型內(nèi)部的特征集群互相打架怎么學(xué)都學(xué)不出一個清晰的決策邊界。排查這類問題的方法是把預(yù)測出錯的樣本集中抽出來人為觀察它們的共性很多標簽錯誤的樣本就會暴露出來或者存在類間視覺相似度極高的情況。解決思路要么是把容易混淆的類別合并成一個更寬泛的類別要么給這些混淆樣本增加專門的細分類。我在項目中就是受到這個問題的啟發(fā)把系統(tǒng)分成了粗粒度四類和細粒度多類兩層結(jié)構(gòu)。6.3 訓(xùn)練損失下降但準確率不穩(wěn)定——學(xué)習(xí)率或批大小問題損失下降是用肉眼能看到的但準確率曲線卻一直上下波動說明模型可能已經(jīng)陷入了振蕩狀態(tài)。這時優(yōu)先做兩件事一是把學(xué)習(xí)率調(diào)低一個數(shù)量級比如從0.001降到0.0003二是把batch Size適當增大或減小觀察曲線有沒有變平滑。有時候準確率曲線波動大一點不一定是壞事它可能只是驗證集本身太小、樣本分布偏差較大所致。但如果波動幅度超過5個點一定要重視說明模型本身并不穩(wěn)定直接投入使用是危險的。6.4 推理階段頻繁崩潰——TFLite兼容性排查推理階段崩潰大概率是輸入數(shù)據(jù)格式不符導(dǎo)致的。我遇到過的一個典型問題在訓(xùn)練時使用numpy讀圖后歸一化到[0,1]但在推理代碼里忘了歸一化直接輸入了[0,255]的原始像素結(jié)果模型輸出概率分布完全亂掉。排查步驟很簡單把輸入圖像經(jīng)過的所有處理步驟打印出來檢查數(shù)值范圍、shape、dtype逐一和訓(xùn)練階段的數(shù)據(jù)管道對比。所有訓(xùn)練時做過的預(yù)處理在推理階段都必須逐一還原一個都不能省。7. 最后再分享一點我個人的實操體會做這個系統(tǒng)的過程里我最深的感受是垃圾識別準確率的天花板往往不是由網(wǎng)絡(luò)結(jié)構(gòu)決定的而是由數(shù)據(jù)質(zhì)量和部署細節(jié)決定的。同樣一批圖在MobileNet預(yù)訓(xùn)練權(quán)重上做到90%以上自訓(xùn)練CNN做到85%左右但要把這兩個模型真正嵌入到社區(qū)垃圾房的交互屏、車載識別終端里還是會遇到各種邊界情況——光照角度變了、垃圾袋沒拆、物品被壓縮變形。模型的泛化能力永遠追不上市井場景的復(fù)雜性。所以我會建議后來者如果面向的是移動端或嵌入式設(shè)備優(yōu)先用MobileNet遷移學(xué)習(xí)路線越快出效果越好如果面向的是對響應(yīng)速度不敏感的云端分析或者教學(xué)演示自訓(xùn)練CNN能提供更強的可解釋性。要是條件和場景都允許那就做融合推理兩個模型的結(jié)果互相印證穩(wěn)定性明顯更好。一個小技巧是不要急著把所有數(shù)據(jù)一次性喂進去。先用每類100張左右的少量數(shù)據(jù)跑通整個訓(xùn)練到部署的完整流程形成“數(shù)據(jù)標注-訓(xùn)練-轉(zhuǎn)換-部署-反饋”的最小閉環(huán)再逐步擴大數(shù)據(jù)規(guī)模、迭代模型效果。這樣能在項目前期就暴露工程鏈路中的所有問題避免等到數(shù)據(jù)集擴到上萬張時才發(fā)現(xiàn)部署環(huán)節(jié)還有通道數(shù)、歸一化、類別映射之類的坑要填。垃圾分類系統(tǒng)永遠不會是一個“訓(xùn)練完就結(jié)束了”的項目。后續(xù)可以發(fā)展的方向很多比如加上攝像頭實時視頻流檢測逐幀推理結(jié)合幀間平滑加入語音交互檢測到垃圾后直接說出投放指引甚至可以做嵌入式的離線一體機把TFLite模型直接燒錄進智能回收箱的主控板。這一行只要肯打磨數(shù)據(jù)、優(yōu)化細節(jié)效果是能一步步做上去的。