김연수

YOLOv5 for LP detection

Showing 60 changed files with 3225 additions and 0 deletions
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
1 +# this drop notebooks from GitHub language stats
2 +*.ipynb linguist-vendored
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
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
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
File mode changed
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)
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()
File mode changed
This diff is collapsed. Click to expand it.
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
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.')
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
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 + ]
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 + ]
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 + ]
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 + ]
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 + ]
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 + ]
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 + ]
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 + ]
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 + ]
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 + ]
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 + ]
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 + ]
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 + ]
This diff is collapsed. Click to expand it.
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 + ]
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 + ]
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 + ]
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 + ]
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
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff could not be displayed because it is too large.
File mode changed
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
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)
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 +--//
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)
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
This diff is collapsed. Click to expand it.
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)
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
This diff is collapsed. Click to expand it.
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
1 +# add these requirements in your app on top of the existing ones
2 +pip==18.1
3 +Flask==1.0.2
4 +gunicorn==19.9.0
1 +runtime: custom
2 +env: flex
3 +
4 +service: yolov5app
5 +
6 +liveness_check:
7 + initial_delay_sec: 600
8 +
9 +manual_scaling:
10 + instances: 1
11 +resources:
12 + cpu: 1
13 + memory_gb: 4
14 + disk_size_gb: 20
...\ No newline at end of file ...\ No newline at end of file
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))
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
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)
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
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)
This diff is collapsed. Click to expand it.
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