• 自定义数据训练的rknn模型部署 踩坑记录


    自己训练了一个只有2种类别的yolov8模型之后,部署到瑞芯微RKNN。

    踩坑一:类别的变化

    之前用COCO数据集训练的.pt模型转rknn后,output0的shape为8400 x 176.
    而把自定义数据集训练的模型转rknn后,output0的shape为8400 x 98.
    为什么会不一样?一度以为模型或代码有问题,拿图片测了下发现模型没问题,能检测出来。

    分析一下8400x176,其中8400是proposal的个数,176是box相关的64+80个类别+32的mask coefficient.
    现在类别变成了2,自然要变成64+2+32=98.

    所以,如果后处理中用到类别数=80,画图中的类别标签用了80个的,这里需要修改一下。

    踩坑二:模型转化(.pt 转 .rknn)

    用转化后的rknn模型检测,只能检测出一种类别,另一种检测不出来。

    于是从后处理出发找原因,
    现输入图片中有两种物体,每种一个,理论上应该检测出2个物体。
    先看NMS之前检测了多少个物体。

    std::vector<int> picked;
    nms_sorted_bboxes(proposals, picked); //picked里面保存的是proposals的下标
    
    int count = picked.size();
    
    • 1
    • 2
    • 3
    • 4

    这里NMS之前 picked.size() = 1, 说明NMS之前就只检测出一个,已经不对了。

    回到NMS之前的处理,
    这里选择较大概率的类别作为label,保存label, score和box坐标。

    int label = -1;
    float score = -FLT_MAX;
    //找到最大score和对应的label
    for (int k = 0; k < num_class; k++) {
        float confidence = deqnt_affine_to_f32(score_ptr[k], zp,
                                               scale);  //反量化,int转float
        if (confidence > score) {
            label = k;
            score = confidence;
        }
    }
    
    float box_prob = sigmoid(score);
    if (box_prob >= thres) {
        //忽略一段处理过程
        obj.rect.x = x0;
        obj.rect.y = y0;
        obj.rect.width = x1 - x0;
        obj.rect.height = y1 - y0;
        obj.label = label;
        obj.prob = box_prob;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    于是追踪label = 0和label = 1的检测概率。
    用同一图片测试,很神奇的是.pt模型(转rknn之前)测试中,label=0和label=1的目标 检测概率都>0.9,
    而转rknn之后label=1的目标 检测概率只有0.5,label=0的目标 检测概率小得出奇。
    观察到score作softmax运算前,label=0的目标 反量化的检测概率小于-7.

    认为这是反量化出现了问题,不过反量化用的是从rknn模型中读出的量化参数scales和zp。

    for (int i = 0; i < io_num.n_output; ++i) {
        output_attrs[i].index = i;
        if(rknn_query(ctx, RKNN_QUERY_OUTPUT_ATTR, &(output_attrs[i]), sizeof(rknn_tensor_attr)) < 0) {
            LOGE("rknn_query output_attrs[%d] fail!\n", i);
            return;
        }
        // set out_scales/out_zps for post_process
        out_scales.push_back(output_attrs[i].scale);
        out_zps.push_back(output_attrs[i].zp);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    如果量化参数有问题,那就是转rknn模型的过程有问题。

    找到转rknn模型的代码。

        OUT_DIR = "rknn_models"
        RKNN_MODEL_PATH = '{}/{}.rknn'.format(OUT_DIR,exp)
        if NEED_BUILD_MODEL:
            DATASET = './dataset.txt'
            rknn.config(mean_values=[[0, 0, 0]], std_values=[[255, 255, 255]], target_platform="rkXXXX")
            # Load model
            print('--> Loading model')
            ret = rknn.load_onnx(MODEL_PATH)
            if ret != 0:
                print('load model failed!')
                exit(ret)
            print('done')
    
            # Build model
            print('--> Building model')
            ret = rknn.build(do_quantization=True, dataset=DATASET)
            if ret != 0:
                print('build model failed.')
                exit(ret)
            print('done')
    
            # Export rknn model
            if not os.path.exists(OUT_DIR):
                os.mkdir(OUT_DIR)
            print('--> Export RKNN model: {}'.format(RKNN_MODEL_PATH))
            ret = rknn.export_rknn(RKNN_MODEL_PATH)
            if ret != 0:
                print('Export rknn model failed.')
                exit(ret)
            print('done')
        else:
            ret = rknn.load_rknn(RKNN_MODEL_PATH)
    
        rknn.release()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    注意到rknn模型的转换用到了dataset.txt,它指定的是如下图片。

    请添加图片描述

    这是原版COCO训练下的yolov8的图片,而现在的自定义数据集中没有这样的图片。
    换成现在自定义数据集中的图片,再次转rknn模型。

    然后观察scales和zp这两个量化值,发现跟之前不一样了。
    再次检测,成功检测出2个目标,且检测概率>0.9,和.pt模型差不多。

    总结:
    转rknn模型时用的图片可能需要用现有数据集中的图片,不要用不相关的图片。
    (原理不清楚)

  • 相关阅读:
    常见树种(贵州省):005竹类
    深度学习计算 - 层和块
    Hdu 3549 Flow Problem(最大流)
    华为OD技术面试案例3-2024年
    数据结构HW2
    一文叫你使用trace查看函数调用关系|分析Linux性能
    使用资源编排 ROS 轻松部署高可用架构网站——以 WordPress 为例
    车云汇元宇宙:开启虚拟与现实融合的汽车养护新篇章
    什么是面向对象编程?
    win11安装双系统Ubuntu的坎坷记录
  • 原文地址:https://blog.csdn.net/level_code/article/details/133810652