-
-
Notifications
You must be signed in to change notification settings - Fork 16.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Use export.py to generate yolov5s.onnx will get a negative number. #343
Comments
Hello @WZTENG, thank you for your interest in our work! Please visit our Custom Training Tutorial to get started, and see our Jupyter Notebook , Docker Image, and Google Cloud Quickstart Guide for example environments. If this is a bug report, please provide screenshots and minimum viable code to reproduce your issue, otherwise we can not help you. If this is a custom model or data training question, please note that Ultralytics does not provide free personal support. As a leader in vision ML and AI, we do offer professional consulting, from simple expert advice up to delivery of fully customized, end-to-end production solutions for our clients, such as:
For more information please visit https://www.ultralytics.com. |
Have you solved the problem? I have the same question here |
This comment has been minimized.
This comment has been minimized.
Hi both, It very much seems that the above script generates the results as per the three raw output layers:
These results are not final. In the detect.py script these are also processed during inference: Lines 29 to 36 in a1c8406
You have two options:
Line 28 in a1c8406
Above needs to be changed to false. I have done this for my own experiments. The ONNX export seems to work, however the CoreML one doesn't.
You could replicate the same logic that's referenced above using In both cases, you do miss the following:
These are currently done as part of the following function: Lines 549 to 554 in a1c8406
Hope this is useful. Good luck! |
thanks! |
@dlawrences model.model[-1].export = False |
@WZTENG what is the error you are encountering? |
I understand why you're saying it feels worse than before, but that it is because you are now missing any NMS step, as specified above. Could you please answer/check on the following points?
Also, I would like to have a look at the .onnx file, just to make sure there's nothing wrong with you. Would you please attach it here? Thanks |
Finally succeeded. It is estimated that some of the internal processing methods are different from what I thought before. If I have time, I will carefully check the internal processing process. The current successful way is to set model.model[-1].export = False, and use the output [0] and call the official NMS to display it correctly. Previously, I used the results with 3 outputs and processed the relevant content myself. However, thank you for providing useful information. |
Hi @WZTENG Great news, happy you have managed to do it! I think it would be really useful for others to create a mini-documentation containing your findings. Would you be willing to put together this info? Tip: It should however be possible to process the output of the three feature maps independently from the Detect layer by replicating all those operations in NumPy/any other framework though. I have managed to do it myself using CoreML ops. Cheers |
Additional info: I am not sure what you mean by "and use the output [0]", but if you are only consuming the results as per the higher level feature map (80x80), then you are missing on some results. Please consider that the Detect layer, at least as per my memory, produces outputs scaled to the dimensions of the input image (i.e. the original image may be 1920x1080, but you have trained using 640x640 inputs, so this is the dimension space). In detect.py, there is some logic that handles this. Namely:
These operations are not done in the |
It is only successful now, but I am still not sure what caused it. If it can be solved, I will send it out. |
It feels a bit different from the data I have seen before, but the output is no problem. The following is the method I implemented, although there are more, but at least I understand how to deal with it. I hope that those who have encountered this problem can refer to it. def detect_onnx(official=True, image_path=None):
num_classes = 80
anchors = [[116, 90, 156, 198, 373, 326], [30, 61, 62, 45, 59, 119], [10, 13, 16, 30, 33, 23]] # 5s
session = onnxruntime.InferenceSession('./weights/yolov5s.onnx')
# print("The model expects input shape: ", session.get_inputs()[0].shape)
batch_size = session.get_inputs()[0].shape[0]
img_size_h = session.get_inputs()[0].shape[2]
img_size_w = session.get_inputs()[0].shape[3]
# input
image_src = Image.open(image_path)
resized = letterbox_image(image_src, (img_size_w, img_size_h))
img_in = np.transpose(resized, (2, 0, 1)).astype(np.float32) # HWC -> CHW
img_in = np.expand_dims(img_in, axis=0)
img_in /= 255.0
# print("Shape of the image input shape: ", img_in.shape)
# inference
input_name = session.get_inputs()[0].name
outputs = session.run(None, {input_name: img_in})
batch_detections = []
if official and len(outputs) == 4: # model.model[-1].export = boolean ---> True:3 False:4
# model.model[-1].export = False ---> outputs[0] (1, xxxx, 85)
# official
batch_detections = torch.from_numpy(np.array(outputs[0]))
batch_detections = non_max_suppression(batch_detections, conf_thres=0.4, iou_thres=0.5, agnostic=False)
else:
# model.model[-1].export = False ---> outputs[1]/outputs[2]/outputs[2]
# model.model[-1].export = True ---> outputs
# (1, 3, 20, 20, 85)
# (1, 3, 40, 40, 85)
# (1, 3, 80, 80, 85)
# myself (from yolo.py Detect)
boxs = []
a = torch.tensor(anchors).float().view(3, -1, 2)
anchor_grid = a.clone().view(3, 1, -1, 1, 1, 2)
if len(outputs) == 4:
outputs = [outputs[1], outputs[2], outputs[3]]
for index, out in enumerate(outputs):
out = torch.from_numpy(out)
batch = out.shape[1]
feature_w = out.shape[2]
feature_h = out.shape[3]
# Feature map corresponds to the original image zoom factor
stride_w = int(img_size_w / feature_w)
stride_h = int(img_size_h / feature_h)
conf = out[..., 4]
pred_cls = out[..., 5:]
grid_x, grid_y = np.meshgrid(np.arange(feature_w), np.arange(feature_h))
# cx, cy, w, h
pred_boxes = torch.FloatTensor(out[..., :4].shape)
pred_boxes[..., 0] = (torch.sigmoid(out[..., 0]) * 2.0 - 0.5 + grid_x) * stride_w # cx
pred_boxes[..., 1] = (torch.sigmoid(out[..., 1]) * 2.0 - 0.5 + grid_y) * stride_h # cy
pred_boxes[..., 2:4] = (torch.sigmoid(out[..., 2:4]) * 2) ** 2 * anchor_grid[index] # wh
conf = torch.sigmoid(conf)
pred_cls = torch.sigmoid(pred_cls)
output = torch.cat((pred_boxes.view(batch_size, -1, 4),
conf.view(batch_size, -1, 1),
pred_cls.view(batch_size, -1, num_classes)),
-1)
boxs.append(output)
outputx = torch.cat(boxs, 1)
# NMS
batch_detections = w_non_max_suppression(outputx, num_classes, conf_thres=0.4, nms_thres=0.3)
return batch_detections If necessary, you can change all the methods used to numpy to achieve better, which is convenient for other frameworks. |
@WZTENG can you share the whole code for onnx inference? |
@WZTENG Thank you again. |
@mukul1em @imyoungyang here. download demo_onnx.zip and unzip. |
Can it be used to test whether the converted best.onnx is OK? |
Yes, but I only wrote the 5s part of the code, other models need to add the corresponding anchors part. Note the order of anchors. |
I use your code te test yolov5s.onnx ,but something eror happened: |
It works normally for me. Did you modify the code? You can also use the conversion function for conversion. |
NO ,i modify nothing. Could you upload your yolov5s.onnx or other onnx so as to check whether the onnx that converted is not correct ? |
I met the same problem. The input image after lettorbox size is (640,480), but the onnx model expected input is (640,640). Have you solved the problem? |
i unzipped and ran the demo_onnx.py. i encountered the error below: OSError: [WinError 127] The specified procedure could not be found. Error loading "C:\Users\User\anaconda3\envs\yolov5\lib\site-packages\torch\lib\cublas64_11.dll" or one of its dependencies. may i know what could be the problem? |
Hi, i tried running the demo_onnx.py. i didn't change anything else except for the number of classes and the anchors. below is the error i got. any idea what the issue is?
|
@gohguodong sorry this code you ran is not part of the official repo code so we can't provide support for it. We are working on providing better inference examples for deployment environments in the future though! |
@glenn-jocher any updates on this? |
@lleye there are constant updates to export. |
@glenn-jocher Is someone currently working on improving the CoreML export? It would be great if it could generate a complete object detection model (including the Detect layers feeding into CoreML's NMS layer) that then could be used easily with Apple's Vision framework. I would be happy to help with this (to the best of my abilities). |
You have to shift the boxes
|
Were you ever able to use an exported coreml model? I'm struggling to figure out how to export correctly. |
@tylercollins590 Yes, I was. See my reply here. |
@pocketpixels thank you. Does this work on V6 of Yolov5 or a previous version? |
@tylercollins590 Not sure. I haven't tested with the latest version. You can find my fork with this script here. Note that I made my changes in the branch |
@pocketpixels got it exported and working in my iOS app. I'm seeing very low FPS (5-7fps) with Yolov5s. Did you experience similar? |
Performance will depend on the device and the image resolution you use. |
@pocketpixels I am using an iphone 12 pro. iDetection from ultralytics runs Yolov5s at about 35 FPS. I am using 640x640 resolution in my exported model. Any ideas where I should focus? |
I am not using it for continuous detection myself. And wouldn’t really recommend that either as iOS devices will burn through battery and will throttle down pretty quickly if you max out the GPU and/or Neural Engine and CPU. |
IDetection uses 320x192. So about 7x less pixels. So the performance you are seeing seems reasonable. |
@tylercollins590 did you get the script by @pocketpixels to work on v6 (or 6.1) of YOLOv5? Managed to work around some numpy syntax changes (line 59) however am running into issues with arrays shapes, a bit beyond me...
|
@mshamash unfortunately I have not been able to get anything to run on any version past v4 |
@tylercollins590 Interesting, as I did get that script to work on my v5 YOLOv5s models in late-2021 (final CoreML models had NMS) |
@tylercollins590 - After much effort, and trial and error, I got the .mlmodel files from the YOLOv5 (v6.1) export.py script to work within my iOS app on still images. If this is something you are also doing with your models I'd be happy to share the code. |
@tylercollins590 - I submitted a pull request #7263 which has an updated export.py script so that the exported CoreML model has a NMS layer. Give it a try with your models! |
❔Question
Use export.py to generate yolov5s.onnx will get a negative number.
This is the code that executes the onnx part
There are already negative numbers in the outputs. Then after the result is processed, it will appear that part of it is correct, such as car in the figure. However, the top/bottom of the bicycle is right, the left/right is wrong, the left/right of the dog is right, and the top/bottom is wrong. What might cause this problem? Thanks.
Additional context
torch:1.5.1
torchvision:0.6.1
onnxruntime:1.3.0
The text was updated successfully, but these errors were encountered: