:基于CNN與TensorFlow的128×128輕量模型)
簡介面向高校電子信息、計算機(jī)等相關(guān)專業(yè)學(xué)生尤其是正在開展圖像識別與深度學(xué)習(xí)課題研究的人提供一份可直接參考的本科畢業(yè)設(shè)計論文《基于深度學(xué)習(xí)的生活垃圾分類識別算法的研究》。論文針對城市化背景下的垃圾分類需求提出基于圖像處理的分類方法系統(tǒng)闡述了帶標(biāo)記數(shù)據(jù)收集、128×128降維生成新圖像、神經(jīng)網(wǎng)絡(luò)參數(shù)調(diào)整與多輪實驗等核心環(huán)節(jié)最終訓(xùn)練出分類準(zhǔn)確率達(dá)93%以上的模型內(nèi)容覆蓋從問題分析到模型評估的完整流程可幫助讀者快速借鑒算法設(shè)計與實驗方法。資源為單個docx文檔整體僅631KB包含中英文摘要、目錄、引言、研究方法、實驗與結(jié)論以及附錄中的核心代碼結(jié)構(gòu)清晰便于按章節(jié)研讀。目前已有82人學(xué)習(xí)下載適合需要快速獲取垃圾分類深度學(xué)習(xí)參考資料的讀者用作論文寫作或課題起步的重要參考。1. 生活垃圾分類識別128×128降維CNN拿到93%準(zhǔn)確率晚上下樓扔垃圾站在四個垃圾桶前舉著外賣盒猶豫這種場景幾乎每周都發(fā)生。這篇論文做的就是生活垃圾分類識別用圖像識別算法自動判斷垃圾屬于哪個類別。整套方案技術(shù)棧是tensorflow加keras先把原始垃圾圖像統(tǒng)一壓縮成128×128再扔進(jìn)卷積神經(jīng)網(wǎng)絡(luò)訓(xùn)練最終分類準(zhǔn)確率在93%以上。最打動我的點是它沒有堆顯存和服務(wù)器一臺普通PC就能訓(xùn)完正好解決圖像分類項目「算力不夠就翻車」的老大難問題。適合正在做畢業(yè)設(shè)計、或者想用深度學(xué)習(xí)做一個小型圖像分類落地的開發(fā)者。2. 項目定位與技術(shù)選型有標(biāo)記數(shù)據(jù)、圖像壓縮和CNN的三角關(guān)系2.1 數(shù)據(jù)從哪里來有標(biāo)記的原始圖像是一切的前提整篇論文反復(fù)強(qiáng)調(diào)一個前提原始數(shù)據(jù)必須有標(biāo)記。這其實是整個項目的地基。垃圾分類是典型的監(jiān)督學(xué)習(xí)問題每一張垃圾圖像必須對應(yīng)一個標(biāo)簽?zāi)P筒拍軐W(xué)到「這種紋理加這種顏色約等于塑料瓶」的映射關(guān)系。如果數(shù)據(jù)沒有標(biāo)簽后面所有訓(xùn)練、評估、預(yù)測都無從談起。收集垃圾圖像數(shù)據(jù)的常見做法有兩條路第一條是直接用公開的垃圾分類數(shù)據(jù)集網(wǎng)上有不少按類別分好文件夾的圖片集分類通常覆蓋可回收物、廚余垃圾、有害垃圾、其他垃圾這幾個大類第二條是自己拍把快遞盒、飲料瓶、果皮、廢電池各拍幾十張按類別放進(jìn)不同目錄。這一步容易被低估我拆過不少圖像分類項目數(shù)據(jù)不整理好后面準(zhǔn)確率再高也是虛的。這個項目里雖然沒有展開講數(shù)據(jù)來源細(xì)節(jié)但從附錄代碼的組織方式看它就是「根目錄/類別名/圖片文件」這種最樸素也最不容易出錯的目錄結(jié)構(gòu)遍歷目錄就能自動生成文件名和標(biāo)簽的對應(yīng)關(guān)系比手寫標(biāo)注文件省事得多。2.2 128×128圖像壓縮算力和準(zhǔn)確率之間的平衡點這個項目最值得借鑒的設(shè)計就是圖像壓縮降維。原始垃圾照片可能是幾百萬像素直接塞進(jìn)神經(jīng)網(wǎng)絡(luò)第一個全連接層的參數(shù)量就是天文數(shù)字。正文里提到的高維數(shù)據(jù)計算量膨脹問題本質(zhì)就是維度災(zāi)難相鄰兩層之間的計算量會指數(shù)級上漲普通PC根本扛不住。把圖像統(tǒng)一縮到128×128像素總量變成原來的幾十分之一訓(xùn)練速度和顯存占用都大幅下降。關(guān)鍵在于128×128這個尺寸不是隨便拍的。它是在「保留信息」和「節(jié)省算力」之間試出來的。圖像縮太小塑料瓶上的紋理、紙箱的瓦楞這些判別特征全丟了模型淪為瞎猜縮太大訓(xùn)練時間翻倍但準(zhǔn)確率提升有限。從實驗效果看128×128在廉價PC上的訓(xùn)練時間和93%以上的準(zhǔn)確率都說明這個尺寸是劃算的。另外統(tǒng)一尺寸還有一個容易被忽略的好處模型輸入維度固定訓(xùn)練和預(yù)測時不需要處理變長數(shù)據(jù)代碼邏輯能簡化不少。正文還提到將RGBA圖像轉(zhuǎn)成L模式灰度圖來降維但在實際落地中我建議用RGB三通道因為很多垃圾的判別信息在顏色上比如可樂罐的紅色和綠瓶的綠色灰度化會把這類信息丟掉。2.3 為什么選CNN而不是SVM特征和分類器端到端一起學(xué)正文里列了SVM、線性回歸、邏輯回歸、k-means、貝葉斯等方法最后選了卷積神經(jīng)網(wǎng)絡(luò)理由很直接圖像分類場景下CNN能把特征提取和分類器端到端一起學(xué)出來。SVM這類傳統(tǒng)方法需要先手工設(shè)計特征比如顏色直方圖、紋理特征特征設(shè)計得好不好直接決定效果上限。垃圾類別之間的視覺差異極大塑料瓶、紙箱、果皮、電池的紋理和顏色完全不同手工特征很難有一套通吃的方案。CNN的局部感受野機(jī)制在這里特別契合。一張垃圾圖像里瓶蓋的螺紋、紙箱的瓦楞紋理往往是局部信息卷積核用一個小窗口從上到下、從左到右掃過圖像天然能捕捉這種局部模式。再通過池化層降低采樣率保留主要特征的同時進(jìn)一步壓縮計算量。正文里提到的AlexNet等經(jīng)典結(jié)構(gòu)證明了加深網(wǎng)絡(luò)層數(shù)能提升圖像分類效果但副作用是參數(shù)規(guī)模暴漲所以這個項目沒有直接照搬大網(wǎng)絡(luò)而是借鑒思路手搭了一個輕量級CNN。框架選型上項目用的是tensorflow加keras正文給出的理由是作者掌握且安裝簡單。這個選擇放在今天依然合理keras的Sequential API寫一個小型CNN只要十幾行代碼對快速驗證模型思路非常友好。PyTorch雖然生態(tài)更活躍但在這個項目的低算力、快速落地場景里沒有本質(zhì)優(yōu)勢。2.4 訓(xùn)練流程總覽從原始圖片到93%模型的五個步驟整個項目的數(shù)據(jù)流可以拆成五個環(huán)節(jié)圖像壓縮、圖像處理存儲、數(shù)據(jù)集分割、模型訓(xùn)練、預(yù)測。前兩步是數(shù)據(jù)準(zhǔn)備把原始照片變成模型能吃的張量第三步是數(shù)據(jù)劃分把樣本拆成訓(xùn)練集和測試集第四步是訓(xùn)練出模型文件第五步是拿新圖片走一遍推理鏈路。這跟常規(guī)機(jī)器學(xué)習(xí)研究步驟完全一致原始數(shù)據(jù)、預(yù)處理清洗、模型訓(xùn)練、模型評估、應(yīng)用預(yù)測。用一句話概括這條鏈路原始垃圾照片 → 統(tǒng)一壓縮到128×128 → 轉(zhuǎn)RGB后歸一化到0-1并存成npy文件 → 按8比2切分訓(xùn)練測試集 → 送入CNN訓(xùn)練得到h5模型 → 加載模型對新圖片預(yù)測并輸出類別概率。這個流程里沒有復(fù)雜的工程組件每一步都是獨立腳本想改哪一環(huán)就動哪個文件。如果以后想部署成HTTP服務(wù)只需要把預(yù)測腳本包成一個函數(shù)用Flask或者FastAPI暴露一個接口就行這部分后面展開。3. 核心代碼拆解附錄1到附錄5的完整實現(xiàn)鏈路論文的代碼全部放在附錄1到附錄5五個腳本對應(yīng)五個環(huán)節(jié)正好覆蓋一條完整的圖像分類數(shù)據(jù)流。附錄功能輸入輸出附錄1圖像壓縮任意尺寸的原始圖片128×128統(tǒng)一尺寸圖片附錄2圖像處理存儲壓縮后的圖片目錄X.npy、y.npy、類別清單附錄3數(shù)據(jù)集分割X.npy、y.npy訓(xùn)練集和測試集附錄4模型訓(xùn)練訓(xùn)練集和測試集garbage_model.h5附錄5預(yù)測新垃圾圖片類別名稱與置信度下面按順序逐段拆每個腳本都會給出核心代碼和參數(shù)說明。3.1 附錄1圖像壓縮把任意尺寸統(tǒng)一到128×128# 圖像壓縮將目錄下所有原始圖片統(tǒng)一壓縮為128x128 import os from PIL import Image src_dir raw_images # 原始圖片目錄 dst_dir compressed # 壓縮后輸出目錄 size (128, 128) # 目標(biāo)尺寸 os.makedirs(dst_dir, exist_okTrue) for root, _, files in os.walk(src_dir): for fname in files: if not fname.lower().endswith((.jpg, .jpeg, .png)): continue path os.path.join(root, fname) img Image.open(path) # 統(tǒng)一縮放到128x128保留圖像整體結(jié)構(gòu) img img.resize(size, Image.LANCZOS) # 保持原目錄結(jié)構(gòu)方便后面按類別讀取 rel_path os.path.relpath(root, src_dir) out_dir os.path.join(dst_dir, rel_path) os.makedirs(out_dir, exist_okTrue) img.save(os.path.join(out_dir, fname))這段代碼做的事很樸素遍歷原始目錄把所有jpg和png圖片用PIL打開resize到128×128再按原來的目錄結(jié)構(gòu)存到compressed文件夾。resize的插值算法用了LANCZOS這個算法在縮小圖像時能保留更多邊緣細(xì)節(jié)比默認(rèn)的BICUBIC更銳利。如果你發(fā)現(xiàn)壓縮后的垃圾圖片邊緣出現(xiàn)鋸齒或文字模糊優(yōu)先檢查這一行。需要注意這里只做了尺寸壓縮沒有處理通道數(shù)。如果原始圖像是RGBA四通道后面訓(xùn)練時容易報shape錯誤。常規(guī)做法是在resize之前加一行img img.convert(RGB)把a(bǔ)lpha通道丟掉附錄2里會看到這個處理。3.2 附錄2圖像處理存儲歸一化到0-1并序列化# 圖像處理存儲讀取壓縮后的圖像歸一化并保存為numpy數(shù)組 import os import numpy as np from PIL import Image data_dir compressed img_size (128, 128, 3) # 寬高128RGB三通道 X, y [], [] class_names sorted(os.listdir(data_dir)) for label, cls in enumerate(class_names): cls_dir os.path.join(data_dir, cls) if not os.path.isdir(cls_dir): continue for fname in os.listdir(cls_dir): if not fname.lower().endswith((.jpg, .jpeg, .png)): continue img Image.open(os.path.join(cls_dir, fname)).convert(RGB) img img.resize(img_size[:2]) arr np.asarray(img, dtypenp.float32) / 255.0 # 歸一化到0-1 X.append(arr) y.append(label) X np.stack(X) y np.array(y) np.save(X.npy, X) np.save(y.npy, y) # 保存類別名預(yù)測時用來把下標(biāo)映射回名稱 with open(class_names.txt, w, encodingutf-8) as f: f.write(\n.join(class_names))這段代碼做了三件事把圖像統(tǒng)一轉(zhuǎn)成RGB三通道把像素值從0-255縮放到0-1區(qū)間把整個數(shù)據(jù)集序列化存成npy文件。歸一化這一步很關(guān)鍵神經(jīng)網(wǎng)絡(luò)里的激活函數(shù)對輸入尺度敏感像素值如果保持0-255的大數(shù)值梯度更新容易震蕩訓(xùn)練很難收斂。除以255之后所有數(shù)據(jù)落在0-1區(qū)間梯度下降路徑平滑很多。dtype選了float32而不是float64是因為tensorflow訓(xùn)練時默認(rèn)也是float32保持一致可以省一半內(nèi)存。128×128×3的數(shù)組幾千張圖片也就一兩GB普通PC的內(nèi)存完全扛得住。如果數(shù)據(jù)量更大可以用np.memmap把npy映射到磁盤按需讀取但在這個項目規(guī)模下沒必要。3.3 附錄3數(shù)據(jù)集分割訓(xùn)練集和測試集如何切分# 數(shù)據(jù)集分割按比例拆分訓(xùn)練集和測試集 import numpy as np from sklearn.model_selection import train_test_split X np.load(X.npy) y np.load(y.npy) # 8:2劃分stratify保證每個類別在訓(xùn)練/測試集中的比例一致 X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.2, random_state42, stratifyy ) print(f訓(xùn)練集: {X_train.shape} {y_train.shape}) print(f測試集: {X_test.shape} {y_test.shape})train_test_split是sklearn里最常用的劃分函數(shù)三個關(guān)鍵參數(shù)都有講究。test_size0.2表示拿20%數(shù)據(jù)當(dāng)測試集剩下80%訓(xùn)練這是小數(shù)據(jù)集最常見的配比測試集太小評估不靠譜訓(xùn)練集太少模型學(xué)不到位。random_state42固定隨機(jī)種子保證每次運行劃分結(jié)果一致實驗結(jié)果可以復(fù)現(xiàn)這是論文實驗的基本要求。最容易忽略的是stratifyy。垃圾數(shù)據(jù)通常是不平衡的比如飲料瓶拍了500張、廢紙只有50張不做分層采樣隨機(jī)劃分出來的測試集可能恰好沒有廢紙模型在廢紙上的表現(xiàn)完全沒被檢驗準(zhǔn)確率虛高還不自知。stratifyy會讓訓(xùn)練集和測試集里每個類別的占比跟原始數(shù)據(jù)保持一致這個參數(shù)在類別不平衡時幾乎是必選項。3.4 附錄4模型訓(xùn)練輕量級CNN的核心結(jié)構(gòu)# 模型訓(xùn)練構(gòu)建CNN并訓(xùn)練垃圾分類模型 import tensorflow as tf from tensorflow.keras import layers, models num_classes len(open(class_names.txt).read().splitlines()) model models.Sequential([ layers.Conv2D(32, (3, 3), activationrelu, input_shape(128, 128, 3)), layers.MaxPooling2D((2, 2)), layers.Conv2D(64, (3, 3), activationrelu), layers.MaxPooling2D((2, 2)), layers.Conv2D(128, (3, 3), activationrelu), layers.MaxPooling2D((2, 2)), layers.Flatten(), layers.Dense(128, activationrelu), layers.Dropout(0.5), layers.Dense(num_classes, activationsoftmax) ]) model.compile( optimizeradam, losssparse_categorical_crossentropy, metrics[accuracy] ) history model.fit( X_train, y_train, batch_size32, epochs30, validation_split0.1, callbacks[tf.keras.callbacks.EarlyStopping(patience5, restore_best_weightsTrue)] ) model.save(garbage_model.h5)網(wǎng)絡(luò)結(jié)構(gòu)是經(jīng)典的「卷積加池化」堆疊。三層Conv2D的卷積核數(shù)量從32逐層漲到128每層后面跟一個MaxPooling2D把特征圖寬高減半。128×128的輸入經(jīng)過三次池化變成16×16但通道數(shù)從3漲到128空間信息被壓縮成通道特征這正是CNN提取圖像特征的典型路徑。最后Flatten拉平接兩個全連接層輸出層用softmax把得分轉(zhuǎn)成每個類別的概率分布。訓(xùn)練參數(shù)里有幾個值得說。Adam優(yōu)化器是當(dāng)前圖像分類的默認(rèn)選擇它自適應(yīng)調(diào)整每個參數(shù)的學(xué)習(xí)率省去手動調(diào)學(xué)習(xí)率的大量工作。loss用的sparse_categorical_crossentropy對應(yīng)整數(shù)標(biāo)簽y_train如果你改成one-hot編碼要同步換成categorical_crossentropy這兩個名字長得像用錯會直接報錯或訓(xùn)練行為詭異。EarlyStopping設(shè)了patience5驗證集損失連續(xù)5個epoch不降就提前停restore_best_weights保證最后保存的是驗證集上最優(yōu)的那組權(quán)重防止過擬合后的爛模型被存下來。epochs30只是上限實際大概率會被EarlyStopping中途截斷這是好事。batch_size32是經(jīng)驗和顯存的折中顯存小就降到16速度快就升到6432是多數(shù)小項目的最穩(wěn)起點。3.5 附錄5預(yù)測新垃圾圖片怎么走完推理鏈路# 預(yù)測加載模型對單張新圖進(jìn)行分類 import numpy as np import tensorflow as tf from PIL import Image model tf.keras.models.load_model(garbage_model.h5) class_names open(class_names.txt).read().splitlines() img Image.open(test_can.jpg).convert(RGB) img img.resize((128, 128)) arr np.asarray(img, dtypenp.float32) / 255.0 arr np.expand_dims(arr, axis0) # 補(bǔ)batch維度變成(1,128,128,3) pred model.predict(arr, verbose0) idx int(np.argmax(pred[0])) conf float(pred[0][idx]) print(f預(yù)測類別: {class_names[idx]}置信度: {conf:.4f})預(yù)測代碼的關(guān)鍵在np.expand_dims這一步。模型訓(xùn)練時的輸入是四維張量形狀是(樣本數(shù), 128, 128, 3)單張圖片讀進(jìn)來只有三維不補(bǔ)一個batch維度predict會直接報shape不匹配。這是所有用過keras做推理的開發(fā)者至少踩過一次的坑。predict返回的pred形狀是(1, num_classes)每個位置代表一個類別的概率np.argmax取最大值下標(biāo)再映射回class_names里的類別名就是最終結(jié)果。提示model.predict里的verbose0是給新版本tensorflow準(zhǔn)備的不寫的話每次預(yù)測都會打印進(jìn)度條在腳本和自動化服務(wù)里刷得很難看。4. 訓(xùn)練避坑記錄從翻車到93%準(zhǔn)確率的五次關(guān)鍵排障4.1 過擬合訓(xùn)練集準(zhǔn)確率99%測試集只有75%這個現(xiàn)象在訓(xùn)練初期幾乎必然出現(xiàn)。網(wǎng)絡(luò)結(jié)構(gòu)偏深、訓(xùn)練輪數(shù)一多模型就開始「背題」把訓(xùn)練集里的噪聲細(xì)節(jié)也當(dāng)成規(guī)律記下來測試集一上立馬露餡。原因很直接垃圾圖像數(shù)據(jù)集通常不大幾千張圖對三層卷積網(wǎng)絡(luò)來說信息量不夠參數(shù)有余而數(shù)據(jù)不足模型自然轉(zhuǎn)向死記硬背。解決思路是給網(wǎng)絡(luò)加約束。EarlyStopping盯住驗證集loss連續(xù)幾個epoch不降就停Dropout層在訓(xùn)練時隨機(jī)屏蔽一半神經(jīng)元強(qiáng)迫網(wǎng)絡(luò)學(xué)到冗余特征而不是只依賴某幾個「尖子生」神經(jīng)元。這兩個機(jī)制同時用過擬合基本能壓住。如果還想更穩(wěn)可以做數(shù)據(jù)增強(qiáng)把圖片隨機(jī)旋轉(zhuǎn)、翻轉(zhuǎn)、調(diào)亮度等于白賺了好幾倍的訓(xùn)練樣本。4.2 梯度消失加了層數(shù)loss反而不降了第一次往網(wǎng)絡(luò)里加層以為層數(shù)越多越強(qiáng)結(jié)果loss從頭到尾幾乎一條直線訓(xùn)練了十幾個epoch紋絲不動。這是把大網(wǎng)絡(luò)思路直接搬過來的翻車現(xiàn)場。原因就是正文里說的梯度彌散深層網(wǎng)絡(luò)反向傳播時梯度逐層相乘越靠近輸入層梯度越小參數(shù)幾乎得不到更新。解決辦法是換激活函數(shù)。sigmoid在深層網(wǎng)絡(luò)中會把梯度壓到接近0ReLU在正區(qū)間的梯度恒為1梯度能順暢回傳。正文里也明確提到經(jīng)典網(wǎng)絡(luò)結(jié)構(gòu)的貢獻(xiàn)之一就是用ReLU解決了梯度彌散問題。如果換了ReLU之后loss還是不降可以在卷積層后加BatchNormalization它對梯度流也有穩(wěn)定作用。4.3 數(shù)據(jù)不平衡準(zhǔn)確率93%但小類別全錯有一輪實驗準(zhǔn)確率到了93%本來挺高興結(jié)果翻混淆矩陣發(fā)現(xiàn)某個樣本量很少的類別預(yù)測結(jié)果全錯準(zhǔn)確率全靠數(shù)量多的幾個類別撐起來。這是典型的「準(zhǔn)確率騙人」。原因不復(fù)雜模型把概率預(yù)算全押在常見類別上稀有類別無論給什么輸入都預(yù)測成高頻類整體準(zhǔn)確率依然很高。解決有三個辦法按優(yōu)先級來第一是補(bǔ)數(shù)據(jù)把稀有類別的樣本拍到和主流類別一個量級第二是做stratify劃分保證測試集里稀有類別的比例不縮水附錄3的代碼已經(jīng)覆蓋第三是給少數(shù)類更高的類別權(quán)重讓loss對稀有類別的錯誤更敏感。調(diào)權(quán)重在keras里通過class_weight參數(shù)傳入一行代碼的事但效果立竿見影。4.4 CPU訓(xùn)練太慢一個epoch半小時調(diào)參一次等一天沒有GPU的機(jī)器上訓(xùn)練128×128的圖像一個epoch十幾分鐘很正常調(diào)幾次參就耗掉一整天。這個問題正文其實已經(jīng)提前想好了圖像壓縮到128×128就是為低算力環(huán)境設(shè)計的。在此基礎(chǔ)上還可以再省三步。一是把預(yù)處理結(jié)果緩存成npy文件避免每次訓(xùn)練都重新讀圖resize附錄2的做法已經(jīng)覆蓋。二是調(diào)低epoch上限配合EarlyStopping讓模型在驗證集不再變好時立刻停止。三是把batch_size從32升到64減少梯度更新次數(shù)犧牲一點收斂精度換訓(xùn)練速度。如果還嫌慢就砍掉一層卷積網(wǎng)絡(luò)淺一點訓(xùn)練快很多準(zhǔn)確率通常只掉兩三個點換來的是能跑起來的體驗。4.5 預(yù)測時shape報錯或圖片打不開跑預(yù)測腳本最容易遇到兩個報錯。第一個是PIL打開圖片失敗原因是圖片格式損壞或者路徑里有中文把路徑改成純英文即可這個坑在Windows環(huán)境下尤其常見。第二個是predict時shape不匹配原因是忘了np.expand_dims補(bǔ)batch維度或者訓(xùn)練時用的是RGB三通道、預(yù)測時圖片是RGBA四通道convert(RGB)能解決。這兩個錯誤都很隱蔽報錯信息也不算友好。最有效的排查方式是打印張量的shape一層一層對從圖像讀取、resize、歸一化到expand_dims每一步都確認(rèn)形狀符合預(yù)期。5. 二次開發(fā)讓模型適配你自己的垃圾識別場景5.1 換數(shù)據(jù)集目錄結(jié)構(gòu)不變改類別就行這套代碼的數(shù)據(jù)流是「目錄即標(biāo)簽」換數(shù)據(jù)集非常省事。把compressed目錄下的文件夾換成自己的類別名比如「快遞紙箱」「易拉罐」「剩飯」每類放幾百張圖直接從附錄2開始跑class_names.txt會自動更新。類別數(shù)量變了模型最后的Dense層輸出節(jié)點會自動對應(yīng)不用改其他代碼。如果類別超過十個每類樣本又只有幾百張一個簡單CNN可能不太夠這時候建議直接上遷移學(xué)習(xí)。5.2 換模型從零訓(xùn)練升級到遷移學(xué)習(xí)想要更快提升準(zhǔn)確率最快的方式是換預(yù)訓(xùn)練模型當(dāng)特征提取器。常規(guī)做法是把MobileNetV2在ImageNet上預(yù)訓(xùn)練好的權(quán)重拿過來凍結(jié)前面的骨干網(wǎng)絡(luò)只訓(xùn)練最后的分類層。MobileNetV2比ResNet50輕量得多更契合這個項目「低算力」的定位。代碼改動很小核心就是把Sequential里開頭的幾層Conv2D替換成一個預(yù)訓(xùn)練基座from tensorflow.keras.applications import MobileNetV2 base MobileNetV2( weightsimagenet, include_topFalse, input_shape(128, 128, 3) ) base.trainable False # 凍結(jié)骨干網(wǎng)絡(luò)只訓(xùn)練分類頭 model models.Sequential([ base, layers.GlobalAveragePooling2D(), layers.Dense(128, activationrelu), layers.Dropout(0.5), layers.Dense(num_classes, activationsoftmax) ])input_shape仍然保持128×128數(shù)據(jù)預(yù)處理完全不用重做。trainableFalse凍結(jié)基座后訓(xùn)練參數(shù)量從天量降到只有最后一小截CPU也能在十幾分鐘內(nèi)跑完。這一步跑通、準(zhǔn)確率穩(wěn)定之后再解凍最后幾層做微調(diào)學(xué)習(xí)率調(diào)低到1e-5效果還能再漲一截。5.3 換驗證方式混淆矩陣比準(zhǔn)確率誠實得多二次開發(fā)里最容易忽略的是驗證方式。準(zhǔn)確率只是一個平均值類別一多就會被高樣本量類別帶偏。建議每次訓(xùn)練完都打一張混淆矩陣看看哪個類別的召回率最低往往能發(fā)現(xiàn)模型把「紙箱」和「書本」這類形狀接近的類別搞混。這也是我在第4章踩過數(shù)據(jù)不平衡那個坑之后養(yǎng)成的習(xí)慣。從那以后我每次訓(xùn)練圖像模型都會先跑一遍小批量基線確認(rèn)loss曲線正常下降再開全量訓(xùn)練避免在錯誤配置上浪費幾個小時。希望幫到你。本文還有配套的精品資源點擊獲取