
已在GitHub开源与本博客同步的MobileSAM_RK3588
项目,地址:MobileSAM_RK3588
详细使用教程,可参考README.md或参考本博客第五章 模型部署**
注:本文是以瑞芯微RK3588 SoC进行示例,同时也可支持瑞芯微其他系列SoC:RK3562、RK3566、RK3568、RK3576、RK3399PRO、RK1808、RV1126、RV1126B、RV1103、RV1106、RV1109等,部署流程也基本一致,如需帮助,可通过Github仓库的 README.md 沟通。
文章目录
- 一、项目回顾
- 二、文件梳理
- 三、模型获取
- 四、ONNX转RKNN
-
- [4.1 解码器模型转换RKNN](#4.1 解码器模型转换RKNN)
- [4.2 编码器模型转换RKNN](#4.2 编码器模型转换RKNN)
- 五、模型部署
一、项目回顾
博主之前有写过在华为Ascend、瑞芯微RK系列、地平线Sunrise系列的SoC上的YOLOv8目标检测&图像分割、YOLOv10目标检测、MoblieNetv2图像分类的以及模型训练、转换、部署文章,也包括部分LLM、VLM的部署内容,感兴趣的小伙伴可以了解下:
【YOLO26部署至RK3588】模型训练→转换RKNN→开发板部署
【FoundationPose部署至AGX Orin】环境配置→模型部署→问题记录
【SAM部署至AGX Orin】环境配置→模型部署→问题记录
【SAM3部署至AGX Orin】环境配置→模型部署→问题记录
【LocateAnything部署至AGX Orin】环境配置→模型部署→问题记录
【Qwen2.5VL-3B部署至RK1828】ONNX转换→模型量化→边缘部署
【YOLOv8cls部署至RDK X5】模型训练→转换bin→Sunrise 5部署
【YOLOv8pose部署至RDK X5】模型训练→转换bin→Sunrise 5部署
【YOLOv8seg部署至RDK X5】模型训练→转换bin→Sunrise 5部署
【YOLOv8det部署至RDK X5】模型训练→转换bin→Sunrise 5部署
【YOLOv8部署至Ascend 310B】模型训练→转换om→310B部署
【YOLO11-obb部署至RK3588】模型训练→转换RKNN→开发板部署
【YOLO11部署至RK3588】模型训练→转换RKNN→开发板部署
【YOLOv10部署RK3588】模型训练→转换rknn→部署流程
【YOLOv8-obb部署至RK3588】模型训练→转换RKNN→开发板部署
【YOLOv8-pose部署至RK3588】模型训练→转换RKNN→开发板部署
【YOLOv8seg部署RK3588】模型训练→转换rknn→部署全流程
【YOLOv8部署至RK3588】模型训练→转换rknn→部署全流程
【YOLOv7部署至RK3588】模型训练→转换RKNN→开发板部署
【YOLOv6部署至RK3588】模型训练→转换RKNN→开发板部署
【YOLOv5部署至RK3588】模型训练→转换RKNN→开发板部署
【MobileNetv2图像分类部署至RK3588】模型训练→转换rknn→部署流程
【ResNet50图像分类部署至RK3588】模型训练→转换RKNN→开发板部署
YOLOv8n部署RK3588开发板全流程(pt→onnx→rknn模型转换、板端后处理检测)
二、文件梳理
模型转换需要以下工具:rknn_model_zoo、rknn-toolkit2,现在详细介绍。
以上文件均与模型训练无关,而是用于模型转换的;在此,先将以上文件的链接放在这:rknn_model_zoo ,rknn-toolkit2。
另外说一下这两个文件的版本,全用最新的 ,rknn_model_zoo用v2.5.0,rknn-toolkit2也用v2.5.0,如下所示:


三、模型获取
MobileSAM模型无需训练,直接从瑞芯微rknn-model-zoo官方链接即可下载适配的.onnx模型:

四、ONNX转RKNN
在进行这一步的时候,如果你是在云服务器上运行,请先确保你租的卡能支持RKNN的转换运行。博主是在自己的虚拟机中进行转换。
先安装转换环境
这里我们先创建环境:
bash
conda create -n rknn250 python=3.8
现在需要用到rknn-toolkit2-2.5.0文件。
进入rknn-toolkit2-2.5.0\rknn-toolkit2\packages\x86_64 文件夹下,看到如下内容:

先安装requirments,如下所示:
bash
pip install -r requirements_cp38.txt -i https://pypi.tuna.tsinghua.edu.cn/simple
再安装toolkit.whl:
bash
pip install rknn_toolkit2-2.5.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
然后,我们的转rknn环境就配置完成了。
4.1 解码器模型转换RKNN
现在先执行解码器convert.py:rknn-model-zoo-2.5.0/examples/mobilesam/python/decoder/convert.py
如下所示:

decoder/convert.py如下所示:
python
import numpy as np
import sys
import cv2
from rknn.api import RKNN
DEFAULT_RKNN_PATH = '../../model/mobilesam_decoder.rknn'
DEFAULT_QUANT = False
NUM_POINTS = 2
dummy_inputs = {
"image_embeddings": [1, 256, 28, 28],
"point_coords": [1, NUM_POINTS, 2],
"point_labels": [1, NUM_POINTS],
"mask_input": [1, 1, 112, 112],
"has_mask_input": [1],
# "orig_im_size": [2],
}
outputs = [
# 'masks',
'iou_predictions',
'low_res_masks',
]
def parse_arg():
if len(sys.argv) < 3:
print("Usage: python3 {} onnx_model_path [platform] [dtype(optional)] [output_rknn_path(optional)]".format(sys.argv[0]))
print(" platform choose from [rk3562, rk3576, rk3588]")
print(" dtype choose from [fp]")
exit(1)
model_path = sys.argv[1]
platform = sys.argv[2]
do_quant = DEFAULT_QUANT
if len(sys.argv) > 3:
model_type = sys.argv[3]
if model_type not in ['fp']:
print("ERROR: Invalid model type: {}".format(model_type))
exit(1)
if len(sys.argv) > 4:
output_path = sys.argv[4]
else:
output_path = DEFAULT_RKNN_PATH
return model_path, platform, do_quant, output_path
if __name__ == '__main__':
model_path, platform, do_quant, output_path = parse_arg()
# Create RKNN object
rknn = RKNN(verbose=True)
# Pre-process config
print('--> Config model')
rknn.config(target_platform=platform,)
print('done')
# Load model
print('--> Loading model')
ret = rknn.load_onnx(model=model_path,
inputs=[*dummy_inputs.keys()],
input_size_list=[*dummy_inputs.values()],
outputs=outputs
)
if ret != 0:
print('Load model failed!')
exit(ret)
print('done')
# Build model
print('--> Building model')
ret = rknn.build(do_quantization=do_quant)
if ret != 0:
print('Build model failed!')
exit(ret)
print('done')
# Export rknn model
print('--> Export rknn model')
ret = rknn.export_rknn(output_path)
if ret != 0:
print('Export rknn model failed!')
exit(ret)
print('done')
# Release
rknn.release()
可以看到,默认是FP16且不支持量化的。
激活刚才的conda环境后,执行解码器转换命令:
bash
python decoder/convert.py ../model/mobilesam_decoder.onnx rk3588 fp ../model/mobilesam_decoder_fp16.rknn
终端如下所示:
bash
(rknn250) yjh@ubuntu:~/rknn_related/rknn_model_zoo-2.5.0/examples/mobilesam/python$ python decoder/convert.py ../model/mobilesam_decoder.onnx rk3588 fp ../model/mobilesam_decoder_fp16.rknn
I rknn-toolkit2 version: 2.5.0
--> Config model
done
--> Loading model
W load_onnx: If you don't need to crop the model, don't set 'inputs'/'input_size_list'/'outputs'!
I Loading : 100%|██████████████████████████████████████████████| 136/136 [00:00<00:00, 35627.09it/s]
W load_onnx: The config.mean_values is None, zeros will be set for input 0!
W load_onnx: The config.std_values is None, ones will be set for input 0!
W load_onnx: The config.mean_values is None, zeros will be set for input 1!
W load_onnx: The config.std_values is None, ones will be set for input 1!
W load_onnx: The config.mean_values is None, zeros will be set for input 2!
W load_onnx: The config.std_values is None, ones will be set for input 2!
W load_onnx: The config.mean_values is None, zeros will be set for input 3!
W load_onnx: The config.std_values is None, ones will be set for input 3!
W load_onnx: The config.mean_values is None, zeros will be set for input 4!
W load_onnx: The config.std_values is None, ones will be set for input 4!
done
--> Building model
D base_optimize ...
D base_optimize done.
D
D fold_constant ...
D fold_constant done.
D fold_constant remove nodes = ['/Concat_12', '/Unsqueeze_18', ............
........
........
........
D RKNN: [20:48:04.576] ----------------------------------------
D RKNN: [20:48:04.576] Total Internal Memory Size: 4338.56KB
D RKNN: [20:48:04.576] Total Weight Memory Size: 9163.88KB
D RKNN: [20:48:04.576] ----------------------------------------
D RKNN: [20:48:04.576] <<<<<<<< end: rknn::RKNNMemStatisticsPass
W Restore temperate env rknn_compute_order=
I rknn building done.
done
--> Export rknn model
done
此时可以看到models文件夹下生成的解码器的rknn模型:

4.2 编码器模型转换RKNN
现在开始执行编码器的convert.py:rknn-model-zoo-2.5.0/examples/mobilesam/python/encoder/convert.py

其convert.py如下所示:
python
import numpy as np
import sys
import cv2
from rknn.api import RKNN
DEFAULT_RKNN_PATH = '../../model/mobilesam_encoder.rknn'
DEFAULT_QUANT = False
def parse_arg():
if len(sys.argv) < 3:
print("Usage: python3 {} onnx_model_path [platform] [dtype(optional)] [output_rknn_path(optional)]".format(sys.argv[0]))
print(" platform choose from [rk3562, rk3576, rk3588]")
print(" dtype choose from [fp]")
exit(1)
model_path = sys.argv[1]
platform = sys.argv[2]
do_quant = DEFAULT_QUANT
if len(sys.argv) > 3:
model_type = sys.argv[3]
if model_type not in ['fp']:
print("ERROR: Invalid model type: {}".format(model_type))
exit(1)
if len(sys.argv) > 4:
output_path = sys.argv[4]
else:
output_path = DEFAULT_RKNN_PATH
return model_path, platform, do_quant, output_path
if __name__ == '__main__':
model_path, platform, do_quant, output_path = parse_arg()
# Create RKNN object
rknn = RKNN(verbose=True)
# Pre-process config
print('--> Config model')
rknn.config(target_platform=platform,
mean_values=[[123.675, 116.28, 103.53]],
std_values=[[58.395, 57.12, 57.375]],)
print('done')
# Load model
print('--> Loading model')
ret = rknn.load_onnx(model=model_path,)
if ret != 0:
print('Load model failed!')
exit(ret)
print('done')
# Build model
print('--> Building model')
ret = rknn.build(do_quantization=do_quant)
if ret != 0:
print('Build model failed!')
exit(ret)
print('done')
# Export rknn model
print('--> Export rknn model')
ret = rknn.export_rknn(output_path)
if ret != 0:
print('Export rknn model failed!')
exit(ret)
print('done')
# Release
rknn.release()
可以看到,编码器同样也是不建议量化的,默认FP16,
执行命令:
bash
python encoder/convert.py ../model/mobilesam_encoder_tiny.onnx rk3588 fp ../model/mobilesam_encoder_tiny_fp16.rknn
终端如下所示:
bash
(rknn250) yjh@ubuntu:~/rknn_related/rknn_model_zoo-2.5.0/examples/mobilesam/python$ python encoder/convert.py ../model/mobilesam_encoder_tiny.onnx rk3588 fp ../model/mobilesam_encoder_tiny_fp16.rknn
I rknn-toolkit2 version: 2.5.0
--> Config model
done
--> Loading model
I Loading : 100%|██████████████████████████████████████████████| 180/180 [00:00<00:00, 34417.16it/s]
done
--> Building model
D base_optimize ...
D base_optimize done.
D
D fold_constant ...
D fold_constant done.
D fold_constant remove nodes = ['/layers.2/downsample/Concat', '/layers.2/downsample/Slice', '/layers.2/downsample/Shape', '/layers.1/downsample/Concat', '/layers.1/downsample/Slice', '/layers.1/downsample/Shape', '/layers.0/downsample/Concat', '/layers.0/downsample/Slice', '/layers.0/downsample/Shape']
D Fixed the shape information of some tensor!
D
D correct_ops ...
D correct_ops done.
D
D fuse_ops ...
D fuse_ops results:
D replace_torch_gelu: remove node = ['/patch_embed/seq/seq.1/Div', '/patch_embed/seq/seq.1/Erf', '/patch_embed/seq/seq.1/Add', '/patch_embed/seq/seq.1/Mul', '/patch_embed/seq/seq.1/Mul_1'], add node = ['/patch_embed/seq/seq.1/Mul_1_2gelu']
......
......
......
D RKNN: [20:45:19.000] 272 exNorm onnx::Mul_2672 FLOAT16 (1,256,1,1) | 0x005f9d40 0x005f9f40 0x00000200
D RKNN: [20:45:19.000] 272 exNorm onnx::Add_2674 FLOAT (1,256,1,1) | 0x005f9f40 0x005fa340 0x00000400
D RKNN: [20:45:19.000] 273 Reshape /Constant_output_0_sw INT64 (4) | 0x013a1780 0x013a17a0 0x00000020
D RKNN: [20:45:19.000] 274 Split /neck/neck.1/Add_1_output_0_split_i1 INT64 (2) | 0x015e4840 0x015e4850 0x00000010
D RKNN: [20:45:19.000] 275 Conv /neck/neck.2/Conv_tile1_i1 FLOAT16 (256,128,3,3) | 0x01674880 0x01704880 0x00090000
D RKNN: [20:45:19.000] 276 ConvAdd /neck/neck.2/Conv_tile0_i1 FLOAT16 (256,128,3,3) | 0x015e4880 0x01674880 0x00090000
D RKNN: [20:45:19.000] 277 exNorm onnx::Mul_2676 FLOAT16 (1,256,1,1) | 0x005fa340 0x005fa540 0x00000200
D RKNN: [20:45:19.000] 277 exNorm onnx::Add_2678 FLOAT (1,256,1,1) | 0x005fa540 0x005fa940 0x00000400
D RKNN: [20:45:19.000] ---------------------------------------------------------------------------------------------------------+---------------------------------
D RKNN: [20:45:20.004] ----------------------------------------
D RKNN: [20:45:20.004] Total Internal Memory Size: 49784KB
D RKNN: [20:45:20.004] Total Weight Memory Size: 25232.1KB
D RKNN: [20:45:20.004] ----------------------------------------
D RKNN: [20:45:20.004] <<<<<<<< end: rknn::RKNNMemStatisticsPass
W Restore temperate env rknn_compute_order=
I rknn building done.
done
--> Export rknn model
done
此时编码器也转换完成,在models下可以看到编码器的rknn模型:

五、模型部署
如果前面流程都已实现,模型的结构也没问题的话,则可以进行最后一步:模型端侧部署。
我已经帮大家做好了所有的环境适配工作,科学上网后访问博主GitHub仓库:MobileSAM_RK3588进行简单的路径修改就即可编译运行。
统一声明:
1、这个仓库的项目只能做图片的批量检测,不支持视频流检测,没时间做这个,有需要的自己修改代码。
2、从GitHub的README.md中加QQ后直接说问题和小星星截图,对于常见的相同问题,很多都已在CSDN博客中提到了(RKNN转换流程是统一的,可去博主所有的RKNN相关博客下去翻评论),已在评论中详细解释过的问题,不予回复。

git clone后把项目复制到开发板上,按如下流程操作:
①:cd build,删除所有build文件夹下的内容
②:cd src 修改main.cc,修改main函数中的如下六个内容,分别是编码解码路径、坐标参数、标签参数、输入图片文件夹路径、输出图片文件夹路径:

其中coords.txt如下所示:

第一行就是你所需要的Point点位的图像坐标值,第二行的0 0是默认占位值
labels.txt也同样,因为SAM模型本身是没有标签概念的,所以直接附1,第二行用 -1 占位:

③:把你之前训练好并已转成RKNN格式的模型放到MobileSAM_RK3588/model文件夹下,然后把你要检测的所有图片都放到MobileSAM_RK3588/inputimage下。
在运行程序后,生成的结果图片在MobileSAM_RK3588/outputimage下
注意:要逐个把输入图片放到inputimage下,然后在coords.txt中修改对应的Point后再保存运行
④:进入build文件夹进行编译
bash
cd build
bash
cmake ..
bash
make
在build下生成可执行文件文件:rknn_mobilesam_demo
在build路径下输入
bash
./rknn_mobilesam_demo
运行结果如下所示:

bash
firefly@firefly:/data/04RKNN_GIthub_related/rknn_play/MobileSAM_RK3588/build$ ./rknn_mobilesam_demo
--> init mobilesam encoder model
model input num: 1, output num: 1
input tensors:
index=0, name=input.1, n_dims=4, dims=[1, 448, 448, 3], n_elems=602112, size=1204224, fmt=NHWC, type=FP16, qnt_type=AFFINE, zp=0, scale=1.000000
output tensors:
index=0, name=2044, n_dims=4, dims=[1, 256, 28, 28], n_elems=200704, size=401408, fmt=NCHW, type=FP16, qnt_type=AFFINE, zp=0, scale=1.000000
model is NHWC input fmt
input image height=448, input image width=448, input image channel=3
--> init mobilesam decoder model
model input num: 5, output num: 2
input tensors:
index=0, name=image_embeddings, n_dims=4, dims=[1, 28, 28, 256], n_elems=200704, size=401408, fmt=NHWC, type=FP16, qnt_type=AFFINE, zp=0, scale=1.000000
index=1, name=point_coords, n_dims=3, dims=[1, 2, 2], n_elems=4, size=8, fmt=UNDEFINED, type=FP16, qnt_type=AFFINE, zp=0, scale=1.000000
index=2, name=point_labels, n_dims=2, dims=[1, 2], n_elems=2, size=4, fmt=UNDEFINED, type=FP16, qnt_type=AFFINE, zp=0, scale=1.000000
index=3, name=mask_input, n_dims=4, dims=[1, 112, 112, 1], n_elems=12544, size=25088, fmt=NHWC, type=FP16, qnt_type=AFFINE, zp=0, scale=1.000000
index=4, name=has_mask_input, n_dims=1, dims=[1], n_elems=1, size=2, fmt=UNDEFINED, type=FP16, qnt_type=AFFINE, zp=0, scale=1.000000
output tensors:
index=0, name=iou_predictions, n_dims=2, dims=[1, 4], n_elems=4, size=8, fmt=UNDEFINED, type=FP16, qnt_type=AFFINE, zp=0, scale=1.000000
index=1, name=low_res_masks, n_dims=4, dims=[1, 4, 112, 112], n_elems=50176, size=100352, fmt=NCHW, type=FP16, qnt_type=AFFINE, zp=0, scale=1.000000
model is NHWC input fmt
input image height=28, input image width=28, input image channel=256
Processing /data/04RKNN_GIthub_related/rknn_play/MobileSAM_RK3588/inputimage/6.jpg
--> inference mobilesam encoder model
src_height:480, src_width:640
newh:336 neww:448 padh:112 padw:0
rknn_run
--> inference mobilesam decoder model
rknn_run
mask score: 0.976562
write_image path: /data/04RKNN_GIthub_related/rknn_play/MobileSAM_RK3588/outputimage/6_out.png width=640 height=480 channel=3 data=0x55b3eba7e0
saved /data/04RKNN_GIthub_related/rknn_play/MobileSAM_RK3588/outputimage/6_out.png
Batch finished: 1 succeeded, 0 failed
原inputimage文件夹下的图片:

结果图片如下所示:

作为对比,博主将没有简化过的原版SAM、SAM3模型在AGX Orin 64GB上做了FP32的测试,详情可参照如下博文:
【SAM3部署至AGX Orin】环境配置→模型部署→问题记录
结果图如下所示:

可以看到,二者还是有很大的差距的,毕竟模型体量差了两个数量级,效果只能差强人意,在要求较高的作业任务中,MobileSAM还是无法胜任的。
以上就是博主此次MobileSAM部署到RK3588的完整流程,包括模型获取、环境搭建、模型转换、边缘部署,欢迎大家留言交流。