yolov5和rknn模型的问题

rknn官方目前1.7.0
对新算子的支持还没跟上, 需要将yolov5中的模型做下面的改变,
改变之后 重新训练新的模型. 再去转onnx, 然后转rknn

(吐槽一下, rknn官方真是 效率太低了. 售后也很不到位, 恨不得去咬他两口.)

额, 下文其实都是抄自
https://github.com/EASY-EAI/yolov5
https://github.com/littledeep/YOLOv5-RK3399Pro
其中 YOLOv5-RK3399Pro 属于功能比较全面的项目.

建议不要使用官方的yolov5 模型, 官方的由于更新太快了, rknn的速度跟不上, 训练和转换模型是往往会出现各种各样的算子不支持的问题. 还是使用 YOLOv5-RK3399Pro 比较好.

其实下面的文章你可以不看, 去下载 https://github.com/littledeep/YOLOv5-RK3399Pro
把, 训练的时候可能会遇到点小问题,

  1. 记得模型转换onnx的时候要把 opset 改成 11
  2. 把训练的weights 参数改成 ” 空字符串, 这样是全新的训练. 不用下载官方模型.

其它的我就不啰嗦了,

关于转换, 说一下我对这个库的总结.

如果yolov5 导出的onnx包含了 Detect层, 也就是最后一层, 会在onnx转rknn的时候出现各种失败. 所以一定要在导出onnx的时候把 Detect层去掉. YOLOv5-RK3399Pro的model/export.py 中 , –grid 一定要设置为False

parser.add_argument('--grid', default=False, action='store_true', help='export Detect() layer grid')

–rknn_mode 要默认True

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('--weights', type=str, default=r'F:\project\AI\yolov5_3399pro\best.pt', help='weights path')
    parser.add_argument('--img-size', nargs='+', type=int, default=[640, 640], help='image size')
    parser.add_argument('--batch-size', type=int, default=1, help='batch size')
    parser.add_argument('--dynamic',  action='store_true', help='dynamic ONNX axes')
    parser.add_argument('--grid', default=False, action='store_true', help='export Detect() layer grid')
    parser.add_argument('--device', default='cpu', help='cuda device, i.e. 0 or 0,1,2,3 or cpu')
    parser.add_argument('--rknn_mode', default=True, action='store_true', help='export rknn-friendly onnx model')
    parser.add_argument('--ignore_output_permute', action='store_true', help='export model without permute layer,which can be used for rknn_yolov5_demo c++ code')
    parser.add_argument('--add_image_preprocess_layer',default=False,  action='store_true', help='add image preprocess layer, benefit for decreasing rknn_input_set time-cost')
    opt = parser.parse_args()

在第 161行, 这里我写死了onnx 输出的3个节点, 改成了下面的3个名字. 后面转rknn的时候就定死即可.


        output_names=['output80x', 'output40x','output20x'],

onnx 转rknn 我用了我自己的代码. 比较简洁. 易懂.

onnx2rknn.py


from rknn.api import RKNN

INPUT_SIZE = 64

if __name__ == '__main__':

    rknn = RKNN()

    add_perm = False
    rknn.config(
        batch_size=1,
        mean_values=[[0, 0, 0]],
        std_values=[[255, 255, 255]],
        reorder_channel='0 1 2',
        force_builtin_perm=add_perm,
        output_optimize=1,
        target_platform='rk3399pro')

    print('--> Loading model')

    ret = rknn.load_onnx(  model='best.onnx' ,
        inputs=['images'],
        outputs=['output80x', 'output40x','output20x'],
        input_size_list=[[3,640,640]],)
    if ret != 0:
        print('Load  onnx  failed!')
        exit(ret)
    print('done')

    print('--> Building model')
    rknn.build(do_quantization=True)
    print('done')

    ret = rknn.export_rknn('./best.rknn')
    if ret != 0:
        print('Export  rknn failed!')
        exit(ret)
    else:
        print('Export  rknn success!')

    rknn.release()

识别用的代码用的是. YOLOv5-RK3399Pro 中的
rknn_detect\rknn_detect_for_yolov5_original.py
代码我就不贴了.

整体能跑通显示图片了, 等我训练出一个合适的模型再继续测试.

下面的你可以不看.直接用上面的库就能正常训练和转换
下面的你可以不看.直接用上面的库就能正常训练和转换
下面的你可以不看.直接用上面的库就能正常训练和转换
下面的你可以不看.直接用上面的库就能正常训练和转换
下面的你可以不看.直接用上面的库就能正常训练和转换

改变如下:

  1. 将Focus层改成Conv层
  2. 将Swish激活函数改成Relu激活函数
  3. 将大kernel_size的MaxPooling改成3×3 MaxPooling Stack结构

第一个 将Focus层改成Conv层, 参考自 @Shmily丶

将 common.py 的


class Focus(nn.Module):

    def __init__(self, c1, c2, k=1, s=1, p=None, g=1, act=True):
        super().__init__()
        self.conv = Conv(c1, c2, k, s, p, g, act)

    def forward(self, x):
        return self.conv(x)

将Swish激活函数改成Relu激活函数
这个比较简单, 因为Swish激活函数是最新出的算法, 所以rknn还没来得及支持.

改变 方法也很简单 目前版本V6.0 只需要改两个地方.

将 common.py 的


 self.act = nn.SiLU() if act is True else (act if isinstance(act, nn.Module) else nn.Identity())

 self.act = nn.ReLU() if act is True else (act if isinstance(act, nn.Module) else nn.Identity())

将export.py中

  m.act = SiLU()

  m.act = nn.ReLU()

第三个,将大kernel_size的MaxPooling改成3×3 MaxPooling Stack结构

yolov5和rknn模型的问题
别人转换后的结构, 如上图, 但是代码还不知道怎么写…

关于yolov5 输出结果结构的后处理

yolov5和rknn模型的问题
据网友说 rknn-toolkit的github issue有人问过这个问题,也有对应的答复。但是我没搜到。
这个输出0的结构是 1 * 25200 * 85

网友提示 25200=40 _40_3 + 20 _20_3 + 80 _80_3
所以 应该怎么解这个矩阵应该也是比较容易理解的了.

关于输出结构后处理可以参考文章.

https://cumtchw.blog.csdn.net/article/details/120860799

如果你的项目模型转换正常了,也不报错了, 但是识别不了.
问题可能出在 img = img[…, ::-1] 这里.

代码在下面

rknn_detect\rknn_detect_for_yolov5_original.py 文件中.

不需要拆分 start

不需要拆分 end
之间的注释掉.

这里是对原图片进行了,切割拆分, 重组.

  def _predict(self, img_src, img, gain):
        src_h, src_w = img_src.shape[:2]

        pred_onx = self._rknn.inference(inputs=[img])

        boxes, classes, scores = [], [], []
        for t in range(1,3):
            input0_data = sigmoid(pred_onx[t][0])
            input0_data = np.transpose(input0_data, (1, 2, 0, 3))
            grid_h, grid_w, channel_n, predict_n = input0_data.shape

参考文章:

https://github.com/rockchip-linux/rknpu/tree/master/rknn/rknn_api/examples/rknn_yolov5_demo (官方的必看)

https://github.com/rockchip-linux/rknpu
https://github.com/EASY-EAI/yolov5

Original: https://blog.csdn.net/phker/article/details/121084160
Author: 走错路的程序员
Title: yolov5和rknn模型的问题

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/707540/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球