人流量檢測(cè):深度可分離卷積與追蹤計(jì)數(shù)實(shí)現(xiàn))
簡(jiǎn)介基于深度學(xué)習(xí)的人流量檢測(cè)方法的論文參考資料適合畢業(yè)設(shè)計(jì)、課程設(shè)計(jì)及論文寫作借鑒。內(nèi)容圍繞輕量級(jí)MobileNet-SSD模型展開詳述了從自制數(shù)據(jù)集、模型訓(xùn)練到行人檢測(cè)與追蹤的完整流程并面向公園、文化廣場(chǎng)等行人移動(dòng)緩慢的特定場(chǎng)景提供了應(yīng)用方案整體邏輯緊密、專業(yè)嚴(yán)謹(jǐn)。資源包為1個(gè)docx文檔大小約224KB屬于純論文類學(xué)習(xí)資料便于閱讀和批注。目前已有81人學(xué)習(xí)下載。文中還包含模型35層結(jié)構(gòu)、深度可分離卷積層及SSD檢測(cè)層配置以及Ubuntu 16.04Caffe等環(huán)境下的訓(xùn)練細(xì)節(jié)可為類似人流量檢測(cè)項(xiàng)目提供具體的實(shí)現(xiàn)思路與參數(shù)參考但該資料定位為論文學(xué)習(xí)參考而非項(xiàng)目源碼建議讀者深入理解后獨(dú)立完成自己的設(shè)計(jì)與寫作。1. 為什么人流量檢測(cè)要換輕量級(jí)網(wǎng)絡(luò)MobileNet-SSD 的選型邏輯與論文能給你的東西公園和文化廣場(chǎng)這類場(chǎng)景看著開闊實(shí)際做視覺人流量檢測(cè)時(shí)很頭疼嬰兒車多、行人走得不快不慢遮擋頻繁再加上疫情特殊時(shí)期要實(shí)時(shí)統(tǒng)計(jì)密度、及時(shí)疏散傳統(tǒng)的 AlexNet、VGG 這類大模型在監(jiān)控端根本跑不動(dòng)。本論文給出的方案是 MobileNet-SSD——用深度可分離卷積把標(biāo)準(zhǔn)卷積核拆開算比傳統(tǒng)卷積少 8 到 9 倍計(jì)算量模型小了、速度反而上去正好卡在移動(dòng)端或嵌入式芯片的算力邊界上。全文按專利格式寫從數(shù)據(jù)集構(gòu)建、Caffe 訓(xùn)練到追蹤計(jì)數(shù)六個(gè)模塊一條線走通參數(shù)給得很具體輸入特征圖 300×100×3、基礎(chǔ)學(xué)習(xí)率 0.0005、訓(xùn)練 35000 次、跳幀數(shù) N30。不管是做畢設(shè)選型參考還是課程設(shè)計(jì)里需要一份能講清為什么選這個(gè)模型的寫作范本這份材料都值得先讀一遍再動(dòng)手。2. 深度可分離卷積與 MobileNet-SSD 網(wǎng)絡(luò)結(jié)構(gòu)35 層怎么搭、6 個(gè)檢測(cè)層怎么選2.1 深度可分離卷積為什么能省計(jì)算先按通道算再用 1×1 點(diǎn)卷積融合MobileNet 系列的核心思路不是發(fā)明新網(wǎng)絡(luò)而是把標(biāo)準(zhǔn)卷積的計(jì)算過程拆成兩步。標(biāo)準(zhǔn)卷積核是 DK×DK 的同時(shí)處理輸入的所有通道假設(shè)輸入維度 M、輸出維度 N、特征圖尺寸 DF×DF一次標(biāo)準(zhǔn)卷積的計(jì)算量是DK * DK * M * N * DF * DF深度可分離卷積把這一步拆成深度卷積和點(diǎn)卷積兩步。深度卷積先按通道分別做 DK×DK 的空間卷積此時(shí)通道數(shù)不變計(jì)算量為 DK×DK×M×DF×DF隨后再用 1×1 卷積做通道間的線性組合計(jì)算量為 M×N×DF×DF??傆?jì)算量DK * DK * M * DF * DF M * N * DF * DF當(dāng) DK3 時(shí)兩者比值約等于 1/8 到 1/9這就是論文里少 8 到 9 倍計(jì)算量的來歷。有個(gè)細(xì)節(jié)值得注意深度卷積這一步只操作單通道所以整個(gè)深度可分離卷積里約 95% 的計(jì)算量集中在 1×1 點(diǎn)卷積上。知道這一條調(diào)參時(shí)就能明白為什么加寬度乘數(shù)對(duì)速度的改善比改分辨率更直接。MobileNet 還給了兩個(gè)超參數(shù)做進(jìn)一步壓縮。寬度乘數(shù) α 作用在通道數(shù)上輸入通道變成 αM、輸出通道變成 αN分辨率乘數(shù) ρ 作用在特征圖上。兩個(gè)參數(shù)引入后的計(jì)算量公式論文里都有簡(jiǎn)單說就是α 越小模型越細(xì)ρ 越小輸入圖越小實(shí)際部署時(shí)一般先固定一個(gè)只調(diào)另一個(gè)不然兩個(gè)參數(shù)一起動(dòng)很難判斷瓶頸在哪。2.2 35 層網(wǎng)絡(luò)逐層拆解Input 到 Conv13 是骨干Conv14 到 Conv17 是 SSD 加的預(yù)測(cè)層論文把 MobileNet-SSD 的結(jié)構(gòu)寫得非常清楚總共有 35 層從 Conv0 到 Conv13 這部分與 MobileNet v1 骨干完全一致相當(dāng)于去掉了全局平均池化、全連接層和 Softmax然后接 8 個(gè)標(biāo)準(zhǔn)卷積層用于 SSD 檢測(cè)即 Conv14_1 到 Conv17_2。每一層輸出特征圖的尺寸和通道數(shù)論文里都列了層名輸出尺寸層類型Input300×100×3輸入層Conv0150×150×323×3 標(biāo)準(zhǔn)卷積Conv1150×150×64深度可分離卷積Conv2/375×75×128深度可分離卷積Conv4/538×38×256深度可分離卷積Conv6~Conv1119×19×512深度可分離卷積Conv12/1310×10×1024深度可分離卷積Conv14_1/14_210×10×256 / 5×5×5121×1 標(biāo)準(zhǔn)卷積Conv15_1/15_25×5×128 / 3×3×2561×1 標(biāo)準(zhǔn)卷積Conv16_1/16_23×3×128 / 2×2×2561×1 標(biāo)準(zhǔn)卷積Conv17_1/17_22×2×64 / 1×1×1281×1 標(biāo)準(zhǔn)卷積注意這里輸入的 300×100×3 不是常規(guī)的 300×300×3論文針對(duì)監(jiān)控畫面比例做了調(diào)整特征圖尺寸也不是整數(shù)倍的縮放寫論文或復(fù)現(xiàn)時(shí)要按這個(gè)尺寸來設(shè)置輸入層不要想當(dāng)然改成正方形。每個(gè)深度可分離卷積層內(nèi)部包含一層深度卷積和一層點(diǎn)卷積嚴(yán)格說 13 個(gè)深度可分離卷積層對(duì)應(yīng) 26 層計(jì)算加上首層標(biāo)準(zhǔn)卷積和末尾 8 個(gè)標(biāo)準(zhǔn)卷積總數(shù)對(duì)得上。SSD 檢測(cè)框架從 35 層中抽了 6 層做多尺度預(yù)測(cè)Conv1119×19×512、Conv1310×10×1024、Conv14_25×5×512、Conv15_23×3×256、Conv16_22×2×256、Conv17_21×1×128。選這 6 層的邏輯是淺層特征圖分辨率高、感受野小適合找小目標(biāo)深層特征圖分辨率低但語義信息強(qiáng)適合找大目標(biāo)。換句話說嬰兒車和行人在畫面里的尺度差異大單靠某一層特征圖做檢測(cè)漏檢率會(huì)很高。2.3 論文寫作里怎么把網(wǎng)絡(luò)結(jié)構(gòu)講清楚先參數(shù)后尺寸再落到檢測(cè)層如果你只是引用這篇論文的思路寫自己的畢設(shè)結(jié)構(gòu)部分最值得抄的寫法是先定義卷積核再說明特征圖變化。原文在權(quán)利要求書里是按卷積核個(gè)數(shù)、卷積核大小、卷積核步數(shù)、權(quán)值初始化方法這個(gè)順序描述網(wǎng)絡(luò)文件的這也正是 Caffe 里 prototxt 的字段順序。下面這段是參考該論文結(jié)構(gòu)寫網(wǎng)絡(luò)文件時(shí)的常見寫法layer { name: conv0 type: Convolution bottom: data top: conv0 convolution_param { num_output: 32 kernel_size: 3 stride: 2 pad: 1 weight_filler { type: xavier } } }參數(shù)說明num_output 對(duì)應(yīng)輸出通道數(shù)kernel_size 是卷積核邊長(zhǎng)stride 為步長(zhǎng)pad 是補(bǔ)零寬度。寫論文時(shí)不要只貼這段配置要把 Conv0 的標(biāo)準(zhǔn)卷積、Conv1 到 Conv13 的深度可分離卷積和 Conv14 到 Conv17 的標(biāo)準(zhǔn)卷積三類層的差異用一段話講清楚再配合前面那張尺寸表評(píng)審不用看代碼也能復(fù)現(xiàn)網(wǎng)絡(luò)。我一般會(huì)建議把 6 個(gè)檢測(cè)層單獨(dú)畫一張小圖標(biāo)注每層的特征圖尺寸和 anchor 數(shù)量。SSD 的 default box 輸出空間是離散化的不同尺寸的 default box 需要分配到不同層圖上標(biāo)清楚哪一層負(fù)責(zé)多大目標(biāo)比大段文字描述直觀得多。3. 自建數(shù)據(jù)集與 Caffe 訓(xùn)練配置爬蟲數(shù)據(jù) VOC person 的合并流程3.1 數(shù)據(jù)集怎么來爬蟲抓嬰兒車VOC 拿 person再做標(biāo)簽一一映射論文里步驟 S1 寫得很實(shí)在用網(wǎng)絡(luò)爬蟲爬取大量嬰兒車數(shù)據(jù)集再結(jié)合 VOC 數(shù)據(jù)集中類別為 person 的數(shù)據(jù)合并制作自己的數(shù)據(jù)集同時(shí)建立數(shù)據(jù)與標(biāo)簽之間的一一映射。這個(gè)思路對(duì)畢設(shè)場(chǎng)景特別實(shí)用——VOC 的 person 類別有現(xiàn)成標(biāo)注嬰兒車是特殊場(chǎng)景目標(biāo)公開數(shù)據(jù)集里很少只能自己爬自己標(biāo)。合并數(shù)據(jù)集時(shí)最容易被忽略的是標(biāo)簽文件格式的統(tǒng)一。VOC 的標(biāo)注是 XML 格式每張圖對(duì)應(yīng)一個(gè)同名 XML目標(biāo)類別、邊界框坐標(biāo)都寫在里面爬蟲抓來的圖要先人工篩選去掉重復(fù)和模糊的再用標(biāo)注工具生成同樣格式的 XML。論文強(qiáng)調(diào)數(shù)據(jù)與標(biāo)簽一一映射實(shí)際操作中我一般會(huì)在合并后跑一遍校驗(yàn)?zāi)_本檢查有沒有圖片缺失標(biāo)簽、標(biāo)簽里有沒有類別名寫錯(cuò)的情況這類錯(cuò)誤在訓(xùn)練時(shí)表現(xiàn)成 loss 異常波動(dòng)排查起來很費(fèi)時(shí)間。3.2 trainval 90% 再取 90%兩級(jí)劃分的用意論文對(duì)數(shù)據(jù)劃分的描述值得細(xì)讀取整個(gè)數(shù)據(jù)集的 90% 作為 trainval 文件再取 trainval 的 90% 作為訓(xùn)練集剩下的 10% 作為驗(yàn)證集且訓(xùn)練集與驗(yàn)證集數(shù)據(jù)之間沒有重復(fù)。這個(gè)兩級(jí)劃分的好處是trainval 占全量的 90%訓(xùn)練集占 trainval 的 90%意味著訓(xùn)練集約占全量的 81%驗(yàn)證集約 9%還有一個(gè)測(cè)試集約 10% 留在外面做最終評(píng)估。這里有個(gè)容易理解錯(cuò)的地方——取整個(gè)數(shù)據(jù)集的 90% 作為 trainval 不代表訓(xùn)練只用 90%而是先把 10% 的測(cè)試數(shù)據(jù)隔離出來再在剩余的 90% 里切訓(xùn)練集和驗(yàn)證集。很多初學(xué)者直接把數(shù)據(jù)隨機(jī)按 8:1:1 切忽略了測(cè)試集必須全程不參與訓(xùn)練和驗(yàn)證集劃分這個(gè)原則。論文這種兩級(jí)切法在代碼里實(shí)現(xiàn)是這樣import os import random from shutil import copyfile # 假設(shè) images 目錄下是所有圖片annotations 是對(duì)應(yīng) XML all_files [f for f in os.listdir(images) if f.endswith(.jpg)] random.seed(42) random.shuffle(all_files) # 第一級(jí)劃分全量的 90% 用作 trainval10% 用作 test split_idx_1 int(len(all_files) * 0.9) trainval_files all_files[:split_idx_1] test_files all_files[split_idx_1:] # 第二級(jí)劃分trainval 的 90% 用作 train10% 用作 val split_idx_2 int(len(trainval_files) * 0.9) train_files trainval_files[:split_idx_2] val_files trainval_files[split_idx_2:] # 生成 trainval.txt / train.txt / val.txt / test.txt with open(trainval.txt, w) as f: for name in trainval_files: f.write(name.replace(.jpg, ) \n) # train/val/test 的 txt 文件寫入方式相同不再重復(fù)邏輯說明這里先對(duì)全部文件做一次 shuffle再按比例切分保證訓(xùn)練、驗(yàn)證、測(cè)試三個(gè)集合的數(shù)據(jù)分布一致。實(shí)際數(shù)據(jù)集如果類別不平衡比如嬰兒車樣本明顯少于行人建議在 shuffle 前先按類別做分層采樣避免某一折里全是行人沒有嬰兒車。參數(shù)說明random.seed(42) 固定隨機(jī)種子保證每次運(yùn)行切分結(jié)果一致。split_idx_1 和 split_idx_2 是切分邊界調(diào)整比例時(shí)只需要改 0.9 這個(gè)系數(shù)。生成的 txt 文件每行是圖片文件名不帶擴(kuò)展名Caffe 的 ImageData 層和 VOC 檢測(cè)訓(xùn)練腳本都依賴這個(gè)格式。3.3 solver 參數(shù)與訓(xùn)練環(huán)境base_lr 0.0005、snapshot 1000、迭代 35000 次論文給出了一套完整的 Caffe 訓(xùn)練參數(shù)開發(fā)環(huán)境是 Ubuntu 16.04 CUDA 8.0 CUDNN 6.0 OpenCV 3.1 Caffe訓(xùn)練迭代 35000 次。solver 文件核心參數(shù)如下net: MobileNet-SSD_train.prototxt test_iter: 200 test_interval: 1000 base_lr: 0.0005 momentum: 0.9 weight_decay: 0.0005 lr_policy: multistep gamma: 0.5 stepvalue: 20000 stepvalue: 30000 snapshot: 1000 snapshot_prefix: snapshot/mobilenet_ssd solver_mode: GPU參數(shù)說明base_lr 設(shè)為 0.0005比常用 SSD 的默認(rèn)學(xué)習(xí)率低因?yàn)槭亲越ㄐ?shù)據(jù)集學(xué)習(xí)率太高容易震蕩。snapshot 設(shè)為 1000即每迭代 1000 步保存一次 caffemodel 和狀態(tài)文件訓(xùn)練中斷后可以從最近快照恢復(fù)。solver_mode 設(shè)為 GPU對(duì)應(yīng)論文里的訓(xùn)練方式。multistep 策略配合 gamma 0.5在 20000 步和 30000 步時(shí)學(xué)習(xí)率減半保證后期收斂穩(wěn)定。訓(xùn)練時(shí)我習(xí)慣把test_interval與snapshot保持一致這樣每次保存模型的同時(shí)就能拿到驗(yàn)證集上的精度指標(biāo)方便對(duì)照是精度提升還是過擬合。35000 次迭代跑完大概需要多長(zhǎng)時(shí)間取決于顯卡論文里的訓(xùn)練環(huán)境是 2019 年前后的主流配置現(xiàn)在用一張中端卡復(fù)現(xiàn)時(shí)間只會(huì)更短。訓(xùn)練集和驗(yàn)證集的用途在論文里也做了區(qū)分訓(xùn)練集用于訓(xùn)練模型以及模型權(quán)重驗(yàn)證集用于確定網(wǎng)絡(luò)結(jié)構(gòu)以及調(diào)整模型的超參數(shù)。這意味著驗(yàn)證集不是拿來看 loss 曲線的而是要真實(shí)地評(píng)估模型在未見數(shù)據(jù)上的泛化表現(xiàn)調(diào)參時(shí)以驗(yàn)證集 mAP 為準(zhǔn)而不是訓(xùn)練集 loss。4. 視頻輸入的檢測(cè)—追蹤流程跳幀閾值 30 與質(zhì)心跟蹤如何配合4.1 狀態(tài)機(jī) waiting/detecting/tracking 與視頻預(yù)處理論文把整個(gè)視頻處理流程抽象成一個(gè)三狀態(tài)狀態(tài)機(jī)初始狀態(tài)為 waiting系統(tǒng)等待對(duì)行人的檢測(cè)和跟蹤檢測(cè)時(shí)進(jìn)入 detecting調(diào)用 MobileNet-SSD 對(duì)當(dāng)前幀做目標(biāo)檢測(cè)檢測(cè)到目標(biāo)后切換為 tracking對(duì)行人進(jìn)行追蹤。這個(gè)設(shè)計(jì)的價(jià)值在于把檢測(cè)和追蹤解耦不會(huì)出現(xiàn)每一幀都在跑檢測(cè)這種計(jì)算浪費(fèi)。數(shù)據(jù)輸入模塊初始化時(shí)需要做四件事初始化視頻流、初始化視頻編寫器、初始化框架尺寸、初始化存儲(chǔ)列表。支持 .MP4 和 .AVI 等預(yù)存視頻文件也支持直接用攝像頭獲取實(shí)時(shí)視頻流。數(shù)據(jù)預(yù)處理包括加載預(yù)訓(xùn)練模型、調(diào)整通道大小、將幀從 BGR 轉(zhuǎn)換到 RGB——這是 OpenCV 讀取圖像的默認(rèn) BGR 格式與 Caffe 模型訓(xùn)練時(shí) RGB 格式之間的必要轉(zhuǎn)換。同時(shí)把視頻幀的最大寬度設(shè)置為 500 像素畫面越小處理越快論文在 i5-7200 CPU、8GB 內(nèi)存的測(cè)試環(huán)境下就是這么跑起來的?;谏疃葘W(xué)習(xí)的視頻分析一般建議先在本地用小分辨率驗(yàn)證流程再逐步上調(diào)分辨率找精度和速度的平衡點(diǎn)。4.2 跳幀 N30為什么不用每幀都跑 SSDSSD 每幀做一次前向推理在 CPU 環(huán)境下很難達(dá)到實(shí)時(shí)。論文的解法是設(shè)置跳過幀參數(shù) N30每 30 幀才用 SSD 做一次完整檢測(cè)其余幀只做追蹤。這樣檢測(cè)和追蹤交替執(zhí)行畫面里行人的位置靠追蹤器來補(bǔ)充。在行人移動(dòng)速度慢的公園、文化廣場(chǎng)場(chǎng)景30 幀的間隔約等于 1 秒按 30fps 視頻算這個(gè)頻率足夠跟上慢速移動(dòng)的目標(biāo)。實(shí)現(xiàn)時(shí)狀態(tài)切換的邏輯可以直接參考論文描述frame_count 0 N 30 state waiting while True: ret, frame video.read() if not ret: break frame_count 1 # 達(dá)到跳過幀時(shí)運(yùn)行檢測(cè)器否則運(yùn)行追蹤器 if frame_count % N 0: detections detector.detect(frame) state detecting # 檢測(cè)結(jié)果傳入追蹤器做質(zhì)心關(guān)聯(lián) else: tracker.update(frame) state tracking邏輯說明frame_count 對(duì)輸入視頻逐幀計(jì)數(shù)每 N 幀才調(diào)用一次 detector.detect()其余幀調(diào)用 tracker.update() 維護(hù)既有目標(biāo)的軌跡。第一次進(jìn)入循環(huán)時(shí)沒有初始化的追蹤目標(biāo)所以狀態(tài)從 waiting 開始檢測(cè)到行人并注冊(cè)對(duì)象 ID 后才進(jìn)入 tracking。判斷是否達(dá)到跳過幀的目的就是加快跟蹤流程避免每幀都跑目標(biāo)檢測(cè)器。參數(shù)說明N 的默認(rèn)值是 30實(shí)際使用中可以按行人速度調(diào)整——行人走得快就減小 N走得慢就增大 N。論文里沒有機(jī)械地寫死而是說根據(jù)實(shí)際情況跳過 N 幀這個(gè)思路在工程上更合理。4.3 質(zhì)心跟蹤 dlib 追蹤新舊質(zhì)心歐氏距離怎么關(guān)聯(lián)目標(biāo)追蹤部分用了兩條線并行質(zhì)心跟蹤算法負(fù)責(zé)關(guān)聯(lián)檢測(cè)到的目標(biāo)框dlib 跟蹤器負(fù)責(zé)在幀間跟蹤目標(biāo)位置。質(zhì)心跟蹤的流程論文寫得很細(xì)先從檢測(cè)模塊拿到邊界框坐標(biāo)計(jì)算邊界框中心作為質(zhì)心然后計(jì)算新質(zhì)心和現(xiàn)有質(zhì)心之間的歐幾里得距離。關(guān)聯(lián)策略是典型的貪心匹配每個(gè)新質(zhì)心選擇距離最近的現(xiàn)有質(zhì)心進(jìn)行關(guān)聯(lián)關(guān)聯(lián)成功后更新質(zhì)心位置如果新質(zhì)心沒有與之關(guān)聯(lián)的現(xiàn)有質(zhì)心就注冊(cè)一個(gè)新的對(duì)象 ID。這里有個(gè)關(guān)鍵細(xì)節(jié)需要注意——貪心匹配在目標(biāo)交叉、遮擋時(shí)容易 ID Switch兩個(gè)目標(biāo)靠近時(shí)分配錯(cuò)誤 ID論文的做法是用 dlib 跟蹤器的預(yù)測(cè)來彌補(bǔ)dlib 將目標(biāo)邊界框在前一幀的的先驗(yàn)位置與當(dāng)前幀獲得的數(shù)據(jù)組合推斷目標(biāo)新位置使跟蹤框即使在檢測(cè)間斷期也能跟上目標(biāo)。dlib 位姿估計(jì)在這里不是用來畫關(guān)鍵點(diǎn)的而是用來提供更魯棒的幀間目標(biāo)位置。我在實(shí)際部署中會(huì)把 dlib 跟蹤器的輸出與質(zhì)心計(jì)算的輸入做一次融合判斷如果兩者偏差過大比如超過邊界框?qū)挾鹊?30%優(yōu)先信任檢測(cè)結(jié)果而不是跟蹤結(jié)果這能顯著減少跟丟后的錯(cuò)誤關(guān)聯(lián)。4.4 進(jìn)出計(jì)數(shù)畫一條基準(zhǔn)線判斷移動(dòng)方向結(jié)果輸出模塊在畫面上繪制一條水平線作為計(jì)數(shù)基準(zhǔn)。行人穿過這條線時(shí)根據(jù)移動(dòng)方向分別累加進(jìn)或出的計(jì)數(shù)器。這里的核心邏輯是通過質(zhì)心跟蹤算法已經(jīng)將對(duì)象 ID 與對(duì)象位置關(guān)聯(lián)后續(xù)只需判斷對(duì)象質(zhì)心在相鄰幀間相對(duì)基準(zhǔn)線的位置變化。論文用 Up 和 Down 兩個(gè)數(shù)值表示不同方向的人流量并注明這是攝像頭俯視角度下的定義目標(biāo)向畫面上方移動(dòng)記為 Down向畫面下方移動(dòng)記為 Up。具體的計(jì)數(shù)規(guī)則是上一幀質(zhì)心在基準(zhǔn)線上方、當(dāng)前幀質(zhì)心在基準(zhǔn)線下方則屬于進(jìn)入反之屬于離開。這樣一套邏輯在人流量密集時(shí)不那么準(zhǔn)但在論文設(shè)定的公園、廣場(chǎng)這類空曠場(chǎng)景下足夠用。5. 復(fù)現(xiàn)避坑Caffe 環(huán)境、弱檢測(cè)過濾、跳幀參數(shù)這三處最翻車5.1 現(xiàn)象Caffe 編譯通過但訓(xùn)練到一半報(bào) Check failed: datum_channels 0原因論文用的是 Ubuntu 16.04 CUDA 8.0 CUDNN 6.0 Caffe 的組合這個(gè)版本組合里 OpenCV 3.1 的 cv::imread 返回的三通道順序是 BGR而 Caffe 的 ImageData 層默認(rèn)按 RGB 讀圖數(shù)據(jù)預(yù)處理部分如果沒做 BGR 到 RGB 轉(zhuǎn)換讀進(jìn)來的通道數(shù)不會(huì)報(bào)錯(cuò)但會(huì)在訓(xùn)練時(shí)出現(xiàn) loss 不下降甚至直接崩掉。解決在數(shù)據(jù)輸入層之前統(tǒng)一加一次通道轉(zhuǎn)換或者直接修改 Caffe 源碼里 data layer 的 read 邏輯。論文在步驟 S3 里明確寫了預(yù)處理包含將幀從 BGR 到 RGB 轉(zhuǎn)換這個(gè)轉(zhuǎn)換不能省。換用新版 Caffe 分支時(shí)還要注意 CUDNN 版本匹配CUDNN 6.0 和完 7.0 的接口不兼容編譯報(bào)錯(cuò)的概率很高。5.2 現(xiàn)象檢測(cè)結(jié)果里全是人嬰兒車基本沒檢出原因數(shù)據(jù)集融合時(shí)比例失衡。論文要求爬取嬰兒車數(shù)據(jù)再結(jié)合 VOC person 數(shù)據(jù)但沒有規(guī)定數(shù)量比例。如果 VOC person 的數(shù)據(jù)量遠(yuǎn)大于爬取的嬰兒車樣本模型訓(xùn)練時(shí)會(huì)偏向多數(shù)類SSD 的 default box 匹配策略對(duì)少樣本類別的召回率會(huì)明顯下降。解決合并數(shù)據(jù)集時(shí)做類別均衡嬰兒車樣本不足時(shí)用數(shù)據(jù)增強(qiáng)來補(bǔ)——水平翻轉(zhuǎn)、亮度擾動(dòng)、隨機(jī)裁剪都有效。我一般會(huì)把嬰兒車主目錄下的圖片復(fù)制一份做增強(qiáng)后放進(jìn)訓(xùn)練集保證兩類樣本比例不低于 1:3。訓(xùn)練時(shí)也留意一下 log 里各類別的 AP 值如果嬰兒車 AP 明顯低于 person優(yōu)先補(bǔ)數(shù)據(jù)而不是調(diào)網(wǎng)絡(luò)結(jié)構(gòu)。5.3 現(xiàn)象計(jì)數(shù)結(jié)果在行人交叉時(shí)出現(xiàn)來回跳變?cè)蛱鴰瑓?shù) N 設(shè)置偏大目標(biāo)在兩次檢測(cè)之間移動(dòng)距離超過質(zhì)心關(guān)聯(lián)的容差范圍舊質(zhì)心和新的檢測(cè)質(zhì)心匹配不上被注冊(cè)成新 ID行人交叉時(shí)質(zhì)心距離最近的原則會(huì)錯(cuò)誤地把 A 的軌跡接到 B 上導(dǎo)致計(jì)數(shù)重復(fù)。解決把 N 從 30 調(diào)小或者按畫面中行人最大移動(dòng)速度估算 N 上限——行人在兩幀之間的位移不應(yīng)超過其邊界框?qū)挾鹊?1/3。更穩(wěn)妥的做法是給質(zhì)心距離加一個(gè)上限閾值歐氏距離超過閾值的直接視為新目標(biāo)而不是強(qiáng)行關(guān)聯(lián)。閾值可以設(shè)為行人平均高度的 0.8 倍這個(gè)值在固定攝像頭場(chǎng)景下變化不大。5.4 現(xiàn)象用 CPU 跑視頻流時(shí)畫面卡頓檢測(cè)一次要好幾秒原因論文測(cè)試環(huán)境是 i5-7200 8GB 內(nèi)存這個(gè)配置在推理 MobileNet-SSD 時(shí)只能保證流程能跑通距離實(shí)時(shí)還有距離。如果直接把輸入分辨率從 500 像素提高到原始 1080p速度會(huì)成倍下降。解決堅(jiān)持把幀最大寬度限制在 500 像素這是論文明確給的預(yù)處理參數(shù)。如果希望更流暢可以進(jìn)一步把輸入高度也壓縮或者把 N 從 30 提高到 40前提是行人速度足夠慢。注意檢測(cè)置信度閾值不宜設(shè)得太低論文要求通過要求置信度最低限度來過濾掉弱檢測(cè)這個(gè)閾值不僅影響精度也影響追蹤輸入的質(zhì)量——無效檢測(cè)框多了質(zhì)心關(guān)聯(lián)會(huì)變得混亂。5.5 現(xiàn)象用訓(xùn)練好的模型檢測(cè)視頻時(shí)命中的邊界框位置偏移明顯原因訓(xùn)練時(shí)輸入尺寸是 300×100×3而部署時(shí)視頻幀 resize 的寬高比例如果不一致圖像被拉伸變形邊界框坐標(biāo)是在變形后的圖上算出來的映射回原始分辨率自然偏移。解決把視頻幀 resize 成與訓(xùn)練輸入一致的寬高比而不是簡(jiǎn)單地設(shè)置最大寬度 500。論文里設(shè)置最大寬度為 500 像素應(yīng)該理解為在這個(gè)寬度限制下保持寬高比縮放然后再 crop 或 pad 到 300×100 的輸入尺寸。保存檢測(cè)結(jié)果時(shí)把 bounding box 坐標(biāo)按縮放比例和 crop 偏移量反向換算回原圖坐標(biāo)這樣疊加顯示才準(zhǔn)確。6. 把論文方法做成你的畢設(shè)最終驗(yàn)證步驟與計(jì)數(shù)可視化技巧論文的驗(yàn)證方法值得直接照搬準(zhǔn)備至少一段包含行人進(jìn)入監(jiān)控區(qū)域—畫面中無行人—行人離開區(qū)域—出現(xiàn)嬰兒車四個(gè)片段的測(cè)試視頻分別驗(yàn)證 detecting、waiting、tracking 三種狀態(tài)和嬰兒車檢測(cè)能力。我自己做這類項(xiàng)目時(shí)會(huì)額外輸出一份帶時(shí)間戳的日志記錄每一幀的狀態(tài)切換和目標(biāo) ID這樣論文里可以貼兩張圖一張是畫了基準(zhǔn)線和進(jìn)出計(jì)數(shù)的監(jiān)控截圖另一張是狀態(tài)變化的時(shí)間線兩張圖就能講完整套工作流程。計(jì)數(shù)可視化有個(gè)小技巧不要只在畫面底部放一個(gè)累計(jì)數(shù)字而是把 Up 和 Down 分開顯示并在行人穿過基準(zhǔn)線瞬間在目標(biāo)框上畫一個(gè)短暫的閃爍標(biāo)記。論文的測(cè)試界面里 Up/Down 兩個(gè)數(shù)值就是這條線的進(jìn)出結(jié)果顯示在畫面上方便實(shí)時(shí)確認(rèn)也方便事后和日志對(duì)照排查計(jì)數(shù)問題。如果需要在論文里展示檢測(cè)效果截圖時(shí)保持?jǐn)z像頭視角的一致性行人框和嬰兒車框用不同顏色區(qū)分圖注里寫清楚是哪一幀、什么狀態(tài)。還要做一組消融對(duì)比才能把輕量級(jí)這個(gè)賣點(diǎn)寫扎實(shí)分別記錄 MobileNet-SSD 和標(biāo)準(zhǔn) SSDVGG 骨干在同一段視頻上的單幀推理耗時(shí)、模型文件大小、檢測(cè)精度。論文里強(qiáng)調(diào) MobileNet-SSD 在保持性能的前提下降低模型大小、提升速度這組數(shù)據(jù)就是你畢設(shè)里的核心實(shí)驗(yàn)表。數(shù)據(jù)不要求多好看真實(shí)跑出來就行重點(diǎn)是明確標(biāo)注測(cè)試環(huán)境——CPU 型號(hào)、內(nèi)存大小、輸入分辨率、跳幀數(shù)這些論文里全是寫明了的你的實(shí)驗(yàn)部分也應(yīng)該同樣透明?;叵肫鹞业谝淮伟催@篇專利的結(jié)構(gòu)復(fù)現(xiàn)整個(gè)流程時(shí)最深的教訓(xùn)是低估了數(shù)據(jù)處理和狀態(tài)機(jī)這兩個(gè)非深度學(xué)習(xí)環(huán)節(jié)的工作量。那時(shí)候我急著調(diào)網(wǎng)絡(luò)參數(shù)結(jié)果訓(xùn)練出的模型檢測(cè)沒問題但追蹤模塊因?yàn)橘|(zhì)心的歐氏距離匹配沒有加閾值目標(biāo)交叉時(shí) ID 亂跳進(jìn)出一團(tuán)亂賬。從那以后我每次跑這種人流量檢測(cè)項(xiàng)目都強(qiáng)制自己在寫檢測(cè)代碼前先把狀態(tài)機(jī)流轉(zhuǎn)圖和質(zhì)心關(guān)聯(lián)的判定條件畫清楚一遍遍核對(duì)跳幀后的狀態(tài)遷移。這篇論文最值錢的地方其實(shí)不在于 MobileNet-SSD 本身——那是公開的結(jié)構(gòu)——而在于它把視頻輸入、檢測(cè)、追蹤、計(jì)數(shù)這條完整鏈路的設(shè)計(jì)取舍都擺了出來跳幀 30 是取舍基準(zhǔn)線計(jì)數(shù)是取舍置信度過濾是取舍這些取舍思路在別的高精度論文里往往是藏起來的。希望這份拆解能幫你在做畢設(shè)或課程設(shè)計(jì)時(shí)少走幾步彎路。本文還有配套的精品資源點(diǎn)擊獲取