Showing
60 changed files
with
3225 additions
and
0 deletions
YOLOv5/.dockerignore
0 → 100644
1 | +# Repo-specific DockerIgnore ------------------------------------------------------------------------------------------- | ||
2 | +#.git | ||
3 | +.cache | ||
4 | +.idea | ||
5 | +runs | ||
6 | +output | ||
7 | +coco | ||
8 | +storage.googleapis.com | ||
9 | + | ||
10 | +data/samples/* | ||
11 | +**/results*.txt | ||
12 | +*.jpg | ||
13 | + | ||
14 | +# Neural Network weights ----------------------------------------------------------------------------------------------- | ||
15 | +**/*.weights | ||
16 | +**/*.pt | ||
17 | +**/*.pth | ||
18 | +**/*.onnx | ||
19 | +**/*.mlmodel | ||
20 | +**/*.torchscript | ||
21 | + | ||
22 | + | ||
23 | +# Below Copied From .gitignore ----------------------------------------------------------------------------------------- | ||
24 | +# Below Copied From .gitignore ----------------------------------------------------------------------------------------- | ||
25 | + | ||
26 | + | ||
27 | +# GitHub Python GitIgnore ---------------------------------------------------------------------------------------------- | ||
28 | +# Byte-compiled / optimized / DLL files | ||
29 | +__pycache__/ | ||
30 | +*.py[cod] | ||
31 | +*$py.class | ||
32 | + | ||
33 | +# C extensions | ||
34 | +*.so | ||
35 | + | ||
36 | +# Distribution / packaging | ||
37 | +.Python | ||
38 | +env/ | ||
39 | +build/ | ||
40 | +develop-eggs/ | ||
41 | +dist/ | ||
42 | +downloads/ | ||
43 | +eggs/ | ||
44 | +.eggs/ | ||
45 | +lib/ | ||
46 | +lib64/ | ||
47 | +parts/ | ||
48 | +sdist/ | ||
49 | +var/ | ||
50 | +wheels/ | ||
51 | +*.egg-info/ | ||
52 | +wandb/ | ||
53 | +.installed.cfg | ||
54 | +*.egg | ||
55 | + | ||
56 | +# PyInstaller | ||
57 | +# Usually these files are written by a python script from a template | ||
58 | +# before PyInstaller builds the exe, so as to inject date/other infos into it. | ||
59 | +*.manifest | ||
60 | +*.spec | ||
61 | + | ||
62 | +# Installer logs | ||
63 | +pip-log.txt | ||
64 | +pip-delete-this-directory.txt | ||
65 | + | ||
66 | +# Unit test / coverage reports | ||
67 | +htmlcov/ | ||
68 | +.tox/ | ||
69 | +.coverage | ||
70 | +.coverage.* | ||
71 | +.cache | ||
72 | +nosetests.xml | ||
73 | +coverage.xml | ||
74 | +*.cover | ||
75 | +.hypothesis/ | ||
76 | + | ||
77 | +# Translations | ||
78 | +*.mo | ||
79 | +*.pot | ||
80 | + | ||
81 | +# Django stuff: | ||
82 | +*.log | ||
83 | +local_settings.py | ||
84 | + | ||
85 | +# Flask stuff: | ||
86 | +instance/ | ||
87 | +.webassets-cache | ||
88 | + | ||
89 | +# Scrapy stuff: | ||
90 | +.scrapy | ||
91 | + | ||
92 | +# Sphinx documentation | ||
93 | +docs/_build/ | ||
94 | + | ||
95 | +# PyBuilder | ||
96 | +target/ | ||
97 | + | ||
98 | +# Jupyter Notebook | ||
99 | +.ipynb_checkpoints | ||
100 | + | ||
101 | +# pyenv | ||
102 | +.python-version | ||
103 | + | ||
104 | +# celery beat schedule file | ||
105 | +celerybeat-schedule | ||
106 | + | ||
107 | +# SageMath parsed files | ||
108 | +*.sage.py | ||
109 | + | ||
110 | +# dotenv | ||
111 | +.env | ||
112 | + | ||
113 | +# virtualenv | ||
114 | +.venv* | ||
115 | +venv*/ | ||
116 | +ENV*/ | ||
117 | + | ||
118 | +# Spyder project settings | ||
119 | +.spyderproject | ||
120 | +.spyproject | ||
121 | + | ||
122 | +# Rope project settings | ||
123 | +.ropeproject | ||
124 | + | ||
125 | +# mkdocs documentation | ||
126 | +/site | ||
127 | + | ||
128 | +# mypy | ||
129 | +.mypy_cache/ | ||
130 | + | ||
131 | + | ||
132 | +# https://github.com/github/gitignore/blob/master/Global/macOS.gitignore ----------------------------------------------- | ||
133 | + | ||
134 | +# General | ||
135 | +.DS_Store | ||
136 | +.AppleDouble | ||
137 | +.LSOverride | ||
138 | + | ||
139 | +# Icon must end with two \r | ||
140 | +Icon | ||
141 | +Icon? | ||
142 | + | ||
143 | +# Thumbnails | ||
144 | +._* | ||
145 | + | ||
146 | +# Files that might appear in the root of a volume | ||
147 | +.DocumentRevisions-V100 | ||
148 | +.fseventsd | ||
149 | +.Spotlight-V100 | ||
150 | +.TemporaryItems | ||
151 | +.Trashes | ||
152 | +.VolumeIcon.icns | ||
153 | +.com.apple.timemachine.donotpresent | ||
154 | + | ||
155 | +# Directories potentially created on remote AFP share | ||
156 | +.AppleDB | ||
157 | +.AppleDesktop | ||
158 | +Network Trash Folder | ||
159 | +Temporary Items | ||
160 | +.apdisk | ||
161 | + | ||
162 | + | ||
163 | +# https://github.com/github/gitignore/blob/master/Global/JetBrains.gitignore | ||
164 | +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm | ||
165 | +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 | ||
166 | + | ||
167 | +# User-specific stuff: | ||
168 | +.idea/* | ||
169 | +.idea/**/workspace.xml | ||
170 | +.idea/**/tasks.xml | ||
171 | +.idea/dictionaries | ||
172 | +.html # Bokeh Plots | ||
173 | +.pg # TensorFlow Frozen Graphs | ||
174 | +.avi # videos | ||
175 | + | ||
176 | +# Sensitive or high-churn files: | ||
177 | +.idea/**/dataSources/ | ||
178 | +.idea/**/dataSources.ids | ||
179 | +.idea/**/dataSources.local.xml | ||
180 | +.idea/**/sqlDataSources.xml | ||
181 | +.idea/**/dynamic.xml | ||
182 | +.idea/**/uiDesigner.xml | ||
183 | + | ||
184 | +# Gradle: | ||
185 | +.idea/**/gradle.xml | ||
186 | +.idea/**/libraries | ||
187 | + | ||
188 | +# CMake | ||
189 | +cmake-build-debug/ | ||
190 | +cmake-build-release/ | ||
191 | + | ||
192 | +# Mongo Explorer plugin: | ||
193 | +.idea/**/mongoSettings.xml | ||
194 | + | ||
195 | +## File-based project format: | ||
196 | +*.iws | ||
197 | + | ||
198 | +## Plugin-specific files: | ||
199 | + | ||
200 | +# IntelliJ | ||
201 | +out/ | ||
202 | + | ||
203 | +# mpeltonen/sbt-idea plugin | ||
204 | +.idea_modules/ | ||
205 | + | ||
206 | +# JIRA plugin | ||
207 | +atlassian-ide-plugin.xml | ||
208 | + | ||
209 | +# Cursive Clojure plugin | ||
210 | +.idea/replstate.xml | ||
211 | + | ||
212 | +# Crashlytics plugin (for Android Studio and IntelliJ) | ||
213 | +com_crashlytics_export_strings.xml | ||
214 | +crashlytics.properties | ||
215 | +crashlytics-build.properties | ||
216 | +fabric.properties |
YOLOv5/.gitattributes
0 → 100644
YOLOv5/.gitignore
0 → 100644
1 | +# Repo-specific GitIgnore ---------------------------------------------------------------------------------------------- | ||
2 | +*.jpg | ||
3 | +*.jpeg | ||
4 | +*.png | ||
5 | +*.bmp | ||
6 | +*.tif | ||
7 | +*.tiff | ||
8 | +*.heic | ||
9 | +*.JPG | ||
10 | +*.JPEG | ||
11 | +*.PNG | ||
12 | +*.BMP | ||
13 | +*.TIF | ||
14 | +*.TIFF | ||
15 | +*.HEIC | ||
16 | +*.mp4 | ||
17 | +*.mov | ||
18 | +*.MOV | ||
19 | +*.avi | ||
20 | +*.data | ||
21 | +*.json | ||
22 | + | ||
23 | +*.cfg | ||
24 | +!cfg/yolov3*.cfg | ||
25 | + | ||
26 | +storage.googleapis.com | ||
27 | +runs/* | ||
28 | +data/* | ||
29 | +!data/images/zidane.jpg | ||
30 | +!data/images/bus.jpg | ||
31 | +!data/coco.names | ||
32 | +!data/coco_paper.names | ||
33 | +!data/coco.data | ||
34 | +!data/coco_*.data | ||
35 | +!data/coco_*.txt | ||
36 | +!data/trainvalno5k.shapes | ||
37 | +!data/*.sh | ||
38 | + | ||
39 | +pycocotools/* | ||
40 | +results*.txt | ||
41 | +gcp_test*.sh | ||
42 | + | ||
43 | +# Datasets ------------------------------------------------------------------------------------------------------------- | ||
44 | +coco/ | ||
45 | +coco128/ | ||
46 | +VOC/ | ||
47 | + | ||
48 | +# MATLAB GitIgnore ----------------------------------------------------------------------------------------------------- | ||
49 | +*.m~ | ||
50 | +*.mat | ||
51 | +!targets*.mat | ||
52 | + | ||
53 | +# Neural Network weights ----------------------------------------------------------------------------------------------- | ||
54 | +*.weights | ||
55 | +*.pt | ||
56 | +*.onnx | ||
57 | +*.mlmodel | ||
58 | +*.torchscript | ||
59 | +darknet53.conv.74 | ||
60 | +yolov3-tiny.conv.15 | ||
61 | + | ||
62 | +# GitHub Python GitIgnore ---------------------------------------------------------------------------------------------- | ||
63 | +# Byte-compiled / optimized / DLL files | ||
64 | +__pycache__/ | ||
65 | +*.py[cod] | ||
66 | +*$py.class | ||
67 | + | ||
68 | +# C extensions | ||
69 | +*.so | ||
70 | + | ||
71 | +# Distribution / packaging | ||
72 | +.Python | ||
73 | +env/ | ||
74 | +build/ | ||
75 | +develop-eggs/ | ||
76 | +dist/ | ||
77 | +downloads/ | ||
78 | +eggs/ | ||
79 | +.eggs/ | ||
80 | +lib/ | ||
81 | +lib64/ | ||
82 | +parts/ | ||
83 | +sdist/ | ||
84 | +var/ | ||
85 | +wheels/ | ||
86 | +*.egg-info/ | ||
87 | +wandb/ | ||
88 | +.installed.cfg | ||
89 | +*.egg | ||
90 | + | ||
91 | + | ||
92 | +# PyInstaller | ||
93 | +# Usually these files are written by a python script from a template | ||
94 | +# before PyInstaller builds the exe, so as to inject date/other infos into it. | ||
95 | +*.manifest | ||
96 | +*.spec | ||
97 | + | ||
98 | +# Installer logs | ||
99 | +pip-log.txt | ||
100 | +pip-delete-this-directory.txt | ||
101 | + | ||
102 | +# Unit test / coverage reports | ||
103 | +htmlcov/ | ||
104 | +.tox/ | ||
105 | +.coverage | ||
106 | +.coverage.* | ||
107 | +.cache | ||
108 | +nosetests.xml | ||
109 | +coverage.xml | ||
110 | +*.cover | ||
111 | +.hypothesis/ | ||
112 | + | ||
113 | +# Translations | ||
114 | +*.mo | ||
115 | +*.pot | ||
116 | + | ||
117 | +# Django stuff: | ||
118 | +*.log | ||
119 | +local_settings.py | ||
120 | + | ||
121 | +# Flask stuff: | ||
122 | +instance/ | ||
123 | +.webassets-cache | ||
124 | + | ||
125 | +# Scrapy stuff: | ||
126 | +.scrapy | ||
127 | + | ||
128 | +# Sphinx documentation | ||
129 | +docs/_build/ | ||
130 | + | ||
131 | +# PyBuilder | ||
132 | +target/ | ||
133 | + | ||
134 | +# Jupyter Notebook | ||
135 | +.ipynb_checkpoints | ||
136 | + | ||
137 | +# pyenv | ||
138 | +.python-version | ||
139 | + | ||
140 | +# celery beat schedule file | ||
141 | +celerybeat-schedule | ||
142 | + | ||
143 | +# SageMath parsed files | ||
144 | +*.sage.py | ||
145 | + | ||
146 | +# dotenv | ||
147 | +.env | ||
148 | + | ||
149 | +# virtualenv | ||
150 | +.venv* | ||
151 | +venv*/ | ||
152 | +ENV*/ | ||
153 | + | ||
154 | +# Spyder project settings | ||
155 | +.spyderproject | ||
156 | +.spyproject | ||
157 | + | ||
158 | +# Rope project settings | ||
159 | +.ropeproject | ||
160 | + | ||
161 | +# mkdocs documentation | ||
162 | +/site | ||
163 | + | ||
164 | +# mypy | ||
165 | +.mypy_cache/ | ||
166 | + | ||
167 | + | ||
168 | +# https://github.com/github/gitignore/blob/master/Global/macOS.gitignore ----------------------------------------------- | ||
169 | + | ||
170 | +# General | ||
171 | +.DS_Store | ||
172 | +.AppleDouble | ||
173 | +.LSOverride | ||
174 | + | ||
175 | +# Icon must end with two \r | ||
176 | +Icon | ||
177 | +Icon? | ||
178 | + | ||
179 | +# Thumbnails | ||
180 | +._* | ||
181 | + | ||
182 | +# Files that might appear in the root of a volume | ||
183 | +.DocumentRevisions-V100 | ||
184 | +.fseventsd | ||
185 | +.Spotlight-V100 | ||
186 | +.TemporaryItems | ||
187 | +.Trashes | ||
188 | +.VolumeIcon.icns | ||
189 | +.com.apple.timemachine.donotpresent | ||
190 | + | ||
191 | +# Directories potentially created on remote AFP share | ||
192 | +.AppleDB | ||
193 | +.AppleDesktop | ||
194 | +Network Trash Folder | ||
195 | +Temporary Items | ||
196 | +.apdisk | ||
197 | + | ||
198 | + | ||
199 | +# https://github.com/github/gitignore/blob/master/Global/JetBrains.gitignore | ||
200 | +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm | ||
201 | +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 | ||
202 | + | ||
203 | +# User-specific stuff: | ||
204 | +.idea/* | ||
205 | +.idea/**/workspace.xml | ||
206 | +.idea/**/tasks.xml | ||
207 | +.idea/dictionaries | ||
208 | +.html # Bokeh Plots | ||
209 | +.pg # TensorFlow Frozen Graphs | ||
210 | +.avi # videos | ||
211 | + | ||
212 | +# Sensitive or high-churn files: | ||
213 | +.idea/**/dataSources/ | ||
214 | +.idea/**/dataSources.ids | ||
215 | +.idea/**/dataSources.local.xml | ||
216 | +.idea/**/sqlDataSources.xml | ||
217 | +.idea/**/dynamic.xml | ||
218 | +.idea/**/uiDesigner.xml | ||
219 | + | ||
220 | +# Gradle: | ||
221 | +.idea/**/gradle.xml | ||
222 | +.idea/**/libraries | ||
223 | + | ||
224 | +# CMake | ||
225 | +cmake-build-debug/ | ||
226 | +cmake-build-release/ | ||
227 | + | ||
228 | +# Mongo Explorer plugin: | ||
229 | +.idea/**/mongoSettings.xml | ||
230 | + | ||
231 | +## File-based project format: | ||
232 | +*.iws | ||
233 | + | ||
234 | +## Plugin-specific files: | ||
235 | + | ||
236 | +# IntelliJ | ||
237 | +out/ | ||
238 | + | ||
239 | +# mpeltonen/sbt-idea plugin | ||
240 | +.idea_modules/ | ||
241 | + | ||
242 | +# JIRA plugin | ||
243 | +atlassian-ide-plugin.xml | ||
244 | + | ||
245 | +# Cursive Clojure plugin | ||
246 | +.idea/replstate.xml | ||
247 | + | ||
248 | +# Crashlytics plugin (for Android Studio and IntelliJ) | ||
249 | +com_crashlytics_export_strings.xml | ||
250 | +crashlytics.properties | ||
251 | +crashlytics-build.properties | ||
252 | +fabric.properties |
YOLOv5/Dockerfile
0 → 100644
1 | +# Start FROM Nvidia PyTorch image https://ngc.nvidia.com/catalog/containers/nvidia:pytorch | ||
2 | +FROM nvcr.io/nvidia/pytorch:21.03-py3 | ||
3 | + | ||
4 | +# Install linux packages | ||
5 | +RUN apt update && apt install -y zip htop screen libgl1-mesa-glx | ||
6 | + | ||
7 | +# Install python dependencies | ||
8 | +COPY requirements.txt . | ||
9 | +RUN python -m pip install --upgrade pip | ||
10 | +RUN pip uninstall -y nvidia-tensorboard nvidia-tensorboard-plugin-dlprof | ||
11 | +RUN pip install --no-cache -r requirements.txt coremltools onnx gsutil notebook | ||
12 | + | ||
13 | +# Create working directory | ||
14 | +RUN mkdir -p /usr/src/app | ||
15 | +WORKDIR /usr/src/app | ||
16 | + | ||
17 | +# Copy contents | ||
18 | +COPY . /usr/src/app | ||
19 | + | ||
20 | +# Set environment variables | ||
21 | +ENV HOME=/usr/src/app | ||
22 | + | ||
23 | + | ||
24 | +# --------------------------------------------------- Extras Below --------------------------------------------------- | ||
25 | + | ||
26 | +# Build and Push | ||
27 | +# t=ultralytics/yolov5:latest && sudo docker build -t $t . && sudo docker push $t | ||
28 | +# for v in {300..303}; do t=ultralytics/coco:v$v && sudo docker build -t $t . && sudo docker push $t; done | ||
29 | + | ||
30 | +# Pull and Run | ||
31 | +# t=ultralytics/yolov5:latest && sudo docker pull $t && sudo docker run -it --ipc=host --gpus all $t | ||
32 | + | ||
33 | +# Pull and Run with local directory access | ||
34 | +# t=ultralytics/yolov5:latest && sudo docker pull $t && sudo docker run -it --ipc=host --gpus all -v "$(pwd)"/coco:/usr/src/coco $t | ||
35 | + | ||
36 | +# Kill all | ||
37 | +# sudo docker kill $(sudo docker ps -q) | ||
38 | + | ||
39 | +# Kill all image-based | ||
40 | +# sudo docker kill $(sudo docker ps -qa --filter ancestor=ultralytics/yolov5:latest) | ||
41 | + | ||
42 | +# Bash into running container | ||
43 | +# sudo docker exec -it 5a9b5863d93d bash | ||
44 | + | ||
45 | +# Bash into stopped container | ||
46 | +# id=$(sudo docker ps -qa) && sudo docker start $id && sudo docker exec -it $id bash | ||
47 | + | ||
48 | +# Send weights to GCP | ||
49 | +# python -c "from utils.general import *; strip_optimizer('runs/train/exp0_*/weights/best.pt', 'tmp.pt')" && gsutil cp tmp.pt gs://*.pt | ||
50 | + | ||
51 | +# Clean up | ||
52 | +# docker system prune -a --volumes |
YOLOv5/LICENSE
0 → 100644
This diff is collapsed. Click to expand it.
YOLOv5/README.md
0 → 100644
This diff is collapsed. Click to expand it.
YOLOv5/__init__.py
0 → 100644
File mode changed
YOLOv5/detect.py
0 → 100644
1 | +import argparse | ||
2 | +import time | ||
3 | +from pathlib import Path | ||
4 | + | ||
5 | +import cv2 | ||
6 | +import torch | ||
7 | +import torch.backends.cudnn as cudnn | ||
8 | + | ||
9 | +from models.experimental import attempt_load | ||
10 | +from utils.datasets import LoadStreams, LoadImages | ||
11 | +from utils.general import check_img_size, check_requirements, check_imshow, non_max_suppression, apply_classifier, \ | ||
12 | + scale_coords, xyxy2xywh, strip_optimizer, set_logging, increment_path, save_one_box | ||
13 | +from utils.plots import colors, plot_one_box | ||
14 | +from utils.torch_utils import select_device, load_classifier, time_synchronized | ||
15 | + | ||
16 | + | ||
17 | +@torch.no_grad() | ||
18 | +def detect(opt): | ||
19 | + # source, weights, view_img, save_txt, imgsz = opt.source, opt.weights, opt.view_img, opt.save_txt, opt.img_size | ||
20 | + source, weights, view_img, save_txt, imgsz = opt.source, opt.weights, opt.view_img, True, opt.img_size | ||
21 | + save_img = not opt.nosave and not source.endswith('.txt') # save inference images | ||
22 | + webcam = source.isnumeric() or source.endswith('.txt') or source.lower().startswith( | ||
23 | + ('rtsp://', 'rtmp://', 'http://', 'https://')) | ||
24 | + | ||
25 | + # Directories | ||
26 | + save_dir = increment_path(Path(opt.project) / opt.name, exist_ok=opt.exist_ok) # increment run | ||
27 | + (save_dir / 'labels' if save_txt else save_dir).mkdir(parents=True, exist_ok=True) # make dir | ||
28 | + | ||
29 | + # Initialize | ||
30 | + set_logging() | ||
31 | + device = select_device(opt.device) | ||
32 | + half = device.type != 'cpu' # half precision only supported on CUDA | ||
33 | + | ||
34 | + # Load model | ||
35 | + model = attempt_load(weights, map_location=device) # load FP32 model | ||
36 | + stride = int(model.stride.max()) # model stride | ||
37 | + imgsz = check_img_size(imgsz, s=stride) # check img_size | ||
38 | + names = model.module.names if hasattr(model, 'module') else model.names # get class names | ||
39 | + if half: | ||
40 | + model.half() # to FP16 | ||
41 | + | ||
42 | + # Second-stage classifier | ||
43 | + classify = False | ||
44 | + if classify: | ||
45 | + modelc = load_classifier(name='resnet101', n=2) # initialize | ||
46 | + modelc.load_state_dict(torch.load('weights/resnet101.pt', map_location=device)['model']).to(device).eval() | ||
47 | + | ||
48 | + # Set Dataloader | ||
49 | + vid_path, vid_writer = None, None | ||
50 | + if webcam: | ||
51 | + view_img = check_imshow() | ||
52 | + cudnn.benchmark = True # set True to speed up constant image size inference | ||
53 | + dataset = LoadStreams(source, img_size=imgsz, stride=stride) | ||
54 | + else: | ||
55 | + dataset = LoadImages(source, img_size=imgsz, stride=stride) | ||
56 | + | ||
57 | + # Run inference | ||
58 | + if device.type != 'cpu': | ||
59 | + model(torch.zeros(1, 3, imgsz, imgsz).to(device).type_as(next(model.parameters()))) # run once | ||
60 | + t0 = time.time() | ||
61 | + for path, img, im0s, vid_cap in dataset: | ||
62 | + img = torch.from_numpy(img).to(device) | ||
63 | + img = img.half() if half else img.float() # uint8 to fp16/32 | ||
64 | + img /= 255.0 # 0 - 255 to 0.0 - 1.0 | ||
65 | + if img.ndimension() == 3: | ||
66 | + img = img.unsqueeze(0) | ||
67 | + | ||
68 | + # Inference | ||
69 | + t1 = time_synchronized() | ||
70 | + pred = model(img, augment=opt.augment)[0] | ||
71 | + | ||
72 | + # Apply NMS | ||
73 | + pred = non_max_suppression(pred, opt.conf_thres, opt.iou_thres, opt.classes, opt.agnostic_nms, | ||
74 | + max_det=opt.max_det) | ||
75 | + t2 = time_synchronized() | ||
76 | + | ||
77 | + # Apply Classifier | ||
78 | + if classify: | ||
79 | + pred = apply_classifier(pred, modelc, img, im0s) | ||
80 | + | ||
81 | + # Process detections | ||
82 | + for i, det in enumerate(pred): # detections per image | ||
83 | + if webcam: # batch_size >= 1 | ||
84 | + p, s, im0, frame = path[i], f'{i}: ', im0s[i].copy(), dataset.count | ||
85 | + else: | ||
86 | + p, s, im0, frame = path, '', im0s.copy(), getattr(dataset, 'frame', 0) | ||
87 | + | ||
88 | + p = Path(p) # to Path | ||
89 | + save_path = str(save_dir / p.name) # img.jpg | ||
90 | + txt_path = str(save_dir / 'labels' / p.stem) + ('' if dataset.mode == 'image' else f'_{frame}') # img.txt | ||
91 | + s += '%gx%g ' % img.shape[2:] # print string | ||
92 | + gn = torch.tensor(im0.shape)[[1, 0, 1, 0]] # normalization gain whwh | ||
93 | + imc = im0.copy() if opt.save_crop else im0 # for opt.save_crop | ||
94 | + if len(det): | ||
95 | + # Rescale boxes from img_size to im0 size | ||
96 | + det[:, :4] = scale_coords(img.shape[2:], det[:, :4], im0.shape).round() | ||
97 | + | ||
98 | + # Print results | ||
99 | + for c in det[:, -1].unique(): | ||
100 | + n = (det[:, -1] == c).sum() # detections per class | ||
101 | + s += f"{n} {names[int(c)]}{'s' * (n > 1)}, " # add to string | ||
102 | + | ||
103 | + # Write results | ||
104 | + for *xyxy, conf, cls in reversed(det): | ||
105 | + if save_txt: # Write to file | ||
106 | + | ||
107 | + # print("+++++++++++++++++++++++++++++++++") | ||
108 | + # print(torch.tensor(xyxy)) | ||
109 | + # print("+++++++++++++++++++++++++++++++++") | ||
110 | + | ||
111 | + xywh = (xyxy2xywh(torch.tensor(xyxy).view(1, 4)) / gn).view(-1).tolist() # normalized xywh | ||
112 | + | ||
113 | + # print("+++++++++++++++++++++++++++++++++") | ||
114 | + # print(xywh) | ||
115 | + # print("+++++++++++++++++++++++++++++++++") | ||
116 | + | ||
117 | + line = (cls, *xywh, conf) if opt.save_conf else (cls, *xywh) # label format | ||
118 | + with open(txt_path + '.txt', 'a') as f: | ||
119 | + f.write(('%g ' * len(line)).rstrip() % line + '\n') | ||
120 | + | ||
121 | + if save_img or opt.save_crop or view_img: # Add bbox to image | ||
122 | + c = int(cls) # integer class | ||
123 | + label = None if opt.hide_labels else (names[c] if opt.hide_conf else f'{names[c]} {conf:.2f}') | ||
124 | + plot_one_box(xyxy, im0, label=label, color=colors(c, True), line_thickness=opt.line_thickness) | ||
125 | + # if opt.save_crop: | ||
126 | + save_one_box(xyxy, imc, file=save_dir / 'crops' / names[c] / f'{p.stem}.jpg', BGR=True) | ||
127 | + | ||
128 | + # Print time (inference + NMS) | ||
129 | + print(f'{s}Done. ({t2 - t1:.3f}s)') | ||
130 | + | ||
131 | + # Stream results | ||
132 | + if view_img: | ||
133 | + cv2.imshow(str(p), im0) | ||
134 | + cv2.waitKey(1) # 1 millisecond | ||
135 | + | ||
136 | + # Save results (image with detections) | ||
137 | + if save_img: | ||
138 | + if dataset.mode == 'image': | ||
139 | + cv2.imwrite(save_path, im0) | ||
140 | + else: # 'video' or 'stream' | ||
141 | + if vid_path != save_path: # new video | ||
142 | + vid_path = save_path | ||
143 | + if isinstance(vid_writer, cv2.VideoWriter): | ||
144 | + vid_writer.release() # release previous video writer | ||
145 | + if vid_cap: # video | ||
146 | + fps = vid_cap.get(cv2.CAP_PROP_FPS) | ||
147 | + w = int(vid_cap.get(cv2.CAP_PROP_FRAME_WIDTH)) | ||
148 | + h = int(vid_cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) | ||
149 | + else: # stream | ||
150 | + fps, w, h = 30, im0.shape[1], im0.shape[0] | ||
151 | + save_path += '.mp4' | ||
152 | + vid_writer = cv2.VideoWriter(save_path, cv2.VideoWriter_fourcc(*'mp4v'), fps, (w, h)) | ||
153 | + vid_writer.write(im0) | ||
154 | + | ||
155 | + if save_txt or save_img: | ||
156 | + s = f"\n{len(list(save_dir.glob('labels/*.txt')))} labels saved to {save_dir / 'labels'}" if save_txt else '' | ||
157 | + print(f"Results saved to {save_dir}{s}") | ||
158 | + | ||
159 | + print(f'Done. ({time.time() - t0:.3f}s)') | ||
160 | + | ||
161 | + | ||
162 | +if __name__ == '__main__': | ||
163 | + parser = argparse.ArgumentParser() | ||
164 | + parser.add_argument('--weights', nargs='+', type=str, default='yolov5s.pt', help='model.pt path(s)') | ||
165 | + parser.add_argument('--source', type=str, default='data/images', help='source') # file/folder, 0 for webcam | ||
166 | + parser.add_argument('--img-size', type=int, default=640, help='inference size (pixels)') | ||
167 | + parser.add_argument('--conf-thres', type=float, default=0.25, help='object confidence threshold') | ||
168 | + parser.add_argument('--iou-thres', type=float, default=0.45, help='IOU threshold for NMS') | ||
169 | + parser.add_argument('--max-det', type=int, default=1000, help='maximum number of detections per image') | ||
170 | + parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu') | ||
171 | + parser.add_argument('--view-img', action='store_true', help='display results') | ||
172 | + parser.add_argument('--save-txt', action='store_true', help='save results to *.txt') | ||
173 | + parser.add_argument('--save-conf', action='store_true', help='save confidences in --save-txt labels') | ||
174 | + parser.add_argument('--save-crop', action='store_true', help='save cropped prediction boxes') | ||
175 | + parser.add_argument('--nosave', action='store_true', help='do not save images/videos') | ||
176 | + parser.add_argument('--classes', nargs='+', type=int, help='filter by class: --class 0, or --class 0 2 3') | ||
177 | + parser.add_argument('--agnostic-nms', action='store_true', help='class-agnostic NMS') | ||
178 | + parser.add_argument('--augment', action='store_true', help='augmented inference') | ||
179 | + parser.add_argument('--update', action='store_true', help='update all models') | ||
180 | + parser.add_argument('--project', default='runs/detect', help='save results to project/name') | ||
181 | + parser.add_argument('--name', default='exp', help='save results to project/name') | ||
182 | + parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment') | ||
183 | + parser.add_argument('--line-thickness', default=3, type=int, help='bounding box thickness (pixels)') | ||
184 | + parser.add_argument('--hide-labels', default=False, action='store_true', help='hide labels') | ||
185 | + parser.add_argument('--hide-conf', default=False, action='store_true', help='hide confidences') | ||
186 | + opt = parser.parse_args() | ||
187 | + print(opt) | ||
188 | + check_requirements(exclude=('tensorboard', 'pycocotools', 'thop')) | ||
189 | + | ||
190 | + if opt.update: # update all models (to fix SourceChangeWarning) | ||
191 | + for opt.weights in ['yolov5s.pt', 'yolov5m.pt', 'yolov5l.pt', 'yolov5x.pt']: | ||
192 | + detect(opt=opt) | ||
193 | + strip_optimizer(opt.weights) | ||
194 | + else: | ||
195 | + detect(opt=opt) |
YOLOv5/hubconf.py
0 → 100644
1 | +"""YOLOv5 PyTorch Hub models https://pytorch.org/hub/ultralytics_yolov5/ | ||
2 | + | ||
3 | +Usage: | ||
4 | + import torch | ||
5 | + model = torch.hub.load('ultralytics/yolov5', 'yolov5s') | ||
6 | +""" | ||
7 | + | ||
8 | +import torch | ||
9 | + | ||
10 | + | ||
11 | +def _create(name, pretrained=True, channels=3, classes=80, autoshape=True, verbose=True, device=None): | ||
12 | + """Creates a specified YOLOv5 model | ||
13 | + | ||
14 | + Arguments: | ||
15 | + name (str): name of model, i.e. 'yolov5s' | ||
16 | + pretrained (bool): load pretrained weights into the model | ||
17 | + channels (int): number of input channels | ||
18 | + classes (int): number of model classes | ||
19 | + autoshape (bool): apply YOLOv5 .autoshape() wrapper to model | ||
20 | + verbose (bool): print all information to screen | ||
21 | + device (str, torch.device, None): device to use for model parameters | ||
22 | + | ||
23 | + Returns: | ||
24 | + YOLOv5 pytorch model | ||
25 | + """ | ||
26 | + from pathlib import Path | ||
27 | + | ||
28 | + from models.yolo import Model, attempt_load | ||
29 | + from utils.general import check_requirements, set_logging | ||
30 | + from utils.google_utils import attempt_download | ||
31 | + from utils.torch_utils import select_device | ||
32 | + | ||
33 | + check_requirements(Path(__file__).parent / 'requirements.txt', exclude=('tensorboard', 'pycocotools', 'thop')) | ||
34 | + set_logging(verbose=verbose) | ||
35 | + | ||
36 | + fname = Path(name).with_suffix('.pt') # checkpoint filename | ||
37 | + try: | ||
38 | + if pretrained and channels == 3 and classes == 80: | ||
39 | + model = attempt_load(fname, map_location=torch.device('cpu')) # download/load FP32 model | ||
40 | + else: | ||
41 | + cfg = list((Path(__file__).parent / 'models').rglob(f'{name}.yaml'))[0] # model.yaml path | ||
42 | + model = Model(cfg, channels, classes) # create model | ||
43 | + if pretrained: | ||
44 | + ckpt = torch.load(attempt_download(fname), map_location=torch.device('cpu')) # load | ||
45 | + msd = model.state_dict() # model state_dict | ||
46 | + csd = ckpt['model'].float().state_dict() # checkpoint state_dict as FP32 | ||
47 | + csd = {k: v for k, v in csd.items() if msd[k].shape == v.shape} # filter | ||
48 | + model.load_state_dict(csd, strict=False) # load | ||
49 | + if len(ckpt['model'].names) == classes: | ||
50 | + model.names = ckpt['model'].names # set class names attribute | ||
51 | + if autoshape: | ||
52 | + model = model.autoshape() # for file/URI/PIL/cv2/np inputs and NMS | ||
53 | + device = select_device('0' if torch.cuda.is_available() else 'cpu') if device is None else torch.device(device) | ||
54 | + return model.to(device) | ||
55 | + | ||
56 | + except Exception as e: | ||
57 | + help_url = 'https://github.com/ultralytics/yolov5/issues/36' | ||
58 | + s = 'Cache may be out of date, try `force_reload=True`. See %s for help.' % help_url | ||
59 | + raise Exception(s) from e | ||
60 | + | ||
61 | + | ||
62 | +def custom(path='path/to/model.pt', autoshape=True, verbose=True, device=None): | ||
63 | + # YOLOv5 custom or local model | ||
64 | + return _create(path, autoshape=autoshape, verbose=verbose, device=device) | ||
65 | + | ||
66 | + | ||
67 | +def yolov5s(pretrained=True, channels=3, classes=80, autoshape=True, verbose=True, device=None): | ||
68 | + # YOLOv5-small model https://github.com/ultralytics/yolov5 | ||
69 | + return _create('yolov5s', pretrained, channels, classes, autoshape, verbose, device) | ||
70 | + | ||
71 | + | ||
72 | +def yolov5m(pretrained=True, channels=3, classes=80, autoshape=True, verbose=True, device=None): | ||
73 | + # YOLOv5-medium model https://github.com/ultralytics/yolov5 | ||
74 | + return _create('yolov5m', pretrained, channels, classes, autoshape, verbose, device) | ||
75 | + | ||
76 | + | ||
77 | +def yolov5l(pretrained=True, channels=3, classes=80, autoshape=True, verbose=True, device=None): | ||
78 | + # YOLOv5-large model https://github.com/ultralytics/yolov5 | ||
79 | + return _create('yolov5l', pretrained, channels, classes, autoshape, verbose, device) | ||
80 | + | ||
81 | + | ||
82 | +def yolov5x(pretrained=True, channels=3, classes=80, autoshape=True, verbose=True, device=None): | ||
83 | + # YOLOv5-xlarge model https://github.com/ultralytics/yolov5 | ||
84 | + return _create('yolov5x', pretrained, channels, classes, autoshape, verbose, device) | ||
85 | + | ||
86 | + | ||
87 | +def yolov5s6(pretrained=True, channels=3, classes=80, autoshape=True, verbose=True, device=None): | ||
88 | + # YOLOv5-small-P6 model https://github.com/ultralytics/yolov5 | ||
89 | + return _create('yolov5s6', pretrained, channels, classes, autoshape, verbose, device) | ||
90 | + | ||
91 | + | ||
92 | +def yolov5m6(pretrained=True, channels=3, classes=80, autoshape=True, verbose=True, device=None): | ||
93 | + # YOLOv5-medium-P6 model https://github.com/ultralytics/yolov5 | ||
94 | + return _create('yolov5m6', pretrained, channels, classes, autoshape, verbose, device) | ||
95 | + | ||
96 | + | ||
97 | +def yolov5l6(pretrained=True, channels=3, classes=80, autoshape=True, verbose=True, device=None): | ||
98 | + # YOLOv5-large-P6 model https://github.com/ultralytics/yolov5 | ||
99 | + return _create('yolov5l6', pretrained, channels, classes, autoshape, verbose, device) | ||
100 | + | ||
101 | + | ||
102 | +def yolov5x6(pretrained=True, channels=3, classes=80, autoshape=True, verbose=True, device=None): | ||
103 | + # YOLOv5-xlarge-P6 model https://github.com/ultralytics/yolov5 | ||
104 | + return _create('yolov5x6', pretrained, channels, classes, autoshape, verbose, device) | ||
105 | + | ||
106 | + | ||
107 | +if __name__ == '__main__': | ||
108 | + model = _create(name='yolov5s', pretrained=True, channels=3, classes=80, autoshape=True, verbose=True) # pretrained | ||
109 | + # model = custom(path='path/to/model.pt') # custom | ||
110 | + | ||
111 | + # Verify inference | ||
112 | + import cv2 | ||
113 | + import numpy as np | ||
114 | + from PIL import Image | ||
115 | + | ||
116 | + imgs = ['data/images/zidane.jpg', # filename | ||
117 | + 'https://github.com/ultralytics/yolov5/releases/download/v1.0/zidane.jpg', # URI | ||
118 | + cv2.imread('data/images/bus.jpg')[:, :, ::-1], # OpenCV | ||
119 | + Image.open('data/images/bus.jpg'), # PIL | ||
120 | + np.zeros((320, 640, 3))] # numpy | ||
121 | + | ||
122 | + results = model(imgs) # batched inference | ||
123 | + results.print() | ||
124 | + results.save() |
YOLOv5/models/__init__.py
0 → 100644
File mode changed
YOLOv5/models/common.py
0 → 100644
This diff is collapsed. Click to expand it.
YOLOv5/models/experimental.py
0 → 100644
1 | +# YOLOv5 experimental modules | ||
2 | + | ||
3 | +import numpy as np | ||
4 | +import torch | ||
5 | +import torch.nn as nn | ||
6 | + | ||
7 | +from models.common import Conv, DWConv | ||
8 | +from utils.google_utils import attempt_download | ||
9 | + | ||
10 | + | ||
11 | +class CrossConv(nn.Module): | ||
12 | + # Cross Convolution Downsample | ||
13 | + def __init__(self, c1, c2, k=3, s=1, g=1, e=1.0, shortcut=False): | ||
14 | + # ch_in, ch_out, kernel, stride, groups, expansion, shortcut | ||
15 | + super(CrossConv, self).__init__() | ||
16 | + c_ = int(c2 * e) # hidden channels | ||
17 | + self.cv1 = Conv(c1, c_, (1, k), (1, s)) | ||
18 | + self.cv2 = Conv(c_, c2, (k, 1), (s, 1), g=g) | ||
19 | + self.add = shortcut and c1 == c2 | ||
20 | + | ||
21 | + def forward(self, x): | ||
22 | + return x + self.cv2(self.cv1(x)) if self.add else self.cv2(self.cv1(x)) | ||
23 | + | ||
24 | + | ||
25 | +class Sum(nn.Module): | ||
26 | + # Weighted sum of 2 or more layers https://arxiv.org/abs/1911.09070 | ||
27 | + def __init__(self, n, weight=False): # n: number of inputs | ||
28 | + super(Sum, self).__init__() | ||
29 | + self.weight = weight # apply weights boolean | ||
30 | + self.iter = range(n - 1) # iter object | ||
31 | + if weight: | ||
32 | + self.w = nn.Parameter(-torch.arange(1., n) / 2, requires_grad=True) # layer weights | ||
33 | + | ||
34 | + def forward(self, x): | ||
35 | + y = x[0] # no weight | ||
36 | + if self.weight: | ||
37 | + w = torch.sigmoid(self.w) * 2 | ||
38 | + for i in self.iter: | ||
39 | + y = y + x[i + 1] * w[i] | ||
40 | + else: | ||
41 | + for i in self.iter: | ||
42 | + y = y + x[i + 1] | ||
43 | + return y | ||
44 | + | ||
45 | + | ||
46 | +class GhostConv(nn.Module): | ||
47 | + # Ghost Convolution https://github.com/huawei-noah/ghostnet | ||
48 | + def __init__(self, c1, c2, k=1, s=1, g=1, act=True): # ch_in, ch_out, kernel, stride, groups | ||
49 | + super(GhostConv, self).__init__() | ||
50 | + c_ = c2 // 2 # hidden channels | ||
51 | + self.cv1 = Conv(c1, c_, k, s, None, g, act) | ||
52 | + self.cv2 = Conv(c_, c_, 5, 1, None, c_, act) | ||
53 | + | ||
54 | + def forward(self, x): | ||
55 | + y = self.cv1(x) | ||
56 | + return torch.cat([y, self.cv2(y)], 1) | ||
57 | + | ||
58 | + | ||
59 | +class GhostBottleneck(nn.Module): | ||
60 | + # Ghost Bottleneck https://github.com/huawei-noah/ghostnet | ||
61 | + def __init__(self, c1, c2, k=3, s=1): # ch_in, ch_out, kernel, stride | ||
62 | + super(GhostBottleneck, self).__init__() | ||
63 | + c_ = c2 // 2 | ||
64 | + self.conv = nn.Sequential(GhostConv(c1, c_, 1, 1), # pw | ||
65 | + DWConv(c_, c_, k, s, act=False) if s == 2 else nn.Identity(), # dw | ||
66 | + GhostConv(c_, c2, 1, 1, act=False)) # pw-linear | ||
67 | + self.shortcut = nn.Sequential(DWConv(c1, c1, k, s, act=False), | ||
68 | + Conv(c1, c2, 1, 1, act=False)) if s == 2 else nn.Identity() | ||
69 | + | ||
70 | + def forward(self, x): | ||
71 | + return self.conv(x) + self.shortcut(x) | ||
72 | + | ||
73 | + | ||
74 | +class MixConv2d(nn.Module): | ||
75 | + # Mixed Depthwise Conv https://arxiv.org/abs/1907.09595 | ||
76 | + def __init__(self, c1, c2, k=(1, 3), s=1, equal_ch=True): | ||
77 | + super(MixConv2d, self).__init__() | ||
78 | + groups = len(k) | ||
79 | + if equal_ch: # equal c_ per group | ||
80 | + i = torch.linspace(0, groups - 1E-6, c2).floor() # c2 indices | ||
81 | + c_ = [(i == g).sum() for g in range(groups)] # intermediate channels | ||
82 | + else: # equal weight.numel() per group | ||
83 | + b = [c2] + [0] * groups | ||
84 | + a = np.eye(groups + 1, groups, k=-1) | ||
85 | + a -= np.roll(a, 1, axis=1) | ||
86 | + a *= np.array(k) ** 2 | ||
87 | + a[0] = 1 | ||
88 | + c_ = np.linalg.lstsq(a, b, rcond=None)[0].round() # solve for equal weight indices, ax = b | ||
89 | + | ||
90 | + self.m = nn.ModuleList([nn.Conv2d(c1, int(c_[g]), k[g], s, k[g] // 2, bias=False) for g in range(groups)]) | ||
91 | + self.bn = nn.BatchNorm2d(c2) | ||
92 | + self.act = nn.LeakyReLU(0.1, inplace=True) | ||
93 | + | ||
94 | + def forward(self, x): | ||
95 | + return x + self.act(self.bn(torch.cat([m(x) for m in self.m], 1))) | ||
96 | + | ||
97 | + | ||
98 | +class Ensemble(nn.ModuleList): | ||
99 | + # Ensemble of models | ||
100 | + def __init__(self): | ||
101 | + super(Ensemble, self).__init__() | ||
102 | + | ||
103 | + def forward(self, x, augment=False): | ||
104 | + y = [] | ||
105 | + for module in self: | ||
106 | + y.append(module(x, augment)[0]) | ||
107 | + # y = torch.stack(y).max(0)[0] # max ensemble | ||
108 | + # y = torch.stack(y).mean(0) # mean ensemble | ||
109 | + y = torch.cat(y, 1) # nms ensemble | ||
110 | + return y, None # inference, train output | ||
111 | + | ||
112 | + | ||
113 | +def attempt_load(weights, map_location=None, inplace=True): | ||
114 | + from models.yolo import Detect, Model | ||
115 | + | ||
116 | + # Loads an ensemble of models weights=[a,b,c] or a single model weights=[a] or weights=a | ||
117 | + model = Ensemble() | ||
118 | + for w in weights if isinstance(weights, list) else [weights]: | ||
119 | + ckpt = torch.load(attempt_download(w), map_location=map_location) # load | ||
120 | + model.append(ckpt['ema' if ckpt.get('ema') else 'model'].float().fuse().eval()) # FP32 model | ||
121 | + | ||
122 | + # Compatibility updates | ||
123 | + for m in model.modules(): | ||
124 | + if type(m) in [nn.Hardswish, nn.LeakyReLU, nn.ReLU, nn.ReLU6, nn.SiLU, Detect, Model]: | ||
125 | + m.inplace = inplace # pytorch 1.7.0 compatibility | ||
126 | + elif type(m) is Conv: | ||
127 | + m._non_persistent_buffers_set = set() # pytorch 1.6.0 compatibility | ||
128 | + | ||
129 | + if len(model) == 1: | ||
130 | + return model[-1] # return model | ||
131 | + else: | ||
132 | + print(f'Ensemble created with {weights}\n') | ||
133 | + for k in ['names']: | ||
134 | + setattr(model, k, getattr(model[-1], k)) | ||
135 | + model.stride = model[torch.argmax(torch.tensor([m.stride.max() for m in model])).int()].stride # max stride | ||
136 | + return model # return ensemble |
YOLOv5/models/export.py
0 → 100644
1 | +"""Exports a YOLOv5 *.pt model to TorchScript, ONNX, CoreML formats | ||
2 | + | ||
3 | +Usage: | ||
4 | + $ python path/to/models/export.py --weights yolov5s.pt --img 640 --batch 1 | ||
5 | +""" | ||
6 | + | ||
7 | +import argparse | ||
8 | +import sys | ||
9 | +import time | ||
10 | +from pathlib import Path | ||
11 | + | ||
12 | +sys.path.append(Path(__file__).parent.parent.absolute().__str__()) # to run '$ python *.py' files in subdirectories | ||
13 | + | ||
14 | +import torch | ||
15 | +import torch.nn as nn | ||
16 | +from torch.utils.mobile_optimizer import optimize_for_mobile | ||
17 | + | ||
18 | +import models | ||
19 | +from models.experimental import attempt_load | ||
20 | +from utils.activations import Hardswish, SiLU | ||
21 | +from utils.general import colorstr, check_img_size, check_requirements, file_size, set_logging | ||
22 | +from utils.torch_utils import select_device | ||
23 | + | ||
24 | +if __name__ == '__main__': | ||
25 | + parser = argparse.ArgumentParser() | ||
26 | + parser.add_argument('--weights', type=str, default='./yolov5s.pt', help='weights path') | ||
27 | + parser.add_argument('--img-size', nargs='+', type=int, default=[640, 640], help='image size') # height, width | ||
28 | + parser.add_argument('--batch-size', type=int, default=1, help='batch size') | ||
29 | + parser.add_argument('--device', default='cpu', help='cuda device, i.e. 0 or 0,1,2,3 or cpu') | ||
30 | + parser.add_argument('--include', nargs='+', default=['torchscript', 'onnx', 'coreml'], help='include formats') | ||
31 | + parser.add_argument('--half', action='store_true', help='FP16 half-precision export') | ||
32 | + parser.add_argument('--inplace', action='store_true', help='set YOLOv5 Detect() inplace=True') | ||
33 | + parser.add_argument('--train', action='store_true', help='model.train() mode') | ||
34 | + parser.add_argument('--optimize', action='store_true', help='optimize TorchScript for mobile') # TorchScript-only | ||
35 | + parser.add_argument('--dynamic', action='store_true', help='dynamic ONNX axes') # ONNX-only | ||
36 | + parser.add_argument('--simplify', action='store_true', help='simplify ONNX model') # ONNX-only | ||
37 | + parser.add_argument('--opset-version', type=int, default=12, help='ONNX opset version') # ONNX-only | ||
38 | + opt = parser.parse_args() | ||
39 | + opt.img_size *= 2 if len(opt.img_size) == 1 else 1 # expand | ||
40 | + opt.include = [x.lower() for x in opt.include] | ||
41 | + print(opt) | ||
42 | + set_logging() | ||
43 | + t = time.time() | ||
44 | + | ||
45 | + # Load PyTorch model | ||
46 | + device = select_device(opt.device) | ||
47 | + model = attempt_load(opt.weights, map_location=device) # load FP32 model | ||
48 | + labels = model.names | ||
49 | + | ||
50 | + # Checks | ||
51 | + gs = int(max(model.stride)) # grid size (max stride) | ||
52 | + opt.img_size = [check_img_size(x, gs) for x in opt.img_size] # verify img_size are gs-multiples | ||
53 | + assert not (opt.device.lower() == 'cpu' and opt.half), '--half only compatible with GPU export, i.e. use --device 0' | ||
54 | + | ||
55 | + # Input | ||
56 | + img = torch.zeros(opt.batch_size, 3, *opt.img_size).to(device) # image size(1,3,320,192) iDetection | ||
57 | + | ||
58 | + # Update model | ||
59 | + if opt.half: | ||
60 | + img, model = img.half(), model.half() # to FP16 | ||
61 | + if opt.train: | ||
62 | + model.train() # training mode (no grid construction in Detect layer) | ||
63 | + for k, m in model.named_modules(): | ||
64 | + m._non_persistent_buffers_set = set() # pytorch 1.6.0 compatibility | ||
65 | + if isinstance(m, models.common.Conv): # assign export-friendly activations | ||
66 | + if isinstance(m.act, nn.Hardswish): | ||
67 | + m.act = Hardswish() | ||
68 | + elif isinstance(m.act, nn.SiLU): | ||
69 | + m.act = SiLU() | ||
70 | + elif isinstance(m, models.yolo.Detect): | ||
71 | + m.inplace = opt.inplace | ||
72 | + m.onnx_dynamic = opt.dynamic | ||
73 | + # m.forward = m.forward_export # assign forward (optional) | ||
74 | + | ||
75 | + for _ in range(2): | ||
76 | + y = model(img) # dry runs | ||
77 | + print(f"\n{colorstr('PyTorch:')} starting from {opt.weights} ({file_size(opt.weights):.1f} MB)") | ||
78 | + | ||
79 | + # TorchScript export ----------------------------------------------------------------------------------------------- | ||
80 | + if 'torchscript' in opt.include or 'coreml' in opt.include: | ||
81 | + prefix = colorstr('TorchScript:') | ||
82 | + try: | ||
83 | + print(f'\n{prefix} starting export with torch {torch.__version__}...') | ||
84 | + f = opt.weights.replace('.pt', '.torchscript.pt') # filename | ||
85 | + ts = torch.jit.trace(model, img, strict=False) | ||
86 | + (optimize_for_mobile(ts) if opt.optimize else ts).save(f) | ||
87 | + print(f'{prefix} export success, saved as {f} ({file_size(f):.1f} MB)') | ||
88 | + except Exception as e: | ||
89 | + print(f'{prefix} export failure: {e}') | ||
90 | + | ||
91 | + # ONNX export ------------------------------------------------------------------------------------------------------ | ||
92 | + if 'onnx' in opt.include: | ||
93 | + prefix = colorstr('ONNX:') | ||
94 | + try: | ||
95 | + import onnx | ||
96 | + | ||
97 | + print(f'{prefix} starting export with onnx {onnx.__version__}...') | ||
98 | + f = opt.weights.replace('.pt', '.onnx') # filename | ||
99 | + torch.onnx.export(model, img, f, verbose=False, opset_version=opt.opset_version, input_names=['images'], | ||
100 | + training=torch.onnx.TrainingMode.TRAINING if opt.train else torch.onnx.TrainingMode.EVAL, | ||
101 | + do_constant_folding=not opt.train, | ||
102 | + dynamic_axes={'images': {0: 'batch', 2: 'height', 3: 'width'}, # size(1,3,640,640) | ||
103 | + 'output': {0: 'batch', 2: 'y', 3: 'x'}} if opt.dynamic else None) | ||
104 | + | ||
105 | + # Checks | ||
106 | + model_onnx = onnx.load(f) # load onnx model | ||
107 | + onnx.checker.check_model(model_onnx) # check onnx model | ||
108 | + # print(onnx.helper.printable_graph(model_onnx.graph)) # print | ||
109 | + | ||
110 | + # Simplify | ||
111 | + if opt.simplify: | ||
112 | + try: | ||
113 | + check_requirements(['onnx-simplifier']) | ||
114 | + import onnxsim | ||
115 | + | ||
116 | + print(f'{prefix} simplifying with onnx-simplifier {onnxsim.__version__}...') | ||
117 | + model_onnx, check = onnxsim.simplify( | ||
118 | + model_onnx, | ||
119 | + dynamic_input_shape=opt.dynamic, | ||
120 | + input_shapes={'images': list(img.shape)} if opt.dynamic else None) | ||
121 | + assert check, 'assert check failed' | ||
122 | + onnx.save(model_onnx, f) | ||
123 | + except Exception as e: | ||
124 | + print(f'{prefix} simplifier failure: {e}') | ||
125 | + print(f'{prefix} export success, saved as {f} ({file_size(f):.1f} MB)') | ||
126 | + except Exception as e: | ||
127 | + print(f'{prefix} export failure: {e}') | ||
128 | + | ||
129 | + # CoreML export ---------------------------------------------------------------------------------------------------- | ||
130 | + if 'coreml' in opt.include: | ||
131 | + prefix = colorstr('CoreML:') | ||
132 | + try: | ||
133 | + import coremltools as ct | ||
134 | + | ||
135 | + print(f'{prefix} starting export with coremltools {ct.__version__}...') | ||
136 | + assert opt.train, 'CoreML exports should be placed in model.train() mode with `python export.py --train`' | ||
137 | + model = ct.convert(ts, inputs=[ct.ImageType('image', shape=img.shape, scale=1 / 255.0, bias=[0, 0, 0])]) | ||
138 | + f = opt.weights.replace('.pt', '.mlmodel') # filename | ||
139 | + model.save(f) | ||
140 | + print(f'{prefix} export success, saved as {f} ({file_size(f):.1f} MB)') | ||
141 | + except Exception as e: | ||
142 | + print(f'{prefix} export failure: {e}') | ||
143 | + | ||
144 | + # Finish | ||
145 | + print(f'\nExport complete ({time.time() - t:.2f}s). Visualize with https://github.com/lutzroeder/netron.') |
YOLOv5/models/hub/anchors.yaml
0 → 100644
1 | +# Default YOLOv5 anchors for COCO data | ||
2 | + | ||
3 | + | ||
4 | +# P5 ------------------------------------------------------------------------------------------------------------------- | ||
5 | +# P5-640: | ||
6 | +anchors_p5_640: | ||
7 | + - [ 10,13, 16,30, 33,23 ] # P3/8 | ||
8 | + - [ 30,61, 62,45, 59,119 ] # P4/16 | ||
9 | + - [ 116,90, 156,198, 373,326 ] # P5/32 | ||
10 | + | ||
11 | + | ||
12 | +# P6 ------------------------------------------------------------------------------------------------------------------- | ||
13 | +# P6-640: thr=0.25: 0.9964 BPR, 5.54 anchors past thr, n=12, img_size=640, metric_all=0.281/0.716-mean/best, past_thr=0.469-mean: 9,11, 21,19, 17,41, 43,32, 39,70, 86,64, 65,131, 134,130, 120,265, 282,180, 247,354, 512,387 | ||
14 | +anchors_p6_640: | ||
15 | + - [ 9,11, 21,19, 17,41 ] # P3/8 | ||
16 | + - [ 43,32, 39,70, 86,64 ] # P4/16 | ||
17 | + - [ 65,131, 134,130, 120,265 ] # P5/32 | ||
18 | + - [ 282,180, 247,354, 512,387 ] # P6/64 | ||
19 | + | ||
20 | +# P6-1280: thr=0.25: 0.9950 BPR, 5.55 anchors past thr, n=12, img_size=1280, metric_all=0.281/0.714-mean/best, past_thr=0.468-mean: 19,27, 44,40, 38,94, 96,68, 86,152, 180,137, 140,301, 303,264, 238,542, 436,615, 739,380, 925,792 | ||
21 | +anchors_p6_1280: | ||
22 | + - [ 19,27, 44,40, 38,94 ] # P3/8 | ||
23 | + - [ 96,68, 86,152, 180,137 ] # P4/16 | ||
24 | + - [ 140,301, 303,264, 238,542 ] # P5/32 | ||
25 | + - [ 436,615, 739,380, 925,792 ] # P6/64 | ||
26 | + | ||
27 | +# P6-1920: thr=0.25: 0.9950 BPR, 5.55 anchors past thr, n=12, img_size=1920, metric_all=0.281/0.714-mean/best, past_thr=0.468-mean: 28,41, 67,59, 57,141, 144,103, 129,227, 270,205, 209,452, 455,396, 358,812, 653,922, 1109,570, 1387,1187 | ||
28 | +anchors_p6_1920: | ||
29 | + - [ 28,41, 67,59, 57,141 ] # P3/8 | ||
30 | + - [ 144,103, 129,227, 270,205 ] # P4/16 | ||
31 | + - [ 209,452, 455,396, 358,812 ] # P5/32 | ||
32 | + - [ 653,922, 1109,570, 1387,1187 ] # P6/64 | ||
33 | + | ||
34 | + | ||
35 | +# P7 ------------------------------------------------------------------------------------------------------------------- | ||
36 | +# P7-640: thr=0.25: 0.9962 BPR, 6.76 anchors past thr, n=15, img_size=640, metric_all=0.275/0.733-mean/best, past_thr=0.466-mean: 11,11, 13,30, 29,20, 30,46, 61,38, 39,92, 78,80, 146,66, 79,163, 149,150, 321,143, 157,303, 257,402, 359,290, 524,372 | ||
37 | +anchors_p7_640: | ||
38 | + - [ 11,11, 13,30, 29,20 ] # P3/8 | ||
39 | + - [ 30,46, 61,38, 39,92 ] # P4/16 | ||
40 | + - [ 78,80, 146,66, 79,163 ] # P5/32 | ||
41 | + - [ 149,150, 321,143, 157,303 ] # P6/64 | ||
42 | + - [ 257,402, 359,290, 524,372 ] # P7/128 | ||
43 | + | ||
44 | +# P7-1280: thr=0.25: 0.9968 BPR, 6.71 anchors past thr, n=15, img_size=1280, metric_all=0.273/0.732-mean/best, past_thr=0.463-mean: 19,22, 54,36, 32,77, 70,83, 138,71, 75,173, 165,159, 148,334, 375,151, 334,317, 251,626, 499,474, 750,326, 534,814, 1079,818 | ||
45 | +anchors_p7_1280: | ||
46 | + - [ 19,22, 54,36, 32,77 ] # P3/8 | ||
47 | + - [ 70,83, 138,71, 75,173 ] # P4/16 | ||
48 | + - [ 165,159, 148,334, 375,151 ] # P5/32 | ||
49 | + - [ 334,317, 251,626, 499,474 ] # P6/64 | ||
50 | + - [ 750,326, 534,814, 1079,818 ] # P7/128 | ||
51 | + | ||
52 | +# P7-1920: thr=0.25: 0.9968 BPR, 6.71 anchors past thr, n=15, img_size=1920, metric_all=0.273/0.732-mean/best, past_thr=0.463-mean: 29,34, 81,55, 47,115, 105,124, 207,107, 113,259, 247,238, 222,500, 563,227, 501,476, 376,939, 749,711, 1126,489, 801,1222, 1618,1227 | ||
53 | +anchors_p7_1920: | ||
54 | + - [ 29,34, 81,55, 47,115 ] # P3/8 | ||
55 | + - [ 105,124, 207,107, 113,259 ] # P4/16 | ||
56 | + - [ 247,238, 222,500, 563,227 ] # P5/32 | ||
57 | + - [ 501,476, 376,939, 749,711 ] # P6/64 | ||
58 | + - [ 1126,489, 801,1222, 1618,1227 ] # P7/128 |
YOLOv5/models/hub/yolov3-spp.yaml
0 → 100644
1 | +# parameters | ||
2 | +nc: 80 # number of classes | ||
3 | +depth_multiple: 1.0 # model depth multiple | ||
4 | +width_multiple: 1.0 # layer channel multiple | ||
5 | + | ||
6 | +# anchors | ||
7 | +anchors: | ||
8 | + - [10,13, 16,30, 33,23] # P3/8 | ||
9 | + - [30,61, 62,45, 59,119] # P4/16 | ||
10 | + - [116,90, 156,198, 373,326] # P5/32 | ||
11 | + | ||
12 | +# darknet53 backbone | ||
13 | +backbone: | ||
14 | + # [from, number, module, args] | ||
15 | + [[-1, 1, Conv, [32, 3, 1]], # 0 | ||
16 | + [-1, 1, Conv, [64, 3, 2]], # 1-P1/2 | ||
17 | + [-1, 1, Bottleneck, [64]], | ||
18 | + [-1, 1, Conv, [128, 3, 2]], # 3-P2/4 | ||
19 | + [-1, 2, Bottleneck, [128]], | ||
20 | + [-1, 1, Conv, [256, 3, 2]], # 5-P3/8 | ||
21 | + [-1, 8, Bottleneck, [256]], | ||
22 | + [-1, 1, Conv, [512, 3, 2]], # 7-P4/16 | ||
23 | + [-1, 8, Bottleneck, [512]], | ||
24 | + [-1, 1, Conv, [1024, 3, 2]], # 9-P5/32 | ||
25 | + [-1, 4, Bottleneck, [1024]], # 10 | ||
26 | + ] | ||
27 | + | ||
28 | +# YOLOv3-SPP head | ||
29 | +head: | ||
30 | + [[-1, 1, Bottleneck, [1024, False]], | ||
31 | + [-1, 1, SPP, [512, [5, 9, 13]]], | ||
32 | + [-1, 1, Conv, [1024, 3, 1]], | ||
33 | + [-1, 1, Conv, [512, 1, 1]], | ||
34 | + [-1, 1, Conv, [1024, 3, 1]], # 15 (P5/32-large) | ||
35 | + | ||
36 | + [-2, 1, Conv, [256, 1, 1]], | ||
37 | + [-1, 1, nn.Upsample, [None, 2, 'nearest']], | ||
38 | + [[-1, 8], 1, Concat, [1]], # cat backbone P4 | ||
39 | + [-1, 1, Bottleneck, [512, False]], | ||
40 | + [-1, 1, Bottleneck, [512, False]], | ||
41 | + [-1, 1, Conv, [256, 1, 1]], | ||
42 | + [-1, 1, Conv, [512, 3, 1]], # 22 (P4/16-medium) | ||
43 | + | ||
44 | + [-2, 1, Conv, [128, 1, 1]], | ||
45 | + [-1, 1, nn.Upsample, [None, 2, 'nearest']], | ||
46 | + [[-1, 6], 1, Concat, [1]], # cat backbone P3 | ||
47 | + [-1, 1, Bottleneck, [256, False]], | ||
48 | + [-1, 2, Bottleneck, [256, False]], # 27 (P3/8-small) | ||
49 | + | ||
50 | + [[27, 22, 15], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5) | ||
51 | + ] |
YOLOv5/models/hub/yolov3-tiny.yaml
0 → 100644
1 | +# parameters | ||
2 | +nc: 80 # number of classes | ||
3 | +depth_multiple: 1.0 # model depth multiple | ||
4 | +width_multiple: 1.0 # layer channel multiple | ||
5 | + | ||
6 | +# anchors | ||
7 | +anchors: | ||
8 | + - [10,14, 23,27, 37,58] # P4/16 | ||
9 | + - [81,82, 135,169, 344,319] # P5/32 | ||
10 | + | ||
11 | +# YOLOv3-tiny backbone | ||
12 | +backbone: | ||
13 | + # [from, number, module, args] | ||
14 | + [[-1, 1, Conv, [16, 3, 1]], # 0 | ||
15 | + [-1, 1, nn.MaxPool2d, [2, 2, 0]], # 1-P1/2 | ||
16 | + [-1, 1, Conv, [32, 3, 1]], | ||
17 | + [-1, 1, nn.MaxPool2d, [2, 2, 0]], # 3-P2/4 | ||
18 | + [-1, 1, Conv, [64, 3, 1]], | ||
19 | + [-1, 1, nn.MaxPool2d, [2, 2, 0]], # 5-P3/8 | ||
20 | + [-1, 1, Conv, [128, 3, 1]], | ||
21 | + [-1, 1, nn.MaxPool2d, [2, 2, 0]], # 7-P4/16 | ||
22 | + [-1, 1, Conv, [256, 3, 1]], | ||
23 | + [-1, 1, nn.MaxPool2d, [2, 2, 0]], # 9-P5/32 | ||
24 | + [-1, 1, Conv, [512, 3, 1]], | ||
25 | + [-1, 1, nn.ZeroPad2d, [[0, 1, 0, 1]]], # 11 | ||
26 | + [-1, 1, nn.MaxPool2d, [2, 1, 0]], # 12 | ||
27 | + ] | ||
28 | + | ||
29 | +# YOLOv3-tiny head | ||
30 | +head: | ||
31 | + [[-1, 1, Conv, [1024, 3, 1]], | ||
32 | + [-1, 1, Conv, [256, 1, 1]], | ||
33 | + [-1, 1, Conv, [512, 3, 1]], # 15 (P5/32-large) | ||
34 | + | ||
35 | + [-2, 1, Conv, [128, 1, 1]], | ||
36 | + [-1, 1, nn.Upsample, [None, 2, 'nearest']], | ||
37 | + [[-1, 8], 1, Concat, [1]], # cat backbone P4 | ||
38 | + [-1, 1, Conv, [256, 3, 1]], # 19 (P4/16-medium) | ||
39 | + | ||
40 | + [[19, 15], 1, Detect, [nc, anchors]], # Detect(P4, P5) | ||
41 | + ] |
YOLOv5/models/hub/yolov3.yaml
0 → 100644
1 | +# parameters | ||
2 | +nc: 80 # number of classes | ||
3 | +depth_multiple: 1.0 # model depth multiple | ||
4 | +width_multiple: 1.0 # layer channel multiple | ||
5 | + | ||
6 | +# anchors | ||
7 | +anchors: | ||
8 | + - [10,13, 16,30, 33,23] # P3/8 | ||
9 | + - [30,61, 62,45, 59,119] # P4/16 | ||
10 | + - [116,90, 156,198, 373,326] # P5/32 | ||
11 | + | ||
12 | +# darknet53 backbone | ||
13 | +backbone: | ||
14 | + # [from, number, module, args] | ||
15 | + [[-1, 1, Conv, [32, 3, 1]], # 0 | ||
16 | + [-1, 1, Conv, [64, 3, 2]], # 1-P1/2 | ||
17 | + [-1, 1, Bottleneck, [64]], | ||
18 | + [-1, 1, Conv, [128, 3, 2]], # 3-P2/4 | ||
19 | + [-1, 2, Bottleneck, [128]], | ||
20 | + [-1, 1, Conv, [256, 3, 2]], # 5-P3/8 | ||
21 | + [-1, 8, Bottleneck, [256]], | ||
22 | + [-1, 1, Conv, [512, 3, 2]], # 7-P4/16 | ||
23 | + [-1, 8, Bottleneck, [512]], | ||
24 | + [-1, 1, Conv, [1024, 3, 2]], # 9-P5/32 | ||
25 | + [-1, 4, Bottleneck, [1024]], # 10 | ||
26 | + ] | ||
27 | + | ||
28 | +# YOLOv3 head | ||
29 | +head: | ||
30 | + [[-1, 1, Bottleneck, [1024, False]], | ||
31 | + [-1, 1, Conv, [512, [1, 1]]], | ||
32 | + [-1, 1, Conv, [1024, 3, 1]], | ||
33 | + [-1, 1, Conv, [512, 1, 1]], | ||
34 | + [-1, 1, Conv, [1024, 3, 1]], # 15 (P5/32-large) | ||
35 | + | ||
36 | + [-2, 1, Conv, [256, 1, 1]], | ||
37 | + [-1, 1, nn.Upsample, [None, 2, 'nearest']], | ||
38 | + [[-1, 8], 1, Concat, [1]], # cat backbone P4 | ||
39 | + [-1, 1, Bottleneck, [512, False]], | ||
40 | + [-1, 1, Bottleneck, [512, False]], | ||
41 | + [-1, 1, Conv, [256, 1, 1]], | ||
42 | + [-1, 1, Conv, [512, 3, 1]], # 22 (P4/16-medium) | ||
43 | + | ||
44 | + [-2, 1, Conv, [128, 1, 1]], | ||
45 | + [-1, 1, nn.Upsample, [None, 2, 'nearest']], | ||
46 | + [[-1, 6], 1, Concat, [1]], # cat backbone P3 | ||
47 | + [-1, 1, Bottleneck, [256, False]], | ||
48 | + [-1, 2, Bottleneck, [256, False]], # 27 (P3/8-small) | ||
49 | + | ||
50 | + [[27, 22, 15], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5) | ||
51 | + ] |
YOLOv5/models/hub/yolov5-fpn.yaml
0 → 100644
1 | +# parameters | ||
2 | +nc: 80 # number of classes | ||
3 | +depth_multiple: 1.0 # model depth multiple | ||
4 | +width_multiple: 1.0 # layer channel multiple | ||
5 | + | ||
6 | +# anchors | ||
7 | +anchors: | ||
8 | + - [10,13, 16,30, 33,23] # P3/8 | ||
9 | + - [30,61, 62,45, 59,119] # P4/16 | ||
10 | + - [116,90, 156,198, 373,326] # P5/32 | ||
11 | + | ||
12 | +# YOLOv5 backbone | ||
13 | +backbone: | ||
14 | + # [from, number, module, args] | ||
15 | + [[-1, 1, Focus, [64, 3]], # 0-P1/2 | ||
16 | + [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 | ||
17 | + [-1, 3, Bottleneck, [128]], | ||
18 | + [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 | ||
19 | + [-1, 9, BottleneckCSP, [256]], | ||
20 | + [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 | ||
21 | + [-1, 9, BottleneckCSP, [512]], | ||
22 | + [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32 | ||
23 | + [-1, 1, SPP, [1024, [5, 9, 13]]], | ||
24 | + [-1, 6, BottleneckCSP, [1024]], # 9 | ||
25 | + ] | ||
26 | + | ||
27 | +# YOLOv5 FPN head | ||
28 | +head: | ||
29 | + [[-1, 3, BottleneckCSP, [1024, False]], # 10 (P5/32-large) | ||
30 | + | ||
31 | + [-1, 1, nn.Upsample, [None, 2, 'nearest']], | ||
32 | + [[-1, 6], 1, Concat, [1]], # cat backbone P4 | ||
33 | + [-1, 1, Conv, [512, 1, 1]], | ||
34 | + [-1, 3, BottleneckCSP, [512, False]], # 14 (P4/16-medium) | ||
35 | + | ||
36 | + [-1, 1, nn.Upsample, [None, 2, 'nearest']], | ||
37 | + [[-1, 4], 1, Concat, [1]], # cat backbone P3 | ||
38 | + [-1, 1, Conv, [256, 1, 1]], | ||
39 | + [-1, 3, BottleneckCSP, [256, False]], # 18 (P3/8-small) | ||
40 | + | ||
41 | + [[18, 14, 10], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5) | ||
42 | + ] |
YOLOv5/models/hub/yolov5-p2.yaml
0 → 100644
1 | +# parameters | ||
2 | +nc: 80 # number of classes | ||
3 | +depth_multiple: 1.0 # model depth multiple | ||
4 | +width_multiple: 1.0 # layer channel multiple | ||
5 | + | ||
6 | +# anchors | ||
7 | +anchors: 3 | ||
8 | + | ||
9 | +# YOLOv5 backbone | ||
10 | +backbone: | ||
11 | + # [from, number, module, args] | ||
12 | + [ [ -1, 1, Focus, [ 64, 3 ] ], # 0-P1/2 | ||
13 | + [ -1, 1, Conv, [ 128, 3, 2 ] ], # 1-P2/4 | ||
14 | + [ -1, 3, C3, [ 128 ] ], | ||
15 | + [ -1, 1, Conv, [ 256, 3, 2 ] ], # 3-P3/8 | ||
16 | + [ -1, 9, C3, [ 256 ] ], | ||
17 | + [ -1, 1, Conv, [ 512, 3, 2 ] ], # 5-P4/16 | ||
18 | + [ -1, 9, C3, [ 512 ] ], | ||
19 | + [ -1, 1, Conv, [ 1024, 3, 2 ] ], # 7-P5/32 | ||
20 | + [ -1, 1, SPP, [ 1024, [ 5, 9, 13 ] ] ], | ||
21 | + [ -1, 3, C3, [ 1024, False ] ], # 9 | ||
22 | + ] | ||
23 | + | ||
24 | +# YOLOv5 head | ||
25 | +head: | ||
26 | + [ [ -1, 1, Conv, [ 512, 1, 1 ] ], | ||
27 | + [ -1, 1, nn.Upsample, [ None, 2, 'nearest' ] ], | ||
28 | + [ [ -1, 6 ], 1, Concat, [ 1 ] ], # cat backbone P4 | ||
29 | + [ -1, 3, C3, [ 512, False ] ], # 13 | ||
30 | + | ||
31 | + [ -1, 1, Conv, [ 256, 1, 1 ] ], | ||
32 | + [ -1, 1, nn.Upsample, [ None, 2, 'nearest' ] ], | ||
33 | + [ [ -1, 4 ], 1, Concat, [ 1 ] ], # cat backbone P3 | ||
34 | + [ -1, 3, C3, [ 256, False ] ], # 17 (P3/8-small) | ||
35 | + | ||
36 | + [ -1, 1, Conv, [ 128, 1, 1 ] ], | ||
37 | + [ -1, 1, nn.Upsample, [ None, 2, 'nearest' ] ], | ||
38 | + [ [ -1, 2 ], 1, Concat, [ 1 ] ], # cat backbone P2 | ||
39 | + [ -1, 1, C3, [ 128, False ] ], # 21 (P2/4-xsmall) | ||
40 | + | ||
41 | + [ -1, 1, Conv, [ 128, 3, 2 ] ], | ||
42 | + [ [ -1, 18 ], 1, Concat, [ 1 ] ], # cat head P3 | ||
43 | + [ -1, 3, C3, [ 256, False ] ], # 24 (P3/8-small) | ||
44 | + | ||
45 | + [ -1, 1, Conv, [ 256, 3, 2 ] ], | ||
46 | + [ [ -1, 14 ], 1, Concat, [ 1 ] ], # cat head P4 | ||
47 | + [ -1, 3, C3, [ 512, False ] ], # 27 (P4/16-medium) | ||
48 | + | ||
49 | + [ -1, 1, Conv, [ 512, 3, 2 ] ], | ||
50 | + [ [ -1, 10 ], 1, Concat, [ 1 ] ], # cat head P5 | ||
51 | + [ -1, 3, C3, [ 1024, False ] ], # 30 (P5/32-large) | ||
52 | + | ||
53 | + [ [ 24, 27, 30 ], 1, Detect, [ nc, anchors ] ], # Detect(P3, P4, P5) | ||
54 | + ] |
YOLOv5/models/hub/yolov5-p6.yaml
0 → 100644
1 | +# parameters | ||
2 | +nc: 80 # number of classes | ||
3 | +depth_multiple: 1.0 # model depth multiple | ||
4 | +width_multiple: 1.0 # layer channel multiple | ||
5 | + | ||
6 | +# anchors | ||
7 | +anchors: 3 | ||
8 | + | ||
9 | +# YOLOv5 backbone | ||
10 | +backbone: | ||
11 | + # [from, number, module, args] | ||
12 | + [ [ -1, 1, Focus, [ 64, 3 ] ], # 0-P1/2 | ||
13 | + [ -1, 1, Conv, [ 128, 3, 2 ] ], # 1-P2/4 | ||
14 | + [ -1, 3, C3, [ 128 ] ], | ||
15 | + [ -1, 1, Conv, [ 256, 3, 2 ] ], # 3-P3/8 | ||
16 | + [ -1, 9, C3, [ 256 ] ], | ||
17 | + [ -1, 1, Conv, [ 512, 3, 2 ] ], # 5-P4/16 | ||
18 | + [ -1, 9, C3, [ 512 ] ], | ||
19 | + [ -1, 1, Conv, [ 768, 3, 2 ] ], # 7-P5/32 | ||
20 | + [ -1, 3, C3, [ 768 ] ], | ||
21 | + [ -1, 1, Conv, [ 1024, 3, 2 ] ], # 9-P6/64 | ||
22 | + [ -1, 1, SPP, [ 1024, [ 3, 5, 7 ] ] ], | ||
23 | + [ -1, 3, C3, [ 1024, False ] ], # 11 | ||
24 | + ] | ||
25 | + | ||
26 | +# YOLOv5 head | ||
27 | +head: | ||
28 | + [ [ -1, 1, Conv, [ 768, 1, 1 ] ], | ||
29 | + [ -1, 1, nn.Upsample, [ None, 2, 'nearest' ] ], | ||
30 | + [ [ -1, 8 ], 1, Concat, [ 1 ] ], # cat backbone P5 | ||
31 | + [ -1, 3, C3, [ 768, False ] ], # 15 | ||
32 | + | ||
33 | + [ -1, 1, Conv, [ 512, 1, 1 ] ], | ||
34 | + [ -1, 1, nn.Upsample, [ None, 2, 'nearest' ] ], | ||
35 | + [ [ -1, 6 ], 1, Concat, [ 1 ] ], # cat backbone P4 | ||
36 | + [ -1, 3, C3, [ 512, False ] ], # 19 | ||
37 | + | ||
38 | + [ -1, 1, Conv, [ 256, 1, 1 ] ], | ||
39 | + [ -1, 1, nn.Upsample, [ None, 2, 'nearest' ] ], | ||
40 | + [ [ -1, 4 ], 1, Concat, [ 1 ] ], # cat backbone P3 | ||
41 | + [ -1, 3, C3, [ 256, False ] ], # 23 (P3/8-small) | ||
42 | + | ||
43 | + [ -1, 1, Conv, [ 256, 3, 2 ] ], | ||
44 | + [ [ -1, 20 ], 1, Concat, [ 1 ] ], # cat head P4 | ||
45 | + [ -1, 3, C3, [ 512, False ] ], # 26 (P4/16-medium) | ||
46 | + | ||
47 | + [ -1, 1, Conv, [ 512, 3, 2 ] ], | ||
48 | + [ [ -1, 16 ], 1, Concat, [ 1 ] ], # cat head P5 | ||
49 | + [ -1, 3, C3, [ 768, False ] ], # 29 (P5/32-large) | ||
50 | + | ||
51 | + [ -1, 1, Conv, [ 768, 3, 2 ] ], | ||
52 | + [ [ -1, 12 ], 1, Concat, [ 1 ] ], # cat head P6 | ||
53 | + [ -1, 3, C3, [ 1024, False ] ], # 32 (P5/64-xlarge) | ||
54 | + | ||
55 | + [ [ 23, 26, 29, 32 ], 1, Detect, [ nc, anchors ] ], # Detect(P3, P4, P5, P6) | ||
56 | + ] |
YOLOv5/models/hub/yolov5-p7.yaml
0 → 100644
1 | +# parameters | ||
2 | +nc: 80 # number of classes | ||
3 | +depth_multiple: 1.0 # model depth multiple | ||
4 | +width_multiple: 1.0 # layer channel multiple | ||
5 | + | ||
6 | +# anchors | ||
7 | +anchors: 3 | ||
8 | + | ||
9 | +# YOLOv5 backbone | ||
10 | +backbone: | ||
11 | + # [from, number, module, args] | ||
12 | + [ [ -1, 1, Focus, [ 64, 3 ] ], # 0-P1/2 | ||
13 | + [ -1, 1, Conv, [ 128, 3, 2 ] ], # 1-P2/4 | ||
14 | + [ -1, 3, C3, [ 128 ] ], | ||
15 | + [ -1, 1, Conv, [ 256, 3, 2 ] ], # 3-P3/8 | ||
16 | + [ -1, 9, C3, [ 256 ] ], | ||
17 | + [ -1, 1, Conv, [ 512, 3, 2 ] ], # 5-P4/16 | ||
18 | + [ -1, 9, C3, [ 512 ] ], | ||
19 | + [ -1, 1, Conv, [ 768, 3, 2 ] ], # 7-P5/32 | ||
20 | + [ -1, 3, C3, [ 768 ] ], | ||
21 | + [ -1, 1, Conv, [ 1024, 3, 2 ] ], # 9-P6/64 | ||
22 | + [ -1, 3, C3, [ 1024 ] ], | ||
23 | + [ -1, 1, Conv, [ 1280, 3, 2 ] ], # 11-P7/128 | ||
24 | + [ -1, 1, SPP, [ 1280, [ 3, 5 ] ] ], | ||
25 | + [ -1, 3, C3, [ 1280, False ] ], # 13 | ||
26 | + ] | ||
27 | + | ||
28 | +# YOLOv5 head | ||
29 | +head: | ||
30 | + [ [ -1, 1, Conv, [ 1024, 1, 1 ] ], | ||
31 | + [ -1, 1, nn.Upsample, [ None, 2, 'nearest' ] ], | ||
32 | + [ [ -1, 10 ], 1, Concat, [ 1 ] ], # cat backbone P6 | ||
33 | + [ -1, 3, C3, [ 1024, False ] ], # 17 | ||
34 | + | ||
35 | + [ -1, 1, Conv, [ 768, 1, 1 ] ], | ||
36 | + [ -1, 1, nn.Upsample, [ None, 2, 'nearest' ] ], | ||
37 | + [ [ -1, 8 ], 1, Concat, [ 1 ] ], # cat backbone P5 | ||
38 | + [ -1, 3, C3, [ 768, False ] ], # 21 | ||
39 | + | ||
40 | + [ -1, 1, Conv, [ 512, 1, 1 ] ], | ||
41 | + [ -1, 1, nn.Upsample, [ None, 2, 'nearest' ] ], | ||
42 | + [ [ -1, 6 ], 1, Concat, [ 1 ] ], # cat backbone P4 | ||
43 | + [ -1, 3, C3, [ 512, False ] ], # 25 | ||
44 | + | ||
45 | + [ -1, 1, Conv, [ 256, 1, 1 ] ], | ||
46 | + [ -1, 1, nn.Upsample, [ None, 2, 'nearest' ] ], | ||
47 | + [ [ -1, 4 ], 1, Concat, [ 1 ] ], # cat backbone P3 | ||
48 | + [ -1, 3, C3, [ 256, False ] ], # 29 (P3/8-small) | ||
49 | + | ||
50 | + [ -1, 1, Conv, [ 256, 3, 2 ] ], | ||
51 | + [ [ -1, 26 ], 1, Concat, [ 1 ] ], # cat head P4 | ||
52 | + [ -1, 3, C3, [ 512, False ] ], # 32 (P4/16-medium) | ||
53 | + | ||
54 | + [ -1, 1, Conv, [ 512, 3, 2 ] ], | ||
55 | + [ [ -1, 22 ], 1, Concat, [ 1 ] ], # cat head P5 | ||
56 | + [ -1, 3, C3, [ 768, False ] ], # 35 (P5/32-large) | ||
57 | + | ||
58 | + [ -1, 1, Conv, [ 768, 3, 2 ] ], | ||
59 | + [ [ -1, 18 ], 1, Concat, [ 1 ] ], # cat head P6 | ||
60 | + [ -1, 3, C3, [ 1024, False ] ], # 38 (P6/64-xlarge) | ||
61 | + | ||
62 | + [ -1, 1, Conv, [ 1024, 3, 2 ] ], | ||
63 | + [ [ -1, 14 ], 1, Concat, [ 1 ] ], # cat head P7 | ||
64 | + [ -1, 3, C3, [ 1280, False ] ], # 41 (P7/128-xxlarge) | ||
65 | + | ||
66 | + [ [ 29, 32, 35, 38, 41 ], 1, Detect, [ nc, anchors ] ], # Detect(P3, P4, P5, P6, P7) | ||
67 | + ] |
YOLOv5/models/hub/yolov5-panet.yaml
0 → 100644
1 | +# parameters | ||
2 | +nc: 80 # number of classes | ||
3 | +depth_multiple: 1.0 # model depth multiple | ||
4 | +width_multiple: 1.0 # layer channel multiple | ||
5 | + | ||
6 | +# anchors | ||
7 | +anchors: | ||
8 | + - [10,13, 16,30, 33,23] # P3/8 | ||
9 | + - [30,61, 62,45, 59,119] # P4/16 | ||
10 | + - [116,90, 156,198, 373,326] # P5/32 | ||
11 | + | ||
12 | +# YOLOv5 backbone | ||
13 | +backbone: | ||
14 | + # [from, number, module, args] | ||
15 | + [[-1, 1, Focus, [64, 3]], # 0-P1/2 | ||
16 | + [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 | ||
17 | + [-1, 3, BottleneckCSP, [128]], | ||
18 | + [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 | ||
19 | + [-1, 9, BottleneckCSP, [256]], | ||
20 | + [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 | ||
21 | + [-1, 9, BottleneckCSP, [512]], | ||
22 | + [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32 | ||
23 | + [-1, 1, SPP, [1024, [5, 9, 13]]], | ||
24 | + [-1, 3, BottleneckCSP, [1024, False]], # 9 | ||
25 | + ] | ||
26 | + | ||
27 | +# YOLOv5 PANet head | ||
28 | +head: | ||
29 | + [[-1, 1, Conv, [512, 1, 1]], | ||
30 | + [-1, 1, nn.Upsample, [None, 2, 'nearest']], | ||
31 | + [[-1, 6], 1, Concat, [1]], # cat backbone P4 | ||
32 | + [-1, 3, BottleneckCSP, [512, False]], # 13 | ||
33 | + | ||
34 | + [-1, 1, Conv, [256, 1, 1]], | ||
35 | + [-1, 1, nn.Upsample, [None, 2, 'nearest']], | ||
36 | + [[-1, 4], 1, Concat, [1]], # cat backbone P3 | ||
37 | + [-1, 3, BottleneckCSP, [256, False]], # 17 (P3/8-small) | ||
38 | + | ||
39 | + [-1, 1, Conv, [256, 3, 2]], | ||
40 | + [[-1, 14], 1, Concat, [1]], # cat head P4 | ||
41 | + [-1, 3, BottleneckCSP, [512, False]], # 20 (P4/16-medium) | ||
42 | + | ||
43 | + [-1, 1, Conv, [512, 3, 2]], | ||
44 | + [[-1, 10], 1, Concat, [1]], # cat head P5 | ||
45 | + [-1, 3, BottleneckCSP, [1024, False]], # 23 (P5/32-large) | ||
46 | + | ||
47 | + [[17, 20, 23], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5) | ||
48 | + ] |
YOLOv5/models/hub/yolov5l6.yaml
0 → 100644
1 | +# parameters | ||
2 | +nc: 80 # number of classes | ||
3 | +depth_multiple: 1.0 # model depth multiple | ||
4 | +width_multiple: 1.0 # layer channel multiple | ||
5 | + | ||
6 | +# anchors | ||
7 | +anchors: | ||
8 | + - [ 19,27, 44,40, 38,94 ] # P3/8 | ||
9 | + - [ 96,68, 86,152, 180,137 ] # P4/16 | ||
10 | + - [ 140,301, 303,264, 238,542 ] # P5/32 | ||
11 | + - [ 436,615, 739,380, 925,792 ] # P6/64 | ||
12 | + | ||
13 | +# YOLOv5 backbone | ||
14 | +backbone: | ||
15 | + # [from, number, module, args] | ||
16 | + [ [ -1, 1, Focus, [ 64, 3 ] ], # 0-P1/2 | ||
17 | + [ -1, 1, Conv, [ 128, 3, 2 ] ], # 1-P2/4 | ||
18 | + [ -1, 3, C3, [ 128 ] ], | ||
19 | + [ -1, 1, Conv, [ 256, 3, 2 ] ], # 3-P3/8 | ||
20 | + [ -1, 9, C3, [ 256 ] ], | ||
21 | + [ -1, 1, Conv, [ 512, 3, 2 ] ], # 5-P4/16 | ||
22 | + [ -1, 9, C3, [ 512 ] ], | ||
23 | + [ -1, 1, Conv, [ 768, 3, 2 ] ], # 7-P5/32 | ||
24 | + [ -1, 3, C3, [ 768 ] ], | ||
25 | + [ -1, 1, Conv, [ 1024, 3, 2 ] ], # 9-P6/64 | ||
26 | + [ -1, 1, SPP, [ 1024, [ 3, 5, 7 ] ] ], | ||
27 | + [ -1, 3, C3, [ 1024, False ] ], # 11 | ||
28 | + ] | ||
29 | + | ||
30 | +# YOLOv5 head | ||
31 | +head: | ||
32 | + [ [ -1, 1, Conv, [ 768, 1, 1 ] ], | ||
33 | + [ -1, 1, nn.Upsample, [ None, 2, 'nearest' ] ], | ||
34 | + [ [ -1, 8 ], 1, Concat, [ 1 ] ], # cat backbone P5 | ||
35 | + [ -1, 3, C3, [ 768, False ] ], # 15 | ||
36 | + | ||
37 | + [ -1, 1, Conv, [ 512, 1, 1 ] ], | ||
38 | + [ -1, 1, nn.Upsample, [ None, 2, 'nearest' ] ], | ||
39 | + [ [ -1, 6 ], 1, Concat, [ 1 ] ], # cat backbone P4 | ||
40 | + [ -1, 3, C3, [ 512, False ] ], # 19 | ||
41 | + | ||
42 | + [ -1, 1, Conv, [ 256, 1, 1 ] ], | ||
43 | + [ -1, 1, nn.Upsample, [ None, 2, 'nearest' ] ], | ||
44 | + [ [ -1, 4 ], 1, Concat, [ 1 ] ], # cat backbone P3 | ||
45 | + [ -1, 3, C3, [ 256, False ] ], # 23 (P3/8-small) | ||
46 | + | ||
47 | + [ -1, 1, Conv, [ 256, 3, 2 ] ], | ||
48 | + [ [ -1, 20 ], 1, Concat, [ 1 ] ], # cat head P4 | ||
49 | + [ -1, 3, C3, [ 512, False ] ], # 26 (P4/16-medium) | ||
50 | + | ||
51 | + [ -1, 1, Conv, [ 512, 3, 2 ] ], | ||
52 | + [ [ -1, 16 ], 1, Concat, [ 1 ] ], # cat head P5 | ||
53 | + [ -1, 3, C3, [ 768, False ] ], # 29 (P5/32-large) | ||
54 | + | ||
55 | + [ -1, 1, Conv, [ 768, 3, 2 ] ], | ||
56 | + [ [ -1, 12 ], 1, Concat, [ 1 ] ], # cat head P6 | ||
57 | + [ -1, 3, C3, [ 1024, False ] ], # 32 (P6/64-xlarge) | ||
58 | + | ||
59 | + [ [ 23, 26, 29, 32 ], 1, Detect, [ nc, anchors ] ], # Detect(P3, P4, P5, P6) | ||
60 | + ] |
YOLOv5/models/hub/yolov5m6.yaml
0 → 100644
1 | +# parameters | ||
2 | +nc: 80 # number of classes | ||
3 | +depth_multiple: 0.67 # model depth multiple | ||
4 | +width_multiple: 0.75 # layer channel multiple | ||
5 | + | ||
6 | +# anchors | ||
7 | +anchors: | ||
8 | + - [ 19,27, 44,40, 38,94 ] # P3/8 | ||
9 | + - [ 96,68, 86,152, 180,137 ] # P4/16 | ||
10 | + - [ 140,301, 303,264, 238,542 ] # P5/32 | ||
11 | + - [ 436,615, 739,380, 925,792 ] # P6/64 | ||
12 | + | ||
13 | +# YOLOv5 backbone | ||
14 | +backbone: | ||
15 | + # [from, number, module, args] | ||
16 | + [ [ -1, 1, Focus, [ 64, 3 ] ], # 0-P1/2 | ||
17 | + [ -1, 1, Conv, [ 128, 3, 2 ] ], # 1-P2/4 | ||
18 | + [ -1, 3, C3, [ 128 ] ], | ||
19 | + [ -1, 1, Conv, [ 256, 3, 2 ] ], # 3-P3/8 | ||
20 | + [ -1, 9, C3, [ 256 ] ], | ||
21 | + [ -1, 1, Conv, [ 512, 3, 2 ] ], # 5-P4/16 | ||
22 | + [ -1, 9, C3, [ 512 ] ], | ||
23 | + [ -1, 1, Conv, [ 768, 3, 2 ] ], # 7-P5/32 | ||
24 | + [ -1, 3, C3, [ 768 ] ], | ||
25 | + [ -1, 1, Conv, [ 1024, 3, 2 ] ], # 9-P6/64 | ||
26 | + [ -1, 1, SPP, [ 1024, [ 3, 5, 7 ] ] ], | ||
27 | + [ -1, 3, C3, [ 1024, False ] ], # 11 | ||
28 | + ] | ||
29 | + | ||
30 | +# YOLOv5 head | ||
31 | +head: | ||
32 | + [ [ -1, 1, Conv, [ 768, 1, 1 ] ], | ||
33 | + [ -1, 1, nn.Upsample, [ None, 2, 'nearest' ] ], | ||
34 | + [ [ -1, 8 ], 1, Concat, [ 1 ] ], # cat backbone P5 | ||
35 | + [ -1, 3, C3, [ 768, False ] ], # 15 | ||
36 | + | ||
37 | + [ -1, 1, Conv, [ 512, 1, 1 ] ], | ||
38 | + [ -1, 1, nn.Upsample, [ None, 2, 'nearest' ] ], | ||
39 | + [ [ -1, 6 ], 1, Concat, [ 1 ] ], # cat backbone P4 | ||
40 | + [ -1, 3, C3, [ 512, False ] ], # 19 | ||
41 | + | ||
42 | + [ -1, 1, Conv, [ 256, 1, 1 ] ], | ||
43 | + [ -1, 1, nn.Upsample, [ None, 2, 'nearest' ] ], | ||
44 | + [ [ -1, 4 ], 1, Concat, [ 1 ] ], # cat backbone P3 | ||
45 | + [ -1, 3, C3, [ 256, False ] ], # 23 (P3/8-small) | ||
46 | + | ||
47 | + [ -1, 1, Conv, [ 256, 3, 2 ] ], | ||
48 | + [ [ -1, 20 ], 1, Concat, [ 1 ] ], # cat head P4 | ||
49 | + [ -1, 3, C3, [ 512, False ] ], # 26 (P4/16-medium) | ||
50 | + | ||
51 | + [ -1, 1, Conv, [ 512, 3, 2 ] ], | ||
52 | + [ [ -1, 16 ], 1, Concat, [ 1 ] ], # cat head P5 | ||
53 | + [ -1, 3, C3, [ 768, False ] ], # 29 (P5/32-large) | ||
54 | + | ||
55 | + [ -1, 1, Conv, [ 768, 3, 2 ] ], | ||
56 | + [ [ -1, 12 ], 1, Concat, [ 1 ] ], # cat head P6 | ||
57 | + [ -1, 3, C3, [ 1024, False ] ], # 32 (P6/64-xlarge) | ||
58 | + | ||
59 | + [ [ 23, 26, 29, 32 ], 1, Detect, [ nc, anchors ] ], # Detect(P3, P4, P5, P6) | ||
60 | + ] |
YOLOv5/models/hub/yolov5s-transformer.yaml
0 → 100644
1 | +# parameters | ||
2 | +nc: 80 # number of classes | ||
3 | +depth_multiple: 0.33 # model depth multiple | ||
4 | +width_multiple: 0.50 # layer channel multiple | ||
5 | + | ||
6 | +# anchors | ||
7 | +anchors: | ||
8 | + - [10,13, 16,30, 33,23] # P3/8 | ||
9 | + - [30,61, 62,45, 59,119] # P4/16 | ||
10 | + - [116,90, 156,198, 373,326] # P5/32 | ||
11 | + | ||
12 | +# YOLOv5 backbone | ||
13 | +backbone: | ||
14 | + # [from, number, module, args] | ||
15 | + [[-1, 1, Focus, [64, 3]], # 0-P1/2 | ||
16 | + [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 | ||
17 | + [-1, 3, C3, [128]], | ||
18 | + [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 | ||
19 | + [-1, 9, C3, [256]], | ||
20 | + [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 | ||
21 | + [-1, 9, C3, [512]], | ||
22 | + [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32 | ||
23 | + [-1, 1, SPP, [1024, [5, 9, 13]]], | ||
24 | + [-1, 3, C3TR, [1024, False]], # 9 <-------- C3TR() Transformer module | ||
25 | + ] | ||
26 | + | ||
27 | +# YOLOv5 head | ||
28 | +head: | ||
29 | + [[-1, 1, Conv, [512, 1, 1]], | ||
30 | + [-1, 1, nn.Upsample, [None, 2, 'nearest']], | ||
31 | + [[-1, 6], 1, Concat, [1]], # cat backbone P4 | ||
32 | + [-1, 3, C3, [512, False]], # 13 | ||
33 | + | ||
34 | + [-1, 1, Conv, [256, 1, 1]], | ||
35 | + [-1, 1, nn.Upsample, [None, 2, 'nearest']], | ||
36 | + [[-1, 4], 1, Concat, [1]], # cat backbone P3 | ||
37 | + [-1, 3, C3, [256, False]], # 17 (P3/8-small) | ||
38 | + | ||
39 | + [-1, 1, Conv, [256, 3, 2]], | ||
40 | + [[-1, 14], 1, Concat, [1]], # cat head P4 | ||
41 | + [-1, 3, C3, [512, False]], # 20 (P4/16-medium) | ||
42 | + | ||
43 | + [-1, 1, Conv, [512, 3, 2]], | ||
44 | + [[-1, 10], 1, Concat, [1]], # cat head P5 | ||
45 | + [-1, 3, C3, [1024, False]], # 23 (P5/32-large) | ||
46 | + | ||
47 | + [[17, 20, 23], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5) | ||
48 | + ] |
YOLOv5/models/hub/yolov5s6.yaml
0 → 100644
1 | +# parameters | ||
2 | +nc: 80 # number of classes | ||
3 | +depth_multiple: 0.33 # model depth multiple | ||
4 | +width_multiple: 0.50 # layer channel multiple | ||
5 | + | ||
6 | +# anchors | ||
7 | +anchors: | ||
8 | + - [ 19,27, 44,40, 38,94 ] # P3/8 | ||
9 | + - [ 96,68, 86,152, 180,137 ] # P4/16 | ||
10 | + - [ 140,301, 303,264, 238,542 ] # P5/32 | ||
11 | + - [ 436,615, 739,380, 925,792 ] # P6/64 | ||
12 | + | ||
13 | +# YOLOv5 backbone | ||
14 | +backbone: | ||
15 | + # [from, number, module, args] | ||
16 | + [ [ -1, 1, Focus, [ 64, 3 ] ], # 0-P1/2 | ||
17 | + [ -1, 1, Conv, [ 128, 3, 2 ] ], # 1-P2/4 | ||
18 | + [ -1, 3, C3, [ 128 ] ], | ||
19 | + [ -1, 1, Conv, [ 256, 3, 2 ] ], # 3-P3/8 | ||
20 | + [ -1, 9, C3, [ 256 ] ], | ||
21 | + [ -1, 1, Conv, [ 512, 3, 2 ] ], # 5-P4/16 | ||
22 | + [ -1, 9, C3, [ 512 ] ], | ||
23 | + [ -1, 1, Conv, [ 768, 3, 2 ] ], # 7-P5/32 | ||
24 | + [ -1, 3, C3, [ 768 ] ], | ||
25 | + [ -1, 1, Conv, [ 1024, 3, 2 ] ], # 9-P6/64 | ||
26 | + [ -1, 1, SPP, [ 1024, [ 3, 5, 7 ] ] ], | ||
27 | + [ -1, 3, C3, [ 1024, False ] ], # 11 | ||
28 | + ] | ||
29 | + | ||
30 | +# YOLOv5 head | ||
31 | +head: | ||
32 | + [ [ -1, 1, Conv, [ 768, 1, 1 ] ], | ||
33 | + [ -1, 1, nn.Upsample, [ None, 2, 'nearest' ] ], | ||
34 | + [ [ -1, 8 ], 1, Concat, [ 1 ] ], # cat backbone P5 | ||
35 | + [ -1, 3, C3, [ 768, False ] ], # 15 | ||
36 | + | ||
37 | + [ -1, 1, Conv, [ 512, 1, 1 ] ], | ||
38 | + [ -1, 1, nn.Upsample, [ None, 2, 'nearest' ] ], | ||
39 | + [ [ -1, 6 ], 1, Concat, [ 1 ] ], # cat backbone P4 | ||
40 | + [ -1, 3, C3, [ 512, False ] ], # 19 | ||
41 | + | ||
42 | + [ -1, 1, Conv, [ 256, 1, 1 ] ], | ||
43 | + [ -1, 1, nn.Upsample, [ None, 2, 'nearest' ] ], | ||
44 | + [ [ -1, 4 ], 1, Concat, [ 1 ] ], # cat backbone P3 | ||
45 | + [ -1, 3, C3, [ 256, False ] ], # 23 (P3/8-small) | ||
46 | + | ||
47 | + [ -1, 1, Conv, [ 256, 3, 2 ] ], | ||
48 | + [ [ -1, 20 ], 1, Concat, [ 1 ] ], # cat head P4 | ||
49 | + [ -1, 3, C3, [ 512, False ] ], # 26 (P4/16-medium) | ||
50 | + | ||
51 | + [ -1, 1, Conv, [ 512, 3, 2 ] ], | ||
52 | + [ [ -1, 16 ], 1, Concat, [ 1 ] ], # cat head P5 | ||
53 | + [ -1, 3, C3, [ 768, False ] ], # 29 (P5/32-large) | ||
54 | + | ||
55 | + [ -1, 1, Conv, [ 768, 3, 2 ] ], | ||
56 | + [ [ -1, 12 ], 1, Concat, [ 1 ] ], # cat head P6 | ||
57 | + [ -1, 3, C3, [ 1024, False ] ], # 32 (P6/64-xlarge) | ||
58 | + | ||
59 | + [ [ 23, 26, 29, 32 ], 1, Detect, [ nc, anchors ] ], # Detect(P3, P4, P5, P6) | ||
60 | + ] |
YOLOv5/models/hub/yolov5x6.yaml
0 → 100644
1 | +# parameters | ||
2 | +nc: 80 # number of classes | ||
3 | +depth_multiple: 1.33 # model depth multiple | ||
4 | +width_multiple: 1.25 # layer channel multiple | ||
5 | + | ||
6 | +# anchors | ||
7 | +anchors: | ||
8 | + - [ 19,27, 44,40, 38,94 ] # P3/8 | ||
9 | + - [ 96,68, 86,152, 180,137 ] # P4/16 | ||
10 | + - [ 140,301, 303,264, 238,542 ] # P5/32 | ||
11 | + - [ 436,615, 739,380, 925,792 ] # P6/64 | ||
12 | + | ||
13 | +# YOLOv5 backbone | ||
14 | +backbone: | ||
15 | + # [from, number, module, args] | ||
16 | + [ [ -1, 1, Focus, [ 64, 3 ] ], # 0-P1/2 | ||
17 | + [ -1, 1, Conv, [ 128, 3, 2 ] ], # 1-P2/4 | ||
18 | + [ -1, 3, C3, [ 128 ] ], | ||
19 | + [ -1, 1, Conv, [ 256, 3, 2 ] ], # 3-P3/8 | ||
20 | + [ -1, 9, C3, [ 256 ] ], | ||
21 | + [ -1, 1, Conv, [ 512, 3, 2 ] ], # 5-P4/16 | ||
22 | + [ -1, 9, C3, [ 512 ] ], | ||
23 | + [ -1, 1, Conv, [ 768, 3, 2 ] ], # 7-P5/32 | ||
24 | + [ -1, 3, C3, [ 768 ] ], | ||
25 | + [ -1, 1, Conv, [ 1024, 3, 2 ] ], # 9-P6/64 | ||
26 | + [ -1, 1, SPP, [ 1024, [ 3, 5, 7 ] ] ], | ||
27 | + [ -1, 3, C3, [ 1024, False ] ], # 11 | ||
28 | + ] | ||
29 | + | ||
30 | +# YOLOv5 head | ||
31 | +head: | ||
32 | + [ [ -1, 1, Conv, [ 768, 1, 1 ] ], | ||
33 | + [ -1, 1, nn.Upsample, [ None, 2, 'nearest' ] ], | ||
34 | + [ [ -1, 8 ], 1, Concat, [ 1 ] ], # cat backbone P5 | ||
35 | + [ -1, 3, C3, [ 768, False ] ], # 15 | ||
36 | + | ||
37 | + [ -1, 1, Conv, [ 512, 1, 1 ] ], | ||
38 | + [ -1, 1, nn.Upsample, [ None, 2, 'nearest' ] ], | ||
39 | + [ [ -1, 6 ], 1, Concat, [ 1 ] ], # cat backbone P4 | ||
40 | + [ -1, 3, C3, [ 512, False ] ], # 19 | ||
41 | + | ||
42 | + [ -1, 1, Conv, [ 256, 1, 1 ] ], | ||
43 | + [ -1, 1, nn.Upsample, [ None, 2, 'nearest' ] ], | ||
44 | + [ [ -1, 4 ], 1, Concat, [ 1 ] ], # cat backbone P3 | ||
45 | + [ -1, 3, C3, [ 256, False ] ], # 23 (P3/8-small) | ||
46 | + | ||
47 | + [ -1, 1, Conv, [ 256, 3, 2 ] ], | ||
48 | + [ [ -1, 20 ], 1, Concat, [ 1 ] ], # cat head P4 | ||
49 | + [ -1, 3, C3, [ 512, False ] ], # 26 (P4/16-medium) | ||
50 | + | ||
51 | + [ -1, 1, Conv, [ 512, 3, 2 ] ], | ||
52 | + [ [ -1, 16 ], 1, Concat, [ 1 ] ], # cat head P5 | ||
53 | + [ -1, 3, C3, [ 768, False ] ], # 29 (P5/32-large) | ||
54 | + | ||
55 | + [ -1, 1, Conv, [ 768, 3, 2 ] ], | ||
56 | + [ [ -1, 12 ], 1, Concat, [ 1 ] ], # cat head P6 | ||
57 | + [ -1, 3, C3, [ 1024, False ] ], # 32 (P6/64-xlarge) | ||
58 | + | ||
59 | + [ [ 23, 26, 29, 32 ], 1, Detect, [ nc, anchors ] ], # Detect(P3, P4, P5, P6) | ||
60 | + ] |
YOLOv5/models/yolo.py
0 → 100644
This diff is collapsed. Click to expand it.
YOLOv5/models/yolov5l.yaml
0 → 100644
1 | +# parameters | ||
2 | +nc: 80 # number of classes | ||
3 | +depth_multiple: 1.0 # model depth multiple | ||
4 | +width_multiple: 1.0 # layer channel multiple | ||
5 | + | ||
6 | +# anchors | ||
7 | +anchors: | ||
8 | + - [10,13, 16,30, 33,23] # P3/8 | ||
9 | + - [30,61, 62,45, 59,119] # P4/16 | ||
10 | + - [116,90, 156,198, 373,326] # P5/32 | ||
11 | + | ||
12 | +# YOLOv5 backbone | ||
13 | +backbone: | ||
14 | + # [from, number, module, args] | ||
15 | + [[-1, 1, Focus, [64, 3]], # 0-P1/2 | ||
16 | + [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 | ||
17 | + [-1, 3, C3, [128]], | ||
18 | + [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 | ||
19 | + [-1, 9, C3, [256]], | ||
20 | + [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 | ||
21 | + [-1, 9, C3, [512]], | ||
22 | + [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32 | ||
23 | + [-1, 1, SPP, [1024, [5, 9, 13]]], | ||
24 | + [-1, 3, C3, [1024, False]], # 9 | ||
25 | + ] | ||
26 | + | ||
27 | +# YOLOv5 head | ||
28 | +head: | ||
29 | + [[-1, 1, Conv, [512, 1, 1]], | ||
30 | + [-1, 1, nn.Upsample, [None, 2, 'nearest']], | ||
31 | + [[-1, 6], 1, Concat, [1]], # cat backbone P4 | ||
32 | + [-1, 3, C3, [512, False]], # 13 | ||
33 | + | ||
34 | + [-1, 1, Conv, [256, 1, 1]], | ||
35 | + [-1, 1, nn.Upsample, [None, 2, 'nearest']], | ||
36 | + [[-1, 4], 1, Concat, [1]], # cat backbone P3 | ||
37 | + [-1, 3, C3, [256, False]], # 17 (P3/8-small) | ||
38 | + | ||
39 | + [-1, 1, Conv, [256, 3, 2]], | ||
40 | + [[-1, 14], 1, Concat, [1]], # cat head P4 | ||
41 | + [-1, 3, C3, [512, False]], # 20 (P4/16-medium) | ||
42 | + | ||
43 | + [-1, 1, Conv, [512, 3, 2]], | ||
44 | + [[-1, 10], 1, Concat, [1]], # cat head P5 | ||
45 | + [-1, 3, C3, [1024, False]], # 23 (P5/32-large) | ||
46 | + | ||
47 | + [[17, 20, 23], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5) | ||
48 | + ] |
YOLOv5/models/yolov5m.yaml
0 → 100644
1 | +# parameters | ||
2 | +nc: 80 # number of classes | ||
3 | +depth_multiple: 0.67 # model depth multiple | ||
4 | +width_multiple: 0.75 # layer channel multiple | ||
5 | + | ||
6 | +# anchors | ||
7 | +anchors: | ||
8 | + - [10,13, 16,30, 33,23] # P3/8 | ||
9 | + - [30,61, 62,45, 59,119] # P4/16 | ||
10 | + - [116,90, 156,198, 373,326] # P5/32 | ||
11 | + | ||
12 | +# YOLOv5 backbone | ||
13 | +backbone: | ||
14 | + # [from, number, module, args] | ||
15 | + [[-1, 1, Focus, [64, 3]], # 0-P1/2 | ||
16 | + [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 | ||
17 | + [-1, 3, C3, [128]], | ||
18 | + [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 | ||
19 | + [-1, 9, C3, [256]], | ||
20 | + [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 | ||
21 | + [-1, 9, C3, [512]], | ||
22 | + [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32 | ||
23 | + [-1, 1, SPP, [1024, [5, 9, 13]]], | ||
24 | + [-1, 3, C3, [1024, False]], # 9 | ||
25 | + ] | ||
26 | + | ||
27 | +# YOLOv5 head | ||
28 | +head: | ||
29 | + [[-1, 1, Conv, [512, 1, 1]], | ||
30 | + [-1, 1, nn.Upsample, [None, 2, 'nearest']], | ||
31 | + [[-1, 6], 1, Concat, [1]], # cat backbone P4 | ||
32 | + [-1, 3, C3, [512, False]], # 13 | ||
33 | + | ||
34 | + [-1, 1, Conv, [256, 1, 1]], | ||
35 | + [-1, 1, nn.Upsample, [None, 2, 'nearest']], | ||
36 | + [[-1, 4], 1, Concat, [1]], # cat backbone P3 | ||
37 | + [-1, 3, C3, [256, False]], # 17 (P3/8-small) | ||
38 | + | ||
39 | + [-1, 1, Conv, [256, 3, 2]], | ||
40 | + [[-1, 14], 1, Concat, [1]], # cat head P4 | ||
41 | + [-1, 3, C3, [512, False]], # 20 (P4/16-medium) | ||
42 | + | ||
43 | + [-1, 1, Conv, [512, 3, 2]], | ||
44 | + [[-1, 10], 1, Concat, [1]], # cat head P5 | ||
45 | + [-1, 3, C3, [1024, False]], # 23 (P5/32-large) | ||
46 | + | ||
47 | + [[17, 20, 23], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5) | ||
48 | + ] |
YOLOv5/models/yolov5s.yaml
0 → 100644
1 | +# parameters | ||
2 | +nc: 1 # number of classes | ||
3 | +depth_multiple: 0.33 # model depth multiple | ||
4 | +width_multiple: 0.50 # layer channel multiple | ||
5 | + | ||
6 | +# anchors | ||
7 | +anchors: | ||
8 | + - [10,13, 16,30, 33,23] # P3/8 | ||
9 | + - [30,61, 62,45, 59,119] # P4/16 | ||
10 | + - [116,90, 156,198, 373,326] # P5/32 | ||
11 | + | ||
12 | +# YOLOv5 backbone | ||
13 | +backbone: | ||
14 | + # [from, number, module, args] | ||
15 | + [[-1, 1, Focus, [64, 3]], # 0-P1/2 | ||
16 | + [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 | ||
17 | + [-1, 3, C3, [128]], | ||
18 | + [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 | ||
19 | + [-1, 9, C3, [256]], | ||
20 | + [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 | ||
21 | + [-1, 9, C3, [512]], | ||
22 | + [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32 | ||
23 | + [-1, 1, SPP, [1024, [5, 9, 13]]], | ||
24 | + [-1, 3, C3, [1024, False]], # 9 | ||
25 | + ] | ||
26 | + | ||
27 | +# YOLOv5 head | ||
28 | +head: | ||
29 | + [[-1, 1, Conv, [512, 1, 1]], | ||
30 | + [-1, 1, nn.Upsample, [None, 2, 'nearest']], | ||
31 | + [[-1, 6], 1, Concat, [1]], # cat backbone P4 | ||
32 | + [-1, 3, C3, [512, False]], # 13 | ||
33 | + | ||
34 | + [-1, 1, Conv, [256, 1, 1]], | ||
35 | + [-1, 1, nn.Upsample, [None, 2, 'nearest']], | ||
36 | + [[-1, 4], 1, Concat, [1]], # cat backbone P3 | ||
37 | + [-1, 3, C3, [256, False]], # 17 (P3/8-small) | ||
38 | + | ||
39 | + [-1, 1, Conv, [256, 3, 2]], | ||
40 | + [[-1, 14], 1, Concat, [1]], # cat head P4 | ||
41 | + [-1, 3, C3, [512, False]], # 20 (P4/16-medium) | ||
42 | + | ||
43 | + [-1, 1, Conv, [512, 3, 2]], | ||
44 | + [[-1, 10], 1, Concat, [1]], # cat head P5 | ||
45 | + [-1, 3, C3, [1024, False]], # 23 (P5/32-large) | ||
46 | + | ||
47 | + [[17, 20, 23], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5) | ||
48 | + ] |
YOLOv5/models/yolov5x.yaml
0 → 100644
1 | +# parameters | ||
2 | +nc: 80 # number of classes | ||
3 | +depth_multiple: 1.33 # model depth multiple | ||
4 | +width_multiple: 1.25 # layer channel multiple | ||
5 | + | ||
6 | +# anchors | ||
7 | +anchors: | ||
8 | + - [10,13, 16,30, 33,23] # P3/8 | ||
9 | + - [30,61, 62,45, 59,119] # P4/16 | ||
10 | + - [116,90, 156,198, 373,326] # P5/32 | ||
11 | + | ||
12 | +# YOLOv5 backbone | ||
13 | +backbone: | ||
14 | + # [from, number, module, args] | ||
15 | + [[-1, 1, Focus, [64, 3]], # 0-P1/2 | ||
16 | + [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 | ||
17 | + [-1, 3, C3, [128]], | ||
18 | + [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 | ||
19 | + [-1, 9, C3, [256]], | ||
20 | + [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 | ||
21 | + [-1, 9, C3, [512]], | ||
22 | + [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32 | ||
23 | + [-1, 1, SPP, [1024, [5, 9, 13]]], | ||
24 | + [-1, 3, C3, [1024, False]], # 9 | ||
25 | + ] | ||
26 | + | ||
27 | +# YOLOv5 head | ||
28 | +head: | ||
29 | + [[-1, 1, Conv, [512, 1, 1]], | ||
30 | + [-1, 1, nn.Upsample, [None, 2, 'nearest']], | ||
31 | + [[-1, 6], 1, Concat, [1]], # cat backbone P4 | ||
32 | + [-1, 3, C3, [512, False]], # 13 | ||
33 | + | ||
34 | + [-1, 1, Conv, [256, 1, 1]], | ||
35 | + [-1, 1, nn.Upsample, [None, 2, 'nearest']], | ||
36 | + [[-1, 4], 1, Concat, [1]], # cat backbone P3 | ||
37 | + [-1, 3, C3, [256, False]], # 17 (P3/8-small) | ||
38 | + | ||
39 | + [-1, 1, Conv, [256, 3, 2]], | ||
40 | + [[-1, 14], 1, Concat, [1]], # cat head P4 | ||
41 | + [-1, 3, C3, [512, False]], # 20 (P4/16-medium) | ||
42 | + | ||
43 | + [-1, 1, Conv, [512, 3, 2]], | ||
44 | + [[-1, 10], 1, Concat, [1]], # cat head P5 | ||
45 | + [-1, 3, C3, [1024, False]], # 23 (P5/32-large) | ||
46 | + | ||
47 | + [[17, 20, 23], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5) | ||
48 | + ] |
YOLOv5/requirements.txt
0 → 100644
1 | +# pip install -r requirements.txt | ||
2 | + | ||
3 | +# base ---------------------------------------- | ||
4 | +matplotlib>=3.2.2 | ||
5 | +numpy>=1.18.5 | ||
6 | +opencv-python>=4.1.2 | ||
7 | +Pillow | ||
8 | +PyYAML>=5.3.1 | ||
9 | +scipy>=1.4.1 | ||
10 | +torch>=1.7.0 | ||
11 | +torchvision>=0.8.1 | ||
12 | +tqdm>=4.41.0 | ||
13 | + | ||
14 | +# logging ------------------------------------- | ||
15 | +tensorboard>=2.4.1 | ||
16 | +# wandb | ||
17 | + | ||
18 | +# plotting ------------------------------------ | ||
19 | +seaborn>=0.11.0 | ||
20 | +pandas | ||
21 | + | ||
22 | +# export -------------------------------------- | ||
23 | +# coremltools>=4.1 | ||
24 | +# onnx>=1.9.0 | ||
25 | +# scikit-learn==0.19.2 # for coreml quantization | ||
26 | + | ||
27 | +# extras -------------------------------------- | ||
28 | +# Cython # for pycocotools https://github.com/cocodataset/cocoapi/issues/172 | ||
29 | +pycocotools>=2.0 # COCO mAP | ||
30 | +thop # FLOPS computation |
YOLOv5/test.py
0 → 100644
This diff is collapsed. Click to expand it.
YOLOv5/train.py
0 → 100644
This diff is collapsed. Click to expand it.
YOLOv5/tutorial.ipynb
0 → 100644
This diff could not be displayed because it is too large.
YOLOv5/utils/__init__.py
0 → 100644
File mode changed
YOLOv5/utils/activations.py
0 → 100644
1 | +# Activation functions | ||
2 | + | ||
3 | +import torch | ||
4 | +import torch.nn as nn | ||
5 | +import torch.nn.functional as F | ||
6 | + | ||
7 | + | ||
8 | +# SiLU https://arxiv.org/pdf/1606.08415.pdf ---------------------------------------------------------------------------- | ||
9 | +class SiLU(nn.Module): # export-friendly version of nn.SiLU() | ||
10 | + @staticmethod | ||
11 | + def forward(x): | ||
12 | + return x * torch.sigmoid(x) | ||
13 | + | ||
14 | + | ||
15 | +class Hardswish(nn.Module): # export-friendly version of nn.Hardswish() | ||
16 | + @staticmethod | ||
17 | + def forward(x): | ||
18 | + # return x * F.hardsigmoid(x) # for torchscript and CoreML | ||
19 | + return x * F.hardtanh(x + 3, 0., 6.) / 6. # for torchscript, CoreML and ONNX | ||
20 | + | ||
21 | + | ||
22 | +# Mish https://github.com/digantamisra98/Mish -------------------------------------------------------------------------- | ||
23 | +class Mish(nn.Module): | ||
24 | + @staticmethod | ||
25 | + def forward(x): | ||
26 | + return x * F.softplus(x).tanh() | ||
27 | + | ||
28 | + | ||
29 | +class MemoryEfficientMish(nn.Module): | ||
30 | + class F(torch.autograd.Function): | ||
31 | + @staticmethod | ||
32 | + def forward(ctx, x): | ||
33 | + ctx.save_for_backward(x) | ||
34 | + return x.mul(torch.tanh(F.softplus(x))) # x * tanh(ln(1 + exp(x))) | ||
35 | + | ||
36 | + @staticmethod | ||
37 | + def backward(ctx, grad_output): | ||
38 | + x = ctx.saved_tensors[0] | ||
39 | + sx = torch.sigmoid(x) | ||
40 | + fx = F.softplus(x).tanh() | ||
41 | + return grad_output * (fx + x * sx * (1 - fx * fx)) | ||
42 | + | ||
43 | + def forward(self, x): | ||
44 | + return self.F.apply(x) | ||
45 | + | ||
46 | + | ||
47 | +# FReLU https://arxiv.org/abs/2007.11824 ------------------------------------------------------------------------------- | ||
48 | +class FReLU(nn.Module): | ||
49 | + def __init__(self, c1, k=3): # ch_in, kernel | ||
50 | + super().__init__() | ||
51 | + self.conv = nn.Conv2d(c1, c1, k, 1, 1, groups=c1, bias=False) | ||
52 | + self.bn = nn.BatchNorm2d(c1) | ||
53 | + | ||
54 | + def forward(self, x): | ||
55 | + return torch.max(x, self.bn(self.conv(x))) | ||
56 | + | ||
57 | + | ||
58 | +# ACON https://arxiv.org/pdf/2009.04759.pdf ---------------------------------------------------------------------------- | ||
59 | +class AconC(nn.Module): | ||
60 | + r""" ACON activation (activate or not). | ||
61 | + AconC: (p1*x-p2*x) * sigmoid(beta*(p1*x-p2*x)) + p2*x, beta is a learnable parameter | ||
62 | + according to "Activate or Not: Learning Customized Activation" <https://arxiv.org/pdf/2009.04759.pdf>. | ||
63 | + """ | ||
64 | + | ||
65 | + def __init__(self, c1): | ||
66 | + super().__init__() | ||
67 | + self.p1 = nn.Parameter(torch.randn(1, c1, 1, 1)) | ||
68 | + self.p2 = nn.Parameter(torch.randn(1, c1, 1, 1)) | ||
69 | + self.beta = nn.Parameter(torch.ones(1, c1, 1, 1)) | ||
70 | + | ||
71 | + def forward(self, x): | ||
72 | + dpx = (self.p1 - self.p2) * x | ||
73 | + return dpx * torch.sigmoid(self.beta * dpx) + self.p2 * x | ||
74 | + | ||
75 | + | ||
76 | +class MetaAconC(nn.Module): | ||
77 | + r""" ACON activation (activate or not). | ||
78 | + MetaAconC: (p1*x-p2*x) * sigmoid(beta*(p1*x-p2*x)) + p2*x, beta is generated by a small network | ||
79 | + according to "Activate or Not: Learning Customized Activation" <https://arxiv.org/pdf/2009.04759.pdf>. | ||
80 | + """ | ||
81 | + | ||
82 | + def __init__(self, c1, k=1, s=1, r=16): # ch_in, kernel, stride, r | ||
83 | + super().__init__() | ||
84 | + c2 = max(r, c1 // r) | ||
85 | + self.p1 = nn.Parameter(torch.randn(1, c1, 1, 1)) | ||
86 | + self.p2 = nn.Parameter(torch.randn(1, c1, 1, 1)) | ||
87 | + self.fc1 = nn.Conv2d(c1, c2, k, s, bias=True) | ||
88 | + self.fc2 = nn.Conv2d(c2, c1, k, s, bias=True) | ||
89 | + # self.bn1 = nn.BatchNorm2d(c2) | ||
90 | + # self.bn2 = nn.BatchNorm2d(c1) | ||
91 | + | ||
92 | + def forward(self, x): | ||
93 | + y = x.mean(dim=2, keepdims=True).mean(dim=3, keepdims=True) | ||
94 | + # batch-size 1 bug/instabilities https://github.com/ultralytics/yolov5/issues/2891 | ||
95 | + # beta = torch.sigmoid(self.bn2(self.fc2(self.bn1(self.fc1(y))))) # bug/unstable | ||
96 | + beta = torch.sigmoid(self.fc2(self.fc1(y))) # bug patch BN layers removed | ||
97 | + dpx = (self.p1 - self.p2) * x | ||
98 | + return dpx * torch.sigmoid(beta * dpx) + self.p2 * x |
YOLOv5/utils/autoanchor.py
0 → 100644
1 | +# Auto-anchor utils | ||
2 | + | ||
3 | +import numpy as np | ||
4 | +import torch | ||
5 | +import yaml | ||
6 | +from tqdm import tqdm | ||
7 | + | ||
8 | +from utils.general import colorstr | ||
9 | + | ||
10 | + | ||
11 | +def check_anchor_order(m): | ||
12 | + # Check anchor order against stride order for YOLOv5 Detect() module m, and correct if necessary | ||
13 | + a = m.anchor_grid.prod(-1).view(-1) # anchor area | ||
14 | + da = a[-1] - a[0] # delta a | ||
15 | + ds = m.stride[-1] - m.stride[0] # delta s | ||
16 | + if da.sign() != ds.sign(): # same order | ||
17 | + print('Reversing anchor order') | ||
18 | + m.anchors[:] = m.anchors.flip(0) | ||
19 | + m.anchor_grid[:] = m.anchor_grid.flip(0) | ||
20 | + | ||
21 | + | ||
22 | +def check_anchors(dataset, model, thr=4.0, imgsz=640): | ||
23 | + # Check anchor fit to data, recompute if necessary | ||
24 | + prefix = colorstr('autoanchor: ') | ||
25 | + print(f'\n{prefix}Analyzing anchors... ', end='') | ||
26 | + m = model.module.model[-1] if hasattr(model, 'module') else model.model[-1] # Detect() | ||
27 | + shapes = imgsz * dataset.shapes / dataset.shapes.max(1, keepdims=True) | ||
28 | + scale = np.random.uniform(0.9, 1.1, size=(shapes.shape[0], 1)) # augment scale | ||
29 | + wh = torch.tensor(np.concatenate([l[:, 3:5] * s for s, l in zip(shapes * scale, dataset.labels)])).float() # wh | ||
30 | + | ||
31 | + def metric(k): # compute metric | ||
32 | + r = wh[:, None] / k[None] | ||
33 | + x = torch.min(r, 1. / r).min(2)[0] # ratio metric | ||
34 | + best = x.max(1)[0] # best_x | ||
35 | + aat = (x > 1. / thr).float().sum(1).mean() # anchors above threshold | ||
36 | + bpr = (best > 1. / thr).float().mean() # best possible recall | ||
37 | + return bpr, aat | ||
38 | + | ||
39 | + anchors = m.anchor_grid.clone().cpu().view(-1, 2) # current anchors | ||
40 | + bpr, aat = metric(anchors) | ||
41 | + print(f'anchors/target = {aat:.2f}, Best Possible Recall (BPR) = {bpr:.4f}', end='') | ||
42 | + if bpr < 0.98: # threshold to recompute | ||
43 | + print('. Attempting to improve anchors, please wait...') | ||
44 | + na = m.anchor_grid.numel() // 2 # number of anchors | ||
45 | + try: | ||
46 | + anchors = kmean_anchors(dataset, n=na, img_size=imgsz, thr=thr, gen=1000, verbose=False) | ||
47 | + except Exception as e: | ||
48 | + print(f'{prefix}ERROR: {e}') | ||
49 | + new_bpr = metric(anchors)[0] | ||
50 | + if new_bpr > bpr: # replace anchors | ||
51 | + anchors = torch.tensor(anchors, device=m.anchors.device).type_as(m.anchors) | ||
52 | + m.anchor_grid[:] = anchors.clone().view_as(m.anchor_grid) # for inference | ||
53 | + m.anchors[:] = anchors.clone().view_as(m.anchors) / m.stride.to(m.anchors.device).view(-1, 1, 1) # loss | ||
54 | + check_anchor_order(m) | ||
55 | + print(f'{prefix}New anchors saved to model. Update model *.yaml to use these anchors in the future.') | ||
56 | + else: | ||
57 | + print(f'{prefix}Original anchors better than new anchors. Proceeding with original anchors.') | ||
58 | + print('') # newline | ||
59 | + | ||
60 | + | ||
61 | +def kmean_anchors(path='./data/coco128.yaml', n=9, img_size=640, thr=4.0, gen=1000, verbose=True): | ||
62 | + """ Creates kmeans-evolved anchors from training dataset | ||
63 | + | ||
64 | + Arguments: | ||
65 | + path: path to dataset *.yaml, or a loaded dataset | ||
66 | + n: number of anchors | ||
67 | + img_size: image size used for training | ||
68 | + thr: anchor-label wh ratio threshold hyperparameter hyp['anchor_t'] used for training, default=4.0 | ||
69 | + gen: generations to evolve anchors using genetic algorithm | ||
70 | + verbose: print all results | ||
71 | + | ||
72 | + Return: | ||
73 | + k: kmeans evolved anchors | ||
74 | + | ||
75 | + Usage: | ||
76 | + from utils.autoanchor import *; _ = kmean_anchors() | ||
77 | + """ | ||
78 | + from scipy.cluster.vq import kmeans | ||
79 | + | ||
80 | + thr = 1. / thr | ||
81 | + prefix = colorstr('autoanchor: ') | ||
82 | + | ||
83 | + def metric(k, wh): # compute metrics | ||
84 | + r = wh[:, None] / k[None] | ||
85 | + x = torch.min(r, 1. / r).min(2)[0] # ratio metric | ||
86 | + # x = wh_iou(wh, torch.tensor(k)) # iou metric | ||
87 | + return x, x.max(1)[0] # x, best_x | ||
88 | + | ||
89 | + def anchor_fitness(k): # mutation fitness | ||
90 | + _, best = metric(torch.tensor(k, dtype=torch.float32), wh) | ||
91 | + return (best * (best > thr).float()).mean() # fitness | ||
92 | + | ||
93 | + def print_results(k): | ||
94 | + k = k[np.argsort(k.prod(1))] # sort small to large | ||
95 | + x, best = metric(k, wh0) | ||
96 | + bpr, aat = (best > thr).float().mean(), (x > thr).float().mean() * n # best possible recall, anch > thr | ||
97 | + print(f'{prefix}thr={thr:.2f}: {bpr:.4f} best possible recall, {aat:.2f} anchors past thr') | ||
98 | + print(f'{prefix}n={n}, img_size={img_size}, metric_all={x.mean():.3f}/{best.mean():.3f}-mean/best, ' | ||
99 | + f'past_thr={x[x > thr].mean():.3f}-mean: ', end='') | ||
100 | + for i, x in enumerate(k): | ||
101 | + print('%i,%i' % (round(x[0]), round(x[1])), end=', ' if i < len(k) - 1 else '\n') # use in *.cfg | ||
102 | + return k | ||
103 | + | ||
104 | + if isinstance(path, str): # *.yaml file | ||
105 | + with open(path) as f: | ||
106 | + data_dict = yaml.safe_load(f) # model dict | ||
107 | + from utils.datasets import LoadImagesAndLabels | ||
108 | + dataset = LoadImagesAndLabels(data_dict['train'], augment=True, rect=True) | ||
109 | + else: | ||
110 | + dataset = path # dataset | ||
111 | + | ||
112 | + # Get label wh | ||
113 | + shapes = img_size * dataset.shapes / dataset.shapes.max(1, keepdims=True) | ||
114 | + wh0 = np.concatenate([l[:, 3:5] * s for s, l in zip(shapes, dataset.labels)]) # wh | ||
115 | + | ||
116 | + # Filter | ||
117 | + i = (wh0 < 3.0).any(1).sum() | ||
118 | + if i: | ||
119 | + print(f'{prefix}WARNING: Extremely small objects found. {i} of {len(wh0)} labels are < 3 pixels in size.') | ||
120 | + wh = wh0[(wh0 >= 2.0).any(1)] # filter > 2 pixels | ||
121 | + # wh = wh * (np.random.rand(wh.shape[0], 1) * 0.9 + 0.1) # multiply by random scale 0-1 | ||
122 | + | ||
123 | + # Kmeans calculation | ||
124 | + print(f'{prefix}Running kmeans for {n} anchors on {len(wh)} points...') | ||
125 | + s = wh.std(0) # sigmas for whitening | ||
126 | + k, dist = kmeans(wh / s, n, iter=30) # points, mean distance | ||
127 | + assert len(k) == n, print(f'{prefix}ERROR: scipy.cluster.vq.kmeans requested {n} points but returned only {len(k)}') | ||
128 | + k *= s | ||
129 | + wh = torch.tensor(wh, dtype=torch.float32) # filtered | ||
130 | + wh0 = torch.tensor(wh0, dtype=torch.float32) # unfiltered | ||
131 | + k = print_results(k) | ||
132 | + | ||
133 | + # Plot | ||
134 | + # k, d = [None] * 20, [None] * 20 | ||
135 | + # for i in tqdm(range(1, 21)): | ||
136 | + # k[i-1], d[i-1] = kmeans(wh / s, i) # points, mean distance | ||
137 | + # fig, ax = plt.subplots(1, 2, figsize=(14, 7), tight_layout=True) | ||
138 | + # ax = ax.ravel() | ||
139 | + # ax[0].plot(np.arange(1, 21), np.array(d) ** 2, marker='.') | ||
140 | + # fig, ax = plt.subplots(1, 2, figsize=(14, 7)) # plot wh | ||
141 | + # ax[0].hist(wh[wh[:, 0]<100, 0],400) | ||
142 | + # ax[1].hist(wh[wh[:, 1]<100, 1],400) | ||
143 | + # fig.savefig('wh.png', dpi=200) | ||
144 | + | ||
145 | + # Evolve | ||
146 | + npr = np.random | ||
147 | + f, sh, mp, s = anchor_fitness(k), k.shape, 0.9, 0.1 # fitness, generations, mutation prob, sigma | ||
148 | + pbar = tqdm(range(gen), desc=f'{prefix}Evolving anchors with Genetic Algorithm:') # progress bar | ||
149 | + for _ in pbar: | ||
150 | + v = np.ones(sh) | ||
151 | + while (v == 1).all(): # mutate until a change occurs (prevent duplicates) | ||
152 | + v = ((npr.random(sh) < mp) * npr.random() * npr.randn(*sh) * s + 1).clip(0.3, 3.0) | ||
153 | + kg = (k.copy() * v).clip(min=2.0) | ||
154 | + fg = anchor_fitness(kg) | ||
155 | + if fg > f: | ||
156 | + f, k = fg, kg.copy() | ||
157 | + pbar.desc = f'{prefix}Evolving anchors with Genetic Algorithm: fitness = {f:.4f}' | ||
158 | + if verbose: | ||
159 | + print_results(k) | ||
160 | + | ||
161 | + return print_results(k) |
YOLOv5/utils/aws/__init__.py
0 → 100644
File mode changed
YOLOv5/utils/aws/mime.sh
0 → 100644
1 | +# AWS EC2 instance startup 'MIME' script https://aws.amazon.com/premiumsupport/knowledge-center/execute-user-data-ec2/ | ||
2 | +# This script will run on every instance restart, not only on first start | ||
3 | +# --- DO NOT COPY ABOVE COMMENTS WHEN PASTING INTO USERDATA --- | ||
4 | + | ||
5 | +Content-Type: multipart/mixed; boundary="//" | ||
6 | +MIME-Version: 1.0 | ||
7 | + | ||
8 | +--// | ||
9 | +Content-Type: text/cloud-config; charset="us-ascii" | ||
10 | +MIME-Version: 1.0 | ||
11 | +Content-Transfer-Encoding: 7bit | ||
12 | +Content-Disposition: attachment; filename="cloud-config.txt" | ||
13 | + | ||
14 | +#cloud-config | ||
15 | +cloud_final_modules: | ||
16 | +- [scripts-user, always] | ||
17 | + | ||
18 | +--// | ||
19 | +Content-Type: text/x-shellscript; charset="us-ascii" | ||
20 | +MIME-Version: 1.0 | ||
21 | +Content-Transfer-Encoding: 7bit | ||
22 | +Content-Disposition: attachment; filename="userdata.txt" | ||
23 | + | ||
24 | +#!/bin/bash | ||
25 | +# --- paste contents of userdata.sh here --- | ||
26 | +--// |
YOLOv5/utils/aws/resume.py
0 → 100644
1 | +# Resume all interrupted trainings in yolov5/ dir including DDP trainings | ||
2 | +# Usage: $ python utils/aws/resume.py | ||
3 | + | ||
4 | +import os | ||
5 | +import sys | ||
6 | +from pathlib import Path | ||
7 | + | ||
8 | +import torch | ||
9 | +import yaml | ||
10 | + | ||
11 | +sys.path.append('./') # to run '$ python *.py' files in subdirectories | ||
12 | + | ||
13 | +port = 0 # --master_port | ||
14 | +path = Path('').resolve() | ||
15 | +for last in path.rglob('*/**/last.pt'): | ||
16 | + ckpt = torch.load(last) | ||
17 | + if ckpt['optimizer'] is None: | ||
18 | + continue | ||
19 | + | ||
20 | + # Load opt.yaml | ||
21 | + with open(last.parent.parent / 'opt.yaml') as f: | ||
22 | + opt = yaml.safe_load(f) | ||
23 | + | ||
24 | + # Get device count | ||
25 | + d = opt['device'].split(',') # devices | ||
26 | + nd = len(d) # number of devices | ||
27 | + ddp = nd > 1 or (nd == 0 and torch.cuda.device_count() > 1) # distributed data parallel | ||
28 | + | ||
29 | + if ddp: # multi-GPU | ||
30 | + port += 1 | ||
31 | + cmd = f'python -m torch.distributed.launch --nproc_per_node {nd} --master_port {port} train.py --resume {last}' | ||
32 | + else: # single-GPU | ||
33 | + cmd = f'python train.py --resume {last}' | ||
34 | + | ||
35 | + cmd += ' > /dev/null 2>&1 &' # redirect output to dev/null and run in daemon thread | ||
36 | + print(cmd) | ||
37 | + os.system(cmd) |
YOLOv5/utils/aws/userdata.sh
0 → 100644
1 | +#!/bin/bash | ||
2 | +# AWS EC2 instance startup script https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/user-data.html | ||
3 | +# This script will run only once on first instance start (for a re-start script see mime.sh) | ||
4 | +# /home/ubuntu (ubuntu) or /home/ec2-user (amazon-linux) is working dir | ||
5 | +# Use >300 GB SSD | ||
6 | + | ||
7 | +cd home/ubuntu | ||
8 | +if [ ! -d yolov5 ]; then | ||
9 | + echo "Running first-time script." # install dependencies, download COCO, pull Docker | ||
10 | + git clone https://github.com/ultralytics/yolov5 -b master && sudo chmod -R 777 yolov5 | ||
11 | + cd yolov5 | ||
12 | + bash data/scripts/get_coco.sh && echo "Data done." & | ||
13 | + sudo docker pull ultralytics/yolov5:latest && echo "Docker done." & | ||
14 | + python -m pip install --upgrade pip && pip install -r requirements.txt && python detect.py && echo "Requirements done." & | ||
15 | + wait && echo "All tasks done." # finish background tasks | ||
16 | +else | ||
17 | + echo "Running re-start script." # resume interrupted runs | ||
18 | + i=0 | ||
19 | + list=$(sudo docker ps -qa) # container list i.e. $'one\ntwo\nthree\nfour' | ||
20 | + while IFS= read -r id; do | ||
21 | + ((i++)) | ||
22 | + echo "restarting container $i: $id" | ||
23 | + sudo docker start $id | ||
24 | + # sudo docker exec -it $id python train.py --resume # single-GPU | ||
25 | + sudo docker exec -d $id python utils/aws/resume.py # multi-scenario | ||
26 | + done <<<"$list" | ||
27 | +fi |
YOLOv5/utils/datasets.py
0 → 100644
This diff is collapsed. Click to expand it.
YOLOv5/utils/flask_rest_api/README.md
0 → 100644
1 | +# Flask REST API | ||
2 | +[REST](https://en.wikipedia.org/wiki/Representational_state_transfer) [API](https://en.wikipedia.org/wiki/API)s are commonly used to expose Machine Learning (ML) models to other services. This folder contains an example REST API created using Flask to expose the YOLOv5s model from [PyTorch Hub](https://pytorch.org/hub/ultralytics_yolov5/). | ||
3 | + | ||
4 | +## Requirements | ||
5 | + | ||
6 | +[Flask](https://palletsprojects.com/p/flask/) is required. Install with: | ||
7 | +```shell | ||
8 | +$ pip install Flask | ||
9 | +``` | ||
10 | + | ||
11 | +## Run | ||
12 | + | ||
13 | +After Flask installation run: | ||
14 | + | ||
15 | +```shell | ||
16 | +$ python3 restapi.py --port 5000 | ||
17 | +``` | ||
18 | + | ||
19 | +Then use [curl](https://curl.se/) to perform a request: | ||
20 | + | ||
21 | +```shell | ||
22 | +$ curl -X POST -F image=@zidane.jpg 'http://localhost:5000/v1/object-detection/yolov5s'` | ||
23 | +``` | ||
24 | + | ||
25 | +The model inference results are returned as a JSON response: | ||
26 | + | ||
27 | +```json | ||
28 | +[ | ||
29 | + { | ||
30 | + "class": 0, | ||
31 | + "confidence": 0.8900438547, | ||
32 | + "height": 0.9318675399, | ||
33 | + "name": "person", | ||
34 | + "width": 0.3264600933, | ||
35 | + "xcenter": 0.7438579798, | ||
36 | + "ycenter": 0.5207948685 | ||
37 | + }, | ||
38 | + { | ||
39 | + "class": 0, | ||
40 | + "confidence": 0.8440024257, | ||
41 | + "height": 0.7155083418, | ||
42 | + "name": "person", | ||
43 | + "width": 0.6546785235, | ||
44 | + "xcenter": 0.427829951, | ||
45 | + "ycenter": 0.6334488392 | ||
46 | + }, | ||
47 | + { | ||
48 | + "class": 27, | ||
49 | + "confidence": 0.3771208823, | ||
50 | + "height": 0.3902671337, | ||
51 | + "name": "tie", | ||
52 | + "width": 0.0696444362, | ||
53 | + "xcenter": 0.3675483763, | ||
54 | + "ycenter": 0.7991207838 | ||
55 | + }, | ||
56 | + { | ||
57 | + "class": 27, | ||
58 | + "confidence": 0.3527112305, | ||
59 | + "height": 0.1540903747, | ||
60 | + "name": "tie", | ||
61 | + "width": 0.0336618312, | ||
62 | + "xcenter": 0.7814827561, | ||
63 | + "ycenter": 0.5065554976 | ||
64 | + } | ||
65 | +] | ||
66 | +``` | ||
67 | + | ||
68 | +An example python script to perform inference using [requests](https://docs.python-requests.org/en/master/) is given in `example_request.py` |
1 | +"""Perform test request""" | ||
2 | +import pprint | ||
3 | + | ||
4 | +import requests | ||
5 | + | ||
6 | +DETECTION_URL = "http://localhost:5000/v1/object-detection/yolov5s" | ||
7 | +TEST_IMAGE = "zidane.jpg" | ||
8 | + | ||
9 | +image_data = open(TEST_IMAGE, "rb").read() | ||
10 | + | ||
11 | +response = requests.post(DETECTION_URL, files={"image": image_data}).json() | ||
12 | + | ||
13 | +pprint.pprint(response) |
YOLOv5/utils/flask_rest_api/restapi.py
0 → 100644
1 | +""" | ||
2 | +Run a rest API exposing the yolov5s object detection model | ||
3 | +""" | ||
4 | +import argparse | ||
5 | +import io | ||
6 | + | ||
7 | +import torch | ||
8 | +from PIL import Image | ||
9 | +from flask import Flask, request | ||
10 | + | ||
11 | +app = Flask(__name__) | ||
12 | + | ||
13 | +DETECTION_URL = "/v1/object-detection/yolov5s" | ||
14 | + | ||
15 | + | ||
16 | +@app.route(DETECTION_URL, methods=["POST"]) | ||
17 | +def predict(): | ||
18 | + if not request.method == "POST": | ||
19 | + return | ||
20 | + | ||
21 | + if request.files.get("image"): | ||
22 | + image_file = request.files["image"] | ||
23 | + image_bytes = image_file.read() | ||
24 | + | ||
25 | + img = Image.open(io.BytesIO(image_bytes)) | ||
26 | + | ||
27 | + results = model(img, size=640) # reduce size=320 for faster inference | ||
28 | + return results.pandas().xyxy[0].to_json(orient="records") | ||
29 | + | ||
30 | + | ||
31 | +if __name__ == "__main__": | ||
32 | + parser = argparse.ArgumentParser(description="Flask API exposing YOLOv5 model") | ||
33 | + parser.add_argument("--port", default=5000, type=int, help="port number") | ||
34 | + args = parser.parse_args() | ||
35 | + | ||
36 | + model = torch.hub.load("ultralytics/yolov5", "yolov5s", force_reload=True) # force_reload to recache | ||
37 | + app.run(host="0.0.0.0", port=args.port) # debug=True causes Restarting with stat |
YOLOv5/utils/general.py
0 → 100644
This diff is collapsed. Click to expand it.
YOLOv5/utils/google_app_engine/Dockerfile
0 → 100644
1 | +FROM gcr.io/google-appengine/python | ||
2 | + | ||
3 | +# Create a virtualenv for dependencies. This isolates these packages from | ||
4 | +# system-level packages. | ||
5 | +# Use -p python3 or -p python3.7 to select python version. Default is version 2. | ||
6 | +RUN virtualenv /env -p python3 | ||
7 | + | ||
8 | +# Setting these environment variables are the same as running | ||
9 | +# source /env/bin/activate. | ||
10 | +ENV VIRTUAL_ENV /env | ||
11 | +ENV PATH /env/bin:$PATH | ||
12 | + | ||
13 | +RUN apt-get update && apt-get install -y python-opencv | ||
14 | + | ||
15 | +# Copy the application's requirements.txt and run pip to install all | ||
16 | +# dependencies into the virtualenv. | ||
17 | +ADD requirements.txt /app/requirements.txt | ||
18 | +RUN pip install -r /app/requirements.txt | ||
19 | + | ||
20 | +# Add the application source code. | ||
21 | +ADD . /app | ||
22 | + | ||
23 | +# Run a WSGI server to serve the application. gunicorn must be declared as | ||
24 | +# a dependency in requirements.txt. | ||
25 | +CMD gunicorn -b :$PORT main:app |
YOLOv5/utils/google_app_engine/app.yaml
0 → 100644
YOLOv5/utils/google_utils.py
0 → 100644
1 | +# Google utils: https://cloud.google.com/storage/docs/reference/libraries | ||
2 | + | ||
3 | +import os | ||
4 | +import platform | ||
5 | +import subprocess | ||
6 | +import time | ||
7 | +from pathlib import Path | ||
8 | + | ||
9 | +import requests | ||
10 | +import torch | ||
11 | + | ||
12 | + | ||
13 | +def gsutil_getsize(url=''): | ||
14 | + # gs://bucket/file size https://cloud.google.com/storage/docs/gsutil/commands/du | ||
15 | + s = subprocess.check_output(f'gsutil du {url}', shell=True).decode('utf-8') | ||
16 | + return eval(s.split(' ')[0]) if len(s) else 0 # bytes | ||
17 | + | ||
18 | + | ||
19 | +def safe_download(file, url, url2=None, min_bytes=1E0, error_msg=''): | ||
20 | + # Attempts to download file from url or url2, checks and removes incomplete downloads < min_bytes | ||
21 | + file = Path(file) | ||
22 | + try: # GitHub | ||
23 | + print(f'Downloading {url} to {file}...') | ||
24 | + torch.hub.download_url_to_file(url, str(file)) | ||
25 | + assert file.exists() and file.stat().st_size > min_bytes # check | ||
26 | + except Exception as e: # GCP | ||
27 | + file.unlink(missing_ok=True) # remove partial downloads | ||
28 | + print(f'Download error: {e}\nRe-attempting {url2 or url} to {file}...') | ||
29 | + os.system(f"curl -L '{url2 or url}' -o '{file}' --retry 3 -C -") # curl download, retry and resume on fail | ||
30 | + finally: | ||
31 | + if not file.exists() or file.stat().st_size < min_bytes: # check | ||
32 | + file.unlink(missing_ok=True) # remove partial downloads | ||
33 | + print(f'ERROR: Download failure: {error_msg or url}') | ||
34 | + print('') | ||
35 | + | ||
36 | + | ||
37 | +def attempt_download(file, repo='ultralytics/yolov5'): | ||
38 | + # Attempt file download if does not exist | ||
39 | + file = Path(str(file).strip().replace("'", '')) | ||
40 | + | ||
41 | + if not file.exists(): | ||
42 | + # URL specified | ||
43 | + name = file.name | ||
44 | + if str(file).startswith(('http:/', 'https:/')): # download | ||
45 | + url = str(file).replace(':/', '://') # Pathlib turns :// -> :/ | ||
46 | + safe_download(file=name, url=url, min_bytes=1E5) | ||
47 | + return name | ||
48 | + | ||
49 | + # GitHub assets | ||
50 | + file.parent.mkdir(parents=True, exist_ok=True) # make parent dir (if required) | ||
51 | + try: | ||
52 | + response = requests.get(f'https://api.github.com/repos/{repo}/releases/latest').json() # github api | ||
53 | + assets = [x['name'] for x in response['assets']] # release assets, i.e. ['yolov5s.pt', 'yolov5m.pt', ...] | ||
54 | + tag = response['tag_name'] # i.e. 'v1.0' | ||
55 | + except: # fallback plan | ||
56 | + assets = ['yolov5s.pt', 'yolov5m.pt', 'yolov5l.pt', 'yolov5x.pt', | ||
57 | + 'yolov5s6.pt', 'yolov5m6.pt', 'yolov5l6.pt', 'yolov5x6.pt'] | ||
58 | + try: | ||
59 | + tag = subprocess.check_output('git tag', shell=True, stderr=subprocess.STDOUT).decode().split()[-1] | ||
60 | + except: | ||
61 | + tag = 'v5.0' # current release | ||
62 | + | ||
63 | + if name in assets: | ||
64 | + safe_download(file, | ||
65 | + url=f'https://github.com/{repo}/releases/download/{tag}/{name}', | ||
66 | + # url2=f'https://storage.googleapis.com/{repo}/ckpt/{name}', # backup url (optional) | ||
67 | + min_bytes=1E5, | ||
68 | + error_msg=f'{file} missing, try downloading from https://github.com/{repo}/releases/') | ||
69 | + | ||
70 | + return str(file) | ||
71 | + | ||
72 | + | ||
73 | +def gdrive_download(id='16TiPfZj7htmTyhntwcZyEEAejOUxuT6m', file='tmp.zip'): | ||
74 | + # Downloads a file from Google Drive. from yolov5.utils.google_utils import *; gdrive_download() | ||
75 | + t = time.time() | ||
76 | + file = Path(file) | ||
77 | + cookie = Path('cookie') # gdrive cookie | ||
78 | + print(f'Downloading https://drive.google.com/uc?export=download&id={id} as {file}... ', end='') | ||
79 | + file.unlink(missing_ok=True) # remove existing file | ||
80 | + cookie.unlink(missing_ok=True) # remove existing cookie | ||
81 | + | ||
82 | + # Attempt file download | ||
83 | + out = "NUL" if platform.system() == "Windows" else "/dev/null" | ||
84 | + os.system(f'curl -c ./cookie -s -L "drive.google.com/uc?export=download&id={id}" > {out}') | ||
85 | + if os.path.exists('cookie'): # large file | ||
86 | + s = f'curl -Lb ./cookie "drive.google.com/uc?export=download&confirm={get_token()}&id={id}" -o {file}' | ||
87 | + else: # small file | ||
88 | + s = f'curl -s -L -o {file} "drive.google.com/uc?export=download&id={id}"' | ||
89 | + r = os.system(s) # execute, capture return | ||
90 | + cookie.unlink(missing_ok=True) # remove existing cookie | ||
91 | + | ||
92 | + # Error check | ||
93 | + if r != 0: | ||
94 | + file.unlink(missing_ok=True) # remove partial | ||
95 | + print('Download error ') # raise Exception('Download error') | ||
96 | + return r | ||
97 | + | ||
98 | + # Unzip if archive | ||
99 | + if file.suffix == '.zip': | ||
100 | + print('unzipping... ', end='') | ||
101 | + os.system(f'unzip -q {file}') # unzip | ||
102 | + file.unlink() # remove zip to free space | ||
103 | + | ||
104 | + print(f'Done ({time.time() - t:.1f}s)') | ||
105 | + return r | ||
106 | + | ||
107 | + | ||
108 | +def get_token(cookie="./cookie"): | ||
109 | + with open(cookie) as f: | ||
110 | + for line in f: | ||
111 | + if "download" in line: | ||
112 | + return line.split()[-1] | ||
113 | + return "" | ||
114 | + | ||
115 | +# def upload_blob(bucket_name, source_file_name, destination_blob_name): | ||
116 | +# # Uploads a file to a bucket | ||
117 | +# # https://cloud.google.com/storage/docs/uploading-objects#storage-upload-object-python | ||
118 | +# | ||
119 | +# storage_client = storage.Client() | ||
120 | +# bucket = storage_client.get_bucket(bucket_name) | ||
121 | +# blob = bucket.blob(destination_blob_name) | ||
122 | +# | ||
123 | +# blob.upload_from_filename(source_file_name) | ||
124 | +# | ||
125 | +# print('File {} uploaded to {}.'.format( | ||
126 | +# source_file_name, | ||
127 | +# destination_blob_name)) | ||
128 | +# | ||
129 | +# | ||
130 | +# def download_blob(bucket_name, source_blob_name, destination_file_name): | ||
131 | +# # Uploads a blob from a bucket | ||
132 | +# storage_client = storage.Client() | ||
133 | +# bucket = storage_client.get_bucket(bucket_name) | ||
134 | +# blob = bucket.blob(source_blob_name) | ||
135 | +# | ||
136 | +# blob.download_to_filename(destination_file_name) | ||
137 | +# | ||
138 | +# print('Blob {} downloaded to {}.'.format( | ||
139 | +# source_blob_name, | ||
140 | +# destination_file_name)) |
YOLOv5/utils/loss.py
0 → 100644
1 | +# Loss functions | ||
2 | + | ||
3 | +import torch | ||
4 | +import torch.nn as nn | ||
5 | + | ||
6 | +from utils.general import bbox_iou | ||
7 | +from utils.torch_utils import is_parallel | ||
8 | + | ||
9 | + | ||
10 | +def smooth_BCE(eps=0.1): # https://github.com/ultralytics/yolov3/issues/238#issuecomment-598028441 | ||
11 | + # return positive, negative label smoothing BCE targets | ||
12 | + return 1.0 - 0.5 * eps, 0.5 * eps | ||
13 | + | ||
14 | + | ||
15 | +class BCEBlurWithLogitsLoss(nn.Module): | ||
16 | + # BCEwithLogitLoss() with reduced missing label effects. | ||
17 | + def __init__(self, alpha=0.05): | ||
18 | + super(BCEBlurWithLogitsLoss, self).__init__() | ||
19 | + self.loss_fcn = nn.BCEWithLogitsLoss(reduction='none') # must be nn.BCEWithLogitsLoss() | ||
20 | + self.alpha = alpha | ||
21 | + | ||
22 | + def forward(self, pred, true): | ||
23 | + loss = self.loss_fcn(pred, true) | ||
24 | + pred = torch.sigmoid(pred) # prob from logits | ||
25 | + dx = pred - true # reduce only missing label effects | ||
26 | + # dx = (pred - true).abs() # reduce missing label and false label effects | ||
27 | + alpha_factor = 1 - torch.exp((dx - 1) / (self.alpha + 1e-4)) | ||
28 | + loss *= alpha_factor | ||
29 | + return loss.mean() | ||
30 | + | ||
31 | + | ||
32 | +class FocalLoss(nn.Module): | ||
33 | + # Wraps focal loss around existing loss_fcn(), i.e. criteria = FocalLoss(nn.BCEWithLogitsLoss(), gamma=1.5) | ||
34 | + def __init__(self, loss_fcn, gamma=1.5, alpha=0.25): | ||
35 | + super(FocalLoss, self).__init__() | ||
36 | + self.loss_fcn = loss_fcn # must be nn.BCEWithLogitsLoss() | ||
37 | + self.gamma = gamma | ||
38 | + self.alpha = alpha | ||
39 | + self.reduction = loss_fcn.reduction | ||
40 | + self.loss_fcn.reduction = 'none' # required to apply FL to each element | ||
41 | + | ||
42 | + def forward(self, pred, true): | ||
43 | + loss = self.loss_fcn(pred, true) | ||
44 | + # p_t = torch.exp(-loss) | ||
45 | + # loss *= self.alpha * (1.000001 - p_t) ** self.gamma # non-zero power for gradient stability | ||
46 | + | ||
47 | + # TF implementation https://github.com/tensorflow/addons/blob/v0.7.1/tensorflow_addons/losses/focal_loss.py | ||
48 | + pred_prob = torch.sigmoid(pred) # prob from logits | ||
49 | + p_t = true * pred_prob + (1 - true) * (1 - pred_prob) | ||
50 | + alpha_factor = true * self.alpha + (1 - true) * (1 - self.alpha) | ||
51 | + modulating_factor = (1.0 - p_t) ** self.gamma | ||
52 | + loss *= alpha_factor * modulating_factor | ||
53 | + | ||
54 | + if self.reduction == 'mean': | ||
55 | + return loss.mean() | ||
56 | + elif self.reduction == 'sum': | ||
57 | + return loss.sum() | ||
58 | + else: # 'none' | ||
59 | + return loss | ||
60 | + | ||
61 | + | ||
62 | +class QFocalLoss(nn.Module): | ||
63 | + # Wraps Quality focal loss around existing loss_fcn(), i.e. criteria = FocalLoss(nn.BCEWithLogitsLoss(), gamma=1.5) | ||
64 | + def __init__(self, loss_fcn, gamma=1.5, alpha=0.25): | ||
65 | + super(QFocalLoss, self).__init__() | ||
66 | + self.loss_fcn = loss_fcn # must be nn.BCEWithLogitsLoss() | ||
67 | + self.gamma = gamma | ||
68 | + self.alpha = alpha | ||
69 | + self.reduction = loss_fcn.reduction | ||
70 | + self.loss_fcn.reduction = 'none' # required to apply FL to each element | ||
71 | + | ||
72 | + def forward(self, pred, true): | ||
73 | + loss = self.loss_fcn(pred, true) | ||
74 | + | ||
75 | + pred_prob = torch.sigmoid(pred) # prob from logits | ||
76 | + alpha_factor = true * self.alpha + (1 - true) * (1 - self.alpha) | ||
77 | + modulating_factor = torch.abs(true - pred_prob) ** self.gamma | ||
78 | + loss *= alpha_factor * modulating_factor | ||
79 | + | ||
80 | + if self.reduction == 'mean': | ||
81 | + return loss.mean() | ||
82 | + elif self.reduction == 'sum': | ||
83 | + return loss.sum() | ||
84 | + else: # 'none' | ||
85 | + return loss | ||
86 | + | ||
87 | + | ||
88 | +class ComputeLoss: | ||
89 | + # Compute losses | ||
90 | + def __init__(self, model, autobalance=False): | ||
91 | + super(ComputeLoss, self).__init__() | ||
92 | + device = next(model.parameters()).device # get model device | ||
93 | + h = model.hyp # hyperparameters | ||
94 | + | ||
95 | + # Define criteria | ||
96 | + BCEcls = nn.BCEWithLogitsLoss(pos_weight=torch.tensor([h['cls_pw']], device=device)) | ||
97 | + BCEobj = nn.BCEWithLogitsLoss(pos_weight=torch.tensor([h['obj_pw']], device=device)) | ||
98 | + | ||
99 | + # Class label smoothing https://arxiv.org/pdf/1902.04103.pdf eqn 3 | ||
100 | + self.cp, self.cn = smooth_BCE(eps=h.get('label_smoothing', 0.0)) # positive, negative BCE targets | ||
101 | + | ||
102 | + # Focal loss | ||
103 | + g = h['fl_gamma'] # focal loss gamma | ||
104 | + if g > 0: | ||
105 | + BCEcls, BCEobj = FocalLoss(BCEcls, g), FocalLoss(BCEobj, g) | ||
106 | + | ||
107 | + det = model.module.model[-1] if is_parallel(model) else model.model[-1] # Detect() module | ||
108 | + self.balance = {3: [4.0, 1.0, 0.4]}.get(det.nl, [4.0, 1.0, 0.25, 0.06, .02]) # P3-P7 | ||
109 | + self.ssi = list(det.stride).index(16) if autobalance else 0 # stride 16 index | ||
110 | + self.BCEcls, self.BCEobj, self.gr, self.hyp, self.autobalance = BCEcls, BCEobj, model.gr, h, autobalance | ||
111 | + for k in 'na', 'nc', 'nl', 'anchors': | ||
112 | + setattr(self, k, getattr(det, k)) | ||
113 | + | ||
114 | + def __call__(self, p, targets): # predictions, targets, model | ||
115 | + device = targets.device | ||
116 | + lcls, lbox, lobj = torch.zeros(1, device=device), torch.zeros(1, device=device), torch.zeros(1, device=device) | ||
117 | + tcls, tbox, indices, anchors = self.build_targets(p, targets) # targets | ||
118 | + | ||
119 | + # Losses | ||
120 | + for i, pi in enumerate(p): # layer index, layer predictions | ||
121 | + b, a, gj, gi = indices[i] # image, anchor, gridy, gridx | ||
122 | + tobj = torch.zeros_like(pi[..., 0], device=device) # target obj | ||
123 | + | ||
124 | + n = b.shape[0] # number of targets | ||
125 | + if n: | ||
126 | + ps = pi[b, a, gj, gi] # prediction subset corresponding to targets | ||
127 | + | ||
128 | + # Regression | ||
129 | + pxy = ps[:, :2].sigmoid() * 2. - 0.5 | ||
130 | + pwh = (ps[:, 2:4].sigmoid() * 2) ** 2 * anchors[i] | ||
131 | + pbox = torch.cat((pxy, pwh), 1) # predicted box | ||
132 | + iou = bbox_iou(pbox.T, tbox[i], x1y1x2y2=False, CIoU=True) # iou(prediction, target) | ||
133 | + lbox += (1.0 - iou).mean() # iou loss | ||
134 | + | ||
135 | + # Objectness | ||
136 | + tobj[b, a, gj, gi] = (1.0 - self.gr) + self.gr * iou.detach().clamp(0).type(tobj.dtype) # iou ratio | ||
137 | + | ||
138 | + # Classification | ||
139 | + if self.nc > 1: # cls loss (only if multiple classes) | ||
140 | + t = torch.full_like(ps[:, 5:], self.cn, device=device) # targets | ||
141 | + t[range(n), tcls[i]] = self.cp | ||
142 | + lcls += self.BCEcls(ps[:, 5:], t) # BCE | ||
143 | + | ||
144 | + # Append targets to text file | ||
145 | + # with open('targets.txt', 'a') as file: | ||
146 | + # [file.write('%11.5g ' * 4 % tuple(x) + '\n') for x in torch.cat((txy[i], twh[i]), 1)] | ||
147 | + | ||
148 | + obji = self.BCEobj(pi[..., 4], tobj) | ||
149 | + lobj += obji * self.balance[i] # obj loss | ||
150 | + if self.autobalance: | ||
151 | + self.balance[i] = self.balance[i] * 0.9999 + 0.0001 / obji.detach().item() | ||
152 | + | ||
153 | + if self.autobalance: | ||
154 | + self.balance = [x / self.balance[self.ssi] for x in self.balance] | ||
155 | + lbox *= self.hyp['box'] | ||
156 | + lobj *= self.hyp['obj'] | ||
157 | + lcls *= self.hyp['cls'] | ||
158 | + bs = tobj.shape[0] # batch size | ||
159 | + | ||
160 | + loss = lbox + lobj + lcls | ||
161 | + return loss * bs, torch.cat((lbox, lobj, lcls, loss)).detach() | ||
162 | + | ||
163 | + def build_targets(self, p, targets): | ||
164 | + # Build targets for compute_loss(), input targets(image,class,x,y,w,h) | ||
165 | + na, nt = self.na, targets.shape[0] # number of anchors, targets | ||
166 | + tcls, tbox, indices, anch = [], [], [], [] | ||
167 | + gain = torch.ones(7, device=targets.device) # normalized to gridspace gain | ||
168 | + ai = torch.arange(na, device=targets.device).float().view(na, 1).repeat(1, nt) # same as .repeat_interleave(nt) | ||
169 | + targets = torch.cat((targets.repeat(na, 1, 1), ai[:, :, None]), 2) # append anchor indices | ||
170 | + | ||
171 | + g = 0.5 # bias | ||
172 | + off = torch.tensor([[0, 0], | ||
173 | + [1, 0], [0, 1], [-1, 0], [0, -1], # j,k,l,m | ||
174 | + # [1, 1], [1, -1], [-1, 1], [-1, -1], # jk,jm,lk,lm | ||
175 | + ], device=targets.device).float() * g # offsets | ||
176 | + | ||
177 | + for i in range(self.nl): | ||
178 | + anchors = self.anchors[i] | ||
179 | + gain[2:6] = torch.tensor(p[i].shape)[[3, 2, 3, 2]] # xyxy gain | ||
180 | + | ||
181 | + # Match targets to anchors | ||
182 | + t = targets * gain | ||
183 | + if nt: | ||
184 | + # Matches | ||
185 | + r = t[:, :, 4:6] / anchors[:, None] # wh ratio | ||
186 | + j = torch.max(r, 1. / r).max(2)[0] < self.hyp['anchor_t'] # compare | ||
187 | + # j = wh_iou(anchors, t[:, 4:6]) > model.hyp['iou_t'] # iou(3,n)=wh_iou(anchors(3,2), gwh(n,2)) | ||
188 | + t = t[j] # filter | ||
189 | + | ||
190 | + # Offsets | ||
191 | + gxy = t[:, 2:4] # grid xy | ||
192 | + gxi = gain[[2, 3]] - gxy # inverse | ||
193 | + j, k = ((gxy % 1. < g) & (gxy > 1.)).T | ||
194 | + l, m = ((gxi % 1. < g) & (gxi > 1.)).T | ||
195 | + j = torch.stack((torch.ones_like(j), j, k, l, m)) | ||
196 | + t = t.repeat((5, 1, 1))[j] | ||
197 | + offsets = (torch.zeros_like(gxy)[None] + off[:, None])[j] | ||
198 | + else: | ||
199 | + t = targets[0] | ||
200 | + offsets = 0 | ||
201 | + | ||
202 | + # Define | ||
203 | + b, c = t[:, :2].long().T # image, class | ||
204 | + gxy = t[:, 2:4] # grid xy | ||
205 | + gwh = t[:, 4:6] # grid wh | ||
206 | + gij = (gxy - offsets).long() | ||
207 | + gi, gj = gij.T # grid xy indices | ||
208 | + | ||
209 | + # Append | ||
210 | + a = t[:, 6].long() # anchor indices | ||
211 | + indices.append((b, a, gj.clamp_(0, gain[3] - 1), gi.clamp_(0, gain[2] - 1))) # image, anchor, grid indices | ||
212 | + tbox.append(torch.cat((gxy - gij, gwh), 1)) # box | ||
213 | + anch.append(anchors[a]) # anchors | ||
214 | + tcls.append(c) # class | ||
215 | + | ||
216 | + return tcls, tbox, indices, anch |
YOLOv5/utils/metrics.py
0 → 100644
1 | +# Model validation metrics | ||
2 | + | ||
3 | +from pathlib import Path | ||
4 | + | ||
5 | +import matplotlib.pyplot as plt | ||
6 | +import numpy as np | ||
7 | +import torch | ||
8 | + | ||
9 | +from . import general | ||
10 | + | ||
11 | + | ||
12 | +def fitness(x): | ||
13 | + # Model fitness as a weighted combination of metrics | ||
14 | + w = [0.0, 0.0, 0.1, 0.9] # weights for [P, R, mAP@0.5, mAP@0.5:0.95] | ||
15 | + return (x[:, :4] * w).sum(1) | ||
16 | + | ||
17 | + | ||
18 | +def ap_per_class(tp, conf, pred_cls, target_cls, plot=False, save_dir='.', names=()): | ||
19 | + """ Compute the average precision, given the recall and precision curves. | ||
20 | + Source: https://github.com/rafaelpadilla/Object-Detection-Metrics. | ||
21 | + # Arguments | ||
22 | + tp: True positives (nparray, nx1 or nx10). | ||
23 | + conf: Objectness value from 0-1 (nparray). | ||
24 | + pred_cls: Predicted object classes (nparray). | ||
25 | + target_cls: True object classes (nparray). | ||
26 | + plot: Plot precision-recall curve at mAP@0.5 | ||
27 | + save_dir: Plot save directory | ||
28 | + # Returns | ||
29 | + The average precision as computed in py-faster-rcnn. | ||
30 | + """ | ||
31 | + | ||
32 | + # Sort by objectness | ||
33 | + i = np.argsort(-conf) | ||
34 | + tp, conf, pred_cls = tp[i], conf[i], pred_cls[i] | ||
35 | + | ||
36 | + # Find unique classes | ||
37 | + unique_classes = np.unique(target_cls) | ||
38 | + nc = unique_classes.shape[0] # number of classes, number of detections | ||
39 | + | ||
40 | + # Create Precision-Recall curve and compute AP for each class | ||
41 | + px, py = np.linspace(0, 1, 1000), [] # for plotting | ||
42 | + ap, p, r = np.zeros((nc, tp.shape[1])), np.zeros((nc, 1000)), np.zeros((nc, 1000)) | ||
43 | + for ci, c in enumerate(unique_classes): | ||
44 | + i = pred_cls == c | ||
45 | + n_l = (target_cls == c).sum() # number of labels | ||
46 | + n_p = i.sum() # number of predictions | ||
47 | + | ||
48 | + if n_p == 0 or n_l == 0: | ||
49 | + continue | ||
50 | + else: | ||
51 | + # Accumulate FPs and TPs | ||
52 | + fpc = (1 - tp[i]).cumsum(0) | ||
53 | + tpc = tp[i].cumsum(0) | ||
54 | + | ||
55 | + # Recall | ||
56 | + recall = tpc / (n_l + 1e-16) # recall curve | ||
57 | + r[ci] = np.interp(-px, -conf[i], recall[:, 0], left=0) # negative x, xp because xp decreases | ||
58 | + | ||
59 | + # Precision | ||
60 | + precision = tpc / (tpc + fpc) # precision curve | ||
61 | + p[ci] = np.interp(-px, -conf[i], precision[:, 0], left=1) # p at pr_score | ||
62 | + | ||
63 | + # AP from recall-precision curve | ||
64 | + for j in range(tp.shape[1]): | ||
65 | + ap[ci, j], mpre, mrec = compute_ap(recall[:, j], precision[:, j]) | ||
66 | + if plot and j == 0: | ||
67 | + py.append(np.interp(px, mrec, mpre)) # precision at mAP@0.5 | ||
68 | + | ||
69 | + # Compute F1 (harmonic mean of precision and recall) | ||
70 | + f1 = 2 * p * r / (p + r + 1e-16) | ||
71 | + if plot: | ||
72 | + plot_pr_curve(px, py, ap, Path(save_dir) / 'PR_curve.png', names) | ||
73 | + plot_mc_curve(px, f1, Path(save_dir) / 'F1_curve.png', names, ylabel='F1') | ||
74 | + plot_mc_curve(px, p, Path(save_dir) / 'P_curve.png', names, ylabel='Precision') | ||
75 | + plot_mc_curve(px, r, Path(save_dir) / 'R_curve.png', names, ylabel='Recall') | ||
76 | + | ||
77 | + i = f1.mean(0).argmax() # max F1 index | ||
78 | + return p[:, i], r[:, i], ap, f1[:, i], unique_classes.astype('int32') | ||
79 | + | ||
80 | + | ||
81 | +def compute_ap(recall, precision): | ||
82 | + """ Compute the average precision, given the recall and precision curves | ||
83 | + # Arguments | ||
84 | + recall: The recall curve (list) | ||
85 | + precision: The precision curve (list) | ||
86 | + # Returns | ||
87 | + Average precision, precision curve, recall curve | ||
88 | + """ | ||
89 | + | ||
90 | + # Append sentinel values to beginning and end | ||
91 | + mrec = np.concatenate(([0.], recall, [recall[-1] + 0.01])) | ||
92 | + mpre = np.concatenate(([1.], precision, [0.])) | ||
93 | + | ||
94 | + # Compute the precision envelope | ||
95 | + mpre = np.flip(np.maximum.accumulate(np.flip(mpre))) | ||
96 | + | ||
97 | + # Integrate area under curve | ||
98 | + method = 'interp' # methods: 'continuous', 'interp' | ||
99 | + if method == 'interp': | ||
100 | + x = np.linspace(0, 1, 101) # 101-point interp (COCO) | ||
101 | + ap = np.trapz(np.interp(x, mrec, mpre), x) # integrate | ||
102 | + else: # 'continuous' | ||
103 | + i = np.where(mrec[1:] != mrec[:-1])[0] # points where x axis (recall) changes | ||
104 | + ap = np.sum((mrec[i + 1] - mrec[i]) * mpre[i + 1]) # area under curve | ||
105 | + | ||
106 | + return ap, mpre, mrec | ||
107 | + | ||
108 | + | ||
109 | +class ConfusionMatrix: | ||
110 | + # Updated version of https://github.com/kaanakan/object_detection_confusion_matrix | ||
111 | + def __init__(self, nc, conf=0.25, iou_thres=0.45): | ||
112 | + self.matrix = np.zeros((nc + 1, nc + 1)) | ||
113 | + self.nc = nc # number of classes | ||
114 | + self.conf = conf | ||
115 | + self.iou_thres = iou_thres | ||
116 | + | ||
117 | + def process_batch(self, detections, labels): | ||
118 | + """ | ||
119 | + Return intersection-over-union (Jaccard index) of boxes. | ||
120 | + Both sets of boxes are expected to be in (x1, y1, x2, y2) format. | ||
121 | + Arguments: | ||
122 | + detections (Array[N, 6]), x1, y1, x2, y2, conf, class | ||
123 | + labels (Array[M, 5]), class, x1, y1, x2, y2 | ||
124 | + Returns: | ||
125 | + None, updates confusion matrix accordingly | ||
126 | + """ | ||
127 | + detections = detections[detections[:, 4] > self.conf] | ||
128 | + gt_classes = labels[:, 0].int() | ||
129 | + detection_classes = detections[:, 5].int() | ||
130 | + iou = general.box_iou(labels[:, 1:], detections[:, :4]) | ||
131 | + | ||
132 | + x = torch.where(iou > self.iou_thres) | ||
133 | + if x[0].shape[0]: | ||
134 | + matches = torch.cat((torch.stack(x, 1), iou[x[0], x[1]][:, None]), 1).cpu().numpy() | ||
135 | + if x[0].shape[0] > 1: | ||
136 | + matches = matches[matches[:, 2].argsort()[::-1]] | ||
137 | + matches = matches[np.unique(matches[:, 1], return_index=True)[1]] | ||
138 | + matches = matches[matches[:, 2].argsort()[::-1]] | ||
139 | + matches = matches[np.unique(matches[:, 0], return_index=True)[1]] | ||
140 | + else: | ||
141 | + matches = np.zeros((0, 3)) | ||
142 | + | ||
143 | + n = matches.shape[0] > 0 | ||
144 | + m0, m1, _ = matches.transpose().astype(np.int16) | ||
145 | + for i, gc in enumerate(gt_classes): | ||
146 | + j = m0 == i | ||
147 | + if n and sum(j) == 1: | ||
148 | + self.matrix[detection_classes[m1[j]], gc] += 1 # correct | ||
149 | + else: | ||
150 | + self.matrix[self.nc, gc] += 1 # background FP | ||
151 | + | ||
152 | + if n: | ||
153 | + for i, dc in enumerate(detection_classes): | ||
154 | + if not any(m1 == i): | ||
155 | + self.matrix[dc, self.nc] += 1 # background FN | ||
156 | + | ||
157 | + def matrix(self): | ||
158 | + return self.matrix | ||
159 | + | ||
160 | + def plot(self, save_dir='', names=()): | ||
161 | + try: | ||
162 | + import seaborn as sn | ||
163 | + | ||
164 | + array = self.matrix / (self.matrix.sum(0).reshape(1, self.nc + 1) + 1E-6) # normalize | ||
165 | + array[array < 0.005] = np.nan # don't annotate (would appear as 0.00) | ||
166 | + | ||
167 | + fig = plt.figure(figsize=(12, 9), tight_layout=True) | ||
168 | + sn.set(font_scale=1.0 if self.nc < 50 else 0.8) # for label size | ||
169 | + labels = (0 < len(names) < 99) and len(names) == self.nc # apply names to ticklabels | ||
170 | + sn.heatmap(array, annot=self.nc < 30, annot_kws={"size": 8}, cmap='Blues', fmt='.2f', square=True, | ||
171 | + xticklabels=names + ['background FP'] if labels else "auto", | ||
172 | + yticklabels=names + ['background FN'] if labels else "auto").set_facecolor((1, 1, 1)) | ||
173 | + fig.axes[0].set_xlabel('True') | ||
174 | + fig.axes[0].set_ylabel('Predicted') | ||
175 | + fig.savefig(Path(save_dir) / 'confusion_matrix.png', dpi=250) | ||
176 | + except Exception as e: | ||
177 | + pass | ||
178 | + | ||
179 | + def print(self): | ||
180 | + for i in range(self.nc + 1): | ||
181 | + print(' '.join(map(str, self.matrix[i]))) | ||
182 | + | ||
183 | + | ||
184 | +# Plots ---------------------------------------------------------------------------------------------------------------- | ||
185 | + | ||
186 | +def plot_pr_curve(px, py, ap, save_dir='pr_curve.png', names=()): | ||
187 | + # Precision-recall curve | ||
188 | + fig, ax = plt.subplots(1, 1, figsize=(9, 6), tight_layout=True) | ||
189 | + py = np.stack(py, axis=1) | ||
190 | + | ||
191 | + if 0 < len(names) < 21: # display per-class legend if < 21 classes | ||
192 | + for i, y in enumerate(py.T): | ||
193 | + ax.plot(px, y, linewidth=1, label=f'{names[i]} {ap[i, 0]:.3f}') # plot(recall, precision) | ||
194 | + else: | ||
195 | + ax.plot(px, py, linewidth=1, color='grey') # plot(recall, precision) | ||
196 | + | ||
197 | + ax.plot(px, py.mean(1), linewidth=3, color='blue', label='all classes %.3f mAP@0.5' % ap[:, 0].mean()) | ||
198 | + ax.set_xlabel('Recall') | ||
199 | + ax.set_ylabel('Precision') | ||
200 | + ax.set_xlim(0, 1) | ||
201 | + ax.set_ylim(0, 1) | ||
202 | + plt.legend(bbox_to_anchor=(1.04, 1), loc="upper left") | ||
203 | + fig.savefig(Path(save_dir), dpi=250) | ||
204 | + | ||
205 | + | ||
206 | +def plot_mc_curve(px, py, save_dir='mc_curve.png', names=(), xlabel='Confidence', ylabel='Metric'): | ||
207 | + # Metric-confidence curve | ||
208 | + fig, ax = plt.subplots(1, 1, figsize=(9, 6), tight_layout=True) | ||
209 | + | ||
210 | + if 0 < len(names) < 21: # display per-class legend if < 21 classes | ||
211 | + for i, y in enumerate(py): | ||
212 | + ax.plot(px, y, linewidth=1, label=f'{names[i]}') # plot(confidence, metric) | ||
213 | + else: | ||
214 | + ax.plot(px, py.T, linewidth=1, color='grey') # plot(confidence, metric) | ||
215 | + | ||
216 | + y = py.mean(0) | ||
217 | + ax.plot(px, y, linewidth=3, color='blue', label=f'all classes {y.max():.2f} at {px[y.argmax()]:.3f}') | ||
218 | + ax.set_xlabel(xlabel) | ||
219 | + ax.set_ylabel(ylabel) | ||
220 | + ax.set_xlim(0, 1) | ||
221 | + ax.set_ylim(0, 1) | ||
222 | + plt.legend(bbox_to_anchor=(1.04, 1), loc="upper left") | ||
223 | + fig.savefig(Path(save_dir), dpi=250) |
YOLOv5/utils/plots.py
0 → 100644
This diff is collapsed. Click to expand it.
YOLOv5/utils/torch_utils.py
0 → 100644
This diff is collapsed. Click to expand it.
YOLOv5/utils/wandb_logging/__init__.py
0 → 100644
File mode changed
YOLOv5/utils/wandb_logging/log_dataset.py
0 → 100644
1 | +import argparse | ||
2 | + | ||
3 | +import yaml | ||
4 | + | ||
5 | +from wandb_utils import WandbLogger | ||
6 | + | ||
7 | +WANDB_ARTIFACT_PREFIX = 'wandb-artifact://' | ||
8 | + | ||
9 | + | ||
10 | +def create_dataset_artifact(opt): | ||
11 | + with open(opt.data) as f: | ||
12 | + data = yaml.safe_load(f) # data dict | ||
13 | + logger = WandbLogger(opt, '', None, data, job_type='Dataset Creation') | ||
14 | + | ||
15 | + | ||
16 | +if __name__ == '__main__': | ||
17 | + parser = argparse.ArgumentParser() | ||
18 | + parser.add_argument('--data', type=str, default='data/coco128.yaml', help='data.yaml path') | ||
19 | + parser.add_argument('--single-cls', action='store_true', help='train as single-class dataset') | ||
20 | + parser.add_argument('--project', type=str, default='YOLOv5', help='name of W&B Project') | ||
21 | + opt = parser.parse_args() | ||
22 | + opt.resume = False # Explicitly disallow resume check for dataset upload job | ||
23 | + | ||
24 | + create_dataset_artifact(opt) |
YOLOv5/utils/wandb_logging/wandb_utils.py
0 → 100644
This diff is collapsed. Click to expand it.
YOLOv5/weights/download_weights.sh
0 → 100644
1 | +#!/bin/bash | ||
2 | +# Download latest models from https://github.com/ultralytics/yolov5/releases | ||
3 | +# Usage: | ||
4 | +# $ bash weights/download_weights.sh | ||
5 | + | ||
6 | +python - <<EOF | ||
7 | +from utils.google_utils import attempt_download | ||
8 | + | ||
9 | +for x in ['s', 'm', 'l', 'x']: | ||
10 | + attempt_download(f'yolov5{x}.pt') | ||
11 | + | ||
12 | +EOF |
-
Please register or login to post a comment