瑞芯微RV1106G3板端部署

前言:

无论是我们执行yolov5/yolov8模型,我们训练结果得到一个best.pt文件作为已经训练好的模型,我们都要将其部署到板端,本章节是笔者在部署瑞芯微RV1106时所整理的笔记。

主体思路:

best.pt -> best.onnx

best.onnx->best.rknn

将其部署到瑞芯微RV1106的板端


1.best.pt -> best.onnx

首先我找到了luckfox的官网

RKNN | LUCKFOX WIKI

下载源码

复制代码
​
git clone https://github.com/airockchip/yolov5.git

配置环境

复制代码
conda pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple create -n yolov5_onnx python=3.8

将pt文件转换为onnx

复制代码
python export.py --rknpu --weight best.pt

当前目录下就有best.onnx


2. best.onnx -> best.rknn

接着要进行best.onnx转换成best.rknn首先应该重新创建个环境

根据之前安装的

复制代码
#切换环境配置并适配rknn_Toolskit2
git clone https://github.com/rockchip-linux/rknn-toolkit2

#下载rknn_model_zoo.git
git clone https://github.com/airockchip/rknn_model_zoo.git

#以防后面报错,提前安装好库
pip install tf-estimator-nightly==2.8.0.dev2021122109

#根据其python版本选择器package下合适的包
pip install -r rknn-toolkit2/packages/requirements_cp38-1.6.0.txt -i https://pypi.mirrors.ustc.edu.cn/simple/

#同样的在rknn-toolkit2下安装他的轮子
pip install rknn-toolkit2/packages/rknn_toolkit2-1.6.0+81f21f4d-cp38-cp38-linux_x86_64.whl

将best.onnx放到yolov5中的model中

python 复制代码
python3 convert.py ../model/best.onnx rv1106

交叉编译:

python 复制代码
#先克隆其目标文件
git clone https://gitee.com/LuckfoxTECH/luckfox-pico.git

适配其环境:

python 复制代码
#配置完成环境后添加权限
chmod +x ./build-linux.sh

#在rknn_model_zoo目录下执行
./build-linux.sh -t rv1106 -a armv7l -d yolov5

执行成功后就会产生一个install文件,将其中的demo传输到板端

python 复制代码
#给板端添加文件夹权限
chmod +x ./rknn_yolov5_demo

#板端本地执行
./rknn_yolov5_demo model/yolov5.rknn model/test.jpg

将生成的out.png传输到本地查看

如果要进行进一步的优化,比如说在推理代码中添加其运行时间,修改其main.cc文件

python 复制代码
// Copyright (c) 2023 by Rockchip Electronics Co., Ltd. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/*-------------------------------------------
                Includes
-------------------------------------------*/
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 新增:时间统计相关头文件
#include <sys/time.h>

#include "yolov5.h"
#include "image_utils.h"
#include "file_utils.h"
#include "image_drawing.h"

#if defined(RV1106_1103) 
    #include "dma_alloc.hpp"
#endif

/*-------------------------------------------
                新增:时间统计工具函数
-------------------------------------------*/
// 获取当前时间(微秒)
static inline uint64_t get_current_time_us() {
    struct timeval tv;
    gettimeofday(&tv, NULL);
    return (uint64_t)tv.tv_sec * 1000000 + tv.tv_usec;
}

// 计算耗时并打印(单位:毫秒,保留3位小数)
static inline void print_elapsed_time(const char* step_name, uint64_t start_us, uint64_t end_us) {
    double elapsed_ms = (end_us - start_us) / 1000.0;
    printf("[TIME] %s: %.3f ms\n", step_name, elapsed_ms);
}

/*-------------------------------------------
                  Main Function
-------------------------------------------*/
int main(int argc, char **argv)
{
    // ==============================================
    // 核心修复:提前声明所有时间变量,避免goto跳过初始化
    // ==============================================
    uint64_t total_start_us, total_end_us;
    uint64_t step1_start, step1_end;
    uint64_t step2_start, step2_end;
    uint64_t step3_start, step3_end, step3_end_all;
    uint64_t step4_start, step4_end;
    uint64_t step5_start, step5_end;
    uint64_t step6_start, step6_end;
    uint64_t step7_start, step7_end;
    uint64_t step8_start, step8_end;
    uint64_t step9_start, step9_end;

    // 总耗时统计
    total_start_us = get_current_time_us();

    if (argc != 3)
    {
        printf("%s <model_path> <image_path>\n", argv[0]);
        return -1;
    }

    const char *model_path = argv[1];
    const char *image_path = argv[2];

    int ret;
    rknn_app_context_t rknn_app_ctx;
    memset(&rknn_app_ctx, 0, sizeof(rknn_app_context_t));

    // 步骤1:初始化后处理(统计耗时)
    step1_start = get_current_time_us();
    init_post_process();
    step1_end = get_current_time_us();
    print_elapsed_time("Init post process", step1_start, step1_end);

    // 步骤2:初始化YOLOv5模型(核心步骤,统计耗时)
    step2_start = get_current_time_us();
    ret = init_yolov5_model(model_path, &rknn_app_ctx);
    step2_end = get_current_time_us();
    print_elapsed_time("Init YOLOv5 model", step2_start, step2_end);
    
    if (ret != 0)
    {
        printf("init_yolov5_model fail! ret=%d model_path=%s\n", ret, model_path);
        goto out;
    }

    // 步骤3:读取图片(统计耗时)
    image_buffer_t src_image;
    memset(&src_image, 0, sizeof(image_buffer_t));
    step3_start = get_current_time_us();
    ret = read_image(image_path, &src_image);
    step3_end = get_current_time_us();

#if defined(RV1106_1103) 
    //RV1106 rga requires that input and output bufs are memory allocated by dma
    ret = dma_buf_alloc(RV1106_CMA_HEAP_PATH, src_image.size, &rknn_app_ctx.img_dma_buf.dma_buf_fd, 
                       (void **) & (rknn_app_ctx.img_dma_buf.dma_buf_virt_addr));
    memcpy(rknn_app_ctx.img_dma_buf.dma_buf_virt_addr, src_image.virt_addr, src_image.size);
    dma_sync_cpu_to_device(rknn_app_ctx.img_dma_buf.dma_buf_fd);
    free(src_image.virt_addr);
    src_image.virt_addr = (unsigned char *)rknn_app_ctx.img_dma_buf.dma_buf_virt_addr;
    src_image.fd = rknn_app_ctx.img_dma_buf.dma_buf_fd;
    rknn_app_ctx.img_dma_buf.size = src_image.size;
#endif
    // 补充:包含RV1106的DMA处理耗时
    step3_end_all = get_current_time_us();
    print_elapsed_time("Read image (include DMA)", step3_start, step3_end_all);

    if (ret != 0)
    {
        printf("read image fail! ret=%d image_path=%s\n", ret, image_path);
        goto out;
    }

    object_detect_result_list od_results;

    // 步骤4:模型推理(核心步骤,统计耗时)
    step4_start = get_current_time_us();
    ret = inference_yolov5_model(&rknn_app_ctx, &src_image, &od_results);
    step4_end = get_current_time_us();
    print_elapsed_time("YOLOv5 inference", step4_start, step4_end);
    
    if (ret != 0)
    {
        printf("inference_yolov5_model fail! ret=%d\n", ret);
        goto out;
    }

    // 步骤5:结果处理(画框+打印+绘图,统计耗时)
    step5_start = get_current_time_us();
    // 画框和概率
    char text[256];
    for (int i = 0; i < od_results.count; i++)
    {
        object_detect_result *det_result = &(od_results.results[i]);
        printf("%s @ (%d %d %d %d) %.3f\n", coco_cls_to_name(det_result->cls_id),
               det_result->box.left, det_result->box.top,
               det_result->box.right, det_result->box.bottom,
               det_result->prop);
        int x1 = det_result->box.left;
        int y1 = det_result->box.top;
        int x2 = det_result->box.right;
        int y2 = det_result->box.bottom;

        draw_rectangle(&src_image, x1, y1, x2 - x1, y2 - y1, COLOR_BLUE, 3);

        sprintf(text, "%s %.1f%%", coco_cls_to_name(det_result->cls_id), det_result->prop * 100);
        draw_text(&src_image, text, x1, y1 - 20, COLOR_RED, 10);
    }
    step5_end = get_current_time_us();
    print_elapsed_time("Result process (draw box/text)", step5_start, step5_end);

    // 步骤6:保存输出图片(统计耗时)
    step6_start = get_current_time_us();
    write_image("out.png", &src_image);
    step6_end = get_current_time_us();
    print_elapsed_time("Write output image", step6_start, step6_end);

out:
    // 步骤7:释放后处理(统计耗时)
    step7_start = get_current_time_us();
    deinit_post_process();
    step7_end = get_current_time_us();
    print_elapsed_time("Deinit post process", step7_start, step7_end);

    // 步骤8:释放模型资源(统计耗时)
    step8_start = get_current_time_us();
    ret = release_yolov5_model(&rknn_app_ctx);
    step8_end = get_current_time_us();
    print_elapsed_time("Release YOLOv5 model", step8_start, step8_end);
    
    if (ret != 0)
    {
        printf("release_yolov5_model fail! ret=%d\n", ret);
    }

    // 步骤9:释放图片内存(统计耗时)
    step9_start = get_current_time_us();
    if (src_image.virt_addr != NULL)
    {
#if defined(RV1106_1103) 
        dma_buf_free(rknn_app_ctx.img_dma_buf.size, &rknn_app_ctx.img_dma_buf.dma_buf_fd, 
                rknn_app_ctx.img_dma_buf.dma_buf_virt_addr);
#else
        free(src_image.virt_addr);
#endif
    }
    step9_end = get_current_time_us();
    print_elapsed_time("Release image memory", step9_start, step9_end);

    // 输出总耗时
    total_end_us = get_current_time_us();
    print_elapsed_time("Total runtime", total_start_us, total_end_us);

    return 0;
}

重新编译程序并部署到板端

python 复制代码
# 激活你的 Conda 环境(可选,确保依赖一致)
conda activate yolov5_rknn

#设置编译器前缀(核心:指向去掉 -gcc 的部分)
export GCC_COMPILER=/root/arm-rockchip830-linux-uclibcgnueabihf/bin/arm-rockchip830-linux-uclibcgnueabihf

# 验证变量是否生效
echo $GCC_COMPILER  # 应输出上面的路径

#重新编译程序
./build-linux.sh -t rv1106 -a armv7l -d yolov5

#推送新程序到板子
adb push 编译后的rknn_yolov5_demo /root/rknn_yolov5_demo/

#在板子上运行
cd /root/rknn_yolov5_demo
chmod +x ./rknn_yolov5_demo
./rknn_yolov5_demo model/yolov5.rknn model/test.jpg

彻底解决GCC_COMPILER

python 复制代码
# 1. 编辑 .bashrc 文件
vim ~/.bashrc

# 2. 在文件末尾添加以下内容(按 i 进入编辑模式)
export GCC_COMPILER=/root/arm-rockchip830-linux-uclibcgnueabihf/bin/arm-rockchip830-linux-uclibcgnueabihf

# 3. 保存退出(按 Esc → 输入 :wq → 回车)

# 4. 使配置生效
source ~/.bashrc

# 5. 验证生效
echo $GCC_COMPILER  # 应输出正确路径

# 6. 重新编译
./build-linux.sh -t rv1106 -a armv7l -d yolov5

总结:

本章是笔者在适配RV1106所整理的笔记,仅供记录和学习使用,希望能给大家带来帮助。

相关推荐
人工智能AI技术2 小时前
CES 2026启示录:端侧AI部署全攻略——用TensorFlow Lite让AI跑在手机上
人工智能
杀生丸学AI2 小时前
【世界模型】AI世界模型的两次物理大考(测评)
人工智能·扩散模型·具身智能·视频生成·世界模型·自回归·空间智能
ATM0062 小时前
专其利AI | 开物之芯团队重磅发布「专其利 AI 专利辅助撰写平台」,30 秒定名、10 分钟出五书!
人工智能·大模型·专利撰写·专其利ai
2401_832298102 小时前
四大厂商云服务器安全创新对比,筑牢数字化转型安全底座
人工智能
Smart-Space2 小时前
cpphtmlbuilder-c++灵活构造html
c++·html
会叫的恐龙2 小时前
C++ 核心知识点汇总(第四日)(循环结构)
c++·算法·循环结构
熵减纪元2 小时前
OpenClaw gateway start 报 401 Invalid API key?一个环境变量的坑
人工智能·aigc
Agentcometoo2 小时前
2026 AI 元年:当人工智能不再以“创新项目”的形式出现
人工智能·文心一言·2026ai元年·时代趋势
2501_933329552 小时前
Infoseek数字公关AI中台技术解析:基于AI的智能舆情治理系统架构与实践
人工智能·系统架构