時目標(biāo)檢測:CUDA/PyTorch環(huán)境配置與攝像頭部署避坑)
簡介這份教程面向計(jì)算機(jī)視覺初學(xué)者與Python開發(fā)者圍繞YOLOv10實(shí)時目標(biāo)檢測系統(tǒng)的搭建串聯(lián)環(huán)境準(zhǔn)備、模型訓(xùn)練、評估與視頻流檢測等環(huán)節(jié)幫助讀者理解從數(shù)據(jù)標(biāo)注到應(yīng)用驗(yàn)證的完整流程。壓縮包內(nèi)共1個doc文件約28KB以目錄化文檔承載核心內(nèi)容便于按章節(jié)查閱和對照實(shí)踐。已有207人學(xué)習(xí)適合希望快速熟悉YOLOv10目標(biāo)檢測開發(fā)路徑的讀者。文檔涵蓋硬件與軟件要求、PyTorch和OpenCV等庫的安裝配置、COCO或自定義數(shù)據(jù)集的準(zhǔn)備與標(biāo)注、訓(xùn)練參數(shù)設(shè)置、mAP等評估指標(biāo)及可視化方法并給出攝像頭視頻流讀取與檢測框繪制的示例思路可幫助讀者建立可復(fù)現(xiàn)的實(shí)驗(yàn)框架并在此基礎(chǔ)上擴(kuò)展更多檢測場景與優(yōu)化方向。1. 攝像頭能亮框卻畫不出來某開發(fā)者把 yolov10 倉庫克隆下來pip 一路裝完python train.py一敲屏幕上跳出 CUDA out of memory退回 CPU 推理一張 640×640 的圖要等三秒多攝像頭畫面卡成 PPT。這類現(xiàn)場我見過太多次。yolov10 實(shí)時目標(biāo)檢測這套環(huán)境難點(diǎn)從來不在裝沒裝上而在版本對沒對上——驅(qū)動支持的 CUDA 檔位、PyTorch 輪子的 cu 標(biāo)簽、Python 小版本錯一個就 GPU 認(rèn)不出來或者訓(xùn)練十個 epoch 后崩在顯存上。這份開發(fā)案例把環(huán)境準(zhǔn)備、訓(xùn)練、評估、實(shí)時檢測串成了一條線適合手里有一張 NVIDIA 顯卡、想從零跑通攝像頭畫面的開發(fā)者。下面按我自己的裝機(jī)順序把命令、參數(shù)和翻車點(diǎn)攤開寫。2. 裝前先對表CUDA、Python 與 PyTorch 的三方版本鎖定裝深度學(xué)習(xí)環(huán)境最忌諱先裝再說。我一般的順序是先看卡再看驅(qū)動然后定 CUDA 檔位最后反推 Python 和 PyTorch中間任何一步跳過后面都要花兩三倍時間回滾。這一章不裝東西只把表對清楚。2.1 硬件門檻4 核 CPU 只是底線顯存才是分水嶺案例里列的四條硬件要求是CPU 至少 4 核、NVIDIA GPU推薦 RTX 系列、內(nèi)存至少 8GB、存儲至少 10GB。照著這份清單配機(jī)器不算錯但它只回答了能不能啟動沒回答能不能訓(xùn)練。真正卡人的是顯存和顯卡算力這兩件事。項(xiàng)目案例給出的要求我實(shí)際會留的余量卡點(diǎn)在哪CPU至少 4 核8 核以上數(shù)據(jù)加載的 dataloader 進(jìn)程吃 CPUGPUNVIDIARTX 系列推薦顯存 8GB 起640 輸入、batch 16 大約吃 6~7GB 顯存內(nèi)存至少 8GB16GB數(shù)據(jù)集緩存、多進(jìn)程讀圖、Matplotlib 畫圖存儲至少 10GB50GB數(shù)據(jù)集解壓 多份權(quán)重 訓(xùn)練日志顯卡算力這一條得單獨(dú)說。PyTorch 新版輪子對老架構(gòu)的支持是在收緊的算力過低的卡裝上之后torch.cuda.is_available()能返回 True但一跑卷積就報 no kernel image is available for execution on the device。筆記本上的低功耗獨(dú)顯跑推理勉強(qiáng)能用訓(xùn)練基本別指望。另外只有 CPU 的機(jī)器并不是完全不能跑只是實(shí)時檢測會退化成準(zhǔn)實(shí)時——640 輸入下單幀推理幾百毫秒到一秒都有可能攝像頭預(yù)覽會明顯滯后。跑之前先確認(rèn)卡被系統(tǒng)認(rèn)出來了# 查看顯卡型號、顯存、驅(qū)動版本右上角那行 CUDA Version 后面會用到 nvidia-smi這條命令輸出的右上角有一個CUDA Version: xx.x很多人誤以為那是本機(jī)裝的 CUDA 版本其實(shí)它是當(dāng)前驅(qū)動最高能支持的 runtime 版本。這個數(shù)字決定了你后面能選哪一檔 PyTorch 輪子記住它。2.2 Python 3.7 到 3.10為什么我一般不裝最新版案例寫的是 Python 3.7 及以上。3.7 這個版本現(xiàn)在已經(jīng)停止維護(hù)很多科學(xué)計(jì)算包早就不發(fā) cp37 的輪子了pip 會退回到源碼編譯在 Windows 上十有八九編譯不過。3.11、3.12 這類較新的版本也會撞上同一個問題——包的最新版未必提供了對應(yīng) ABI 的預(yù)編譯輪子。我一般鎖 3.9 或 3.10這兩個版本在 PyTorch、OpenCV、NumPy 這一圈里輪子最全出了問題也最好搜到現(xiàn)成的解決方案。先看本機(jī)裝了什么# Windows 上用 python --versionLinux/macOS 上區(qū)分 python 和 python3 python --version python3 -V # 機(jī)器上同時裝了多個解釋器時確認(rèn)當(dāng)前 shell 指向哪一個 which python # Windows: where python如果輸出是 3.11 以上別急著卸用 conda 單獨(dú)建一個 3.10 的環(huán)境就行系統(tǒng) Python 不要動——很多系統(tǒng)工具依賴它刪了會連帶把包管理器搞壞這是我早年踩過的血淚教訓(xùn)。2.3 驅(qū)動、CUDA Toolkit 與 PyTorch 自帶 cu 庫別混為一談新手最容易在這里繞圈看到教程說要裝 CUDA就去官網(wǎng)下了幾個 G 的 CUDA Toolkit裝完發(fā)現(xiàn) PyTorch 還是認(rèn)不到 GPU。原因在于這是三個不同的東西顯卡驅(qū)動操作系統(tǒng)層面的nvidia-smi能出結(jié)果就說明驅(qū)動正常。CUDA Toolkit包含 nvcc 編譯器只有你要自己編譯 CUDA 算子、或者跑某些需要現(xiàn)場編譯的擴(kuò)展時才需要。PyTorch 輪子自帶的 CUDA runtime 和 cuDNNpip 裝cu118、cu121這類標(biāo)簽的包時運(yùn)行庫是打包在輪子里的跟系統(tǒng)有沒有裝 Toolkit 無關(guān)。所以常規(guī)路線是只裝驅(qū)動不裝 Toolkit直接裝對應(yīng) cu 標(biāo)簽的 PyTorch。案例給的cu113屬于比較早的檔位現(xiàn)在這個檔位對應(yīng)的輪子版本已經(jīng)很老硬裝要么找不到包要么被降級到一個跟新版代碼不兼容的 torch。驅(qū)動版本和可選輪子標(biāo)簽大致這樣對應(yīng)具體以 PyTorch 官方安裝矩陣為準(zhǔn)nvidia-smi右上角顯示我一般選的輪子標(biāo)簽11.8cu11812.1cu118 或 cu12112.4 及以上cu121 或更高檔位高版本驅(qū)動向下兼容低檔位輪子反過來不行。所以驅(qū)動新、輪子選低一檔是最省事的組合。還有一條容易忽略的Windows 上原生環(huán)境和 WSL2 是兩套驅(qū)動棧WSL2 里能跑不代表原生 Windows 能跑反之亦然。團(tuán)隊(duì)協(xié)作時把這一條寫進(jìn)環(huán)境說明能省掉一半我這兒明明能跑的爭論。3. 按順序裝conda 環(huán)境、PyTorch 輪子與推理依賴對完表就可以動手了。這一章的四步是有嚴(yán)格順序的尤其是第二步和第三步順序反了會出現(xiàn) pip 把已經(jīng)裝好的 torch 覆蓋成 CPU 版這種玄學(xué)問題。3.1 建一個不污染系統(tǒng)的 conda 環(huán)境# 創(chuàng)建名為 yolov10 的環(huán)境顯式指定 Python 小版本 conda create -n yolov10 python3.10 -y # 激活環(huán)境 conda activate yolov10 # 確認(rèn) pip 和 python 指向同一個解釋器 python -c import sys; print(sys.executable) pip -V三條命令里最關(guān)鍵是最后那條sys.executable。它會打印當(dāng)前 python 的絕對路徑正常應(yīng)該落在.../envs/yolov10/python.exe或.../envs/yolov10/bin/python下面。如果打印出來的是系統(tǒng)路徑說明 conda 沒激活成功后面 pip 裝的東西全都會進(jìn)系統(tǒng)環(huán)境等你發(fā)現(xiàn)問題時已經(jīng)污染了一片。pip -V的輸出里也會帶一個路徑它必須和sys.executable的目錄一致。這兩個對不上就是pip 裝完 import 還是找不到的根源。激活環(huán)境后建議每次新開終端都先跑一遍conda activate yolov10別嫌煩省下的排錯時間遠(yuǎn)超這幾秒。3.2 選對 PyTorch 安裝源--index-url和--extra-index-url差一個字結(jié)果差很多案例給的命令是pip install torch torchvision torchaudio --extra-index-url https://download.pytorch.org/whl/cu113 pip install opencv-python matplotlib這條命令本身能跑通但有兩個問題。第一cu113檔位現(xiàn)在對應(yīng)的 torch 版本很老第二--extra-index-url是額外源pip 會同時去 PyPI 找同名包而 PyPI 上的torch默認(rèn)是 CPU 版。兩個源里版本號相同時pip 不一定選哪個結(jié)果就是你以為裝了 GPU 版實(shí)際裝的是 CPU 版。按第 2 章確認(rèn)的檔位改成--index-url讓它只認(rèn)這一個源# 有 NVIDIA 顯卡按 nvidia-smi 顯示的檔位選這里以 cu121 為例 pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121 # 沒有獨(dú)顯、或者只想先跑通 CPU 推理 pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cpu參數(shù)說明--index-url是替換默認(rèn)源--extra-index-url是追加源。裝 PyTorch 這類有 CPU/GPU 同名包的情況我一律用前者。裝完立刻驗(yàn)證別等到跑訓(xùn)練時才發(fā)現(xiàn)# 期望輸出 True 和顯卡數(shù)量False 就回第 2 章查驅(qū)動 python -c import torch; print(torch.__version__, torch.cuda.is_available(), torch.cuda.device_count()) # 打印當(dāng)前顯卡名確認(rèn)是獨(dú)顯不是核顯 python -c import torch; print(torch.cuda.get_device_name(0))如果版本號里帶cpu后綴說明裝錯了先pip uninstall torch torchvision torchaudio -y再按上面重裝。這個后綴是最直觀的判斷依據(jù)。3.3 補(bǔ)齊 OpenCV、Matplotlib 與標(biāo)注工具# 圖像讀寫、畫框、攝像頭取流 pip install opencv-python # 訓(xùn)練曲線和評估結(jié)果可視化 pip install matplotlib # 數(shù)據(jù)加載與配置解析訓(xùn)練腳本會直接依賴 pip install numpy pyyaml tqdm pillow # 數(shù)據(jù)集標(biāo)注工具只在本地標(biāo)注時用得到 pip install labelImgopencv-python和opencv-contrib-python不要同時裝兩者提供同名模塊后裝的會覆蓋先裝的import 時表現(xiàn)得很隨機(jī)。需要 SIFT 這類擴(kuò)展算法才裝 contrib 版普通的讀幀畫框用基礎(chǔ)版足夠。另外如果這套環(huán)境裝在沒有圖形界面的服務(wù)器上把opencv-python換成opencv-python-headless。帶 GUI 的版本依賴一堆 X11 庫在容器里 import 會直接報libGL.so.1: cannot open shared object file換成 headless 版就沒事。代價是不能用cv2.imshow得改成寫視頻文件或者推流。labelImg在部分系統(tǒng)上還需要額外的 Qt 依賴裝不上不影響主流程標(biāo)注可以換到有桌面的機(jī)器上做標(biāo)注結(jié)果是一堆 txt拷過來就能用。3.4 三條自檢命令把環(huán)境黑匣子打開裝完先別急著拉代碼跑這三條# 1. torch 能不能看見 GPUcuDNN 版本是否正常 python -c import torch; print(torch, torch.__version__); print(cuda, torch.cuda.is_available()); print(cudnn, torch.backends.cudnn.version()) # 2. OpenCV 能不能正常 import版本是多少 python -c import cv2; print(cv2, cv2.__version__) # 3. 做一次真實(shí)的小矩陣運(yùn)算確認(rèn) kernel 能跑起來 python -c import torch; atorch.randn(1000,1000,devicecuda); print((aa).sum().item())第一條期望看到cuda True和一個 cuDNN 版本號。第二條只要打印出版本就行報 DLL 或 so 找不到就回 3.3 節(jié)看是不是裝成了帶 GUI 的版本。第三條最關(guān)鍵——它不只是檢查is_available()而是真的在 GPU 上跑了一次矩陣乘法前面提到的 no kernel image 那種情況只有到這一步才會暴露。三條都過了環(huán)境這關(guān)就算過了。后面再出問題基本都能定位在代碼、數(shù)據(jù)或權(quán)限上范圍一下縮小很多。4. 拉代碼、放權(quán)重、改配置從倉庫到攝像頭畫面的完整鏈路環(huán)境通了接下來是把倉庫、權(quán)重、配置、腳本這條鏈路接上。這一章按先能推理再能訓(xùn)練的順序排反過來的話你會在還沒驗(yàn)證模型能不能加載的情況下花幾小時排查訓(xùn)練不收斂。4.1 克隆倉庫后的目錄結(jié)構(gòu)與權(quán)重落位# 倉庫地址用項(xiàng)目方給出的實(shí)際地址替換這里用占位符 git clone repo-url yolo-v10 cd yolo-v10 # 看目錄結(jié)構(gòu)確認(rèn)入口腳本和配置文件都在 ls -la一個典型的目錄長這樣不同分支會有出入但核心幾項(xiàng)跑不掉yolo-v10/ ├── train.py # 訓(xùn)練入口 ├── evaluate.py # 評估入口 ├── configs/ # 模型與訓(xùn)練配置 │ └── yolov10.yaml ├── weights/ # 權(quán)重文件存放位置 │ └── yolov10.pt └── data/ # 數(shù)據(jù)集配置 └── data.yaml權(quán)重文件yolov10.pt從項(xiàng)目方發(fā)布的地址下載后放在倉庫根目錄或weights/下都行關(guān)鍵是訓(xùn)練和推理命令里的--weights路徑要跟實(shí)際位置對上。相對路徑是相對當(dāng)前工作目錄算的不是相對腳本位置所以在yolo-v10/外面執(zhí)行python yolo-v10/train.py --weights yolov10.pt會找不到文件。這類報錯信息往往是FileNotFoundError看著像權(quán)重沒下下來實(shí)際是路徑錯了。下載完建議校驗(yàn)一下文件完整性權(quán)重文件不完整時加載會報 unpickling 相關(guān)的錯# 看文件大小是否合理幾百 MB 量級 ls -lh weights/yolov10.pt # 有官方校驗(yàn)值時對一下 sha256sum weights/yolov10.pt4.2 訓(xùn)練參數(shù)與數(shù)據(jù)集 YAML每一項(xiàng)改動都會在顯存和收斂上體現(xiàn)案例給的配置是這樣的# config.yaml batch_size: 16 learning_rate: 0.001 epochs: 50 img_size: 640四個參數(shù)逐項(xiàng)過一遍這些是我實(shí)際會調(diào)整的地方batch_size直接決定顯存占用幾乎線性相關(guān)。640 輸入、8GB 顯存下16 是能跑但不寬裕的值顯存緊張的機(jī)器降到 8 甚至 4配合梯度累積補(bǔ)回等效批量。這個值設(shè)大了第一個 epoch 就 OOM設(shè)太小BN 層統(tǒng)計(jì)不準(zhǔn)mAP 會掉得莫名其妙。learning_rate取 0.001 偏保守。YOLO 系列在 SGD 優(yōu)化器下常用 0.01 起步配合 warmup0.001 更適合 Adam 系。案例沒指定優(yōu)化器我一般先按默認(rèn)跑看前幾個 epoch 的 loss 曲線——loss 劇烈震蕩就往下調(diào)一個數(shù)量級loss 幾乎不動就往上調(diào)。epochs設(shè) 50 在自建小數(shù)據(jù)集上很容易過擬合。我一般把值設(shè)大一點(diǎn)比如 200靠驗(yàn)證集 mAP 連續(xù)若干輪不漲就早停比拍腦袋定 50 靠譜。img_size必須是 32 的整數(shù)倍因?yàn)橹鞲删W(wǎng)絡(luò)的下采樣倍率決定了這個約束。填 600 會直接報錯或者被靜默取整訓(xùn)練出來的模型輸入尺寸和你以為的不一致。640 是通用值小目標(biāo)多的話可以提到 1280但顯存占用漲得很快。數(shù)據(jù)集的data.yaml是另一個必改文件# data.yaml path: ../datasets/mydata # 數(shù)據(jù)集根目錄相對本文件或絕對路徑 train: images/train # 訓(xùn)練圖目錄相對 path val: images/val # 驗(yàn)證圖目錄 nc: 3 # 類別數(shù) names: [person, car, bike] # 類別名順序即 class idnc和names必須和標(biāo)注文件里的 class id 嚴(yán)格對應(yīng)。標(biāo)注時 person 是 0、car 是 1這里寫成[car, person, bike]模型能訓(xùn)練、loss 也能降但預(yù)測出來的框全貼著錯誤的標(biāo)簽——這種錯誤在指標(biāo)上幾乎看不出來只有肉眼看檢測結(jié)果才會發(fā)現(xiàn)屬于最陰的一類。數(shù)據(jù)集目錄結(jié)構(gòu)也要對齊 YOLO 格式mydata/ ├── images/ │ ├── train/ xxx.jpg │ └── val/ yyy.jpg └── labels/ ├── train/ xxx.txt # 與圖片同名每行 類別 中心x 中心y 寬 高全部歸一化到 0~1 └── val/ yyy.txt標(biāo)完先抽查幾個 txt確認(rèn)坐標(biāo)都在 0 到 1 之間。有工具導(dǎo)出的格式是絕對像素坐標(biāo)混進(jìn)去訓(xùn)練時不會報錯只是 loss 收斂得特別慢、框到處都是。4.3 訓(xùn)練命令與日志從 loss 曲線判斷是不是白跑# 單卡訓(xùn)練--device 0 指定第一張卡 python train.py \ --data data.yaml \ --cfg yolov10.yaml \ --weights yolov10.pt \ --img-size 640 \ --batch 16 \ --epochs 50 \ --device 0參數(shù)含義--data指向數(shù)據(jù)集配置--cfg是模型結(jié)構(gòu)配置--weights是預(yù)訓(xùn)練權(quán)重從它開始微調(diào)比從零訓(xùn)練收斂快得多--img-size與配置文件里的值保持一致--device填0表示第一張卡填cpu強(qiáng)制走 CPU排錯時用得上。啟動后頭幾十行輸出要重點(diǎn)看三件事模型參數(shù)量和 GFLOPs、數(shù)據(jù)集里訓(xùn)練集和驗(yàn)證集的圖片數(shù)量、顯存占用。圖片數(shù)量對不上多半是data.yaml里的相對路徑?jīng)]解析對訓(xùn)練會拿空數(shù)據(jù)集跑loss 一直是常數(shù)。顯存占用接近上限的話趁早把 batch 降下來不然跑到一半 OOM 更難受。訓(xùn)練日志和權(quán)重一般落在runs/目錄下每輪一個子目錄里面有權(quán)重、results.csv、混淆矩陣和 PR 曲線。results.csv是后面畫曲線的數(shù)據(jù)源別急著刪。4.4 實(shí)時檢測腳本從 VideoCapture 到畫框的每一行案例給的推理腳本是這樣的我加了注釋import cv2 import torch # 加載模型。torch.hub.load 要求倉庫里有 hubconf.py # 沒有的話會報找不到 entrypoint改用倉庫自己的推理入口或直接加載本地權(quán)重 model torch.hub.load(yourusername/yolo-v10, yolov10, pretrainedTrue) model.eval() # 切推理模式關(guān)掉 dropout、固定 BN 統(tǒng)計(jì)量 cap cv2.VideoCapture(0) # 0 是默認(rèn)攝像頭外接 USB 相機(jī)通常從 1、2 開始 while True: ret, frame cap.read() if not ret: break # 讀幀失敗可能是設(shè)備被占用或已斷開 # 預(yù)處理縮放、歸一化、HWC 轉(zhuǎn) CHW、補(bǔ) batch 維 img cv2.resize(frame, (640, 640)) img img / 255.0 img img.transpose((2, 0, 1)) img torch.tensor(img).float().unsqueeze(0) # 推理 results model(img) # 逐框繪制坐標(biāo)、置信度、類別 for *box, conf, cls in results.xyxy[0]: label f{model.names[int(cls)]} {conf:.2f} cv2.rectangle(frame, (int(box[0]), int(box[1])), (int(box[2]), int(box[3])), (255, 0, 0), 2) cv2.putText(frame, label, (int(box[0]), int(box[1]) - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 0, 0), 2) cv2.imshow(YOLOv10 Detection, frame) if cv2.waitKey(1) 0xFF ord(q): break cap.release() cv2.destroyAllWindows()幾個需要說明的點(diǎn)。cap.read()返回的ret必須判斷攝像頭被其他程序占用、或者設(shè)備號填錯時它返回 False不判斷就會在cv2.resize那里報 NoneType 錯誤看著像 resize 的問題實(shí)際是取流失敗。img / 255.0之后再transpose和unsqueeze這個順序不能亂轉(zhuǎn)成 tensor 之后再除也能跑但會多一次顯存拷貝。推理前記得把張量搬到 GPU 上img img.cuda()否則模型在 GPU、輸入在 CPU會直接報設(shè)備不一致。results.xyxy[0]這種取法依賴具體返回結(jié)構(gòu)。不同版本的推理入口返回的可能是 tensor、可能是帶.boxes屬性的對象硬套一種寫法換個權(quán)重就崩。我一般的做法是先在單張圖上跑一次print(type(results))和print(results)看清楚結(jié)構(gòu)再寫解析代碼比照著教程猜快得多。5. 避坑排查五個裝完跑不起來的現(xiàn)場這一章全是真實(shí)現(xiàn)場。每條按現(xiàn)象、原因、解決寫遇到對應(yīng)的直接對號入座。5.1 現(xiàn)象torch.cuda.is_available()返回 False原因按概率從高到低排——裝成了 CPU 版輪子版本號帶cpu顯卡驅(qū)動太老支持的 CUDA 檔位低于輪子要求--extra-index-url導(dǎo)致 pip 從 PyPI 拿了 CPU 版在 WSL2 里裝的原生 Windows 版 Python兩套驅(qū)動棧對不上。解決先看版本號后綴帶cpu就卸了按 3.2 節(jié)用--index-url重裝再看nvidia-smi是否正常輸出報NVIDIA-SMI has failed說明驅(qū)動本身有問題先修驅(qū)動驅(qū)動正常但檔位太低就換低一檔的輪子標(biāo)簽。三步走完還是 False跑python -c import torch; print(torch.version.cuda)輸出為 None 就是 CPU 版無疑。5.2 現(xiàn)象訓(xùn)練第一個 epoch 就CUDA out of memory原因batch_size 相對顯存設(shè)大了img_size提到了 1280 但沒同步降 batch同一張卡上還跑著別的進(jìn)程沒退干凈數(shù)據(jù)加載的 worker 數(shù)太多每個進(jìn)程都占一份顯存上下文。解決先把 batch 減半試能跑就把--batch 8寫進(jìn)命令確認(rèn)沒有僵尸進(jìn)程nvidia-smi看顯存占用有殘留就kill -9掉對應(yīng) PID還是不夠就把img_size降到 512 或 416。另外有個容易忽略的點(diǎn)PyTorch 的緩存分配器不會立刻把顯存還給系統(tǒng)報 OOM 時實(shí)際空閑顯存可能比nvidia-smi顯示的更多遇到明明還有顯存卻 OOM的情況在訓(xùn)練腳本開頭加torch.cuda.empty_cache()試一次。5.3 現(xiàn)象cap.read()一直返回 False或者畫面卡住不動原因設(shè)備號不對筆記本內(nèi)置攝像頭是 0外接 USB 相機(jī)往往是 1 或 2攝像頭被瀏覽器、會議軟件占用Linux 下當(dāng)前用戶沒有/dev/video*的讀權(quán)限imshow后沒有waitKey導(dǎo)致窗口不刷新。解決寫個小循環(huán)遍歷設(shè)備號看哪個能讀出幀# 逐個試設(shè)備號能讀到幀就打印分辨率并退出 python -c import cv2 for i in range(5): cap cv2.VideoCapture(i) ok, frame cap.read() print(i, ok, frame.shape if ok else None) cap.release() 有輸出 True 的那個編號就是該用的。全是 False 就檢查是不是被其他程序占用Linux 下把用戶加進(jìn)video組再重新登錄。5.4 現(xiàn)象檢測框位置整體偏移或者標(biāo)簽全是錯的類別原因預(yù)處理里做了 resize 但畫框時用的是原圖坐標(biāo)兩套坐標(biāo)系沒對齊data.yaml里的names順序和標(biāo)注時的 class id 不一致標(biāo)注文件里混進(jìn)了絕對像素坐標(biāo)沒歸一化。解決畫框前把檢測結(jié)果按原圖寬/640、原圖高/640縮放回原圖坐標(biāo)系names列表順序逐項(xiàng)核對標(biāo)注工具的類別配置抽查幾個 label txt確認(rèn)所有數(shù)值都落在 0~1 之間超了就是沒歸一化用腳本批量除以圖片寬高修正。5.5 現(xiàn)象import cv2或import torch報 DLL load failed原因Windows 上缺 Visual C 運(yùn)行庫裝的是帶 GUI 的 OpenCV 但系統(tǒng)沒有圖形環(huán)境conda 環(huán)境里混進(jìn)了系統(tǒng) site-packages 的同名包多個 Python 版本共存pip 和 python 指向不同解釋器。解決先跑 3.1 節(jié)的sys.executable和pip -V對比路徑服務(wù)器或容器環(huán)境換成opencv-python-headlessWindows 裝一遍微軟的 VC 運(yùn)行庫還不行就pip list | grep -i opencvWindows 用findstr看是不是裝了多個 OpenCV 包卸到只剩一個。6. 裝完怎么驗(yàn)證三條命令加一張對照表把系統(tǒng)跑通環(huán)境裝完不等于系統(tǒng)跑通。我習(xí)慣按能加載、能推理、能實(shí)時、指標(biāo)對得上四層往下驗(yàn)每層都有明確的通過標(biāo)準(zhǔn)任何一層不過就停在那兒查不往下走。第一層環(huán)境自檢就是 3.4 節(jié)那三條命令重點(diǎn)看 GPU 上真實(shí)跑一次矩陣乘法的結(jié)果。第二層單圖推理。拿一張確認(rèn)有目標(biāo)的圖跑一次前向看輸出的框數(shù)量和置信度是否合理# 單圖推理--conf 過濾低置信度框先看 0.25 以上的 python detect.py --weights weights/yolov10.pt --source test.jpg --img-size 640 --conf 0.25如果一張明顯有人的圖輸出零個框先別懷疑模型把--conf降到 0.05 再看——有框但置信度低說明預(yù)處理或類別映射有問題依然零框說明權(quán)重沒加載成功。第三層實(shí)時鏈路。跑攝像頭并統(tǒng)計(jì)幀率只統(tǒng)計(jì)推理加繪制的耗時不含imshow的等待# 跑 100 幀輸出平均單幀耗時和等效 FPS import time, cv2, torch cap cv2.VideoCapture(0) times [] for i in range(100): ok, frame cap.read() if not ok: break t0 time.time() # 這里放你的預(yù)處理 model(frame) 畫框 times.append(time.time() - t0) cap.release() avg sum(times) / len(times) print(favg {avg*1000:.1f} ms, fps {1/avg:.1f})第四層指標(biāo)復(fù)核。用驗(yàn)證集跑一遍評估把 mAP 和訓(xùn)練日志最后一輪的數(shù)值對一下python evaluate.py --weights best.pt --data data.yaml驗(yàn)證項(xiàng)命令或動作通過標(biāo)準(zhǔn)不通過先查GPU 可用torch.cuda.is_available()返回 True 且版本號無cpu3.2 節(jié)輪子源單圖推理detect.py --source test.jpg框數(shù)量與肉眼一致--conf閾值、權(quán)重路徑實(shí)時幀率100 幀計(jì)時腳本單幀耗時穩(wěn)定無逐幀遞增是否每幀都在建 tensor、有沒有torch.no_grad()評估指標(biāo)evaluate.py --weights best.ptmAP 與訓(xùn)練日志末輪接近data.yaml的 val 路徑幀率那一項(xiàng)有個隱蔽的坑推理時忘了套torch.no_grad()每幀都會建計(jì)算圖顯存一路漲前幾十幀看著正常后面越來越慢直到 OOM??吹胶臅r逐幀遞增先補(bǔ)這一句。從那以后我每次裝完這套環(huán)境不管多急都會把單圖推理和 100 幀計(jì)時這兩步強(qiáng)制走一遍——玄學(xué)問題大多在這兩步就現(xiàn)原形了等接上業(yè)務(wù)代碼再發(fā)現(xiàn)排查成本要翻好幾倍。希望幫到你。本文還有配套的精品資源點(diǎn)擊獲取