【MobileSAM部署至RK3588】环境适配→转换RKNN→开发板部署

已在GitHub开源与本博客同步的MobileSAM_RK3588
项目,地址:MobileSAM_RK3588
详细使用教程,可参考README.md或参考
本博客第五章 模型部署**

注:本文是以瑞芯微RK3588 SoC进行示例,同时也可支持瑞芯微其他系列SoC:RK3562、RK3566、RK3568、RK3576、RK3399PRO、RK1808、RV1126、RV1126B、RV1103、RV1106、RV1109等,部署流程也基本一致,如需帮助,可通过Github仓库的 README.md 沟通。

文章目录

一、项目回顾

博主之前有写过在华为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的完整流程,包括模型获取、环境搭建、模型转换、边缘部署,欢迎大家留言交流。

相关推荐
Ada's1 小时前
【公司系列】001:墨芯科技
人工智能·科技
HANDY092001 小时前
从“不照人”到“剂量达标”:扇叶遮挡式UV-C空气消毒的工程边界与可验证评估框架
开发语言·人工智能·嵌入式硬件·智能家居
lucas_AI1 小时前
想公开警告 AI 风险?先看看你的合同:DeepMind 员工抗议「终身禁言条款」
人工智能
阿文和她的Key1 小时前
算力零售化的四层架构:从 0.01 元月卡看 AI 服务的计量、履约与复购
人工智能·架构·零售
青少儿编程课堂1 小时前
蓝桥杯·全国青少年信息素养大赛·电子学会C/C++考级:分层图最短路解析
c++·python·算法·bfs·信息学竞赛
ss2731 小时前
不用向量库,我用 MySQL 跑通了蔬菜 RAG--基于 RuoYi-AI 的蔬菜种植知识库 + 智能咨询系统,普通开发机就能跑
数据库·人工智能·智慧农业·ruoyi·知识库·rag
l5507255411 小时前
汽车总布置人机|SAE J826 驾驶人体二维模板绘制要点
人工智能·汽车
天远数科1 小时前
零信任架构实战:基于天远全能家政风险报告构建自动化即时到家保洁与短工抢单安全核验网关
运维·人工智能·架构·自动化