識別與LSTM關(guān)鍵點(diǎn)時(shí)序建模)
簡介一套基于MediaPipe設(shè)計(jì)實(shí)現(xiàn)、面向深度學(xué)習(xí)項(xiàng)目實(shí)踐的人體姿態(tài)識別Python源碼與模型包源自大四畢業(yè)設(shè)計(jì)經(jīng)導(dǎo)師指導(dǎo)并獲96.5高分主要面向計(jì)算機(jī)、人工智能、自動化等相關(guān)專業(yè)正在做畢設(shè)或需要項(xiàng)目實(shí)戰(zhàn)的學(xué)生也可作為課程設(shè)計(jì)、期末大作業(yè)。壓縮包共138個文件、約11MB包含7個Python腳本、120個npy數(shù)據(jù)文件、1個H5模型文件以及mp4演示視頻和README說明文檔其中npy文件用于保存關(guān)鍵點(diǎn)序列數(shù)據(jù)h5為訓(xùn)練好的模型權(quán)重mp4為運(yùn)行效果演示。代碼均測試運(yùn)行成功可順利完成從關(guān)鍵點(diǎn)檢測、動作特征提取到分類識別的完整流程包括數(shù)據(jù)準(zhǔn)備、模型加載、實(shí)時(shí)推理與結(jié)果輸出等環(huán)節(jié)便于讀者快速上手MediaPipe項(xiàng)目開發(fā)。目前已有206人學(xué)習(xí)整體結(jié)構(gòu)清晰可在此基礎(chǔ)上擴(kuò)展其他功能或作為畢業(yè)設(shè)計(jì)、課設(shè)項(xiàng)目的直接參考。1. 基于MediaPipe設(shè)計(jì)的人體姿態(tài)識別關(guān)鍵點(diǎn)時(shí)序建模把畢設(shè)難度降到可控范圍做人體姿態(tài)識別方向的項(xiàng)目最尷尬的狀態(tài)是“網(wǎng)絡(luò)搭好了但不知道下一步該驗(yàn)證什么”。這套基于MediaPipe設(shè)計(jì)實(shí)現(xiàn)的人體姿態(tài)識別Python源碼模型把脈絡(luò)理得很清楚利用MediaPipe Pose從視頻或攝像頭畫面里逐幀提取33個骨骼關(guān)鍵點(diǎn)坐標(biāo)再把關(guān)鍵點(diǎn)序列喂給深度學(xué)習(xí)模型action.h5做動作分類。與端到端圖像分類相比這種方式天然屏蔽衣服顏色、光照和背景干擾更適合左右揮手、上下擺動這類動作識別。壓縮包自帶模型權(quán)重與測試視頻當(dāng)前正在做畢設(shè)、課程設(shè)計(jì)或期末大作業(yè)的同學(xué)拿它能快速跑通一條完整鏈路。2. 技術(shù)選型為什么MediaPipe關(guān)鍵點(diǎn)序列比純CNN圖像分類更穩(wěn)2.1 MediaPipe Pose在整個識別鏈路中的真實(shí)定位人體姿態(tài)識別有兩條技術(shù)路線。第一條是端到端方案直接拿視頻幀訓(xùn)練一個卷積神經(jīng)網(wǎng)絡(luò)做動作分類第二條是兩段式方案先用姿態(tài)估計(jì)模型提取骨骼關(guān)鍵點(diǎn)再把關(guān)鍵點(diǎn)序列送給時(shí)序模型做分類。這個項(xiàng)目走的是第二條路MediaPipe Pose承擔(dān)的是“特征提取器”而不是最終分類器。MediaPipe Pose輸出的是33個關(guān)鍵點(diǎn)的坐標(biāo)信息。每個關(guān)鍵點(diǎn)包含x、y、z三個空間坐標(biāo)以及一個visibility可見性分?jǐn)?shù)。x和y是經(jīng)過歸一化的圖像坐標(biāo)取值范圍在0到1之間z表示關(guān)鍵點(diǎn)在相機(jī)坐標(biāo)系下的深度估計(jì)相對大小有意義但絕對值不能跨場景直接比較visibility則反映這個關(guān)鍵點(diǎn)是否被有效檢測到遮擋嚴(yán)重時(shí)數(shù)值會明顯掉下去。在動作識別場景里真正關(guān)心的是“關(guān)節(jié)位置怎么變化”而不是“人長什么樣”。骨骼關(guān)鍵點(diǎn)恰好只保留幾何結(jié)構(gòu)把服裝、膚色、光照這些干擾項(xiàng)全部丟掉了。有些同學(xué)最初用CNN分類圖像做動作識別訓(xùn)練集背景是實(shí)驗(yàn)室白墻測試時(shí)換到教室就掉點(diǎn)嚴(yán)重而關(guān)鍵點(diǎn)方案幾乎沒有這類問題這也是兩段式架構(gòu)在直覺上更穩(wěn)的原因之一。2.2 為什么時(shí)序部分要用LSTM而不是直接對單幀分類“揮手”和“舉手”單看某一幀圖像可能非常接近差異體現(xiàn)在時(shí)間維度上。舉手是從低到高的位移軌跡揮手是在同一高度左右往復(fù)。動作識別不能只看單幀必須考慮關(guān)鍵點(diǎn)隨時(shí)間的變化。LSTM這類循環(huán)神經(jīng)網(wǎng)絡(luò)能學(xué)習(xí)到這種跨幀的時(shí)序依賴它會記住前面若干幀的狀態(tài)并用這些歷史信息來解釋當(dāng)前幀。action.h5是這個項(xiàng)目的核心產(chǎn)物一個用訓(xùn)練數(shù)據(jù)擬合出來的Keras模型結(jié)構(gòu)通常是LSTM或加了雙向LSTM也可以疊加全連接層。模型輸入形狀一般是(batch, timesteps, features)。常見實(shí)現(xiàn)里timesteps取30幀左右features是33個關(guān)鍵點(diǎn)的坐標(biāo)拼接只用x和y就是66維加上z則變成99維再加上visibility就是132維。打開模型文件確認(rèn)輸入維度之后才能確定預(yù)處理腳本里要保留幾個坐標(biāo)分量。在實(shí)現(xiàn)細(xì)節(jié)上LSTM訓(xùn)練有個值得注意的點(diǎn)序列數(shù)據(jù)本身帶有時(shí)間相關(guān)性batch內(nèi)樣本順序不能隨意打亂否則模型可能學(xué)到不存在的跨樣本時(shí)間關(guān)系。數(shù)據(jù)加載器應(yīng)該保持序列內(nèi)部順序不變。小數(shù)據(jù)集很容易過擬合常見做法是在LSTM輸出后接Dropout層用早停來防止訓(xùn)練后期震蕩。action.h5既然已經(jīng)訓(xùn)練好了這些細(xì)節(jié)推理時(shí)不直接可見但如果你打算重新訓(xùn)練它們會直接影響最終效果。2.3 選型里隱含的三個實(shí)際收益第一是部署成本低。MediaPipe有現(xiàn)成的Python APICPU上也能實(shí)時(shí)推理相比OpenPose需要較重的運(yùn)行庫MediaPipe對畢設(shè)和課設(shè)環(huán)境友好得多。第二是訓(xùn)練成本低。LSTM參數(shù)規(guī)模遠(yuǎn)小于圖像分類網(wǎng)絡(luò)幾百個樣本就能擬合出能用的分類器沒有GPU也能完成訓(xùn)練。第三是調(diào)試直觀。關(guān)鍵點(diǎn)序列可以可視化繪制在畫面上哪個動作識別出錯一眼就能看出是檢測丟了關(guān)鍵點(diǎn)還是分類器判斷錯了不用像圖像CNN那樣“黑匣子”式猜問題。2.4 數(shù)據(jù)流向與模塊邊界從原始視頻到最終類別輸出整條鏈路是視頻幀 → MediaPipe關(guān)鍵點(diǎn)提取 → 坐標(biāo)歸一化與拼接 → 滑窗切片 → LSTM模型預(yù)測 → 輸出類別與置信度。每個環(huán)節(jié)的邊界要清楚。MediaPipe只負(fù)責(zé)出點(diǎn)不做分類LSTM只負(fù)責(zé)分類不做目標(biāo)檢測。這種職責(zé)劃分讓排錯變得容易如果畫面中人檢測正常但分類錯誤問題定位在分類器如果關(guān)鍵點(diǎn)完全錯亂問題定位在MediaPipe檢測參數(shù)。真正跑起來時(shí)最值得關(guān)注的是兩個銜接點(diǎn)一是MediaPipe輸出的坐標(biāo)是否和訓(xùn)練時(shí)用的坐標(biāo)系一致二是滑窗切片長度是否和action.h5的輸入尺寸一致。這兩個點(diǎn)也是后面避坑章節(jié)里最常出問題的位置。2.5 訓(xùn)練階段的關(guān)鍵點(diǎn)序列是怎么組織成數(shù)據(jù)集的常見做法是先用一個動作捕捉腳本錄制原始視頻每段視頻只含一類動作時(shí)長約2到3秒。錄制完成后對每段視頻逐幀調(diào)用MediaPipe提取關(guān)鍵點(diǎn)把每一幀的坐標(biāo)拼接成一個特征向量再把整段視頻的特征向量按時(shí)間順序保存為一個序列樣本。類別標(biāo)簽按文件夾或文件名映射成整數(shù)索引。比如l0.mp4這類帶動作編號的文件編號可以直接作為標(biāo)簽。數(shù)據(jù)集規(guī)模不需要很大一個動作錄50到100段總共幾百個序列樣本模型就能達(dá)到可用的精度。損失函數(shù)用交叉熵優(yōu)化器用Adam學(xué)習(xí)率從1e-3起步這是這類小數(shù)據(jù)集時(shí)序分類任務(wù)的常規(guī)組合。2.6 滑窗切片的邏輯與數(shù)學(xué)含義模型輸入長度固定視頻幀數(shù)不固定切窗口是必須的。直接從頭切到尾的問題在于動作邊界容易被切斷比如揮手的前幾幀落在窗口末尾、后幾幀落在下一個窗口開頭兩個窗口都學(xué)不到完整動作。常見做法是設(shè)定窗口長度和步長。窗口長度等于模型輸入timesteps步長取窗口長度的一半。這樣相鄰窗口有50%的重疊動作邊界大概率會被某個窗口完整包含。推理階段同樣用滑窗遍歷幀序列每個窗口得到一個類別概率分布再做投票或加權(quán)平均輸出穩(wěn)定結(jié)果。這一步是后面效果穩(wěn)定的基礎(chǔ)。3. 資源包里的文件怎么用模型、測試視頻與預(yù)處理腳本的配合方式3.1 action.h5這個深度學(xué)習(xí)模型文件能做什么action.h5是Keras標(biāo)準(zhǔn)模型格式包含網(wǎng)絡(luò)結(jié)構(gòu)和權(quán)重。拿到這個文件后直接用tensorflow.keras.models.load_model加載即可不需要重新訓(xùn)練。項(xiàng)目已經(jīng)把訓(xùn)練好的權(quán)重打包進(jìn)來下載后可以立即推理。模型能識別的具體動作類別數(shù)需要看源碼里的類別映射表。通常類別數(shù)等于輸出層神經(jīng)元的個數(shù)。用以下代碼可以快速確認(rèn)模型的輸入和輸出形狀避免后續(xù)腳本參數(shù)對不上from tensorflow.keras.models import load_model model load_model(action.h5) print(輸入形狀:, model.inputs[0].shape) print(輸出形狀:, model.outputs[0].shape)如果輸出形狀是(None, 6)說明模型最后是6個類別的Softmax輸入形狀是(None, 30, 132)說明需要30幀、每幀132維特征。這一步建議放在所有預(yù)處理之前等于先拿到模型對輸入的要求清單。3.2 視頻文件在項(xiàng)目里的兩種用途l0.mp4、r0.mp4、r1.mp4、1.mp4這些視頻我一般把它們理解為“動作樣本原始素材”。文件名里的l和r通常表示左右方向數(shù)字是動作編號。這類文件在項(xiàng)目里有兩種用途一是作為演示數(shù)據(jù)跑通推理流程并驗(yàn)證模型輸出是否合理二是作為補(bǔ)充參考素材理解訓(xùn)練數(shù)據(jù)大概長什么樣。不建議把這些視頻直接當(dāng)全部訓(xùn)練數(shù)據(jù)因?yàn)閿?shù)量太少。合理做法是拿它們做冒煙測試先確認(rèn)模型能正確輸出類別再擴(kuò)充自己的數(shù)據(jù)做微調(diào)或重新訓(xùn)練。3.3 從視頻到關(guān)鍵點(diǎn)序列的完整預(yù)處理腳本用OpenCV讀視頻幀再交給MediaPipe做姿態(tài)估計(jì)是標(biāo)準(zhǔn)的預(yù)處理方式。代碼可以這樣寫import cv2 import mediapipe as mp mp_pose mp.solutions.pose pose mp_pose.Pose(static_image_modeFalse, model_complexity1, min_detection_confidence0.5, min_tracking_confidence0.5) cap cv2.VideoCapture(r0.mp4) keypoints_sequence [] while cap.isOpened(): ret, frame cap.read() if not ret: break frame_rgb cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) results pose.process(frame_rgb) if results.pose_landmarks is None: continue landmarks [] for lm in results.pose_landmarks.landmark: landmarks.extend([lm.x, lm.y, lm.z, lm.visibility]) keypoints_sequence.append(landmarks) cap.release()這里有兩個參數(shù)需要解釋。min_detection_confidence控制初始檢測的置信度閾值值小容易多檢但誤檢率高值大容易漏檢側(cè)身姿態(tài)0.5在這個項(xiàng)目場景是安全和準(zhǔn)確之間的平衡點(diǎn)。model_complexity取1表示使用中等模型0最輕量、2精度最高畢設(shè)場景下1是常見選擇。結(jié)果處理上需要注意results.pose_landmarks為None說明這一幀沒有檢測到人直接continue會造成序列不連續(xù)。我習(xí)慣在這里統(tǒng)計(jì)連續(xù)無人幀數(shù)超過一定閾值就說明視頻本身有問題否則暫時(shí)跳過不會影響整體。3.4 落盤格式與中間產(chǎn)物管理預(yù)處理完的關(guān)鍵點(diǎn)序列建議落盤保存成.npy文件這樣有兩個好處。一是之后調(diào)整窗口參數(shù)不需要重新跑MediaPipe省掉大量重復(fù)檢測時(shí)間二是訓(xùn)練腳本可以直接讀取離線特征方便對比實(shí)驗(yàn)。我習(xí)慣的目錄結(jié)構(gòu)是這樣landmarks/ ├── r0_001.npy ├── r0_002.npy ├── l0_001.npy └── ...每個文件保存一個完整視頻段的關(guān)鍵點(diǎn)序列shape是(幀數(shù), 特征維度)幀數(shù)可以不同滑窗切片時(shí)再做截?cái)嗪吞畛?。保存時(shí)順便把類別標(biāo)簽寫成同名JSON或者CSV后面加載數(shù)據(jù)時(shí)直接對照。3.5 README.md里值得先看的三件事下載后第一步建議打開README.md重點(diǎn)看三處。第一處是環(huán)境版本要求項(xiàng)目能否直接跑起來依賴沖突是第一個關(guān)卡。第二處是類別映射表缺少這個說明模型輸出就只是一個沒有含義的整數(shù)。第三處是運(yùn)行入口文件的順序預(yù)處理、訓(xùn)練、推理三個腳本先用哪個后啟用哪個按文檔說明走能少走不少彎路。如果README里沒有類別映射表就從源碼里找訓(xùn)練標(biāo)簽的列表或者用模型輸出層神經(jīng)元數(shù)量推斷。標(biāo)簽順序一旦搞反識別結(jié)果看起來就會完全錯亂這個問題比模型不準(zhǔn)更隱蔽。4. 動手跑通這個項(xiàng)目環(huán)境配置、推理代碼與效果驗(yàn)證4.1 環(huán)境依賴清單與版本踩坑提醒跑項(xiàng)目之前先裝依賴。這個項(xiàng)目基于MediaPipe、TensorFlow、OpenCV和NumPy常用的版本組合如下pip install opencv-python4.5.5.64 pip install mediapipe0.8.9.2 pip install tensorflow2.8.0 pip install numpy1.21.6版本不是越新越好。MediaPipe 0.8.x系列對Python 3.7到3.9支持最穩(wěn)定新版本如果和TensorFlow 2.x的protobuf沖突會導(dǎo)致導(dǎo)入失敗。TensorFlow 2.8.0和MediaPipe 0.8.9.2是大量項(xiàng)目驗(yàn)證過的共存組合如果之前已經(jīng)裝了更高版本的TensorFlow跑不通時(shí)可以先把環(huán)境退到這個組合再試。4.2 加載action.h5模型并完成一次推理下面這段代碼完成從讀視頻到輸出動作類別的完整閉環(huán)。它基于第3章生成的keypoints_sequence這里假設(shè)已經(jīng)從視頻里提取好了關(guān)鍵點(diǎn)序列。import numpy as np from tensorflow.keras.models import load_model model load_model(action.h5) window_length int(model.inputs[0].shape[1]) # 例如 30 def predict_action(sequence): if len(sequence) window_length: return None, 0.0 windows [] step window_length // 2 for start in range(0, len(sequence) - window_length 1, step): windows.append(sequence[start:start window_length]) windows np.array(windows) probs model.predict(windows, verbose0) avg_prob np.mean(probs, axis0) action_id int(np.argmax(avg_prob)) confidence float(np.max(avg_prob)) return action_id, confidence action_id, confidence predict_action(keypoints_sequence) print(f預(yù)測動作編號: {action_id}, 置信度: {confidence:.2f})這里的關(guān)鍵點(diǎn)在于window_length從模型輸入shape動態(tài)讀取不要手寫死。手寫30意味著一旦模型實(shí)際輸入是28或32幀切片邏輯就會錯位。step取窗口長度的一半保證相鄰窗口50%重疊動作邊界不會被切碎。預(yù)測時(shí)對每個窗口的概率取平均再取argmax比用單個窗口預(yù)測穩(wěn)得多這個技巧在實(shí)時(shí)場景尤其管用。4.3 推理輸出的類別映射怎么確認(rèn)模型輸出的是整數(shù)索引不是動作名稱。索引到動作名的映射在源碼里通常是一個列表或字典action_labels [左揮手, 右揮手, 下蹲, 舉手]確認(rèn)映射是推理前最重要的一步。如果映射對不上輸出結(jié)果看起來會完全錯亂。建議打印模型輸出層神經(jīng)元的數(shù)量和標(biāo)簽列表長度比對兩者必須一致。類別順序以訓(xùn)練時(shí)為準(zhǔn)不要以自己猜測為準(zhǔn)否則結(jié)果完全不可信。4.4 置信度閾值與無動作場景處理實(shí)際使用中會出現(xiàn)畫面里沒有人的情況MediaPipe輸出為空直接跳過即可。另一種情況是模型對某個窗口完全不確定但即使所有類別概率都很低argmax也一定會選出一個類別這時(shí)候只看最大置信度是不夠的因?yàn)椤?.9置信度但類別錯誤”比“低置信度”更危險(xiǎn)。常見做法是設(shè)定一個置信度閾值低于閾值就輸出“未知動作”。閾值設(shè)在0.5到0.7之間比較合適具體數(shù)值要看驗(yàn)證結(jié)果。如果視頻中某個動作頻繁被標(biāo)為“未知”說明模型對該動作的置信度偏低需要檢查是否有丟關(guān)鍵點(diǎn)或序列過短的問題。4.5 攝像頭實(shí)時(shí)識別模式下要調(diào)整哪些參數(shù)從視頻文件改成攝像頭實(shí)時(shí)識別參數(shù)策略要變。static_image_mode必須保持False讓MediaPipe啟用跟蹤模式而不是每幀重新檢測幀率會提升很多。min_tracking_confidence可以比min_detection_confidence稍低因?yàn)楦櫮J较律弦粠慕Y(jié)果能輔助當(dāng)前幀匹配。實(shí)時(shí)模式下另一個重點(diǎn)是狀態(tài)清理?;瓣?duì)列要先進(jìn)先出每來一幀append一次隊(duì)列滿就彈出最舊的幀。這樣模型每幀都可以輸出一次預(yù)測結(jié)果。再加一道防抖連續(xù)5幀輸出同一動作類別才真正顯示否則保持上一次顯示結(jié)果。這個邏輯能濾掉單幀閃爍效果非常明顯。4.6 效果評估從輸出概率看模型是否真的在工作評估模型不能只看最終類別。打印模型預(yù)測概率分布是更直接的評估方法一個合格模型的輸出應(yīng)該滿足正確動作類別的概率在多數(shù)窗口最高其他類別概率明顯偏低。如果所有窗口都是低置信度說明模型對當(dāng)前輸入很陌生如果正確類只在部分窗口排到第二第三說明動作邊界切分有問題或幀率不穩(wěn)定。我經(jīng)常把每段測試視頻的所有窗口概率打印成表格逐行檢查是否有窗口在正確類別和其他類別之間反復(fù)橫跳。出現(xiàn)橫跳就說明滑窗位置對結(jié)果影響大需要檢查步長和重疊比例是否合理而不是急著調(diào)模型。5. 避坑指南跑這套項(xiàng)目最容易翻車的五個細(xì)節(jié)5.1 模型加載失敗文件路徑與版本環(huán)境兩個隱形雷現(xiàn)象執(zhí)行model load_model(action.h5)時(shí)報(bào)OSError或ValueError提示無法識別文件結(jié)構(gòu)或者文件明明在同目錄卻提示找不到。原因這種問題多半不是模型文件損壞而是兩處環(huán)境問題。第一是路徑里帶中文或特殊空格Windows下TensorFlow對Unicode路徑支持不好。第二是Keras與TensorFlow版本錯配比如裝了TensorFlow 2.x又單獨(dú)pip install了keras2.3加載HDF5格式時(shí)序列化方式不兼容。解決先把整個項(xiàng)目目錄放到純英文路徑下比如C:\pose_project。然后檢查keras和tensorflow版本如果出現(xiàn)兩個獨(dú)立的keras條目直接卸載多余的那個。最后用h5py打開h5文件確認(rèn)里面至少包含model_weights和model_config兩個group都不缺再重新執(zhí)行加載。5.2 識別精度異常攝像頭鏡像和光照導(dǎo)致的檢測錯亂現(xiàn)象視頻文件測試一切正常打開攝像頭實(shí)時(shí)識別時(shí)動作全亂或者側(cè)身、陰影遮擋場景下關(guān)鍵點(diǎn)位置大面積漂移。原因第一個成因是攝像頭預(yù)覽默認(rèn)鏡像MediaPipe拿到的坐標(biāo)和訓(xùn)練數(shù)據(jù)左右相反模型在左上學(xué)到的動作被套到右手上。第二個成因是訓(xùn)練集里光照均勻、背景干凈攝像頭場景下高光或陰影降低了MediaPipe檢測置信度關(guān)鍵點(diǎn)抖動頻繁。解決對攝像頭畫面先做cv2.flip(frame, 1)再送入MediaPipe這是最直接的鏡像對齊手段。同時(shí)在代碼里對關(guān)鍵點(diǎn)做平滑取最近5幀同一關(guān)鍵點(diǎn)坐標(biāo)的加權(quán)平均權(quán)重按時(shí)間衰減。光照問題更頑固可以在界面里加一個亮度提示當(dāng)畫面平均亮度低于閾值時(shí)提醒補(bǔ)光而不是用算法硬扛。5.3 輸出類別抖動窗口切分與幀率不穩(wěn)的連鎖反應(yīng)現(xiàn)象動作保持不變識別結(jié)果卻每隔幾幀在兩類之間跳變看起來完全沒有穩(wěn)定性。原因模型按固定時(shí)間步長切窗口如果視頻幀率不是穩(wěn)定30fps實(shí)際動作在時(shí)間上被壓縮或拉伸同一個動作在滑窗里的軌跡形態(tài)變化很大。另一個成因是動作邊界恰好落在窗口內(nèi)部窗口前半段是動作A、后半段是動作B模型自然給出接近50%的兩類概率。解決用三層過濾。第一層把滑窗步長從整窗口縮短到半窗口保證重疊第二層對多個窗口的預(yù)測概率做平均用平均后的分布做argmax第三層在輸出端做狀態(tài)機(jī)同一個類別連續(xù)出現(xiàn)至少3次才切換顯示。這三層在實(shí)時(shí)和離線場景都適用抖動基本能消除到肉眼可接受。5.4 序列斷裂導(dǎo)致模型無法預(yù)測空窗口現(xiàn)象運(yùn)行推理時(shí)報(bào)錯說輸入序列太短或者返回的預(yù)測結(jié)果固定是第一個類別。原因錄制視頻時(shí)人出現(xiàn)在畫面外MediaPipe在這段時(shí)間輸出為空關(guān)鍵點(diǎn)序列中間被跳過最終序列長度不足一個窗口。另一種情況是跳過空幀后沒有記錄幀索引序列在時(shí)間軸上錯位模型拿到的根本不是連續(xù)動作軌跡。解決處理空幀時(shí)不要直接跳過而是用填充策略。把上一個有效幀的關(guān)鍵點(diǎn)復(fù)制一份填入序列如果連續(xù)超過5幀無檢測就放棄這段窗口并重新開始。這樣既能保持序列連續(xù)也能避免長時(shí)間無人時(shí)的無效計(jì)算。關(guān)鍵點(diǎn)連續(xù)性對LSTM非常重要寧可填充也不要用斷裂的數(shù)據(jù)去預(yù)測。5.5 換機(jī)器精度下降構(gòu)圖差異比模型更先翻車現(xiàn)象同一套模型在自己電腦上識別率很高換到另一臺電腦后掉點(diǎn)嚴(yán)重甚至某些動作完全失效。原因兩臺電腦的攝像頭安裝高度和角度不同人站在同一距離時(shí)畫面中人體的占比和位置差異很大。訓(xùn)練集里人體居中、上下約占畫面60%遷移環(huán)境里人體縮小到30%關(guān)鍵點(diǎn)分布相對訓(xùn)練分布明顯偏移LSTM對分布外數(shù)據(jù)自然不敏感。解決在推理端固定一個ROI裁剪框框內(nèi)人體占比盡量接近訓(xùn)練分布。先運(yùn)行一次MediaPipe得到人體的bounding box再按目標(biāo)高度裁剪并縮放這個過程屬于純推理端校準(zhǔn)不需要重新訓(xùn)練。如果還是不行錄制幾十個新樣本做一次增量微調(diào)通常能恢復(fù)精度。6. 進(jìn)階驗(yàn)證模型可信度與遷移到自定義動作驗(yàn)證模型不能只看測試集準(zhǔn)確率。我習(xí)慣把模型的輸出概率分布完整打印出來觀察分類正確的樣本是否給了高置信度分類錯誤的樣本是接近均勻分布還是給出了自信但錯誤的答案。如果一個錯誤樣本置信度高達(dá)0.9說明模型學(xué)到了某種與動作無關(guān)的偽特征這比“模型笨”更危險(xiǎn)。另一個實(shí)用驗(yàn)證方式叫窗口投票穩(wěn)定性測試對同一段視頻跑三次每次用不同滑窗起點(diǎn)比較三次輸出是否一致。如果三次結(jié)果不一致說明動作邊界在窗口中的位置對結(jié)果影響太大需要回退增加數(shù)據(jù)多樣性或者重新調(diào)整滑窗步長和重疊比例。這個測試成本很低但能暴露很多測試集中發(fā)現(xiàn)不了的問題。如果想把這套項(xiàng)目遷移到自己的動作類別上路徑很清晰。第一步錄制新動作視頻并做關(guān)鍵點(diǎn)提取把序列長度改到和模型輸入一致第二步保留已有模型的部分權(quán)重把最后全連接層換成新的類別數(shù)量做少量迭代訓(xùn)練。用少量樣本微調(diào)通常比從零訓(xùn)練更穩(wěn)定但如果原模型類別相差太遠(yuǎn)也可以直接按項(xiàng)目里的訓(xùn)練邏輯從頭跑。我自己的教訓(xùn)是有次把動作類別從4類擴(kuò)到6類依賴已有模型做了20輪微調(diào)驗(yàn)證集準(zhǔn)確率看著還行換了個背景就全亂。后來強(qiáng)制把“視頻 → 關(guān)鍵點(diǎn) → 序列 → 模型 → 人工核對”完整走了一遍才發(fā)現(xiàn)問題出在新動作數(shù)據(jù)和舊數(shù)據(jù)錄制高度不一致上。從那以后每次改動數(shù)據(jù)或訓(xùn)練參數(shù)我都會重跑這個閉環(huán)用三次滑窗起點(diǎn)不一致性測試確認(rèn)交付結(jié)果。希望幫到你。本文還有配套的精品資源點(diǎn)擊獲取