Skip to main content

Deepx M1 PCIe M.2 Key Adapter

DX-M1 AI芯片是DEEPX公司, 凭借突破性的能效设计,功耗仅1–5W,却能释放高达200 GPU级TOPS的算力,将边缘设备从被动接收者,转变为主动决策者。 这里介绍如何在Neardi RK3588开发板上面运行DX M1算力卡。

1. Environments

1.1 Hardware

首先准备好Neardi RK3588开发板和DX-M1算力卡,如下:

1.2 Software

需要从Deepx github下载NPU driverdx-runtime。 从上面地址克隆后, 则进行编译及安装。

2. Build NPU driver

NPU驱动目录代码如下: linx@ubuntu2204-docker:~/dx_rt_npu_linux_driver$ tree -L 1

.
├── debian
├── dkms.conf
├── install.sh
├── LICENSE
├── modules
├── README.md
├── release
├── RELEASE_NOTES_MATERIAL.md
├── RELEASE_NOTES.md
├── release.ver
├── scripts
└── uninstall.sh

驱动代码是在modules目录里, 在此目录创建一个编译脚本, 如下:

make DEVICE=m1 PCIE=deepx \
ARCH=arm64 CROSS_COMPILE=/mnt/data/linx/rk3588.r6/prebuilts/gcc/linux-x86/aarch64/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu/bin/aarch64-none-linux-gnu- \
KERNEL_DIR=/mnt/data/linx/rk3588.r6/kernel

需要指定交叉编译工具和kernel目录。 这样就可以进行编译, 如下:

linx@ubuntu2204-docker:~/rk3588.r6/dx_rt_npu_linux_driver/modules$ ./compile.sh
** Standard Build **
** RT Driver Version : 2.1.0 **
** PCie Driver Version : 2.0.1 **
make -C /mnt/data/linx/rk3588.r6/kernel M=/mnt/data/linx/rk3588.r6/dx_rt_npu_linux_driver/modules ARCH=arm64 CROSS_COMPILE=/mnt/data/linx/rk3588.r6/prebuilts/gcc/linux-x86/aarch64/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu/bin/aarch64-none-linux-gnu- modules CCFLAGS="-DRT_VERSION_MAJOR=2 -DRT_VERSION_MINOR=1 -DRT_VERSION_PATCH=0 -DPCIE_VERSION_MAJOR=2 -DPCIE_VERSION_MINOR=0 -DPCIE_VERSION_PATCH=1"
make[1]: Entering directory '/mnt/data/linx/rk3588.r6/kernel-6.1'
CC [M] /mnt/data/linx/rk3588.r6/dx_rt_npu_linux_driver/modules/rt/dxrt_drv.o
CC [M] /mnt/data/linx/rk3588.r6/dx_rt_npu_linux_driver/modules/rt/dxrt_drv_cdev.o
CC [M] /mnt/data/linx/rk3588.r6/dx_rt_npu_linux_driver/modules/rt/dxrt_drv_message.o
CC [M] /mnt/data/linx/rk3588.r6/dx_rt_npu_linux_driver/modules/rt/dxrt_drv_queue.o
CC [M] /mnt/data/linx/rk3588.r6/dx_rt_npu_linux_driver/modules/rt/dxrt_sched.o
CC [M] /mnt/data/linx/rk3588.r6/dx_rt_npu_linux_driver/modules/rt/dxrt_drv_dl.o
LD [M] /mnt/data/linx/rk3588.r6/dx_rt_npu_linux_driver/modules/rt/dxrt_driver.o
CC [M] /mnt/data/linx/rk3588.r6/dx_rt_npu_linux_driver/modules/pci_deepx/dw-edma-pcie.o
CC [M] /mnt/data/linx/rk3588.r6/dx_rt_npu_linux_driver/modules/pci_deepx/dw-edma-core.o
CC [M] /mnt/data/linx/rk3588.r6/dx_rt_npu_linux_driver/modules/pci_deepx/dw-edma-v0-core.o
CC [M] /mnt/data/linx/rk3588.r6/dx_rt_npu_linux_driver/modules/pci_deepx/dw-edma-v0-debugfs.o
CC [M] /mnt/data/linx/rk3588.r6/dx_rt_npu_linux_driver/modules/pci_deepx/dw-edma-thread.o
CC [M] /mnt/data/linx/rk3588.r6/dx_rt_npu_linux_driver/modules/pci_deepx/dx_util.o
CC [M] /mnt/data/linx/rk3588.r6/dx_rt_npu_linux_driver/modules/pci_deepx/dx_cdev.o
CC [M] /mnt/data/linx/rk3588.r6/dx_rt_npu_linux_driver/modules/pci_deepx/dx_sgdma_cdev.o
CC [M] /mnt/data/linx/rk3588.r6/dx_rt_npu_linux_driver/modules/pci_deepx/dx_cdev_ctrl.o
CC [M] /mnt/data/linx/rk3588.r6/dx_rt_npu_linux_driver/modules/pci_deepx/dx_cdev_events.o
CC [M] /mnt/data/linx/rk3588.r6/dx_rt_npu_linux_driver/modules/pci_deepx/dx_sgdma.o
CC [M] /mnt/data/linx/rk3588.r6/dx_rt_npu_linux_driver/modules/pci_deepx/dw-edma-mem.o
CC [M] /mnt/data/linx/rk3588.r6/dx_rt_npu_linux_driver/modules/pci_deepx/dx_message.o
LD [M] /mnt/data/linx/rk3588.r6/dx_rt_npu_linux_driver/modules/pci_deepx/dx_dma.o
MODPOST /mnt/data/linx/rk3588.r6/dx_rt_npu_linux_driver/modules/Module.symvers
CC [M] /mnt/data/linx/rk3588.r6/dx_rt_npu_linux_driver/modules/pci_deepx/dx_dma.mod.o
LD [M] /mnt/data/linx/rk3588.r6/dx_rt_npu_linux_driver/modules/pci_deepx/dx_dma.ko
CC [M] /mnt/data/linx/rk3588.r6/dx_rt_npu_linux_driver/modules/rt/dxrt_driver.mod.o
LD [M] /mnt/data/linx/rk3588.r6/dx_rt_npu_linux_driver/modules/rt/dxrt_driver.ko
make[1]: Leaving directory '/mnt/data/linx/rk3588.r6/kernel-6.1'

生成的KO文件, 拷贝到RK3588开发板上。并如下方法加载驱动:

neardi@RK3588:~/dx-all-suite/ko$ ls
dx_dma.ko dxrt_driver.ko
neardi@RK3588:~/dx-all-suite/ko$ sudo insmod dx_dma.ko
neardi@RK3588:~/dx-all-suite/ko$ sudo insmod dxrt_driver.ko
neardi@RK3588:~/dx-all-suite/ko$ dmesg
[ 68.069802] dx_dma: loading out-of-tree module taints kernel.
[ 68.071872] dx_dma_pcie 0000:01:00.0: enabling device (0000 -> 0002)
[ 68.072049] dx_dma_pcie 0000:01:00.0: dw->dx_ver: 3
[ 68.079384] debugfs: Directory '0000:01:00.0' with parent 'dmaengine' already present!
[ 68.079868] dx_dma_pcie 0000:01:00.0: [dx_dma_pcie_probe] Probe Done!!
[ 73.469152] dxrt_driver_cdev_init: 1 devices
[ 73.470102] [200] created device 0:510:0, 00000000d437eb63, 0000000000000000
[ 74.721389] dxrt_recovery_device
neardi@RK3588:~/dx-all-suite/ko$ lsmod
Module Size Used by
dxrt_driver 49152 2
dx_dma 471040 9 dxrt_driver

3. Install DX-runtime

下载dx-all-suite后, 有如下目录,

neardi@RK3588:~/dx-all-suite$ tree -L 1
.
├── docker
├── docker_build.sh
├── docker_down.sh
├── docker_run.sh
├── docs
├── dummy.crt
├── dx-compiler
├── dx-modelzoo
├── dx-runtime
├── getting-started
├── LICENSE
├── README.md
├── RELEASE_NOTES.md
├── release.ver
├── scripts
├── tests
├── uninstall.sh
└── workspace

之后安装这里步骤安装。 或者进入dx-rutime目录执行下面的命令:

neardi@RK3588:~/dx/dx-all-suite/dx-runtime$ ./install.sh --target=dx_rt
x_rt/build_aarch64/lib"
[INFO] [Install python package ...]
[INFO] Checking Python version from virtual environment: /home/neardi/dx/dx-all-suite/dx-runtime/venv-dx-runtime/bin/python3
[INFO] Python version (3.11.15) meets the requirements.

dx-engine 1.1.4
[INFO] The Python package has been installed in the following Python version folder.
: pip 26.0.1 from /home/neardi/dx/dx-all-suite/dx-runtime/venv-dx-runtime/lib/python3.11/site-packages/pip (python 3.11)
[SUCCESS] [Installed python package]
[HINT] To activate the virtual environment, run:
source /home/neardi/dx/dx-all-suite/dx-runtime/venv-dx-runtime/bin/activate
[INFO] Service mode: on

[SUCCESS] [Created dxrt.service file]
[SUCCESS] [Reloaded systemd daemon]
[INFO] [dxrt service not enabled]
Created symlink /etc/systemd/system/multi-user.target.wants/dxrt.service → /etc/systemd/system/dxrt.service.
[SUCCESS] [Enabled the dxrt service (dxrtd)]
[INFO] [dxrt service not started]
[SUCCESS] [Started the dxrt service (dxrtd)]
[SUCCESS] Build mode completed
~/dx/dx-all-suite/dx-runtime
[SUCCESS] Installing dx_rt completed.

dx-runtime安装成功后, 可以通过如下方法来验证:

neardi@RK3588:~$ sudo systemctl status dxrt
● dxrt.service - DX-RT Service
Loaded: loaded (/etc/systemd/system/dxrt.service; enabled; vendor preset: enabled)
Active: active (running) since Thu 2026-04-09 08:55:26 UTC; 3min 43s ago
Main PID: 9061 (dxrtd)
CPU: 12ms
CGroup: /system.slice/dxrt.service
└─9061 /usr/local/bin/dxrtd

Apr 09 08:55:26 RK3588 systemd[1]: Started DX-RT Service.
Apr 09 08:55:26 RK3588 dxrtd[9061]: [DXRT_SVC][dxrt_service_main] Uses Default FIFO Scheduler
Apr 09 08:55:26 RK3588 dxrtd[9061]: [DXRT_SVC][Process] 0: Send recovery command
Apr 09 08:55:26 RK3588 dxrtd[9061]: [DXRT_SVC][DxrtService] Initialized Devices count=1
Apr 09 08:55:26 RK3588 dxrtd[9061]: [DXRT_SVC][DxrtService] Initialized Scheduler
Apr 09 08:55:26 RK3588 dxrtd[9061]: [DXRT_SVC][DxrtService] Initialized IPC Server
Apr 09 08:55:26 RK3588 dxrtd[9061]: [DXRT_SVC][ClearResidualIPCMessages] Clearing residual IPC messages from previous sessions...
Apr 09 08:55:26 RK3588 dxrtd[9061]: [DXRT_SVC][DxrtService] Loading PPCPU Firmware for devices, Size: 3616 bytes
Apr 09 08:55:26 RK3588 dxrtd[9061]: [DXRT_SVC][LoadPPCPUFirmware] PPCPU firmware loaded to device 0 successfully.
Apr 09 08:55:26 RK3588 dxrtd[9061]: [DXRT_SVC][die_check_thread] Started client process status check thread
neardi@RK3588:~$ dxrt-cli -s
DXRT v3.2.0
=======================================================
* Device 0: M1, Accelerator type
--------------------- Version ---------------------
* RT Driver version : v2.1.0
* PCIe Driver version : v2.0.1
-------------------------------------------------------
* FW version : v2.4.0
--------------------- Device Info ---------------------
* Memory : LPDDR5 5600 Mbps, 3.92GiB
* Board : M.2, Rev 1.0
* Chip Offset : 0
* PCIe : Gen3 X2 [01:00:00]

NPU 0: voltage 750 mV, clock 1000 MHz, temperature 49'C
NPU 1: voltage 750 mV, clock 1000 MHz, temperature 48'C
NPU 2: voltage 750 mV, clock 1000 MHz, temperature 48'C
=======================================================

这样就安装好了dx-runtime.

4. Run dx_app Demo

4.1 build demo app

进入dx-all-suite/dx-runtime/dx_app, 执行build.sh如下:

neardi@RK3588:~/dx-all-suite/dx-runtime/dx_app$ ./build.sh
~/dx-all-suite/dx-runtime/dx_app ~/dx-all-suite/dx-runtime/dx_app
cmake args : -DCMAKE_TOOLCHAIN_FILE=cmake/toolchain.aarch64.cmake -DCMAKE_VERBOSE_MAKEFILE=false -DCMAKE_BUILD_TYPE=release -DCMAKE_GENERATOR=Ninja
~/dx-all-suite/dx-runtime/dx_app/build_aarch64 ~/dx-all-suite/dx-runtime/dx_app ~/dx-all-suite/dx-runtime/dx_app
-- The C compiler identification is GNU 11.4.0
-- The CXX compiler identification is GNU 11.4.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/aarch64-linux-gnu-gcc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/aarch64-linux-gnu-g++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Looking for pthread.h
-- Looking for pthread.h - found
-- Performing Test CMAKE_HAVE_LIBC_PTHREAD
-- Performing Test CMAKE_HAVE_LIBC_PTHREAD - Success
...
Successfully built dx-postprocess
Installing collected packages: dx-postprocess
Attempting uninstall: dx-postprocess
Found existing installation: dx-postprocess 1.0.0
Uninstalling dx-postprocess-1.0.0:
Successfully uninstalled dx-postprocess-1.0.0
Successfully installed dx-postprocess-1.0.0
dx_postprocess installation completed successfully!
✓ Installed to: /usr

Build Done. (release)
=================================================
clean_build : false
verbose : false
build_type : release
target_arch : aarch64
=================================================

编译成功后, 生成的可执行文件如下:

neardi@RK3588:~/dx-all-suite/dx-runtime/dx_app/bin$ ls
deeplabv3_async scrfd_ppu_sync yolov12_async yolov26obb_sync yolov5_async yolov5pose_sync yolov7_ppu_sync yolov8seg_sync
deeplabv3_sync scrfd_sync yolov12_sync yolov26pose_async yolov5face_async yolov5_ppu_async yolov7_sync yolov8_sync
efficientnet_async yolov10_async yolov26_async yolov26pose_sync yolov5face_sync yolov5_ppu_sync yolov7_x_deeplabv3_async yolov9_async
efficientnet_sync yolov10_sync yolov26cls_async yolov26seg_async yolov5pose_async yolov5_sync yolov7_x_deeplabv3_sync yolov9_sync
scrfd_async yolov11_async yolov26cls_sync yolov26seg_sync yolov5pose_ppu_async yolov7_async yolov8_async yolox_async
scrfd_ppu_async yolov11_sync yolov26obb_async yolov26_sync yolov5pose_ppu_sync yolov7_ppu_async yolov8seg_async yolox_sync

4.2 run demo app

直接运行run_demo.sh, 如果没有下载DXNN模型, ��这个脚本会自动下载, 如下:

neardi@RK3588:~/dx-all-suite/dx-runtime/dx_app$ ./run_demo.sh
~/dx-all-suite/dx-runtime/dx_app ~/dx-all-suite/dx-runtime/dx_app
[INFO] DX_APP_PATH: /home/neardi/dx-all-suite/dx-runtime/dx_app
[INFO] Models and Videos directory already exists. Skipping download.
[INFO] Adding /home/neardi/dx-all-suite/dx-runtime/dx_app/lib to LD_LIBRARY_PATH
0: Object Detection (YOLOv7)
1: Object Detection with PPU (YOLOv7-640)
2: Object Detection (YOLOv8N)
3: Object Detection (YOLOv9S)
4: Object Detection With PPU (YOLOv5S-512)
5: Face Detection (YOLOV5S_Face)
6: Face Detection With PPU (SCRFD500M-640)
7: Pose Estimation
8: Pose Estimation With PPU (YOLOv5Pose-640)
9: Semantic Segmentation
10: Multi-Model Object Detection (YOLOv7) & Segmentation
11: Object Detection (YOLOv26S)
12: Pose Estimation (YOLOv26S-Pose)
13: Instance Segmentation (YOLOv26S-Seg)
14: Object Detection - Oriented Bounding Box (YOLOv26S-OBB)
which AI demo do you want to run? (default:0): (19s) 11
[INFO] Model loaded: assets/models/yolo26s-1.dxnn
[INFO] Model input size (WxH): 640x640

loopTest is set to 1 when a video file is provided.
[INFO] Video file: assets/videos/snowboard.mp4
[INFO] Input source resolution (WxH): 1920x1080
[INFO] Input source FPS: 23.98
[INFO] Total frames: 855

[INFO] Starting inference...

==================================================
PERFORMANCE SUMMARY
==================================================
Pipeline Step Avg Latency Throughput
--------------------------------------------------
Read 6.58 ms 152.1 FPS
Preprocess 7.95 ms 125.9 FPS
Inference 42.70 ms 67.1 FPS*
Postprocess 0.02 ms 60220.8 FPS
Display 4.94 ms 202.4 FPS
--------------------------------------------------
* Actual throughput via async inference
--------------------------------------------------
Infer Completed : 855
Infer Inflight Avg : 2.8
Infer Inflight Max : 5
--------------------------------------------------
Total Frames : 855
Total Time : 12.8 s
Overall FPS : 66.7 FPS
==================================================
~/dx-all-suite/dx-runtime/dx_app

5. dx_com

dx_com是编译DXNN的SDK, dx-all-suite/dx-compiler包含此目录; dx_com运行环境是在X86电脑上面, 我这里是 Linux Ubuntu 20.04的环境。 克隆了dx-all-suite后, 使用如下进行安装环境:

linx@ubuntu2004:/samba2/home/linx/work/dx-all-suite$ ./dx-compiler/install.sh

如果上面安装失败, 也可以从DEEPX官方网站下载dx_com_M1_v2.2.1.

5.1 DXNN模型转换

下载转换SDK, 目录结构如下:

linx@ubuntu2004:/samba2/home/linx/dx_com_M1_v2.2.1$ tree -L 1
.
├── calibration_dataset
├── dx_com
├── LICENSE
├── Makefile
├── RELEASE_NOTES.md
└── sample

默认的模型转换配置文件是Makefile, 如下:

.PHONY: MobileNetV1-1 ResNet50-1 YOLOV5-1 YOLOV11S-1
all: MobileNetV1-1 ResNet50-1 YOLOV5-1 YOLOV11S-1
MobileNetV1-1:
dx_com/dx_com \
-m sample/MobileNetV1-1.onnx \
-c sample/MobileNetV1-1.json \
-o sample/MobileNetV1-1
ResNet50-1:
dx_com/dx_com \
-m sample/ResNet50-1.onnx \
-c sample/ResNet50-1.json \
-o sample/ResNet50-1
YOLOV5-1:
dx_com/dx_com \
-m sample/YOLOV5-1.onnx \
-c sample/YOLOV5-1.json \
-o sample/YOLOV5-1

另外需要把对应的ONNX模型放在sample目录, 如下:

linx@ubuntu2004:/samba2/home/linx/dx_com_M1_v2.2.1/sample$ ls
food.onnx MobileNetV1-1.onnx ResNet50-1.onnx yolo26n-1.json yolo26s-1.json YOLOV11S-1 YOLOV5-1.json
MobileNetV1-1 ResNet50-1 yolo26m-1.json yolo26n-1.onnx yolo26s-1.onnx YOLOV11S-1.json YOLOV5-1.onnx
MobileNetV1-1.json ResNet50-1.json yolo26n-1 yolo26s-1 YOLOV11M-1.json YOLOV5-1

在此目录里, 执行make即可把ONNX模型转换成DXNN模型。如下:

linx@ubuntu2004:/samba2/home/linx/dx_com_M1_v2.2.1$ make
dx_com/dx_com \
-m sample/MobileNetV1-1.onnx \
-c sample/MobileNetV1-1.json \
-o sample/MobileNetV1-1
[INFO] - Using optimization level 1. Compilation may take longer.
[INFO] - For faster compilation, consider using --opt_level 0 (may increase NPU latency).
[INFO] -
[INFO] - ================================================================================
[INFO] - COMPILATION CONFIGURATION
[INFO] - ================================================================================
[INFO] - Compiler Version : 2.2.1
[INFO] - ONNX Model : sample/MobileNetV1-1.onnx
[INFO] - Config File : sample/MobileNetV1-1.json
[INFO] - Output Directory : sample/MobileNetV1-1
[INFO] - ================================================================================
[INFO] -
[INFO] - Final result: 1 NPU groups, 0 CPU groups
[INFO] - Inserting preprocessing operations to NPU graph: 3 nodes added
[INFO] - Added nodes: Div(x=255.0) -> Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
[INFO] - Skipped nodes (cannot be inserted in NPU graph): convertColor, resize, centercrop, transpose, expandDim
Compiling Model : 100%|█████████████████████████████████████████████████████████████████████████████████████

编译生成的DXNN模型在sample目录, 比如:

linx@ubuntu2004:/samba2/home/linx/dx_com_M1_v2.2.1/sample$ tree
.
├── food.onnx
├── MobileNetV1-1
│   └── MobileNetV1-1.dxnn
├── MobileNetV1-1.json
├── MobileNetV1-1.onnx
├── ResNet50-1
│   └── ResNet50-1.dxnn
├── ResNet50-1.json
├── ResNet50-1.onnx
├── yolo26m-1.json
├── yolo26n-1
│   └── yolo26n-1.dxnn
├── yolo26n-1.json
├── yolo26n-1.onnx
├── yolo26s-1
│   └── yolo26s-1.dxnn
├── yolo26s-1.json
├── yolo26s-1.onnx
├── YOLOV11M-1.json
├── YOLOV11S-1
│   └── food.dxnn
├── YOLOV11S-1.json
├── YOLOV5-1
│   └── YOLOV5-1.dxnn
├── YOLOV5-1.json
└── YOLOV5-1.onnx

5.2 自定义模型转换DXNN

在实际项目中, 通常是自定义训练的模型需要部署到DEEPX NPU上, 我们来把之前使用YOLO11训练的菜品模型进行转换, 通过如下步骤来实现。

  • 导出ONNX: Yolo11框架训练后, 会生成best.pt格式的模型, 使用下面的python程序即可导出ONNX:
from ultralytics import YOLO

# Load a model
model = YOLO("./best.pt") # load a custom-trained model

# Export the model
model.export(format="onnx", opset=21, simplify=True)
  • 创建JSON配置文件: 在sample目录里, 创建如下的JSON配置文件:
{
"inputs": {
"images": [
1,
3,
640,
640
]
},
"calibration_num": 100,
"calibration_method": "ema",
"train_batchsize": 32,
"num_samples": 1024,
"default_loader": {
"dataset_path": "./food",
"file_extensions": [
"jpeg",
"jpg",
"png",
"JPEG"
],
"preprocessings": [
{
"resize": {
"mode": "pad",
"size": 640,
"pad_location": "edge",
"pad_value": [
114,
114,
114
]
}
},
{
"div": {
"x": 255
}
},
{
"convertColor": {
"form": "BGR2RGB"
}
},
{
"transpose": {
"axis": [
2,
0,
1
]
}
},
{
"expandDim": {
"axis": 0
}
}
]
}
}
  • 拷贝模型的验证数据集: 转换成DXNN模型时需要验证数据, 在当前路径创建food目录,同时修改JSON配置里的dataset_path: ./food.
  • 修改Makefile: 修改dx_com_M1_v2.2.1/Makefile, 内容如下:
.PHONY: MobileNetV1-1 ResNet50-1 YOLOV5-1 YOLOV11S-1
all: MobileNetV1-1 ResNet50-1 YOLOV5-1 YOLOV11S-1
MobileNetV1-1:
dx_com/dx_com \
-m sample/MobileNetV1-1.onnx \
-c sample/MobileNetV1-1.json \
-o sample/MobileNetV1-1
ResNet50-1:
dx_com/dx_com \
-m sample/ResNet50-1.onnx \
-c sample/ResNet50-1.json \
-o sample/ResNet50-1
YOLOV5-1:
dx_com/dx_com \
-m sample/YOLOV5-1.onnx \
-c sample/YOLOV5-1.json \
-o sample/YOLOV5-1
YOLOV11S-1:
dx_com/dx_com \
-m sample/food.onnx \
-c sample/YOLOV11S-1.json \
-o sample/YOLOV11S-1
  • 执行make: 最后, 在dx_com_M1_v2.2.1路径下执行make, 如下:
linx@ubuntu2004:/samba2/home/linx/dx_com_M1_v2.2.1$ make
dx_com/dx_com \
-m sample/food.onnx \
-c sample/YOLOV11S-1.json \
-o sample/YOLOV11S-1
[INFO] - Using optimization level 1. Compilation may take longer.
[INFO] - For faster compilation, consider using --opt_level 0 (may increase NPU latency).
[INFO] -
[INFO] - ================================================================================
[INFO] - COMPILATION CONFIGURATION
[INFO] - ================================================================================
[INFO] - Compiler Version : 2.2.1
[INFO] - ONNX Model : sample/food.onnx
[INFO] - Config File : sample/YOLOV11S-1.json
[INFO] - Output Directory : sample/YOLOV11S-1
[INFO] - ================================================================================
[INFO] -
[INFO] - Infection complete: Marked 8 MemoryOp(s) from NPU to CPU
[INFO] - Final result: 1 NPU groups, 1 CPU groups
[INFO] - Inserting preprocessing operations to NPU graph: 1 nodes added
[INFO] - Added nodes: Div(x=255)
[INFO] - Skipped nodes (cannot be inserted in NPU graph): resize, convertColor, transpose, expandDim
Compiling Model : 100%|█████████████████████████████████████████████████████████████████████████████████

生成的DXNN在sample/YOLOV11S-1.

6. 部署及运行自定义模型

把自定义训练模型及转换后的DXNN拷贝到rk3588设备上, 修改dx-all-suite/dx-runtime/dx_app, 如下:

diff --git a/src/cpp_example/object_detection/yolov11/yolov11_async.cpp b/src/cpp_example/object_detection/yolov11/yolov11_async.cpp
index eb6e360..c2fbfa2 100644
--- a/src/cpp_example/object_detection/yolov11/yolov11_async.cpp
+++ b/src/cpp_example/object_detection/yolov11/yolov11_async.cpp
@@ -816,6 +816,7 @@ int main(int argc, char* argv[]) {
}

dxrt::InferenceOption io;
+ io.useORT = true;
dxrt::InferenceEngine ie(args.modelPath, io);
if (!dxapp::common::minversionforRTandCompiler(&ie)) {
std::cerr << "[DXAPP] [ER] The version of the compiled model is not "
diff --git a/src/cpp_example/object_detection/yolov11/yolov11_sync.cpp b/src/cpp_example/object_detection/yolov11/yolov11_sync.cpp
index 37fbd40..c62eda5 100644
--- a/src/cpp_example/object_detection/yolov11/yolov11_sync.cpp
+++ b/src/cpp_example/object_detection/yolov11/yolov11_sync.cpp
@@ -424,7 +424,7 @@ bool process_single_frame(
dxrt::InferenceEngine& ie,
YOLOv11PostProcess& post_processor, ProfilingMetrics& metrics,
cv::VideoWriter& writer, bool no_display, bool saveVideo, double t_read) {
if (input_frame.empty()) {
std::cerr << "[ERROR] Empty input frame" << std::endl;
return false;
@@ -561,6 +561,7 @@ int main(int argc, char* argv[]) {
}

dxrt::InferenceOption io;
+ io.useORT = true;
dxrt::InferenceEngine ie(args.modelPath, io);
if (!dxapp::common::minversionforRTandCompiler(&ie)) {
std::cerr << "[DXAPP] [ER] The version of the compiled model is not "
diff --git a/src/postprocess/yolov11/yolov11_postprocess.cpp b/src/postprocess/yolov11/yolov11_postprocess.cpp
index 2268d6c..d0c82f0 100644
--- a/src/postprocess/yolov11/yolov11_postprocess.cpp
+++ b/src/postprocess/yolov11/yolov11_postprocess.cpp
@@ -5,6 +5,7 @@
#include <iostream>
#include <iterator>
#include <sstream>
+#include <iostream>

#include "common_util.hpp"

@@ -204,7 +205,7 @@ std::vector<YOLOv11Result> YOLOv11PostProcess::decoding_npu_outputs(
YOLOv11Result result;
result.confidence = max_cls_conf;
result.class_id = max_cls;
- result.class_name = dxapp::common::get_coco_class_name(max_cls);
+ result.class_name = dxapp::common::get_food_class_name(max_cls);
result.box = {x1, y1, x2, y2};
detections.push_back(result);
}
@@ -232,12 +233,18 @@ std::vector<YOLOv11Result> YOLOv11PostProcess::decoding_cpu_outputs(

for (size_t output_idx = 0; output_idx < outputs.size(); ++output_idx) {
const float* output = static_cast<const float*>(outputs[output_idx]->data());
+ if (outputs[output_idx]->shape().size() != 3 || outputs[output_idx]->shape()[1] < 5) {
+ std::cout << "skip this shape" << std::endl;
+ continue;
+ }
+
+ const int class_count = static_cast<int>(outputs[output_idx]->shape()[1]) - 4;
auto num_dets = outputs[output_idx]->shape()[2];
for (int i = 0; i < num_dets; ++i) {
// Find the class with highest confidence
int max_cls = -1;
float max_cls_conf = score_threshold_;
- for (int cls = 0; cls < num_classes_; ++cls) {
+ for (int cls = 0; cls < class_count; ++cls) {
int score_idx = (4 + cls) * num_dets + i;
float class_conf = output[score_idx];
if (class_conf > max_cls_conf) {
@@ -252,8 +259,8 @@ std::vector<YOLOv11Result> YOLOv11PostProcess::decoding_cpu_outputs(
std::vector<float> box_temp{0.f, 0.f, 0.f, 0.f};
result.confidence = max_cls_conf;
result.class_id = max_cls;
- result.class_name = dxapp::common::get_coco_class_name(max_cls);
-
+ // result.class_name = dxapp::common::get_coco_class_name(max_cls);
+ result.class_name = dxapp::common::get_food_class_name(max_cls);
for (int j = 0; j < 4; j++) {
int box_idx = j * num_dets + i;
box_temp[j] = output[box_idx];
@@ -268,6 +275,7 @@ std::vector<YOLOv11Result> YOLOv11PostProcess::decoding_cpu_outputs(
detections.push_back(result);
}
}
+
return detections;
}

@@ -343,4 +351,4 @@ std::string YOLOv11PostProcess::get_config_info() const {
}

return oss.str();
-}
+}
\ No newline at end of file
diff --git a/src/utility/common_util.cpp b/src/utility/common_util.cpp
index a5e3c96..4354640 100644
--- a/src/utility/common_util.cpp
+++ b/src/utility/common_util.cpp
@@ -358,5 +358,16 @@ std::string get_dota_class_name(const int class_id) {
return class_names.at(class_id);
}

+std::string get_food_class_name(const int class_id) {
+ static const std::vector<std::string> class_names = {
+ "Chili_Pork",
+ "Rice",
+ "Tomato_Eggs",
+ "Tofu",
+ "Shao_Mai",
+ "Youtiao"};
+ return class_names.at(class_id);
+}
+
} // namespace common
} // namespace dxapp
diff --git a/src/utility/common_util.hpp b/src/utility/common_util.hpp
index 05aed95..7d505ab 100644
--- a/src/utility/common_util.hpp
+++ b/src/utility/common_util.hpp
@@ -144,5 +144,7 @@ std::string get_coco_class_name(const int class_id);

std::string get_dota_class_name(const int class_id);

+std::string get_food_class_name(const int class_id);
+
} // namespace common
} // namespace dxapp

再编译app, 这样运行即可:

neardi@RK3588:~/dx-all-suite/dx-runtime/dx_app$ ./bin/yolov11_sync -m ./food.dxnn -i food/015.jpg -l 100
[INFO] Model loaded: ./food.dxnn
[INFO] Model input size (WxH): 640x640

[INFO] Starting inference...

==================================================
PERFORMANCE SUMMARY
==================================================
Pipeline Step Avg Latency Throughput
--------------------------------------------------
Read 67.78 ms 14.8 FPS
Preprocess 8.29 ms 120.6 FPS
Inference 22.90 ms 43.7 FPS
Postprocess 0.11 ms 9125.2 FPS
Display 2.27 ms 441.0 FPS
--------------------------------------------------
Total Frames : 1000
Total Time : 101.4 s
Overall FPS : 9.9 FPS
==================================================

推理结果如下: