OAK相机如何将yoloV6模型转换成blob格式?(2.0 及之后版本)

news2024/9/28 5:25:25

编辑:OAK中国
首发:oakchina.cn
喜欢的话,请多多👍⭐️✍
内容可能会不定期更新,官网内容都是最新的,请查看首发地址链接。

▌前言

Hello,大家好,这里是OAK中国,我是助手君。

最近咱社群里有几个朋友在将yolox转换成blob的过程有点不清楚,所以我就写了这篇博客。(请夸我贴心!咱的原则:合理要求,有求必应!)

1.其他Yolo转换及使用教程请参考
2.检测类的yolo模型建议使用在线转换(地址),如果在线转换不成功,你再根据本教程来做本地转换。

.pt 转换为 .onnx

使用下列脚本(将脚本放到 YOLOv6 根目录中)将 pytorch 模型转换为 onnx 模型,若已安装 openvino_dev,则可进一步转换为 OpenVINO 模型:

示例用法:

python export_onnx.py -w <path_to_model>.pt -imgsz 640 

export_onnx.py :

#!/usr/bin/env python3
# -*- coding:utf-8 -*-
import argparse
import json
import subprocess
import sys
import time
from pathlib import Path

import onnx
import torch
import torch.nn as nn

ROOT = Path.cwd()
if str(ROOT) not in sys.path:
    sys.path.append(str(ROOT))

from yolov6.layers.common import *
from yolov6.models.efficientrep import (CSPBepBackbone, CSPBepBackbone_P6,
                                        EfficientRep, EfficientRep6)
from yolov6.models.effidehead import Detect
from yolov6.models.yolo import *
from yolov6.utils.checkpoint import load_checkpoint
from yolov6.utils.events import LOGGER


class YoloV6BackBone(nn.Module):
    """
    Backbone of YoloV6 model, it takes the model's original backbone and wraps it in this
    universal class. This was created for backwards compatibility with R2 models.
    """

    def __init__(self, old_layer, uses_fuse_P2=True, uses_6_erblock=False):
        super().__init__()

        self.uses_fuse_P2 = uses_fuse_P2
        self.uses_6_erblock = uses_6_erblock

        self.fuse_P2 = old_layer.fuse_P2 if hasattr(old_layer, "fuse_P2") else False

        self.stem = old_layer.stem
        self.ERBlock_2 = old_layer.ERBlock_2
        self.ERBlock_3 = old_layer.ERBlock_3
        self.ERBlock_4 = old_layer.ERBlock_4
        self.ERBlock_5 = old_layer.ERBlock_5
        if uses_6_erblock:
            self.ERBlock_6 = old_layer.ERBlock_6

    def forward(self, x):
        outputs = []
        x = self.stem(x)
        x = self.ERBlock_2(x)
        if self.uses_fuse_P2 and self.fuse_P2:
            outputs.append(x)
        elif not self.uses_fuse_P2:
            outputs.append(x)
        x = self.ERBlock_3(x)
        outputs.append(x)
        x = self.ERBlock_4(x)
        outputs.append(x)
        x = self.ERBlock_5(x)
        outputs.append(x)
        if self.uses_6_erblock:
            x = self.ERBlock_6(x)
            outputs.append(x)

        return tuple(outputs)


class DetectV6R2(nn.Module):
    """Efficient Decoupled Head for YOLOv6 R2&R3
    With hardware-aware degisn, the decoupled head is optimized with
    hybridchannels methods.
    """

    # def __init__(self, num_classes=80, anchors=1, num_layers=3, inplace=True, head_layers=None, use_dfl=True, reg_max=16):  # detection layer
    def __init__(self, old_detect):  # detection layer
        super().__init__()
        self.nc = old_detect.nc  # number of classes
        self.no = old_detect.no  # number of outputs per anchor
        self.nl = old_detect.nl  # number of detection layers
        if hasattr(old_detect, "anchors"):
            self.anchors = old_detect.anchors
        self.grid = old_detect.grid  # [torch.zeros(1)] * self.nl
        self.prior_prob = 1e-2
        self.inplace = old_detect.inplace
        stride = [8, 16, 32]  # strides computed during build
        self.stride = torch.tensor(stride)
        self.use_dfl = old_detect.use_dfl
        self.reg_max = old_detect.reg_max
        self.proj_conv = old_detect.proj_conv
        self.grid_cell_offset = 0.5
        self.grid_cell_size = 5.0

        # Init decouple head
        self.stems = old_detect.stems
        self.cls_convs = old_detect.cls_convs
        self.reg_convs = old_detect.reg_convs
        self.cls_preds = old_detect.cls_preds
        self.reg_preds = old_detect.reg_preds

    def forward(self, x):
        outputs = []
        for i in range(self.nl):
            b, _, h, w = x[i].shape
            l = h * w
            x[i] = self.stems[i](x[i])
            cls_x = x[i]
            reg_x = x[i]
            cls_feat = self.cls_convs[i](cls_x)
            cls_output = self.cls_preds[i](cls_feat)
            reg_feat = self.reg_convs[i](reg_x)
            reg_output = self.reg_preds[i](reg_feat)

            if self.use_dfl:
                reg_output = reg_output.reshape([-1, 4, self.reg_max + 1, l]).permute(
                    0, 2, 1, 3
                )
                reg_output = self.proj_conv(F.softmax(reg_output, dim=1))[:, 0]
                reg_output = reg_output.reshape([-1, 4, h, w])

            cls_output = torch.sigmoid(cls_output)
            conf, _ = cls_output.max(1, keepdim=True)
            output = torch.cat([reg_output, conf, cls_output], axis=1)
            outputs.append(output)

        return outputs


if __name__ == "__main__":
    parser = argparse.ArgumentParser(
        formatter_class=argparse.ArgumentDefaultsHelpFormatter
    )
    parser.add_argument(
        "-w", "--weights", type=Path, default="./yolov6s.pt", help="weights path"
    )
    parser.add_argument(
        "-imgsz",
        "--img-size",
        nargs="+",
        type=int,
        default=[640, 640],
        help="image size",
    )  # height, width
    parser.add_argument(
        "--inplace", action="store_true", help="set Detect() inplace=True"
    )
    parser.add_argument("--opset", type=int, default=12, help="opset version")
    args = parser.parse_args()
    args.img_size *= 2 if len(args.img_size) == 1 else 1  # expand
    print(args)
    t = time.time()

    # Check device
    device = torch.device("cpu")
    # Load PyTorch model
    model = load_checkpoint(
        str(args.weights), map_location=device, inplace=True, fuse=True
    )  # load FP32 model

    labels = model.names  # get class names

    for layer in model.modules():
        if isinstance(layer, RepVGGBlock):
            layer.switch_to_deploy()

    for n, module in model.named_children():
        if isinstance(module, EfficientRep) or isinstance(module, CSPBepBackbone):
            setattr(model, n, YoloV6BackBone(module))
        elif isinstance(module, EfficientRep6):
            setattr(model, n, YoloV6BackBone(module, uses_6_erblock=True))
        elif isinstance(module, CSPBepBackbone_P6):
            setattr(
                model,
                n,
                YoloV6BackBone(module, uses_fuse_P2=False, uses_6_erblock=True),
            )

    # Input
    img = torch.zeros(1, 3, *args.img_size).to(
        device
    )  # image size(1,3,320,192) iDetection

    # Update model
    model.eval()
    for k, m in model.named_modules():
        if isinstance(m, Conv):  # assign export-friendly activations
            if isinstance(m.act, nn.SiLU):
                m.act = SiLU()
        elif isinstance(m, Detect):
            m.inplace = args.inplace

    model.detect = DetectV6R2(model.detect)
    num_branches = len(model.detect.grid)

    y = model(img)  # dry run

    # ONNX export
    try:
        LOGGER.info("\nStarting to export ONNX...")
        output_list = [f"output{i+1}_yolov6r2" for i in range(num_branches)]
        export_file = args.weights.with_suffix(".onnx")  # filename
        torch.onnx.export(
            model,
            img,
            export_file,
            verbose=False,
            opset_version=args.opset,
            training=torch.onnx.TrainingMode.EVAL,
            do_constant_folding=True,
            input_names=["images"],
            output_names=output_list,
            dynamic_axes=None,
        )

        # Checks
        onnx_model = onnx.load(export_file)  # load onnx model
        onnx.checker.check_model(onnx_model)  # check onnx model
        try:
            import onnxsim

            LOGGER.info("\nStarting to simplify ONNX...")
            onnx_model, check = onnxsim.simplify(onnx_model)
            assert check, "assert check failed"
        except Exception as e:
            LOGGER.info(f"Simplifier failure: {e}")
        LOGGER.info(f"ONNX export success, saved as {export_file}")
    except Exception as e:
        LOGGER.info(f"ONNX export failure: {e}")

    export_json = export_file.with_suffix(".json")
    export_json.with_suffix(".json").write_text(
        json.dumps(
            {
                "anchors": [],
                "anchor_masks": {},
                "coordinates": 4,
                "labels": labels,
                "num_classes": model.nc,
            },
            indent=4,
        )
    )
    LOGGER.info("Labels data export success, saved as %s" % export_json)

    # OpenVINO export
    LOGGER.info("\nStarting to export OpenVINO...")
    export_dir = Path(str(export_file).replace(".onnx", "_openvino"))
    OpenVINO_cmd = (
        "mo --input_model %s --output_dir %s --data_type FP16 --scale 255 --reverse_input_channel --output '%s' "
        % (export_file, export_dir, ",".join(output_list))
    )
    try:
        subprocess.check_output(OpenVINO_cmd, shell=True)
        LOGGER.info(f"OpenVINO export success, saved as {export_dir}")
    except Exception as e:
        LOGGER.info(f"OpenVINO export failure: {e}")
        LOGGER.info("\nBy the way, you can try to export OpenVINO use:")
        LOGGER.info("\n%s" % OpenVINO_cmd)

    # OAK Blob export
    LOGGER.info("\nThen you can try to export blob use:")
    export_xml = export_dir / export_file.with_suffix(".xml")
    export_blob = export_dir / export_file.with_suffix(".blob")
    blob_cmd = (
        "compile_tool -m %s -ip U8 -d MYRIAD -VPU_NUMBER_OF_SHAVES 6 -VPU_NUMBER_OF_CMX_SLICES 6 -o %s"
        % (export_xml, export_blob)
    )
    LOGGER.info("\n%s" % blob_cmd)

    # Finish
    LOGGER.info("\nExport complete (%.2fs)" % (time.time() - t))

可以使用 Netron 查看模型结构:

在这里插入图片描述

▌转换

openvino 本地转换

onnx -> openvino

mo 是 openvino_dev 2022.1 中脚本,

安装命令为 pip install openvino-dev

mo --input_model yolov6n.onnx --reverse_input_channel

openvino -> blob

<path>/compile_tool -m yolov6n.xml \
-ip U8 -d MYRIAD \
-VPU_NUMBER_OF_SHAVES 6 \
-VPU_NUMBER_OF_CMX_SLICES 6

在线转换

blobconvert 网页 http://blobconverter.luxonis.com/

  • 进入网页,按下图指示操作:

在这里插入图片描述

  • 修改参数,转换模型:

在这里插入图片描述

  1. 选择 onnx 模型
  2. 修改 optimizer_params--data_type=FP16 --scale 255 --reverse_input_channel
  3. 修改 shaves6
  4. 转换

blobconverter python 代码

blobconverter.from_onnx(
            "yolov6n.onnx",	
            optimizer_params=[
                "--scale 255",
                "--reverse_input_channel",
            ],
            shaves=6,
        )

blobconvert cli

	blobconverter --onnx yolov6n.onnx -sh 6 -o . --optimizer-params "scale=255 --reverse_input_channel"

▌DepthAI 示例

正确解码需要可配置的网络相关参数:

  • setNumClasses - YOLO 检测类别的数量
  • setIouThreshold - iou 阈值
  • setConfidenceThreshold - 置信度阈值,低于该阈值的对象将被过滤掉
import cv2
import depthai as dai
import numpy as np

model = dai.OpenVINO.Blob("yolov6n.blob")
dim = model.networkInputs.get("images").dims
W, H = dim[:2]
labelMap = [
    # "class_1","class_2","..."
    "class_%s"%i for i in range(80)
]

# Create pipeline
pipeline = dai.Pipeline()

# Define sources and outputs
camRgb = pipeline.create(dai.node.ColorCamera)
detectionNetwork = pipeline.create(dai.node.YoloDetectionNetwork)
xoutRgb = pipeline.create(dai.node.XLinkOut)
nnOut = pipeline.create(dai.node.XLinkOut)

xoutRgb.setStreamName("rgb")
nnOut.setStreamName("nn")

# Properties
camRgb.setPreviewSize(W, H)
camRgb.setResolution(dai.ColorCameraProperties.SensorResolution.THE_1080_P)
camRgb.setInterleaved(False)
camRgb.setColorOrder(dai.ColorCameraProperties.ColorOrder.BGR)
camRgb.setFps(40)

# Network specific settings
detectionNetwork.setBlob(model)
detectionNetwork.setConfidenceThreshold(0.5)
detectionNetwork.setNumClasses(80)
detectionNetwork.setCoordinateSize(4)
detectionNetwork.setAnchors([])
detectionNetwork.setAnchorMasks({})
detectionNetwork.setIouThreshold(0.5)

# Linking
camRgb.preview.link(detectionNetwork.input)
camRgb.preview.link(xoutRgb.input)
detectionNetwork.out.link(nnOut.input)

# Connect to device and start pipeline
with dai.Device(pipeline) as device:
    # Output queues will be used to get the rgb frames and nn data from the outputs defined above
    qRgb = device.getOutputQueue(name="rgb", maxSize=4, blocking=False)
    qDet = device.getOutputQueue(name="nn", maxSize=4, blocking=False)

    frame = None
    detections = []
    color2 = (255, 255, 255)

    # nn data, being the bounding box locations, are in <0..1> range - they need to be normalized with frame width/height
    def frameNorm(frame, bbox):
        normVals = np.full(len(bbox), frame.shape[0])
        normVals[::2] = frame.shape[1]
        return (np.clip(np.array(bbox), 0, 1) * normVals).astype(int)

    def displayFrame(name, frame):
        color = (255, 0, 0)
        for detection in detections:
            bbox = frameNorm(frame, (detection.xmin, detection.ymin, detection.xmax, detection.ymax))
            cv2.putText(frame, labelMap[detection.label], (bbox[0] + 10, bbox[1] + 20), cv2.FONT_HERSHEY_TRIPLEX, 0.5, 255)
            cv2.putText(frame, f"{int(detection.confidence * 100)}%", (bbox[0] + 10, bbox[1] + 40), cv2.FONT_HERSHEY_TRIPLEX, 0.5, 255)
            cv2.rectangle(frame, (bbox[0], bbox[1]), (bbox[2], bbox[3]), color, 2)
        # Show the frame
        cv2.imshow(name, frame)

    while True:
        inRgb = qRgb.tryGet()
        inDet = qDet.tryGet()

        if inRgb is not None:
            frame = inRgb.getCvFrame()

        if inDet is not None:
            detections = inDet.detections


        if frame is not None:
            displayFrame("rgb", frame)

        if cv2.waitKey(1) == ord('q'):
            break

▌参考资料

https://www.oakchina.cn/2023/02/23/yolov6-blob/
https://docs.oakchina.cn/en/latest/
https://www.oakchina.cn/selection-guide/


OAK中国
| OpenCV AI Kit在中国区的官方代理商和技术服务商
| 追踪AI技术和产品新动态

戳「+关注」获取最新资讯↗↗

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/371443.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【对比学习论文】SimCLR 视觉表征对比学习的简单框架

文章题目&#xff1a;A Simple Framework for Contrastive Learning of Visual Representations时间&#xff1a;2020 摘要 本文提出了SimCLR:一种用于视觉表征对比学习的简单框架。我们简化了最近提出的对比自监督学习算法&#xff0c;而不需要专门的架构或内存库。为了了解…

websocket报错集锦-不断更新中

问题1&#xff1a;Failed to construct ‘WebSocket’: An insecure WebSocket connection may not be initiated from a page loaded over HTTPS. 问题描述 Mixed Content: The page at https://AAAAAA.com was loaded over HTTPS, but attempted to connect to the insecur…

Linux系统下命令行安装MySQL5.7+详细步骤

一起学编程&#xff0c;让生活更随和&#xff01; 如果你觉得是个同道中人&#xff0c;欢迎关注博主 gzh &#xff1a;【随和的皮蛋桑】。 专注于Java基础、进阶、面试以及计算机基础知识分享&#x1f433;。偶尔认知思考、日常水文&#x1f40c;。 目录1、下载安装包2、检查…

STM32 使用microros与ROS2通信

本文主要介绍如何在STM32中使用microros与ROS2进行通信&#xff0c;在ROS1中标准的库是rosserial,在ROS2中则是microros,目前网上的资料也有一部分了&#xff0c;但是都没有提供完整可验证的demo&#xff0c;本文将根据提供的demo一步步给大家进行演示。1、首先如果你用的不是S…

JUC 之 线程局部变量 ThreadLocal

—— ThreadLocal 基本概念 ThreadLocal 提供线程局部变量。这些变量与正常的变量不同&#xff0c;因为每一个线程在访问 ThreadLocal 实例的时候&#xff08;通过其get 或者 set 方法&#xff09;都有自己的、独立初始化的变副本。ThreadLocal实例通常是类中的私有静态字段&…

104-JVM优化

JVM优化为什么要学习JVM优化&#xff1a; 1&#xff1a;深入地理解 Java 这门语言 我们常用的布尔型 Boolean&#xff0c;我们都知道它有两个值&#xff0c;true 和 false&#xff0c;但你们知道其实在运行时&#xff0c;Java 虚拟机是 没有布尔型 Boolean 这种类型的&#x…

@Autowired和@Resource的区别

文章目录1. Autowired和Resource的区别2. 一个接口多个实现类的处理2.1 注入时候报错情况2.2 使用Primary注解处理2.3 使用Qualifer注解处理2.4 根据业务情况动态的决定注入哪个serviceImpl1. Autowired和Resource的区别 Aurowired是根据type来匹配&#xff1b;Resource可以根…

数据结构栈的经典OJ题【leetcode最小栈问题大剖析】【leetcode有效的括号问题大剖析】

目录 0.前言 1.最小栈 1.1 原题展示 1.2 思路分析 1.2.1 场景引入 1.2.2 思路 1.3 代码实现 1.3.1 最小栈的删除 1.3.2 最小栈的插入 1.3.3 获取栈顶元素 1.3.4 获取当前栈的最小值 2. 有效的括号 0.前言 本篇博客已经把两个关于栈的OJ题分块&#xff0c;可以根据目…

【蓝牙mesh】Upper协议层介绍

【蓝牙mesh】Upper协议层介绍 Upper层简介 Upper协议层用于处理网络层以上的功能&#xff0c;包括设备的应用层数据、安全、群组等信息&#xff0c;是实现蓝牙mesh应用功能的关键协议之一。Upper层接收来自Access层的数据或者是Upper层自己生成的Control数据&#xff0c;并且将…

typing库

typing 库 引入 在日常代码编写中&#xff0c;由于python语言特性&#xff0c;不用像go等编译性语言一样&#xff0c;在定义函数时就规范参数和放回值的类型。 def demo(a, b):return "ab" 此时 a 和 b 可以传入任意类型参数毫无疑问&#xff0c;这一特性&#…

漏洞分析: WSO2 API Manager 任意文件上传、远程代码执行漏洞

漏洞描述 某些WSO2产品允许不受限制地上传文件&#xff0c;从而执行远程代码。以WSO2 API Manager 为例&#xff0c;它是一个完全开源的 API 管理平台。它支持API设计&#xff0c;API发布&#xff0c;生命周期管理&#xff0c;应用程序开发&#xff0c;API安全性&#xff0c;速…

【RockerMQ】001-RockerMQ 概述

【RockerMQ】001-RockerMQ 概述 文章目录【RockerMQ】001-RockerMQ 概述一、MQ 概述1、MQ 简介2、MQ 用途限流削峰异步解耦数据收集3、常见 MQ 产品概述对比4、MQ 常见协议二、RocketMQ 概述1、简介2、发展历史一、MQ 概述 1、MQ 简介 MQ&#xff0c;Message Queue&#xff0…

C++设计模式(22)——状态模式

亦称&#xff1a; State 意图 状态模式是一种行为设计模式&#xff0c; 让你能在一个对象的内部状态变化时改变其行为&#xff0c; 使其看上去就像改变了自身所属的类一样。 问题 状态模式与有限状态机 的概念紧密相关。 有限状态机。 其主要思想是程序在任意时刻仅可处…

【数据库】数据库的完整性

第五章 数据库完整性 数据库完整性 数据库的完整性是指数据的正确性和相容性 数据的正确性是指数据是符合现实世界语义&#xff0c;反映当前实际状况的数据的相容性是指数据库的同一对象在不同的关系中的数据是符合逻辑的 关系模型中有三类完整性约束&#xff1a;实体完整性…

中创公益|中创算力荣获“2022年度突出贡献爱心企业”

公益是什么&#xff1f;不啻微芒造炬成阳萤火虽微愿为其芒公益是持之以恒的努力&#xff0c;中创于2021年1月成立&#xff0c;同年4月中创就开始了公益活动&#xff0c;并对尖山村贫困儿童进行定期捐助。截至2023年&#xff0c;中创先后7次来到被捐助的贫困儿童家中&#xff0c…

【Git】IDEA整合Git详细步骤 — IDEA如何配置Git忽略文件

目录 一、IDEA整合Git 定位 Git 程序 —》IDEA配置Git程序 初始化本地库—》在idea中初始化项目&#xff0c;将项目纳入git管理 添加到暂存区 提交到本地库 方法一: 右键点击项目---> Git ----> Commit Directory 方法二: 点击绿色图标 √ 切换版本 创建分支 切换分…

chatgpt的原理 第一部分

前言 这两天&#xff0c;ChatGPT模型真可谓称得上是狂拽酷炫D炸天的存在了。一度登上了CSDN热搜&#xff0c;这对科技类话题是非常难的存在。不光是做人工智能、机器学习的人关注&#xff0c;而是大量的各行各业从业人员都来关注这个模型&#xff0c;真可谓空前盛世。 我赶紧把…

无人驾驶路径规划论文简要

A Review of Motion Planning Techniques for Automated Vehicles综述和分类0Motion Planning for Autonomous Driving with a Conformal Spatiotemporal Lattice从unstructured环境向structured环境的拓展&#xff0c;同时还从state lattice拓展到了spatiotemporal lattice从而…

【数据结构】双向链表的接口实现(附图解和源码)

双向链表的接口实现&#xff08;附图解和源码&#xff09; 文章目录双向链表的接口实现&#xff08;附图解和源码&#xff09;前言一、定义结构体二、接口实现&#xff08;附图解源码&#xff09;1.初始化双向链表2.开辟新空间3.尾插数据4.尾删数据5.打印双向链表中数据6.头插数…

含分布式电源的配电网日前两阶段优化调度模型(Matlab代码实现)

&#x1f468;‍&#x1f393;个人主页&#xff1a;研学社的博客&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5;&#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密…