已在GitHub開源與本博客同步的YOLOv8_RK3588_object_pose
項目,地址:https://github.com/A7bert777/YOLOv8_RK3588_object_pose
詳細使用教程,可參考README.md或參考本博客第六章 模型部署
文章目錄
- 一、項目回顧
- 二、文件梳理
- 三、YOLOv8-pose模型訓練
- 四、PT轉ONNX
- 五、ONNX轉RKNN
- 六、模型部署
一、項目回顧
博主之前有寫過YOLO11、YOLOv8目標檢測&圖像分割、YOLOv10目標檢測、MoblieNetv2圖像分類的模型訓練、轉換、部署文章,感興趣的小伙伴可以了解下:
【YOLO11部署至RK3588】模型訓練→轉換RKNN→開發板部署
【YOLOv8部署至RK3588】模型訓練→轉換rknn→部署全流程
【YOLOv8seg部署RK3588】模型訓練→轉換rknn→部署全流程
【YOLOv10部署RK3588】模型訓練→轉換rknn→部署流程
【MobileNetv2圖像分類部署至RK3588】模型訓練→轉換rknn→部署流程
YOLOv8n部署RK3588開發板全流程(pt→onnx→rknn模型轉換、板端后處理檢測)
最近做了一個YOLOv8 pose的關鍵點檢測項目,涉及模型訓練、轉ONNX、轉RKNN量化以及RK3588開發板調試部署,查了下CSDN上暫未有關于YOLOv8 pose在RK系列開發板的免費詳細教程,遂開此文,相互學習。
二、文件梳理
YOLOv8 pose的訓練、轉換、部署所需四個項目文件:
第一個:YOLOv8模型訓練項目文件(鏈接在此),
第二個:瑞芯微倉庫中YOLOv8的pt轉onnx項目文件(鏈接在此);
第三個:用于在虛擬機中進行onnx轉rknn的虛擬環境配置項目文件(鏈接在此);
第四個:在開發板上做模型部署的項目文件(鏈接在此)。
注:
1.第四個項目文件中的內容很多,里面涉及到rknn模型轉換以及模型部署的所有內容,所以該文件在模型轉換中也要與第三個文件配合使用。
2.我上面的四個鏈接都是已經鏈接到項目的對應版本了,打開鏈接后直接git clone或者download zip即可。
這四個文件的版本如下:
第一個模型訓練文件是v8.3之前的版本,因為v8.3之后就是YOLO11了,此處選擇的是v8.2.82
第二個ONNX轉換文件為默認main分支
第三個文件rknn-toolkit2為v2.1.0
第四個文件rknn_model_zoo也用v2.1.0(rknn-toolkit2盡量和rknn_model_zoo版本一致)
如圖所示:
三、YOLOv8-pose模型訓練
YOLOv8-pose的模型訓練和此前的YOLOv8、YOLOv10基本一致。
先從訓練環境搭建開始,YOLOv8-pose的環境搭建非常簡單,不需要再pip install -r requirements.txt和pip install -e .了。
步驟如下:
1. conda create -n yolov8 python=3.9
2. conda activate yolov8
3. pip install ultralytics
配置好環境后,把另外一些必要的文件準備好:
自己創建一個train.py腳本,放在和ultralytics文件夾同級位置,然后把ultralytics文件夾中的yolov8.yaml文件復制出來,在把yolov8n.pt放進來,因為訓練開始前會用預訓練權重進行Automatic Mixed Precision(AMP自動混合精度)check,如果你沒放預訓練權重,終端會自己下載,但是速度較慢,所以先提前放置過來。
train.py內容如下:
from ultralytics import YOLO# 加載模型
model = YOLO("yolov8-pose.yaml") # 從頭開始構建新模型
#model = YOLO("yolov8n.pt") # 加載預訓練模型(推薦用于訓練)# Use the model
# 以下設置最好不要改動!!!可能會出現關鍵點漂移的問題
results = model.train(data="knob-pose.yaml",epochs=300,batch=4,augment=False, # 關閉所有數據增強degrees=0, # 旋轉角度=0translate=0, # 平移=0scale=0, # 縮放=0shear=0, # 剪切=0flipud=0, # 上下翻轉概率=0fliplr=0 # 左右翻轉概率=0
)
yolov8.yaml內容如下:
# Ultralytics YOLO 🚀, AGPL-3.0 license
# YOLOv8 object detection model with P3-P5 outputs. For Usage examples see https://docs.ultralytics.com/tasks/detect# Parameters
nc: 1 # number of classes
scales: # model compound scaling constants, i.e. 'model=yolov8n.yaml' will call yolov8.yaml with scale 'n'# [depth, width, max_channels]n: [0.33, 0.25, 1024] # YOLOv8n summary: 225 layers, 3157200 parameters, 3157184 gradients, 8.9 GFLOPss: [0.33, 0.50, 1024] # YOLOv8s summary: 225 layers, 11166560 parameters, 11166544 gradients, 28.8 GFLOPsm: [0.67, 0.75, 768] # YOLOv8m summary: 295 layers, 25902640 parameters, 25902624 gradients, 79.3 GFLOPsl: [1.00, 1.00, 512] # YOLOv8l summary: 365 layers, 43691520 parameters, 43691504 gradients, 165.7 GFLOPsx: [1.00, 1.25, 512] # YOLOv8x summary: 365 layers, 68229648 parameters, 68229632 gradients, 258.5 GFLOPs# YOLOv8.0n backbone
backbone:# [from, repeats, module, args]- [-1, 1, Conv, [64, 3, 2]] # 0-P1/2- [-1, 1, Conv, [128, 3, 2]] # 1-P2/4- [-1, 3, C2f, [128, True]]- [-1, 1, Conv, [256, 3, 2]] # 3-P3/8- [-1, 6, C2f, [256, True]]- [-1, 1, Conv, [512, 3, 2]] # 5-P4/16- [-1, 6, C2f, [512, True]]- [-1, 1, Conv, [1024, 3, 2]] # 7-P5/32- [-1, 3, C2f, [1024, True]]- [-1, 1, SPPF, [1024, 5]] # 9# YOLOv8.0n head
head:- [-1, 1, nn.Upsample, [None, 2, "nearest"]]- [[-1, 6], 1, Concat, [1]] # cat backbone P4- [-1, 3, C2f, [512]] # 12- [-1, 1, nn.Upsample, [None, 2, "nearest"]]- [[-1, 4], 1, Concat, [1]] # cat backbone P3- [-1, 3, C2f, [256]] # 15 (P3/8-small)- [-1, 1, Conv, [256, 3, 2]]- [[-1, 12], 1, Concat, [1]] # cat head P4- [-1, 3, C2f, [512]] # 18 (P4/16-medium)- [-1, 1, Conv, [512, 3, 2]]- [[-1, 9], 1, Concat, [1]] # cat head P5- [-1, 3, C2f, [1024]] # 21 (P5/32-large)- [[15, 18, 21], 1, Detect, [nc]] # Detect(P3, P4, P5)
knob-pose.yaml文件如下:
# Ultralytics YOLO 🚀, AGPL-3.0 license
# Custom Knob Pose Dataset Configuration# Dataset paths (absolute paths already specified)
train: /xxx/Dataset/Patrol_system/Knob/Knob_KeyPoint_Dataset/v2_new_koutu_dataset/v2/images/train
val: /xxx/Dataset/Patrol_system/Knob/Knob_KeyPoint_Dataset/v2_new_koutu_dataset/v2/images/val# Keypoints configuration
kpt_shape: [2, 2] # 2 keypoints (head, tail), each with (x,y,visibility)
#flip_idx: [1, 0] # When image is flipped horizontally, head<->tail should swap
flip_idx: [] # 設為空列表,禁用翻轉交換
# Classes
names:0: knob# No need for download section since using custom dataset
執行train.py文件:python train.py,訓練完成后,如下所示:
四、PT轉ONNX
把前面訓練得到的PT模型放置到第二個項目文件中
注:我把PT模型重命名為4_8_knob_pose_head_tail_best.pt,把第二項目文件重命名為ultralytics_yolov8_pt2onnx_8.2.82,其余照舊。
注:放yolov8n.pt是為了避免自動下載模型,因為要做AMP自動混合精度檢測,提前放模型進去,避免龜速下載。
調整 ./ultralytics/cfg/default.yaml 中 model 文件路徑,默認為 yolov8n.pt,若自己訓練模型,請調接至對應的路徑。支持檢測、分割、姿態、旋轉框檢測模型。我修改的結果如下:
修改完default.yaml后,在終端輸入:
export PYTHONPATH=./
python ./ultralytics/engine/exporter.py
執行完畢后,會生成 4_8_knob_pose_head_tail_best.onnx 模型,如下所示:
★★★
這里要著重說一下,如果你之前在配置yolov8的conda環境時,命令如下:pip install ultralytics,那么你的環境列表中應該有當前最新版本的ultralytics,輸入conda list -n xxx,查詢你現在環境中的ultralytics版本,博主此時的最新版本為8.3.112
但是你在ultralytics_yolov8_pt2onnx_8.2.82文件夾下運行python ./ultralytics/engine/exporter.py時,終端應該會顯示8.2.82版本:
,
這是合理的,因為在瑞芯微提供的ultralytics_yolov8中,他們使用的ultralytics即ultralytics文件夾是8.2.82的,而當前工作目錄下的 ultralytics 8.2.82文件夾覆蓋了已安裝的包版本,所以如果你在轉ONNX模型時,終端顯示若不是8.2.82版本的ultralytics,則轉換失敗
所以說,瑞芯微統一提供了一個使用8.2.82版本的ultralytics(并在此基礎上做了微調)供模型轉換。
得到onnx模型后,用netron工具打開,看輸入輸出是否正常:
輸入統一都是1×3×640×640,輸出的話,前面三個大家都是統一的,即1×65×80×80,1×65×40×40,1×65×20×20,這是對應80×80、40×40、20×20大小的特征圖,最后一個輸出1×2×2×8400,每個人不一樣,1為batchsize,2為關鍵點,2為x,y,8400為8400個anchor:80×80+40×40+20×20=8400。
以下是瑞芯微官方ONNX模型和自己轉換的ONNX模型的對比:
至于說為什么瑞芯微官方的ONNX模型輸出的第三個參數為3,是因為在訓練的時候,x,y,visible參數設置了3,而我設置為2:
,所以,如果大家為了能夠直接適配我的板端部署代碼,建議在訓練的時候,也在yaml文件中設置為2
五、ONNX轉RKNN
在進行這一步的時候,如果你是在云服務器上運行,請先確保你租的卡能支持RKNN的轉換運行。博主是在自己的虛擬機中進行轉換。
先安裝轉換環境
這里我們先conda create -n rknn210 python=3.8創建環境,創建完成如下所示:
現在需要用到rknn-toolkit2-2.1.0文件。
進入rknn-toolkit2-2.1.0\rknn-toolkit2-2.1.0\rknn-toolkit2\packages文件夾下,看到如下內容:
在終端激活環境,在終端輸入pip install -r requirements_cp38-2.1.0.txt -i https://pypi.tuna.tsinghua.edu.cn/simple
然后再輸入pip install rknn_toolkit2-2.1.0+708089d1-cp38-cp38-linux_x86_64.whl
然后,我們的轉rknn環境就配置完成了。
現在要進行模型轉換,其實大家可以參考rknn_model_zoo-2.1.0\examples\yolov8_pose下的README指導進行轉換:
這里我也詳細再說一遍轉換流程:先進入rknn_model_zoo-2.1.0\examples\yolov8_pose\python文件夾,先打開convert.py,進行適配參數修改:
第一步:
第二步:
修改convert.py中的custom_hybrid :
這一步極為重要,直接關系到你的模型在開發板上能否正常運行以及運行后的效果!
所謂custom_hybrid ,是指用于指定混合量化時的 ??自定義量化節點對??。每個子列表包含兩個節點:
??第一個節點??:需要量化的操作(如卷積層輸出)。
??第二個節點??:該量化操作的后續節點(如 Concat 層的輸入節點)
RKNN Toolkit 會根據這兩個節點的連接關系,確定量化的范圍。
下面來講如何修改custom_hybrid:
用netron打開你的onnx模型,找到圖示位置,即16×64×3×3Conv、16×128×3×3Conc、16×256×3×3Conv:,找到這幾個Conv下的激活函數即Relu(因為我用的是Relu激活函數,如果你的是Silu或Mul激活函數,也無所謂,都會在此處顯示,以此類推)
先點擊圖中1號Relu,如下所示:
可以看到,1號Relu的輸出名name是286,依次類推,我們看到2號和3號的輸出名name是298和310
,然后,把找到的286,298和310寫到convert.py中的該位置處:
最后,再用netron工具,打開onnx模型,查下最終的輸出名:
,可以看到,最終的輸出是443,此時在convert.py的此處均修改為443:
當然,此處完全根據你自己轉出的ONNX模型中對應節點的名稱來,有的是純數字,有的是很長的地址如/model.22/cv4.2/cv4.2.0/act/Relu_output_0,都無所謂,只要找對位置即可。
修改完成后,在yolov8_pose/model下放自己的ONNX模型,然后在yolov8_pose/python下啟動終端并啟動環境,執行命令:python convert.py ../model/4_8_knob_pose_head_tail_best.onnx rk3588
結果如下:
可以看到,我們的模型轉換并量化成功。
轉換后的rknn模型已保存在model文件夾下。
將該模型復制到win主機下,用netron打開,如下所示:
可以看到,我們的模型為1×2×2×8400,和瑞芯微官方ONNX模型轉出的RKNN模型對比如下:
可以看到,唯一不同的是,我們的output3是1×2×2×8400,官方的output3是1×17×3×8400。
2和17:是每個目標的關鍵點數量
2和3:是x,y,visible,我訓練時沒有加visible,所以為2
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
拓展:
這里講一下為什么要在convert.py中進行修改,而不是直接將py文件中的proposal設為True,如下所示:
在我把proposal設為True后,表示啟用自動建議混合量化節點,這個時候的量化由RKNN-Toolkit自動完成,此時執行轉換命令,似乎也能成功,如下所示:
但如果我們去用這個rknn模型在開發板上推理時,終端會顯示如下:
作為對比,同樣的一張輸入圖片,用proposal設為False后修改custom_hybrid參數后轉出的rknn模型再去推理,如下所示:
換言之,如果想用瑞芯微官方提供的推理、后處理代碼,關鍵點輸出通道是不能被量化的,因此選擇自動量化后,所有通道均被量化,與代碼不再適配,導致關鍵點坐標輸出錯誤,因此方便起見,采用手動設置custom_hybrid參數方法。
各位大佬可以自己寫下推理和后處理代碼,以適配全自動量化的各個通道輸出(狗頭)
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
六、模型部署
如果前面流程都已實現,模型的結構也沒問題的話,則可以進行最后一步:模型端側部署。
我已經幫大家做好了所有的環境適配工作,科學上網后訪問博主GitHub倉庫:YOLOv8_RK3588_object_pose 進行簡單的路徑修改就即可編譯運行。
重點:請大家舉手之勞,幫我的倉庫點個小星星
點了小星星的同學可以免費幫你解決轉模型與部署過程中遇到的問題。
git clone后把項目復制到開發板上,按如下流程操作:
①:cd build,刪除所有build文件夾下的內容
②:cd src 修改main.cc,修改main函數中的如下三個內容:
將這三個參數改成自己的絕對路徑,
并根據自己的情況設置skeleton:
③:cd src 修改postprocess.cc下的txt標簽的相對路徑:
解釋一下,這個標簽路徑中的內容如下所示:
其實就是你在訓練yolov8時在yaml配置文件中的類別名
④修改include/postprocess.h 中的宏 OBJ_CLASS_NUM
⑤:把你之前訓練好并已轉成RKNN格式的模型放到YOLOv8_RK3588_object_pose/model文件夾下,然后把你要檢測的所有圖片都放到YOLOv8_RK3588_object_pose/inputimage下。
在運行程序后,生成的結果圖片在YOLOv8_RK3588_object_pose/outputimage下
⑥:進入build文件夾進行編譯
cd build
cmake ..
make
在build下生成可執行文件文件:rknn_yolov8pose_demo
在build路徑下輸入
./rknn_yolov8pose_demo
運行結果如下所示:
原inputimage文件夾下的圖片:
在執行完./rknn_yolov8pose_demo后在outputimage下的輸出結果圖片:
原inputimage文件夾下的圖片:
在執行完./rknn_yolov8pose_demo后在outputimage下的輸出結果圖片:
注:由于我的檢測結果幾乎就是整個圖片,所以藍色的檢測框和圖片大小幾乎一致,導致目標框左上角的目標類別和置信度看不到,不過沒關系,可以在終端看到,得分非常高,接近100,關鍵點的位置檢測也非常準。
上述即博主此次更新的YOLOv8-pose部署RK3588,包含PT轉ONNX轉RKNN的全流程步驟,歡迎交流!