yolov5去掉后处理转onnx后是否还能用detect.py验证

yolov5转onnx,加了train=True去掉后处理以后得到的onnx模型,还能用python detect.py --weights=best.onnx来验证么?本人去掉后处理以后得到的onnx用detect.py验证报错张量维度不匹配,但是如果不去除后处理就不会报错。看了一下输出维度都是一样的,除了多了一个后处理output。看了一下报错的位置就是detect.py的后处理部分,猜想是不是去掉了后处理的onnx不能用detect验证?那我如果直接用这个去掉了后处理的onnx部署安卓会受影响么?

这不是通过--inplace这个参数来去掉detect层的吗?另外,去掉这个层之后,你需要自己去遍历三个输出口,还需要自己计算anchors来还原对应层的检测框,所以这就是为什么你直接去掉之后用原来的检测报错,应为原本的网络遍历的是统一三个输出口之后的输出,而不是分开遍历的

  • 这篇博客: yolov5的onnx推断示例和思路记录(包含detect.py的最新源码解读)中的 2.对图片进行预处理 部分也许能够解决你的问题, 你可以仔细阅读以下内容或跳转源博客中阅读:
  • # detect.py
    if webcam:
            view_img = check_imshow()
            cudnn.benchmark = True  # set True to speed up constant image size inference
            dataset = LoadStreams(source, img_size=imgsz, stride=stride, auto=pt)
            bs = len(dataset)  # batch_size
        else:
            dataset = LoadImages(source, img_size=imgsz, stride=stride, auto=pt)
            bs = 1  # batch_size
    

    因为我们是只对单张图片进行推断,所以肯定是使用了else循环下的LoadImages函数,这里涉及到两个参数img_sizeauto
    img_size是onnx模型的输入尺寸,一般来说,默认导出的是(640,640),这个值在你导出onnx模型的时候是可以修改的。
    auto是你是不是用了pt,我们是onnx,所以auto应该等于False。
    接下来看这个函数的具体实现(在utils下的dataloaders.py里):

    # dataloaders.py
    else:
        # Read image
        self.count += 1
        img0 = cv2.imread(path)  # BGR
        assert img0 is not None, f'Image Not Found {path}'
        s = f'image {self.count}/{self.nf} {path}: '
    
            # Padded resize
    img = letterbox(img0, self.img_size, stride=self.stride, auto=self.auto)[0]
    
            # Convert
    img = img.transpose((2, 0, 1))[::-1]  # HWC to CHW, BGR to RGB
    img = np.ascontiguousarray(img)
    

    因为我们只有一张图片,所以直接跳到else部分,这里面先用cv2.imread读取了图片,再用letterbox转换成了640x640的图片,再进行维度转换,最后成为一个array数组,所以我们自己写的时候只需要把letterbox方法(在utilsaugmentations.py下)合理的copy下来就可以成功的预处理了。

  • 以下回答由chatgpt基于相关博客总结生成:

    由于问题出在detect.py的后处理部分,建议先查看detect.py中的后处理部分代码,尤其是与模型输出张量维度有关的部分。如果模型输出维度与后处理部分有关,那么去除后处理部分将导致张量维度不匹配的报错。

    如果确信模型输出张量维度与后处理部分无关,可以排除后处理部分的影响。此时可以考虑以下两步操作:

    1. 验证ONNX模型输出维度: 可以使用onnxruntime包载入ONNX模型,使用infer方法推断数据,进而验证其输出张量维度是否与去除后处理的yolov5模型输出一致。

    示例代码:

    import onnxruntime as ort
    import numpy as np
    
    # 加载ONNX模型
    sess = ort.InferenceSession('test.onnx') # test.onnx是ONNX模型路径
    
    # 构造测试数据
    batch_size = 1
    input_size = (3, 640, 640)  # 模型输入张量维度
    test_input = np.random.randn(batch_size, *input_size).astype(np.float32)
    
    # 推断并获取输出
    ort_output = sess.run(None, {'image': test_input})  # 'image'是ONNX模型中输入节点名称
    print('ONNX模型输出维度:', ort_output[0].shape)
    

    若ONNX模型输出维度与去除后处理的yolov5模型输出一致,则可以进一步尝试第二步操作。

    1. 修改detect.py的后处理部分: 如果确信张量维度一致,可以考虑修改detect.py的后处理部分,使其能够适应去除后处理的yolov5模型输出维度。可以参考yolov5源码中的detect.py文件,在输出维度不变的情况下修改后处理部分的代码逻辑,使其适应去除后处理的yolov5模型。

    示例代码:

    def post_process(detections, img_size, conf_thres=0.1, nms_thres=0.45):
        """
        将模型预测结果转换为检测框
    
        :param detections: 模型预测结果
        :param img_size: 原始图片尺寸
        :param conf_thres: 置信度阈值
        :param nms_thres: NMS阈值
        :return: 检测框信息,每个元素为[x1, y1, x2, y2, conf, cls]
        """
        max_det = int(self.opt.max_det)
        detections = non_max_suppression(torch.cat(detections), conf_thres, nms_thres, max_det=max_det)
        result = []
        for detect in detections:
            if detect is None:
                continue
            # 获取检测框信息
            for x1, y1, x2, y2, conf, cls in detect:
                # 将bbox尺寸缩放到原始图像尺寸
                x1, y1, x2, y2 = scale_coords(img_size, (x1, y1, x2, y2), self.im0.shape).astype(np.int)
                w, h = x2 - x1, y2 - y1
                xc, yc = x1 + w / 2, y1 + h / 2
                obj = [x1, y1, x2, y2, conf, cls]
                result.append(obj)
        return result
    

    其中,non_max_suppression函数是yolov5源码中的另一个函数,用于实现NMS,可以自己另外实现。

    还需要根据实际情况修改其他部分代码,如推断数据的预处理等。

应该可以正常验证的