Skip to content
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

About not being able to customize the anchors #7015

Closed
1 task done
jayer95 opened this issue Mar 17, 2022 · 11 comments · Fixed by #7060
Closed
1 task done

About not being able to customize the anchors #7015

jayer95 opened this issue Mar 17, 2022 · 11 comments · Fixed by #7060
Labels
bug Something isn't working question Further information is requested

Comments

@jayer95
Copy link

jayer95 commented Mar 17, 2022

Search before asking

Question

I'm training a model for license plate character detection, this is the training command I use,

python train.py
--img 160
--batch 256
--epochs 300
--data data/number_plate_00_02_08_09_18_19_all_mixing.yaml
--weights ''
--cfg models/yolov5n-number_plate_00_02_08_09_18_19_all_mixing_160.yaml
--hyp data/hyps/hyp.scratch-low-number_plate_00_02_08_09_18_19_all_mixing.yaml

When the training is completed, I found that its anchors use the default anchors, and there is no automatic recalculation.

import torch
from models.experimental import attempt_load

model = attempt_load('./yolov5n-number_plate_00_02_08_09_18_19_all_mixing_best_0317_160x160.pt', map_location=torch.device('cpu'))
m = model.module.model[-1] if hasattr(model, 'module') else model.model[-1]
print(m.anchor_grid)

anchors:

  • [10,13, 16,30, 33,23] # P3/8
  • [30,61,62,45,59,119] # P4/16
  • [116,90, 156,198, 373,326] # P5/32

I don't think it's reasonable, this model is very bad at detecting small objects,

Since there are no autoanchors during training, I recalculate the anchors on my dataset,

import utils.autoanchor as autoAC

new_anchors = autoAC.kmean_anchors('./data/number_plate_00_02_08_09_18_19_all_mixing.yaml', 9, 160, 5.0, 5000, True)
print(new_anchors)

Get the following new anchors,

  • [17,21, 19,35, 18,40] # P3/8
  • [22,36, 21,40, 25,38] # P4/16
  • [24,42, 28,40, 29,50] # P5/32

I go to yolov5/models/yolov5n.yaml,

anchors:

  • [10,13, 16,30, 33,23] # P3/8
  • [30,61,62,45,59,119] # P4/16
  • [116,90, 156,198, 373,326] # P5/32

replace with

  • [17,21, 19,35, 18,40] # P3/8
  • [22,36, 21,40, 25,38] # P4/16
  • [24,42, 28,40, 29,50] # P5/32

and retrain,

python train.py
--img 160
--batch 256
--epochs 300
--data data/number_plate_00_02_08_09_18_19_all_mixing.yaml
--weights ''
--cfg models/yolov5n-number_plate_00_02_08_09_18_19_all_mixing_160.yaml
--hyp data/hyps/hyp.scratch-low-number_plate_00_02_08_09_18_19_all_mixing.yaml
--noautoanchor

After the training, I re-checked best.pt/last.pt and got:

  • [6,11, 7,10, 7,13] # P3/8
  • [22,36, 21,40, 25,38] # P4/16
  • [68,84, 76,140, ​​72,160] # P5/32

I used "--noautoanchor" during training, but the model was not constructed based on the anchors I specified? The model also recomputed a new set of anchors?

I refer to #6966

@jayer95 jayer95 added the question Further information is requested label Mar 17, 2022
@glenn-jocher
Copy link
Member

@jayer95 YOLOv5 🚀 anchors are saved as Detect() layer attributes on model creation, and updated as necessary by AutoAnchor before training starts. Their exact location is here:

self.register_buffer('anchors', torch.tensor(anchors).float().view(self.nl, -1, 2)) # shape(nl,na,2)

You can examine the anchors of any trained YOLOv5 model like this:

Input

import torch

# Model
model = torch.hub.load('ultralytics/yolov5', 'yolov5s', autoshape=False)  # official model
model = torch.hub.load('ultralytics/yolov5', 'custom', 'path/to/best.pt',  autoshape=False)  # custom model

# Anchors
m = model.model.model[-1]  # Detect() layer
print(m.anchors * m.stride.view(-1, 1, 1))  # print anchors

Output

YOLOv5 🚀 2021-11-22 torch 1.10.0+cu111 CUDA:0 (Tesla V100-SXM2-16GB, 16160MiB)
#           x     y
tensor([[[ 10.,  13.],
         [ 16.,  30.],
         [ 33.,  23.]],  # P3/8-small

        [[ 30.,  61.],
         [ 62.,  45.],
         [ 59., 119.]],  # P4/16-medium

        [[116.,  90.],
         [156., 198.],
         [373., 326.]]], dtype=torch.float16)  # P5/32-large

Example

Screenshot 2022-03-14 at 10 37 19

Good luck 🍀 and let us know if you have any other questions!

@glenn-jocher
Copy link
Member

@jayer95 if you really want to force autoanchor you can lower the threshold here:

if bpr > 0.98: # threshold to recompute

@jayer95
Copy link
Author

jayer95 commented Mar 17, 2022

@glenn-jocher

Hi,

I have deleted the default anchors in "yolov5/models/yolov5n.yaml", as follows,
[10,13, 16,30, 33,23] # P3/8
[30,61,62,45,59,119] # P4/16
[116,90,156,198,373,326] # P5/32

Replaced my own defined anchors, as follows,

[17,21, 19,35, 18,40] # P3/8
[22,36, 21,40, 25,38] # P4/16
[24,42, 28,40, 29,50] # P5/32

When training the model, the model also correctly read my new anchors, and also set the "--noautoanchor" parameter. I checked the training diary and wrote noautoanchor=true,
Despite the above, the trained model actually has a third anchors?

What I want to express is the above situation, I don't want to recalculate the anchors during training.

In addition, I also experimented with the above situation. I did not set the "--noautoanchor" parameter. During training, noautoanchor=false, the program called the autoanchor function and returned "There is no need to recalculate the anchors, because the original anchors are already very perfect", then the model also correctly reads my custom anchors, as follows,

[17,21, 19,35, 18,40] # P3/8
[22,36, 21,40, 25,38] # P4/16
[24,42, 28,40, 29,50] # P5/32

But the model generated by training has a third case of its anchors, neither the preset anchors nor my custom anchors?

@jayer95
Copy link
Author

jayer95 commented Mar 17, 2022

The third anchors, as follows, are neither preset anchors nor my custom anchors.

[6,11, 7,10, 7,13] # P3/8
[22,36, 21,40, 25,38] # P4/16
[68,84, 76,140, ​​72,160] # P5/32

@glenn-jocher
Copy link
Member

glenn-jocher commented Mar 17, 2022

@jayer95 our team is very small and very busy. If you believe you have an issue please verify it is reproducible before asking us to assist. We do not have time to pursue non-reproducible issues.

!python train.py --weights yolov5s.pt --cfg yolov5s.yaml --noautoanchor --epochs 3

Screenshot 2022-03-17 at 19 02 12

How to create a Minimal, Reproducible Example

When asking a question, people will be better able to provide help if you provide code that they can easily understand and use to reproduce the problem. This is referred to by community members as creating a minimum reproducible example. Your code that reproduces the problem should be:

  • Minimal – Use as little code as possible to produce the problem
  • Complete – Provide all parts someone else needs to reproduce the problem
  • Reproducible – Test the code you're about to provide to make sure it reproduces the problem

For Ultralytics to provide assistance your code should also be:

  • Current – Verify that your code is up-to-date with GitHub master, and if necessary git pull or git clone a new copy to ensure your problem has not already been solved in master.
  • Unmodified – Your problem must be reproducible using official YOLOv5 code without changes. Ultralytics does not provide support for custom code ⚠️.

If you believe your problem meets all the above criteria, please close this issue and raise a new one using the 🐛 Bug Report template with a minimum reproducible example to help us better understand and diagnose your problem.

Thank you! 😃

@PonyPC
Copy link

PonyPC commented Mar 20, 2022

@glenn-jocher I confirmed he met same problem like me.

@glenn-jocher
Copy link
Member

@PonyPC @jayer95 for us to start looking into this we require a reproducible example that fully replicates the issue on a common dataset (i.e. COOC128, VOC, etc.) using a common model.

@jayer95
Copy link
Author

jayer95 commented Mar 20, 2022

@glenn-jocher
No problem, I'll go prepare a reproducible example.

@glenn-jocher
Copy link
Member

@jayer95 @PonyPC good news 😃! Your original issue may now be fixed ✅ in PR #7060.

I investigated AutoAnchor behavior when started with --weights and when starting from scratch with --weights '' --cfg yolov5s.yaml and observed that in the second cases check_anchor_order() was running with grid-space anchors (pixel-space divided by stride) rather than pixel-space anchors. This is a silent-error bug (this is my fault) that may have caused some trainings from scratch to accidentally reverse their anchor order, resulting in lower recall and lower mAP. This should all be resolved now in #7060.

To receive this update:

  • Gitgit pull from within your yolov5/ directory or git clone https://github.com/ultralytics/yolov5 again
  • PyTorch Hub – Force-reload model = torch.hub.load('ultralytics/yolov5', 'yolov5s', force_reload=True)
  • Notebooks – View updated notebooks Open In Colab Open In Kaggle
  • Dockersudo docker pull ultralytics/yolov5:latest to update your image Docker Pulls

Thank you for spotting this issue and informing us of the problem. Please let us know if this update resolves the issue for you, and feel free to inform us of any other issues you discover or feature requests that come to mind. Happy trainings with YOLOv5 🚀!

@jayer95
Copy link
Author

jayer95 commented Mar 22, 2022

@glenn-jocher
Hi,
the problem has been solved when I "git pull".

@glenn-jocher
Copy link
Member

@jayer95 awesome! Thanks for the your feedback.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working question Further information is requested
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants