RA8P1 模型轉(zhuǎn)換與部署教程(手勢識(shí)別)
適用范圍 :RA8P1 (Ethos?U55)
工具鏈 :e2 studio 集成 RUHMI
說明 :本工程是基于官方示例人臉識(shí)別工程基礎(chǔ)上進(jìn)行教學(xué),本教程僅新增 手勢識(shí)別 模型的獲取、轉(zhuǎn)換與部署。
0. 基礎(chǔ)知識(shí)與技術(shù)棧簡介
為了更好地理解本教程,建議先了解以下核心技術(shù)概念,這將有助于你理解為什么需要進(jìn)行“模型轉(zhuǎn)換”和“量化”操作。
核心硬件:RA8P1 與 Ethos-U55
- Renesas RA8P1 : 業(yè)界首款基于 Arm Cortex-M85 內(nèi)核的微控制器。M85 搭載了 Helium? 矢量處理單元,DSP/ML 性能及其強(qiáng)悍。
- Arm Ethos-U55 : RA8P1 內(nèi)部集成的微型神經(jīng)網(wǎng)絡(luò)處理器 (microNPU)。它的作用是專門處理繁重的卷積和矩陣運(yùn)算。
核心算法:YOLO-Fastest
- YOLO-Fastest : YOLO (You Only Look Once) 系列中最輕量級(jí)的版本之一。
- 為什么選它 :標(biāo)準(zhǔn) YOLOv5/v8 對(duì)于 MCU 來說過于龐大。YOLO-Fastest 優(yōu)化了網(wǎng)絡(luò)結(jié)構(gòu)(如使用深度可分離卷積),在保持檢測速度(FPS)的同時(shí),模型體積通常能控制在 1MB 以內(nèi),非常適合部署在 MCU 的片內(nèi) Flash 中。
核心流程:RUHMI 與 量化 (Quantization)
- RUHMI / AI Navigator : Renesas 的 AI 部署工具鏈。它的核心任務(wù)是將通用的 AI 模型(如 .pt/.onnx)“翻譯”成嵌入式工程可用的 C 代碼。
- INT8 量化 (關(guān)鍵) :Ethos-U55 是一個(gè) 定點(diǎn)加速器 ,它只能通過整數(shù)(INT8)進(jìn)行計(jì)算,不支持浮點(diǎn)數(shù)(Float32)。
- 轉(zhuǎn)換 :工具會(huì)將模型中的權(quán)重(如 0.1234)映射為整數(shù)(如 12)。
- 校準(zhǔn) (Calibration) :為了讓整數(shù)運(yùn)算的結(jié)果盡可能接近原始浮點(diǎn)結(jié)果,我們需要提供“校準(zhǔn)集”圖片,讓工具統(tǒng)計(jì)數(shù)據(jù)的分布范圍(動(dòng)態(tài)范圍)。如果校準(zhǔn)沒做好(如 Mean/Std 設(shè)置錯(cuò)誤),模型在板子上跑出來的結(jié)果就會(huì)完全不可用。
1. 環(huán)境搭建與 RUHMI 安裝
RUHMI (Renesas AI) 有兩種安裝方式:一種是圖形化界面,一種是命令行。本教程講解通過圖形化界面進(jìn)行安裝與配置。
1.1 安裝 e2 studio
首先下載并安裝 Pyron e2 studio。安裝完成后打開模型轉(zhuǎn)換工具(RUHMI Dashboard)。

(圖示路徑)
1.2 安裝配置 Python 3.10 (關(guān)鍵步驟)
如果在選擇路徑后提示環(huán)境缺失(如提示找不到 Python),請按照以下步驟安裝。
第一步:下載 Python 3.10
e2 studio 通過 Windows 的 py 啟動(dòng)器檢測版本,必須安裝官方純凈版。
下載地址 或前往 Python 官網(wǎng)下載 Python 3.10.x(建議 3.10.11 或更新版本)。
第二步:安裝設(shè)置(非常重要)
運(yùn)行安裝包時(shí),在第一個(gè)界面:
- 不要勾選
Add Python 3.10 to PATH—— 保護(hù)現(xiàn)有環(huán)境,避免沖突。 - 務(wù)必勾選
Install launcher for all users (Recommended)—— 讓 e2 studio 能通過py -3.10命令找到它。 - 點(diǎn)擊
Install Now完成安裝。
安裝完成后,重啟 e2 studio,按照之前的步驟再次點(diǎn)擊 Setup Environment 。
當(dāng)出現(xiàn)如下圖示時(shí),代表環(huán)境配置成功:
2. 模型訓(xùn)練:手勢檢測 (YOLO-Fastest)
本節(jié)介紹從數(shù)據(jù)集準(zhǔn)備到訓(xùn)練出 .pt 文件的全流程。
- 任務(wù) :2 類目標(biāo)檢測:
ok、palm(張開手掌) - 模型 :YOLO-Fastest (2路輸出 head)
- 輸入 :
192x192,RGB 3通道 - 預(yù)處理 :
x/255(0..1),無 mean/std 減法
2.1 準(zhǔn)備數(shù)據(jù)集 (HaGRID 子集)
我們使用 HaGRID 的 YOLO 格式數(shù)據(jù),僅保留兩類(0=ok, 1=palm)。
下載與解壓
在 Windows PowerShell 執(zhí)行以下命令:
mkdir D:gesture_ai
cd D:gesture_ai
# 下載示例數(shù)據(jù)集 (約10GB)
curl.exe -L -o yolo_format.zip "https://huggingface.co/datasets/testdummyvt/hagRIDv2_512px_10GB/resolve/main/yolo_format.zip?download=true"
# 解壓
mkdir hagrid_yolo_sample
tar -xf .yolo_format.zip -C .hagrid_yolo_sample
目錄結(jié)構(gòu)示例 :
D:gesture_aihagrid_ok_palm_1imagestrain|val|testD:gesture_aihagrid_ok_palm_1labelstrain|val|testD:gesture_aihagrid_ok_palm_1data_ok_palm.yaml

2.2 訓(xùn)練環(huán)境配置
1. 拉取代碼庫
cd D:gesture_ai
git clone https://github.com/Nota-NetsPresso/ModelZoo-YOLOFastest-for-ARM-U55-M85.git
cd .ModelZoo-YOLOFastest-for-ARM-U55-M85
pip install -r requirements.txt
2. 解決版本兼容性問題
- 該倉庫建議
torch >= 1.11, < 2.0。 - 如果使用 torch 1.x,需降級(jí) NumPy 防止報(bào)錯(cuò):
pip install "numpy<2" - RTX 4060 顯卡建議安裝 CUDA 11.7 對(duì)應(yīng)的 torch 版本:
pip uninstall -y torch torchvision pip install torch==1.13.1+cu117 torchvision==0.14.1+cu117 --index-url https://download.pytorch.org/whl/cu117
2.3 執(zhí)行訓(xùn)練
D:gesture_ai.venvScriptspython.exe train.py
--data D:gesture_aihagrid_ok_palm_1data_ok_palm.yaml
--cfg .modelsyolo-fastest.yaml
--weights ""
--imgsz 192
--batch-size 64
--epochs 200
--device 0
--workers 4
--project D:gesture_airuns
--name ok_palm_192
--exist-ok
--noplots

訓(xùn)練完成后得到 best.pt。
常見問題:DataLoader worker exited unexpectedly
解決方法:將 --workers 設(shè)為 0 并續(xù)訓(xùn)。
D:gesture_ai.venvScriptspython.exe train.py
--resume D:gesture_airunsok_palm_192weightslast.pt
--epochs 200
--workers 0
...
3. 模型導(dǎo)出 (ONNX)
RUHMI 支持導(dǎo)入 ONNX,因此我們需要將 PyTorch 模型導(dǎo)出為 ONNX 格式。需要保留兩路 head 輸出給板端處理。
注意 :必須在倉庫根目錄下運(yùn)行導(dǎo)出腳本,否則會(huì)報(bào) ModuleNotFoundError: No module named 'models'。
3.1 創(chuàng)建導(dǎo)出腳本 export_onnx_heads.py
在倉庫根目錄新建文件 export_onnx_heads.py,代碼如下:
import torch
import torch.nn as nn
CKPT = r"D:gesture_ai
unsok_palm_192weightsest.pt"
OUT = r"D:gesture_aiok_palm_192_heads.onnx"
ck = torch.load(CKPT, map_location="cpu")
model = ck["model"].float().eval()
class HeadWrapper(nn.Module):
def __init__(self, m):
super().__init__()
self.m = m
def forward(self, x):
y, feats = self.m(x)
# feats[0] - > (1,3,12,12,7)
# feats[1] - > (1,3,6,6,7)
return feats[0], feats[1]
w = HeadWrapper(model)
dummy = torch.zeros(1, 3, 192, 192)
torch.onnx.export(
w,
dummy,
OUT,
input_names=["images"],
output_names=["p4_12x12", "p5_6x6"],
opset_version=13,
do_constant_folding=False,
)
print("saved:", OUT)
3.2 運(yùn)行導(dǎo)出
D:gesture_ai.venvScriptspython.exe .export_onnx_heads.py
正常導(dǎo)出的 ONNX 文件大小約為 1MB 左右。
4. RUHMI 模型轉(zhuǎn)換 (AI Navigator)
參考關(guān)于RA生態(tài)工作室的視頻號(hào)回放:
啟動(dòng) RUHMI AI Navigator 進(jìn)行轉(zhuǎn)換。
4.1 準(zhǔn)備校準(zhǔn)數(shù)據(jù)集 (Calibration Dataset)
用于 INT8 量化校準(zhǔn)。建議從訓(xùn)練集中隨機(jī)抽取 200 張圖片。
PowerShell 隨機(jī)抽取腳本:
$src = "D:gesture_aihagrid_ok_palm_1images rain"
$dst = "D:gesture_aicalib_ok_palm_200"
mkdir $dst -Force | Out-Null
Get-ChildItem $src -File | Get-Random -Count 200 | Copy-Item -Destination $dst
在 AI Navigator 中選擇該目錄作為 Calibration dataset。
4.2 設(shè)置 Mean / Std (重要)
由于訓(xùn)練時(shí)只做了 x/255 歸一化,板端輸入必須匹配。
推薦設(shè)置(板端輸入 0..1 float) :
- Mean :
0, 0, 0 - Std :
1, 1, 1(如果在板端沒做 /255,這里要設(shè)為 255)
注意 :不要使用
mean=127.5, std=127.5,那是 -1..1 的歸一化方式。

4.3 檢查轉(zhuǎn)換輸出
轉(zhuǎn)換成功后,關(guān)鍵生成的源文件位于 buildMCUcompilationsrc:
model.c/.hsub_xxxx_model_data.c/.hsub_xxxx_invoke.c/.h- ...

5. 部署到工程:CPU 版本
目標(biāo):將 CPU-only 產(chǎn)物集成到 RT-Thread 工程,驗(yàn)證前處理與解碼邏輯。
5.1 文件集成
將 RUHMI 生成的 compilationsrc 下的文件復(fù)制到工程目錄 src/models/:
compute_sub_0000.cmodel.ckernel_library_int.ckernel_library_utils.c

5.2 編譯配置 (SConscript)
修改 src/models/SConscript,加入剛復(fù)制的源文件:
src = [
os.path.join(cwd, 'model.c'),
os.path.join(cwd, 'compute_sub_0000.c'),
os.path.join(cwd, 'kernel_library_int.c'),
os.path.join(cwd, 'kernel_library_utils.c'),
]

5.3 關(guān)鍵代碼修改
1. 輸入前處理對(duì)齊
修改 src/hal_entry.c,確保輸入轉(zhuǎn)為 0..1 (float):
const float inv255 = 1.0f / 255.0f;
dst[0 * plane_size + pixel_idx] = (float)r * inv255;
dst[1 * plane_size + pixel_idx] = (float)g * inv255;
dst[2 * plane_size + pixel_idx] = (float)b * inv255;

2. 后處理解碼 (YOLOv5公式)
修改 src/yolo/yolo_rtthread.c,使用 YOLOv5 的解碼公式替代傳統(tǒng) Darknet 公式:
float stride_pix = (float)INPUT_W / (float)grid;
float cx = (sigmoid(tx) * 2.0f - 0.5f + j) * stride_pix;
float cy = (sigmoid(ty) * 2.0f - 0.5f + i) * stride_pix;
float ww = (sigmoid(tw) * 2.0f); ww = ww * ww * anchor_w;
float hh = (sigmoid(th) * 2.0f); hh = hh * hh * anchor_h;

3. 調(diào)試顯示優(yōu)化
建議在 LCD 顯示分類文本、置信度,并用不同顏***分 OK/PALM。

6. 部署到工程:NPU (Ethos-U55) 版本
目標(biāo):啟用 NPU 加速。RUHMI 針對(duì) NPU 通常生成“三段式”代碼:前處理(CPU) -> NPU推理 -> 后處理(CPU)。
6.1 文件集成
RUHMI NPU 版輸出包含 sub_0001 (NPU) 等部分。需復(fù)制以下文件到 src/models/:
compute_sub_0000.c(CPU 前處理)compute_sub_0002.c(CPU 后處理)sub_0001_*.c(NPU 相關(guān):command strteam, weights, invoke)model.c,ethosu_common.h等

6.2 編譯配置
修改 SConscript,加入所有新文件:
src = [
os.path.join(cwd, 'model.c'),
os.path.join(cwd, 'compute_sub_0000.c'),
os.path.join(cwd, 'compute_sub_0002.c'),
os.path.join(cwd, 'sub_0001_command_stream.c'),
os.path.join(cwd, 'sub_0001_invoke.c'),
os.path.join(cwd, 'sub_0001_model_data.c'),
os.path.join(cwd, 'sub_0001_tensors.c'),
# ... 其他依賴庫
]
6.3 關(guān)鍵點(diǎn):NPU 內(nèi)存配置 (Arena)
1. Arena 放入 OSPI RAM
修改 sub_0001_invoke.c,將 arena 數(shù)組放到 OSPI 段,避免占用寶貴的內(nèi)部 SRAM:
__attribute__((aligned(16), section(".ospi1_cs0_noinit"))) uint8_t sub_0001_arena[...];

2. 輸入數(shù)據(jù)寫入 Arena
NPU 的輸入通常直接映射到 Arena 的起始位置(offset 0)。
修改 model.c, 直接將量化后的數(shù)據(jù)寫入 Arena ,而不是臨時(shí) buffer:
// 獲取 NPU 輸入在 Arena 中的地址
int8_t* npu_in = (int8_t*)(sub_0001_arena + sub_0001_address_images_...);
// 執(zhí)行前處理,直接輸出到 npu_in
compute_sub_0000(compute_arena_sub_0000, buf_images, npu_in);
3. Cache 維護(hù) (非常重要)
在調(diào)用 NPU 前后必須維護(hù) D-Cache,否則 NPU 讀不到最新數(shù)據(jù)或 CPU 讀不到 NPU 的輸出。
// Invoke 前:Clean (將 CPU 寫的數(shù)據(jù)刷入 RAM)
SCB_CleanDCache_by_Addr(sub_0001_arena, sizeof(sub_0001_arena));
// Invoke
sub_0001_invoke(...);
// Invoke 后:Invalidate (讓 CPU 重新從 RAM 讀取)
SCB_InvalidateDCache_by_Addr(sub_0001_arena, sizeof(sub_0001_arena));
6.4 調(diào)試建議
- 驗(yàn)證 NPU 是否工作 :打印輸入和輸出的 hash 值或 min/max 值。如果輸入變了但輸出 hash 不變,說明 NPU 沒運(yùn)行或 invoke 失敗。
- 調(diào)整閾值 :初期將
CONF_THRESH設(shè)低(如 0.2),觀察max_sig,確認(rèn)有檢測結(jié)果后再調(diào)高。

審核編輯 黃宇
-
AI
+關(guān)注
關(guān)注
91文章
39812瀏覽量
301479 -
NPU
+關(guān)注
關(guān)注
2文章
374瀏覽量
21108
發(fā)布評(píng)論請先 登錄
【瑞薩AI挑戰(zhàn)賽】階段一:基于RA8P1的人臉識(shí)別模型轉(zhuǎn)換和部署
直播有禮 | RUHMI工具介紹及模型部署演示--瑞薩AI線上技術(shù)月收官!!
留言有禮+直播有禮 | 瑞薩邊緣AI線上技術(shù)月——瑞薩高性能AI MCU RA8P1介紹及應(yīng)用
“芯”年來襲 | 瑞薩邊緣AI線上技術(shù)月暨挑戰(zhàn)賽
1 GHz Arm? Cortex?-M85 MCU上部署AI模型
RA8P1部署ai模型指南:從訓(xùn)練模型到部署?|?本周六
【直播預(yù)告】RT-Thread帶你首發(fā)體驗(yàn):基于瑞薩RA8P1 MCU的Titan Board | 問學(xué)直播
正式上市: Cortex-M85 RA8P1 Titan Board重新定義,邊緣AI的性能邊界 | 產(chǎn)品動(dòng)態(tài)
RT-Thread首款AI硬件搶先曝光!——RA8P1 Titan Board
貿(mào)澤開售Renesas Electronics RA8P1微控制器 為先進(jìn)AI提供高CPU性能
地表最強(qiáng)M85內(nèi)核芯片-RA8P1測評(píng) | 技術(shù)集結(jié)
【瑞薩AI挑戰(zhàn)賽】從 0 到 1 跑通 RA8P1 NPU:YOLO-Fastest 訓(xùn)練、轉(zhuǎn)換與端側(cè)部署全鏈路實(shí)戰(zhàn)
評(píng)論