ultralytics / yolov5

YOLOv5 🚀 in PyTorch > ONNX > CoreML > TFLite
https://docs.ultralytics.com
GNU Affero General Public License v3.0
50.74k stars 16.34k forks source link

About not being able to customize the anchors #7015

Closed jayer95 closed 2 years ago

jayer95 commented 2 years ago

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:

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,

I go to yolov5/models/yolov5n.yaml,

anchors:

replace with

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:

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

glenn-jocher commented 2 years ago

@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: https://github.com/ultralytics/yolov5/blob/f17c86b7f0d2038288d7292cb82dec2433cc91e5/models/yolo.py#L45

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 commented 2 years ago

@jayer95 if you really want to force autoanchor you can lower the threshold here: https://github.com/ultralytics/yolov5/blob/3f634d43c8ecea14aa9037e2fd28ded0433d491d/utils/autoanchor.py#L46

jayer95 commented 2 years ago

@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 commented 2 years ago

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 commented 2 years ago

@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:

For Ultralytics to provide assistance your code should also be:

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 commented 2 years ago

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

glenn-jocher commented 2 years ago

@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 commented 2 years ago

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

glenn-jocher commented 2 years ago

@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:

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 commented 2 years ago

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

glenn-jocher commented 2 years ago

@jayer95 awesome! Thanks for the your feedback.