:圖像分類、微調(diào)與特征提取完整指南)
簡介面向MATLAB平臺深度學(xué)習(xí)使用者的VGG16工具包專用于圖像分類與特征提取借助Deep Learning Toolbox框架調(diào)用預(yù)訓(xùn)練卷積神經(jīng)網(wǎng)絡(luò)完成推理和遷移學(xué)習(xí)省去手動下載模型權(quán)重與配置環(huán)境的步驟。壓縮包內(nèi)共六個文件以四個m腳本文件為主體分別覆蓋模型加載、圖像預(yù)處理、分類預(yù)測和結(jié)果可視化等核心環(huán)節(jié)代碼結(jié)構(gòu)清晰便于二次修改另有一個license_addendum許可補充文件和一個xml配置文件用于明確授權(quán)范圍并注冊依賴支持包。整個資源包壓縮后僅2KB輕量精簡適合快速接入現(xiàn)有MATLAB項目。目前已有1664人學(xué)習(xí)下載。通過該工具包讀者可以拿到完整的VGG16調(diào)用腳本、配置說明與授權(quán)信息在本地環(huán)境中直接跑通圖像識別流程同時理解預(yù)訓(xùn)練模型在分類任務(wù)中的使用方式適合計算機視覺研究者、算法工程師以及深度學(xué)習(xí)初學(xué)者作為入門參考或二次開發(fā)基礎(chǔ)避免重復(fù)造輪子。1. 從一段 vgg16工具包.7z 聊起這個壓縮包到底能幫你省多少事如果你在網(wǎng)盤或同事的共享目錄里見過vgg16工具包.7z這個文件名大概率手里正攥著一個圖像分類、特征提取或遷移學(xué)習(xí)的活兒。這個壓縮包不是某個框架的官方安裝包而是把 VGG16 在落地時最常用的權(quán)重文件、配置文件、推理腳本、數(shù)據(jù)預(yù)處理邏輯和微調(diào)模板打包在一起讓你不用從零開始到處找模型文件、調(diào)歸一化參數(shù)、對著報錯猜 API 的“直接可用集合”。它的核心價值是在大多數(shù)公開數(shù)據(jù)集上你能在解壓后的第一小時就拿到一張圖片的 Top-5 分類結(jié)果在自己的業(yè)務(wù)數(shù)據(jù)上你能用它作為預(yù)訓(xùn)練權(quán)重做遷移學(xué)習(xí)省下幾周的 GPU 訓(xùn)練時間。這篇筆記就是按“這是什么→怎么跑通→怎么調(diào)→坑在哪”的順序把這個壓縮包拆開給新手一條可復(fù)現(xiàn)的操作路徑也把老手容易忽略的邊界條件點出來。2. 解開壓縮包之前VGG16 的參數(shù)規(guī)模、結(jié)構(gòu)記憶點和工具包內(nèi)部布局2.1 先用一句話喚起你對 VGG16 的結(jié)構(gòu)記憶——16 層到底數(shù)在哪里VGG16 的“16”指的是帶可學(xué)習(xí)參數(shù)的層數(shù)13 個卷積層加 3 個全連接層池化層和 ReLU 不算在內(nèi)。這個數(shù)字在落地時非常容易數(shù)錯因為很多人會把 5 個最大池化層也數(shù)進去然后在調(diào)整網(wǎng)絡(luò)頭時找錯層。結(jié)構(gòu)上它是一條非常直白的鏈?zhǔn)浇Y(jié)構(gòu)連續(xù)幾個 3×3 卷積后接一個 2×2 最大池化特征圖尺寸從 224×224 一路降到 7×7最后展平成 4096 維的向量再接兩個 4096 維的全連接層最后輸出 1000 類。絕大多數(shù)分類任務(wù)里你要動的位置只有一個最后一層全連接。而“工具包”里已經(jīng)預(yù)置好的就是這條鏈上每一層在 ImageNet 上訓(xùn)練得到的權(quán)重以及對應(yīng)的預(yù)處理要求。2.2 工具包.7z 的常見內(nèi)部布局權(quán)重、配置、腳本、樣例一個都不能少拿到壓縮包先別急著重命名文件夾。我見過的vgg16工具包.7z內(nèi)部布局雖然各家略有出入但大體逃不開這幾類內(nèi)容權(quán)重文件比如vgg16_weights_torch.pth或vgg16_weights_tf.h5、推理腳本infer.py、微調(diào)腳本train.py、配置文件config.yaml或config.py、類別標(biāo)簽文件imagenet_classes.txt以及一兩張測試圖片。文件名里的vgg16要和框架對應(yīng)起來這點后面專門講。解壓后我一般會先執(zhí)行一條find命令按文件擴展名把內(nèi)容摸一遍避免腳本里用了相對路徑但目錄結(jié)構(gòu)被改動過。unzip -l vgg16工具包.7z || 7z l vgg16工具包.7z注意Linux 下unzip解不開 7z 格式要么裝 p7zip-full 里的7z命令要么直接把壓縮包里的文件列表打出來。先看列表再解壓的好處是你能確認(rèn)權(quán)重文件是否分片、是不是有README也能提前發(fā)現(xiàn)某個腳本是不是依賴了額外的數(shù)據(jù)目錄。這一步別跳過尤其是從網(wǎng)盤上下載的包文件校驗非常關(guān)鍵。2.3 為什么這套是“工具包”而不是“模型文件”把硬編碼從業(yè)務(wù)代碼里剝離直接給一個.pth文件其實用起來很痛苦因為你要自己寫預(yù)處理、自己處理設(shè)備顯存、自己把類別標(biāo)簽拼回去。而工具包的思路是把這些重復(fù)勞動固化成腳本和配置圖片讀入、resize、中心裁剪、歸一化、forward、top-5 輸出、結(jié)果格式化能寫進公共函數(shù)就寫進公共函數(shù)。這樣做的落地價值是你做業(yè)務(wù)時只需要改數(shù)據(jù)路徑和類別文件不用每次重新調(diào)試預(yù)處理管道。我在某公司接過一個做包裝箱標(biāo)簽識別的活拿到手的包就是這種形式——里面的 VGG16 權(quán)重我只用來做特征提取最后加了自己的分類頭整個工程跟這個包的解耦關(guān)系非常干凈。3. 用 VGG16 工具包跑通第一張圖從解壓到輸出 Top-5 預(yù)測的完整命令3.1 解壓與目錄校驗先確認(rèn)哈希再動手這個步驟看起來多余但解壓出來的權(quán)重文件如果有損壞后面所有報錯都會被誤判成“模型沒加載對”。我一般會先解壓到一個獨立的目錄然后查看包內(nèi)是否自帶校驗信息文件比如checksums.txt。mkdir -p ./vgg16_kit 7z x vgg16工具包.7z -o./vgg16_kit cd ./vgg16_kit if [ -f checksums.txt ]; then sha256sum -c checksums.txt fi參數(shù)說明-o指定輸出目錄注意7z的-o后面不能有空格sha256sum -c會按照checksums.txt里預(yù)存的哈希逐文件比對輸出OK才算通過。如果包里沒帶校驗文件我會單獨對權(quán)重文件算一次哈希去對比壓縮包發(fā)布方給的哈希值兩邊都對不上就說明文件在傳輸過程中變了直接解壓跑大幾率會報“尺寸不匹配”或“加載權(quán)重時意外 EOF”。3.2 最小推理腳本30 行代碼跑通一張圖的分類我習(xí)慣先不碰包里帶的推理腳本自己寫一個最小可復(fù)現(xiàn)的版本用它來驗證權(quán)重文件和運行環(huán)境是否正常。這樣即使后續(xù)出問題調(diào)試范圍也被我限制住了。下面的腳本用 PyTorch 風(fēng)格加載權(quán)重輸入是任意一張圖片。import torch import torchvision.transforms as T from PIL import Image from torchvision.models import vgg16 # 加載模型替換掉原來的 1000 類分類頭但保留特征部分和全連接前兩層 model vgg16(weightsNone) state_dict torch.load(vgg16_weights_torch.pth, map_locationcpu) model.load_state_dict(state_dict) model.eval() # ImageNet 標(biāo)準(zhǔn)預(yù)處理參數(shù)RGB 三通道各自做標(biāo)準(zhǔn)化 mean, std [0.485, 0.456, 0.406], [0.229, 0.224, 0.225] tf T.Compose([ T.Resize(256), T.CenterCrop(224), T.ToTensor(), T.Normalize(mean, std) ]) img Image.open(test_dog.jpg).convert(RGB) x tf(img).unsqueeze(0) with torch.no_grad(): logits model(x) probs torch.softmax(logits, dim1) vals, idx torch.topk(probs, k5)這段代碼的關(guān)鍵點有兩個。第一load_state_dict要求權(quán)重文件的層名和vgg16()構(gòu)造出來的層名一一對應(yīng)如果工具包里給的是vgg16-397923af.pth這類官方哈希命名的文件你放心用如果給的是vgg16_weights_tf.h5那這個腳本跑不了因為那是 TensorFlow 的格式。第二Resize(256) CenterCrop(224)是 ImageNet 推理的標(biāo)準(zhǔn)尺寸策略直接把圖縮到 224 會讓精度掉一到兩個點這個差異在細(xì)分類任務(wù)里尤其明顯。3.3 三個必調(diào)的推理參數(shù)input_size、mean/std、解碼方式跑通了第一張圖后先別急著換成自己的業(yè)務(wù)數(shù)據(jù)把包里的config打開對照三個參數(shù)確認(rèn)一下。第一個是input_size確認(rèn)它是(224, 224)如果工具包為某個特殊場景改成了(320, 320)那么權(quán)重大概率也重訓(xùn)過不能用標(biāo)準(zhǔn) VGG16 權(quán)重替代。第二個是mean/std這兩個三元組必須是[0.485, 0.456, 0.406]和[0.229, 0.224, 0.225]這是 ImageNet 統(tǒng)計出來的很多人圖省事變ToTensor()后直接乘 255得到的結(jié)果就是錯亂的概率分布softmax 后所有類別都趨近于同一個值。第三個是解碼方式RGB讀取和BGR讀取出來的效果截然不同——如果權(quán)重是從 Caffe 格式轉(zhuǎn)過來的預(yù)處理里通常要保持 BGR 順序和減均值模式和 PyTorch 的標(biāo)準(zhǔn)不同。你可以先跑一張明顯的圖測試如果模型判斷正確的類別出現(xiàn)在 Top-5 里只是位置靠后大概率是預(yù)處理只有輕微偏差如果 Top-5 完全是驢唇不對馬嘴優(yōu)先檢查通道順序。4. 換個數(shù)據(jù)集再訓(xùn)練基于工具包做遷移學(xué)習(xí)與微調(diào)的落地方案4.1 凍結(jié)前幾層的微調(diào)實驗什么時候用 VGG16什么時候換架構(gòu)VGG16 放在今天依然適合很多中小型分類任務(wù)原因是它結(jié)構(gòu)簡單、調(diào)參經(jīng)驗豐富、社區(qū)踩坑記錄多。新項目里我不會一上來就換 ResNet 或 ViT先拿 VGG16 工具包跑一個 baseline 的結(jié)果跑不通說明數(shù)據(jù)和標(biāo)簽問題更大跑通了再決定要不要換更強的骨架。常見的微調(diào)策略是凍結(jié)前四個卷積塊只訓(xùn)練最后一個卷積塊和全連接頭這在數(shù)據(jù)量只有幾千張的情況下非常穩(wěn)。# 假設(shè) model 是 torchvision 風(fēng)格的 vgg16 count 0 for name, param in model.named_parameters(): param.requires_grad not param_name.startswith(features.0) and \ not param_name.startswith(features.1) and \ not param_name.startswith(features.2) and \ not param_name.startswith(features.3)這段代碼的邏輯features.0到features.3是前兩個卷積塊包含 block1 和 block2 的卷積和激活層VGG16 的features子模塊帶有序號索引你需要數(shù)清楚自己的權(quán)重文件對應(yīng) block 的序號邊界比如features.0~4是第一塊features.5~9是第二塊。凍結(jié)之后模型需要訓(xùn)練的參數(shù)量大概從 1.3 億降到 2000 萬左右這直接決定了你該選擇多大的 batch size。4.2 數(shù)據(jù)組織與標(biāo)簽文件ImageNet 格式還是簡單的目錄結(jié)構(gòu)VGG16 工具包里大概率有一份標(biāo)簽文件是 ImageNet 的 1000 個類別格式常常是每行一個類名。做遷移學(xué)習(xí)時你要么保留這 1000 類做一階微調(diào)要么替換掉最后一個全連接層輸出成自己的類別數(shù)。替換之后數(shù)據(jù)組織推薦用一個子目錄代表一個類別然后做一個train.txt和val.txt每行是圖片路徑 標(biāo)簽索引。這個格式很多舊的工具包腳本都認(rèn)改起來最快。dog_001.jpg 0 dog_002.jpg 0 cat_001.jpg 1注意標(biāo)簽索引必須從 0 開始不能從 1 開始否則和CrossEntropyLoss的默認(rèn)行為對不上。還有就是 VGG16 的特征層容量很大數(shù)據(jù)量少的時候特別容易把類別索引“背下來”所以標(biāo)簽 shuffle 和數(shù)據(jù)集劃分標(biāo)準(zhǔn)很重要常見的 8:2 劃分在幾千張的小數(shù)據(jù)上不穩(wěn)定建議直接用sklearn.model_selection.StratifiedShuffleSplit保證每個類別在兩個集合里都有足夠的比例。4.3 訓(xùn)練腳本里的關(guān)鍵超參數(shù)batch、lr、epsilon按經(jīng)驗給初始值VGG16 的全連接層參數(shù)量巨大如果用 224 輸入全連接第一層的權(quán)重矩陣是 25088×4096顯存占用比幾個卷積塊加起來還高。所以初始值我一般這樣給從零訓(xùn)練時batch32學(xué)習(xí)率1e-3用預(yù)訓(xùn)練權(quán)重微調(diào)時batch64學(xué)習(xí)率1e-4分類頭替換成新的輸出維度后新的全連接層學(xué)習(xí)率可以單獨設(shè)置成1e-3其余層保持1e-4。優(yōu)化器優(yōu)先選 SGD 加 momentum0.9權(quán)重衰減5e-4這和 ImageNet 預(yù)訓(xùn)練的配置靠得最近。如果你拿到的是一個config.yaml里面的weight_decay和lr_policy字段含義要與這幾個值對齊。以下是一組可以放進config.yaml的參考配置optimizer: type: sgd lr: 0.0001 momentum: 0.9 weight_decay: 0.0005 scheduler: type: step step_size: 30 gamma: 0.1 train: batch_size: 64 num_epochs: 50參數(shù)說明step_size30表示每訓(xùn)練 30 個 epoch 學(xué)習(xí)率乘以 0.1num_epochs50時會在第 30 和第 40 個 epoch 各降一次這也是圖像分類任務(wù)里一個非常保守但穩(wěn)定的學(xué)習(xí)率衰減節(jié)奏。你要記住 VGG16 本身不挑優(yōu)化器但挑學(xué)習(xí)率我見過很多人一上來用1e-3微調(diào)loss 直接沖到 Nan。與其反復(fù)調(diào)不如先把學(xué)習(xí)率降到3e-4試一個 epoch觀察 loss 的下降斜率再決定進退。5. 照著這些坑檢查你的 VGG16 工具包五個在真實環(huán)境里反復(fù)出現(xiàn)的翻車現(xiàn)場5.1 解壓報錯“file CRC mismatch”或者權(quán)重文件加載到一半停下來現(xiàn)象7z x解壓過程中提示某個文件 CRC 校驗失敗或者 Python 加載權(quán)重時提示unexpected end of data。這種問題最隱蔽因為問題不在代碼里而是壓縮包本身在下載過程中損壞。原因網(wǎng)盤下載被中斷、瀏覽器多線程下載工具對壓縮包做了拼接覆蓋、以及直接把.7z文件在手機和電腦之間騰挪導(dǎo)致文件頭損壞都會引起 CRC 錯誤。解決重新從來源處下載壓縮包下載完成后不要第一時間解壓先對.7z文件本身做一次校驗。工具包如果有sha256.txt比對這個如果沒有先嘗試用7z t vgg16工具包.7z做一次完整性測試。這個指令會挨個文件檢查壓縮包內(nèi)部數(shù)據(jù)比解壓過程中報錯更早暴露問題。7z t vgg16工具包.7z如果測試到一半卡住基本可以確定包有壞塊不要用7z y去強制跳過放在訓(xùn)練里會讓某些樣本反復(fù)概率崩潰得不償失。5.2 推理結(jié)果永遠(yuǎn)是少數(shù)幾個類別且置信度都接近 1.0現(xiàn)象無論輸入貓、狗還是汽車模型輸出永遠(yuǎn)在“柯基犬、金毛犬、貴賓犬”三個里面切換而且 softmax 后的概率都大于 0.99。原因這種癥狀十有八九是歸一化參數(shù)錯了具體說就是我前面提到過的mean和std被填成了 0 和 1或者輸入圖像被轉(zhuǎn)成了float之后沒有除以 255導(dǎo)致每個像素值都偏大。你喂給網(wǎng)絡(luò)的分布和 ImageNet 預(yù)訓(xùn)練分布相差太遠(yuǎn)網(wǎng)絡(luò)只能給出一個非?!白孕拧钡腻e誤結(jié)果。解決老老實實把歸一化參數(shù)寫成mean [0.485, 0.456, 0.406] std [0.229, 0.224, 0.225]ToTensor()已經(jīng)幫你做了像素值從 0~255 到 0~1 的縮放Normalize再按通道做減均值除方差。你把模型輸入直接打印出來看一眼像素值大致在-2.5~2.5之間就是對的如果成了-120~130問題就在這里。5.3 微調(diào)時 loss 在第一輪就變成 Nan 或者劇烈震蕩不下降現(xiàn)象加載 VGG16 預(yù)訓(xùn)練權(quán)重后用自己的數(shù)據(jù)微調(diào)第一個 epoch 的 loss 直接是 Nan或者 train loss 從 2.3 跳到 8.5 再跳到 3.1完全無收斂性。原因大多數(shù) Nan 來自全連接層替換后沒有做權(quán)重初始化。很多人直接把分類頭nn.Linear(4096, 1000)改成nn.Linear(4096, 5)但沒有給新層設(shè)置合理的初始化方式而 PyTorch 默認(rèn)的kaiming_uniform_和預(yù)訓(xùn)練層的分布差異很大會梯度爆炸。解決替換分類頭之后手動初始化或者干脆用一個小常數(shù)來放縮import torch.nn as nn head nn.Linear(4096, 5) nn.init.xavier_uniform_(head.weight, gain1.0) nn.init.zeros_(head.bias)另外如果你的數(shù)據(jù)類別非常多且不均衡不要用CrossEntropyLoss先試LabelSmoothingCrossEntropy或者把label_smoothing參數(shù)設(shè)為 0.1這能顯著抑制劇烈震蕩。還有一點全連接層前面加上nn.Dropout(p0.5)預(yù)訓(xùn)練權(quán)重本身是按有 Dropout 的分布訓(xùn)出來的去掉它會讓微調(diào)過程中全連接層過于敏感。5.4 torchvision 和 keras 的 VGG16 混用導(dǎo)致輸入通道順序錯亂現(xiàn)象同一個工具包里既有vgg16_weights_tf.h5又有vgg16_weights_torch.pth你按 PyTorch 習(xí)慣讀了一張圖喂給 TensorFlow 的權(quán)重結(jié)果 top-1 錯誤率直接超過 80%。原因TensorFlow 的 Keras 應(yīng)用層默認(rèn)輸入是(224, 224, 3)的 RGB內(nèi)部會把weights反轉(zhuǎn)變換PyTorch 的習(xí)慣是(3, 224, 224)的 C 維在前。如果你從包里的樣例腳本抽了一個preprocess_input函數(shù)它通常是 Keras 風(fēng)格的x x - 111.0之類的“減去均值但不除方差”方案換到 PyTorch 的 Normalize 邏輯上就是雙重錯誤。解決只要看到.h5和.pth兩個文件同時出現(xiàn)在一個包里就直接用對應(yīng)框架各自的預(yù)處理流程。一種更省心的做法是只在 PyTorch 環(huán)境里把.h5轉(zhuǎn)成.pth但需要按 Keras 的層名映射表逐層拷貝權(quán)重這個過程非常容易漏層。我的建議是推理和微調(diào)全程只用同一個框架的文件因為轉(zhuǎn)換過程中最容易被替換錯的就是卷積核通道順序。5.5 顯存占用超出預(yù)期訓(xùn)練連 batch_size8 都炸現(xiàn)象一張 12G 顯存的卡batch size 設(shè)成 8輸入是 224×224一開始訓(xùn)練就報 CUDA out of memory。原因VGG16 的前兩個全連接層每個都有 4096 個神經(jīng)元中間連了一層 25088×4096 的矩陣這層光是權(quán)重就占 400MB前向和反向過程中的激活值顯存會把這個數(shù)字放大 3~4 倍。很多人以為把batch_size從 32 降到 8 就能繼續(xù)跑但你忽略了 7×7×512 的 feature map 本身也要保留梯度。解決換一種思路微調(diào)時凍結(jié)前幾層卷積塊像第 4 章那樣只訓(xùn)練最后一個塊和全連接頭。另外可以在forward里加上torch.cuda.empty_cache()的時機但更有效的是把數(shù)據(jù)加載器的num_workers調(diào)低一些避免數(shù)據(jù)預(yù)取和模型并行搶顯存。如果你用的是 PyTorch 2.x 及以上版本開啟torch.compile(model)也可以減少一部分內(nèi)存峰值但注意編譯時間和算子兼容性老 GPU 卡容易在編譯后出現(xiàn)推理結(jié)果不同的問題。6. 把工具包用得更順手用 VGG16 做特征提取搭一套復(fù)用到不同任務(wù)的圖像特征引擎6.1 抽 Feature 時用哪一層的輸出——pool5 比 fc1 更“通用”做遷移學(xué)習(xí)的人都知道要從 VGG16 中間層抽取特征但具體取哪一層是個岔路。我一般不會用fc1或者fc2的輸出因為 4096 維向量維度高、又高度偏向 ImageNet 的類別結(jié)構(gòu)我常用的是最后一個池化層pool5對應(yīng)輸出是(512, 7, 7)的特征圖先做全局平均池化得到 512 維的向量。這個向量保留了較多空間結(jié)構(gòu)信息在對新類別做分類時配合一個簡單的sklearn.svm.LinearSVC或者LogisticRegression效果往往比直接用 fc1 的 4096 維向量好一截。做法是替換掉分類頭輸出nn.AdaptiveAvgPool2d((1, 1))。import torch.nn as nn import torch.nn.functional as F class VGGExtractor(torch.nn.Module): def __init__(self, base): super().__init__() self.features base.features self.avgpool nn.AdaptiveAvgPool2d((1, 1)) self.fc base.classifier[0] # 只取第一個全連接層前的展平操作不用 def forward(self, x): x self.features(x) x self.avgpool(x) x torch.flatten(x, 1) return F.normalize(x, p2, dim1)注意這個寫法里base.classifier[0]是nn.Linear(25088, 4096)我故意不用它因為沒有必要把 512 維特征圖強行展平成 25088 維再去過全連接層。改為avgpool之后特征維數(shù)是 512對后續(xù)分類器更友好訓(xùn)練也更快。6.2 把工具包的腳本改造成一條龍配置驅(qū)動 批量處理當(dāng)你發(fā)現(xiàn)你需要在十多個數(shù)據(jù)集上反復(fù)抽特征時就會后悔當(dāng)初沒有把工具包里的腳本再封裝一層。我的習(xí)慣是準(zhǔn)備一個extract.py它只負(fù)責(zé)三件事讀配置里的權(quán)重路徑讀配置里的圖片目錄把特征寫成.npy文件。這樣的好處是業(yè)務(wù)側(cè)完全不碰模型框架你面對的就是一個特征文件拿去訓(xùn)練任何機器學(xué)習(xí)模型都可以。python extract.py --config configs/dog.yaml --split train python extract.py --config configs/dog.yaml --split valdog.yaml里面寫的是數(shù)據(jù)目錄、輸出目錄、權(quán)重路徑、是否做水平翻轉(zhuǎn)增強等參數(shù)。翻轉(zhuǎn)增強的策略我自己踩過一個坑如果抽取特征時同時保留原圖和翻轉(zhuǎn)圖的特征拼接分類精度會穩(wěn)定提高約 0.5~1 個百分點但計算量翻倍。如果你是在做提交比賽類的任務(wù)這個方法值得用如果是上線系統(tǒng)就要考慮線上推理時會不會多一次翻轉(zhuǎn)計算。說到底vgg16工具包.7z這種包的價值不在壓縮算法本身而在它把一個經(jīng)典網(wǎng)絡(luò)做成了一套可以讓業(yè)務(wù)直接消費的組件。它給了你一個可以反復(fù)使用的標(biāo)準(zhǔn)步驟校驗、推理、微調(diào)、抽特征。我現(xiàn)在的習(xí)慣是收到任何工具包都先按這個順序走一遍驗證沒問題再進業(yè)務(wù)代碼如果哪天你遇到一個解壓就能跑、跑通了還沒出坑的包請記住這一次的順利是權(quán)重文件、腳本參數(shù)和環(huán)境三者恰好在同一頻段上的結(jié)果。希望這篇筆記里的每一步和五個翻車現(xiàn)場能讓你在拿到下一個工具包時少走幾段彎路。本文還有配套的精品資源點擊獲取