yolov5转onnx,加了train=True去掉后处理以后得到的onnx模型,还能用python detect.py --weights=best.onnx来验证么?本人去掉后处理以后得到的onnx用detect.py验证报错张量维度不匹配,但是如果不去除后处理就不会报错。看了一下输出维度都是一样的,除了多了一个后处理output。看了一下报错的位置就是detect.py的后处理部分,猜想是不是去掉了后处理的onnx不能用detect验证?那我如果直接用这个去掉了后处理的onnx部署安卓会受影响么?
这不是通过--inplace这个参数来去掉detect层的吗?另外,去掉这个层之后,你需要自己去遍历三个输出口,还需要自己计算anchors来还原对应层的检测框,所以这就是为什么你直接去掉之后用原来的检测报错,应为原本的网络遍历的是统一三个输出口之后的输出,而不是分开遍历的
# 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_size和auto:
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方法(在utils的augmentations.py下)合理的copy下来就可以成功的预处理了。
由于问题出在detect.py的后处理部分,建议先查看detect.py中的后处理部分代码,尤其是与模型输出张量维度有关的部分。如果模型输出维度与后处理部分有关,那么去除后处理部分将导致张量维度不匹配的报错。
如果确信模型输出张量维度与后处理部分无关,可以排除后处理部分的影响。此时可以考虑以下两步操作:
示例代码:
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模型输出一致,则可以进一步尝试第二步操作。
示例代码:
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,可以自己另外实现。
还需要根据实际情况修改其他部分代码,如推断数据的预处理等。
应该可以正常验证的