Spaces:
Build error
Build error
Upload 213 files
Browse filesThis view is limited to 50 files because it contains too many changes.
See raw diff
- .gitattributes +7 -0
- .gitignore +150 -0
- .pre-commit-config.yaml +65 -0
- CONTRIBUTING.md +113 -0
- MANIFEST.in +5 -0
- README.md +82 -12
- YOLOv8_DeepSORT_TRACKING_SCRIPT.ipynb +3 -0
- YOLOv8_Detection_Tracking_CustomData_Complete.ipynb +3 -0
- figure/figure1.png +3 -0
- figure/figure2.png +3 -0
- figure/figure3.png +3 -0
- mkdocs.yml +95 -0
- requirements.txt +46 -0
- setup.cfg +54 -0
- setup.py +53 -0
- ultralytics/__init__.py +9 -0
- ultralytics/hub/__init__.py +133 -0
- ultralytics/hub/auth.py +70 -0
- ultralytics/hub/session.py +122 -0
- ultralytics/hub/utils.py +150 -0
- ultralytics/models/README.md +36 -0
- ultralytics/models/v3/yolov3-spp.yaml +47 -0
- ultralytics/models/v3/yolov3-tiny.yaml +38 -0
- ultralytics/models/v3/yolov3.yaml +47 -0
- ultralytics/models/v5/yolov5l.yaml +44 -0
- ultralytics/models/v5/yolov5m.yaml +44 -0
- ultralytics/models/v5/yolov5n.yaml +44 -0
- ultralytics/models/v5/yolov5s.yaml +45 -0
- ultralytics/models/v5/yolov5x.yaml +44 -0
- ultralytics/models/v8/cls/yolov8l-cls.yaml +23 -0
- ultralytics/models/v8/cls/yolov8m-cls.yaml +23 -0
- ultralytics/models/v8/cls/yolov8n-cls.yaml +23 -0
- ultralytics/models/v8/cls/yolov8s-cls.yaml +23 -0
- ultralytics/models/v8/cls/yolov8x-cls.yaml +23 -0
- ultralytics/models/v8/seg/yolov8l-seg.yaml +40 -0
- ultralytics/models/v8/seg/yolov8m-seg.yaml +40 -0
- ultralytics/models/v8/seg/yolov8n-seg.yaml +40 -0
- ultralytics/models/v8/seg/yolov8s-seg.yaml +40 -0
- ultralytics/models/v8/seg/yolov8x-seg.yaml +40 -0
- ultralytics/models/v8/yolov8l.yaml +40 -0
- ultralytics/models/v8/yolov8m.yaml +40 -0
- ultralytics/models/v8/yolov8n.yaml +40 -0
- ultralytics/models/v8/yolov8s.yaml +40 -0
- ultralytics/models/v8/yolov8x.yaml +40 -0
- ultralytics/models/v8/yolov8x6.yaml +50 -0
- ultralytics/nn/__init__.py +0 -0
- ultralytics/nn/autobackend.py +381 -0
- ultralytics/nn/modules.py +688 -0
- ultralytics/nn/tasks.py +416 -0
- ultralytics/yolo/cli.py +52 -0
.gitattributes
CHANGED
@@ -32,3 +32,10 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
32 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
33 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
34 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
32 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
33 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
34 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
35 |
+
figure/figure1.png filter=lfs diff=lfs merge=lfs -text
|
36 |
+
figure/figure2.png filter=lfs diff=lfs merge=lfs -text
|
37 |
+
figure/figure3.png filter=lfs diff=lfs merge=lfs -text
|
38 |
+
ultralytics/yolo/v8/detect/deep_sort_pytorch/deep_sort/deep/checkpoint/ckpt.t7 filter=lfs diff=lfs merge=lfs -text
|
39 |
+
ultralytics/yolo/v8/detect/night_motorbikes.mp4 filter=lfs diff=lfs merge=lfs -text
|
40 |
+
YOLOv8_DeepSORT_TRACKING_SCRIPT.ipynb filter=lfs diff=lfs merge=lfs -text
|
41 |
+
YOLOv8_Detection_Tracking_CustomData_Complete.ipynb filter=lfs diff=lfs merge=lfs -text
|
.gitignore
ADDED
@@ -0,0 +1,150 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Byte-compiled / optimized / DLL files
|
2 |
+
__pycache__/
|
3 |
+
*.py[cod]
|
4 |
+
*$py.class
|
5 |
+
|
6 |
+
# C extensions
|
7 |
+
*.so
|
8 |
+
|
9 |
+
# Distribution / packaging
|
10 |
+
.Python
|
11 |
+
build/
|
12 |
+
develop-eggs/
|
13 |
+
dist/
|
14 |
+
downloads/
|
15 |
+
eggs/
|
16 |
+
.eggs/
|
17 |
+
lib/
|
18 |
+
lib64/
|
19 |
+
parts/
|
20 |
+
sdist/
|
21 |
+
var/
|
22 |
+
wheels/
|
23 |
+
pip-wheel-metadata/
|
24 |
+
share/python-wheels/
|
25 |
+
*.egg-info/
|
26 |
+
.installed.cfg
|
27 |
+
*.egg
|
28 |
+
MANIFEST
|
29 |
+
|
30 |
+
# PyInstaller
|
31 |
+
# Usually these files are written by a python script from a template
|
32 |
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
33 |
+
*.manifest
|
34 |
+
*.spec
|
35 |
+
|
36 |
+
# Installer logs
|
37 |
+
pip-log.txt
|
38 |
+
pip-delete-this-directory.txt
|
39 |
+
|
40 |
+
# Unit test / coverage reports
|
41 |
+
htmlcov/
|
42 |
+
.tox/
|
43 |
+
.nox/
|
44 |
+
.coverage
|
45 |
+
.coverage.*
|
46 |
+
.cache
|
47 |
+
nosetests.xml
|
48 |
+
coverage.xml
|
49 |
+
*.cover
|
50 |
+
*.py,cover
|
51 |
+
.hypothesis/
|
52 |
+
.pytest_cache/
|
53 |
+
|
54 |
+
# Translations
|
55 |
+
*.mo
|
56 |
+
*.pot
|
57 |
+
|
58 |
+
# Django stuff:
|
59 |
+
*.log
|
60 |
+
local_settings.py
|
61 |
+
db.sqlite3
|
62 |
+
db.sqlite3-journal
|
63 |
+
|
64 |
+
# Flask stuff:
|
65 |
+
instance/
|
66 |
+
.webassets-cache
|
67 |
+
|
68 |
+
# Scrapy stuff:
|
69 |
+
.scrapy
|
70 |
+
|
71 |
+
# Sphinx documentation
|
72 |
+
docs/_build/
|
73 |
+
|
74 |
+
# PyBuilder
|
75 |
+
target/
|
76 |
+
|
77 |
+
# Jupyter Notebook
|
78 |
+
.ipynb_checkpoints
|
79 |
+
|
80 |
+
# IPython
|
81 |
+
profile_default/
|
82 |
+
ipython_config.py
|
83 |
+
|
84 |
+
# pyenv
|
85 |
+
.python-version
|
86 |
+
|
87 |
+
# pipenv
|
88 |
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
89 |
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
90 |
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
91 |
+
# install all needed dependencies.
|
92 |
+
#Pipfile.lock
|
93 |
+
|
94 |
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
|
95 |
+
__pypackages__/
|
96 |
+
|
97 |
+
# Celery stuff
|
98 |
+
celerybeat-schedule
|
99 |
+
celerybeat.pid
|
100 |
+
|
101 |
+
# SageMath parsed files
|
102 |
+
*.sage.py
|
103 |
+
|
104 |
+
# Environments
|
105 |
+
.env
|
106 |
+
.venv
|
107 |
+
env/
|
108 |
+
venv/
|
109 |
+
ENV/
|
110 |
+
env.bak/
|
111 |
+
venv.bak/
|
112 |
+
|
113 |
+
# Spyder project settings
|
114 |
+
.spyderproject
|
115 |
+
.spyproject
|
116 |
+
|
117 |
+
# Rope project settings
|
118 |
+
.ropeproject
|
119 |
+
|
120 |
+
# mkdocs documentation
|
121 |
+
/site
|
122 |
+
|
123 |
+
# mypy
|
124 |
+
.mypy_cache/
|
125 |
+
.dmypy.json
|
126 |
+
dmypy.json
|
127 |
+
|
128 |
+
# Pyre type checker
|
129 |
+
.pyre/
|
130 |
+
|
131 |
+
# datasets and projects
|
132 |
+
datasets/
|
133 |
+
runs/
|
134 |
+
wandb/
|
135 |
+
|
136 |
+
.DS_Store
|
137 |
+
|
138 |
+
# Neural Network weights -----------------------------------------------------------------------------------------------
|
139 |
+
*.weights
|
140 |
+
*.pt
|
141 |
+
*.pb
|
142 |
+
*.onnx
|
143 |
+
*.engine
|
144 |
+
*.mlmodel
|
145 |
+
*.torchscript
|
146 |
+
*.tflite
|
147 |
+
*.h5
|
148 |
+
*_saved_model/
|
149 |
+
*_web_model/
|
150 |
+
*_openvino_model/
|
.pre-commit-config.yaml
ADDED
@@ -0,0 +1,65 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Define hooks for code formations
|
2 |
+
# Will be applied on any updated commit files if a user has installed and linked commit hook
|
3 |
+
|
4 |
+
default_language_version:
|
5 |
+
python: python3.8
|
6 |
+
|
7 |
+
exclude: 'docs/'
|
8 |
+
# Define bot property if installed via https://github.com/marketplace/pre-commit-ci
|
9 |
+
ci:
|
10 |
+
autofix_prs: true
|
11 |
+
autoupdate_commit_msg: '[pre-commit.ci] pre-commit suggestions'
|
12 |
+
autoupdate_schedule: monthly
|
13 |
+
# submodules: true
|
14 |
+
|
15 |
+
repos:
|
16 |
+
- repo: https://github.com/pre-commit/pre-commit-hooks
|
17 |
+
rev: v4.3.0
|
18 |
+
hooks:
|
19 |
+
# - id: end-of-file-fixer
|
20 |
+
- id: trailing-whitespace
|
21 |
+
- id: check-case-conflict
|
22 |
+
- id: check-yaml
|
23 |
+
- id: check-toml
|
24 |
+
- id: pretty-format-json
|
25 |
+
- id: check-docstring-first
|
26 |
+
|
27 |
+
- repo: https://github.com/asottile/pyupgrade
|
28 |
+
rev: v2.37.3
|
29 |
+
hooks:
|
30 |
+
- id: pyupgrade
|
31 |
+
name: Upgrade code
|
32 |
+
args: [ --py37-plus ]
|
33 |
+
|
34 |
+
- repo: https://github.com/PyCQA/isort
|
35 |
+
rev: 5.10.1
|
36 |
+
hooks:
|
37 |
+
- id: isort
|
38 |
+
name: Sort imports
|
39 |
+
|
40 |
+
- repo: https://github.com/pre-commit/mirrors-yapf
|
41 |
+
rev: v0.32.0
|
42 |
+
hooks:
|
43 |
+
- id: yapf
|
44 |
+
name: YAPF formatting
|
45 |
+
|
46 |
+
- repo: https://github.com/executablebooks/mdformat
|
47 |
+
rev: 0.7.16
|
48 |
+
hooks:
|
49 |
+
- id: mdformat
|
50 |
+
name: MD formatting
|
51 |
+
additional_dependencies:
|
52 |
+
- mdformat-gfm
|
53 |
+
- mdformat-black
|
54 |
+
# exclude: "README.md|README.zh-CN.md|CONTRIBUTING.md"
|
55 |
+
|
56 |
+
- repo: https://github.com/PyCQA/flake8
|
57 |
+
rev: 5.0.4
|
58 |
+
hooks:
|
59 |
+
- id: flake8
|
60 |
+
name: PEP8
|
61 |
+
|
62 |
+
#- repo: https://github.com/asottile/yesqa
|
63 |
+
# rev: v1.4.0
|
64 |
+
# hooks:
|
65 |
+
# - id: yesqa
|
CONTRIBUTING.md
ADDED
@@ -0,0 +1,113 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
## Contributing to YOLOv8 🚀
|
2 |
+
|
3 |
+
We love your input! We want to make contributing to YOLOv8 as easy and transparent as possible, whether it's:
|
4 |
+
|
5 |
+
- Reporting a bug
|
6 |
+
- Discussing the current state of the code
|
7 |
+
- Submitting a fix
|
8 |
+
- Proposing a new feature
|
9 |
+
- Becoming a maintainer
|
10 |
+
|
11 |
+
YOLOv8 works so well due to our combined community effort, and for every small improvement you contribute you will be
|
12 |
+
helping push the frontiers of what's possible in AI 😃!
|
13 |
+
|
14 |
+
## Submitting a Pull Request (PR) 🛠️
|
15 |
+
|
16 |
+
Submitting a PR is easy! This example shows how to submit a PR for updating `requirements.txt` in 4 steps:
|
17 |
+
|
18 |
+
### 1. Select File to Update
|
19 |
+
|
20 |
+
Select `requirements.txt` to update by clicking on it in GitHub.
|
21 |
+
|
22 |
+
<p align="center"><img width="800" alt="PR_step1" src="https://user-images.githubusercontent.com/26833433/122260847-08be2600-ced4-11eb-828b-8287ace4136c.png"></p>
|
23 |
+
|
24 |
+
### 2. Click 'Edit this file'
|
25 |
+
|
26 |
+
Button is in top-right corner.
|
27 |
+
|
28 |
+
<p align="center"><img width="800" alt="PR_step2" src="https://user-images.githubusercontent.com/26833433/122260844-06f46280-ced4-11eb-9eec-b8a24be519ca.png"></p>
|
29 |
+
|
30 |
+
### 3. Make Changes
|
31 |
+
|
32 |
+
Change `matplotlib` version from `3.2.2` to `3.3`.
|
33 |
+
|
34 |
+
<p align="center"><img width="800" alt="PR_step3" src="https://user-images.githubusercontent.com/26833433/122260853-0a87e980-ced4-11eb-9fd2-3650fb6e0842.png"></p>
|
35 |
+
|
36 |
+
### 4. Preview Changes and Submit PR
|
37 |
+
|
38 |
+
Click on the **Preview changes** tab to verify your updates. At the bottom of the screen select 'Create a **new branch**
|
39 |
+
for this commit', assign your branch a descriptive name such as `fix/matplotlib_version` and click the green **Propose
|
40 |
+
changes** button. All done, your PR is now submitted to YOLOv8 for review and approval 😃!
|
41 |
+
|
42 |
+
<p align="center"><img width="800" alt="PR_step4" src="https://user-images.githubusercontent.com/26833433/122260856-0b208000-ced4-11eb-8e8e-77b6151cbcc3.png"></p>
|
43 |
+
|
44 |
+
### PR recommendations
|
45 |
+
|
46 |
+
To allow your work to be integrated as seamlessly as possible, we advise you to:
|
47 |
+
|
48 |
+
- ✅ Verify your PR is **up-to-date** with `ultralytics/ultralytics` `master` branch. If your PR is behind you can update
|
49 |
+
your code by clicking the 'Update branch' button or by running `git pull` and `git merge master` locally.
|
50 |
+
|
51 |
+
<p align="center"><img width="751" alt="Screenshot 2022-08-29 at 22 47 15" src="https://user-images.githubusercontent.com/26833433/187295893-50ed9f44-b2c9-4138-a614-de69bd1753d7.png"></p>
|
52 |
+
|
53 |
+
- ✅ Verify all YOLOv8 Continuous Integration (CI) **checks are passing**.
|
54 |
+
|
55 |
+
<p align="center"><img width="751" alt="Screenshot 2022-08-29 at 22 47 03" src="https://user-images.githubusercontent.com/26833433/187296922-545c5498-f64a-4d8c-8300-5fa764360da6.png"></p>
|
56 |
+
|
57 |
+
- ✅ Reduce changes to the absolute **minimum** required for your bug fix or feature addition. _"It is not daily increase
|
58 |
+
but daily decrease, hack away the unessential. The closer to the source, the less wastage there is."_ — Bruce Lee
|
59 |
+
|
60 |
+
### Docstrings
|
61 |
+
|
62 |
+
Not all functions or classes require docstrings but when they do, we follow [google-stlye docstrings format](https://google.github.io/styleguide/pyguide.html#38-comments-and-docstrings). Here is an example:
|
63 |
+
|
64 |
+
```python
|
65 |
+
"""
|
66 |
+
What the function does - performs nms on given detection predictions
|
67 |
+
|
68 |
+
Args:
|
69 |
+
arg1: The description of the 1st argument
|
70 |
+
arg2: The description of the 2nd argument
|
71 |
+
|
72 |
+
Returns:
|
73 |
+
What the function returns. Empty if nothing is returned
|
74 |
+
|
75 |
+
Raises:
|
76 |
+
Exception Class: When and why this exception can be raised by the function.
|
77 |
+
"""
|
78 |
+
```
|
79 |
+
|
80 |
+
## Submitting a Bug Report 🐛
|
81 |
+
|
82 |
+
If you spot a problem with YOLOv8 please submit a Bug Report!
|
83 |
+
|
84 |
+
For us to start investigating a possible problem we need to be able to reproduce it ourselves first. We've created a few
|
85 |
+
short guidelines below to help users provide what we need in order to get started.
|
86 |
+
|
87 |
+
When asking a question, people will be better able to provide help if you provide **code** that they can easily
|
88 |
+
understand and use to **reproduce** the problem. This is referred to by community members as creating
|
89 |
+
a [minimum reproducible example](https://stackoverflow.com/help/minimal-reproducible-example). Your code that reproduces
|
90 |
+
the problem should be:
|
91 |
+
|
92 |
+
- ✅ **Minimal** – Use as little code as possible that still produces the same problem
|
93 |
+
- ✅ **Complete** – Provide **all** parts someone else needs to reproduce your problem in the question itself
|
94 |
+
- ✅ **Reproducible** – Test the code you're about to provide to make sure it reproduces the problem
|
95 |
+
|
96 |
+
In addition to the above requirements, for [Ultralytics](https://ultralytics.com/) to provide assistance your code
|
97 |
+
should be:
|
98 |
+
|
99 |
+
- ✅ **Current** – Verify that your code is up-to-date with current
|
100 |
+
GitHub [master](https://github.com/ultralytics/ultralytics/tree/main), and if necessary `git pull` or `git clone` a new
|
101 |
+
copy to ensure your problem has not already been resolved by previous commits.
|
102 |
+
- ✅ **Unmodified** – Your problem must be reproducible without any modifications to the codebase in this
|
103 |
+
repository. [Ultralytics](https://ultralytics.com/) does not provide support for custom code ⚠️.
|
104 |
+
|
105 |
+
If you believe your problem meets all of the above criteria, please close this issue and raise a new one using the 🐛
|
106 |
+
**Bug Report** [template](https://github.com/ultralytics/ultralytics/issues/new/choose) and providing
|
107 |
+
a [minimum reproducible example](https://stackoverflow.com/help/minimal-reproducible-example) to help us better
|
108 |
+
understand and diagnose your problem.
|
109 |
+
|
110 |
+
## License
|
111 |
+
|
112 |
+
By contributing, you agree that your contributions will be licensed under
|
113 |
+
the [GPL-3.0 license](https://choosealicense.com/licenses/gpl-3.0/)
|
MANIFEST.in
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
include *.md
|
2 |
+
include requirements.txt
|
3 |
+
include LICENSE
|
4 |
+
include setup.py
|
5 |
+
recursive-include ultralytics *.yaml
|
README.md
CHANGED
@@ -1,12 +1,82 @@
|
|
1 |
-
|
2 |
-
|
3 |
-
|
4 |
-
|
5 |
-
|
6 |
-
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<H1 align="center">
|
2 |
+
YOLOv8 Object Detection with DeepSORT Tracking(ID + Trails) </H1>
|
3 |
+
|
4 |
+
## Google Colab File Link (A Single Click Solution)
|
5 |
+
The google colab file link for yolov8 object detection and tracking is provided below, you can check the implementation in Google Colab, and its a single click implementation, you just need to select the Run Time as GPU, and click on Run All.
|
6 |
+
|
7 |
+
[`Google Colab File`](https://colab.research.google.com/drive/1U6cnTQ0JwCg4kdHxYSl2NAhU4wK18oAu?usp=sharing)
|
8 |
+
|
9 |
+
## Object Detection and Tracking (ID + Trails) using YOLOv8 on Custom Data
|
10 |
+
## Google Colab File Link (A Single Click Solution)
|
11 |
+
[`Google Colab File`](https://colab.research.google.com/drive/1dEpI2k3m1i0vbvB4bNqPRQUO0gSBTz25?usp=sharing)
|
12 |
+
|
13 |
+
## YOLOv8 Segmentation with DeepSORT Object Tracking
|
14 |
+
|
15 |
+
[`Github Repo Link`](https://github.com/MuhammadMoinFaisal/YOLOv8_Segmentation_DeepSORT_Object_Tracking.git)
|
16 |
+
|
17 |
+
## Steps to run Code
|
18 |
+
|
19 |
+
- Clone the repository
|
20 |
+
```
|
21 |
+
git clone https://github.com/MuhammadMoinFaisal/YOLOv8-DeepSORT-Object-Tracking.git
|
22 |
+
```
|
23 |
+
- Goto the cloned folder.
|
24 |
+
```
|
25 |
+
cd YOLOv8-DeepSORT-Object-Tracking
|
26 |
+
```
|
27 |
+
- Install the dependecies
|
28 |
+
```
|
29 |
+
pip install -e '.[dev]'
|
30 |
+
|
31 |
+
```
|
32 |
+
|
33 |
+
- Setting the Directory.
|
34 |
+
```
|
35 |
+
cd ultralytics/yolo/v8/detect
|
36 |
+
|
37 |
+
```
|
38 |
+
- Downloading the DeepSORT Files From The Google Drive
|
39 |
+
```
|
40 |
+
|
41 |
+
https://drive.google.com/drive/folders/1kna8eWGrSfzaR6DtNJ8_GchGgPMv3VC8?usp=sharing
|
42 |
+
```
|
43 |
+
- After downloading the DeepSORT Zip file from the drive, unzip it go into the subfolders and place the deep_sort_pytorch folder into the yolo/v8/detect folder
|
44 |
+
|
45 |
+
- Downloading a Sample Video from the Google Drive
|
46 |
+
```
|
47 |
+
gdown "https://drive.google.com/uc?id=1rjBn8Fl1E_9d0EMVtL24S9aNQOJAveR5&confirm=t"
|
48 |
+
```
|
49 |
+
|
50 |
+
- Run the code with mentioned command below.
|
51 |
+
|
52 |
+
- For yolov8 object detection + Tracking
|
53 |
+
```
|
54 |
+
python predict.py model=yolov8l.pt source="test3.mp4" show=True
|
55 |
+
```
|
56 |
+
- For yolov8 object detection + Tracking + Vehicle Counting
|
57 |
+
- Download the updated predict.py file from the Google Drive and place it into ultralytics/yolo/v8/detect folder
|
58 |
+
- Google Drive Link
|
59 |
+
```
|
60 |
+
https://drive.google.com/drive/folders/1awlzTGHBBAn_2pKCkLFADMd1EN_rJETW?usp=sharing
|
61 |
+
```
|
62 |
+
- For yolov8 object detection + Tracking + Vehicle Counting
|
63 |
+
```
|
64 |
+
python predict.py model=yolov8l.pt source="test3.mp4" show=True
|
65 |
+
```
|
66 |
+
|
67 |
+
### RESULTS
|
68 |
+
|
69 |
+
#### Vehicles Detection, Tracking and Counting
|
70 |
+
![](./figure/figure1.png)
|
71 |
+
|
72 |
+
#### Vehicles Detection, Tracking and Counting
|
73 |
+
|
74 |
+
![](./figure/figure3.png)
|
75 |
+
|
76 |
+
### Watch the Complete Step by Step Explanation
|
77 |
+
|
78 |
+
- Video Tutorial Link [`YouTube Link`](https://www.youtube.com/watch?v=9jRRZ-WL698)
|
79 |
+
|
80 |
+
|
81 |
+
[![Watch the Complete Tutorial for the Step by Step Explanation](https://img.youtube.com/vi/9jRRZ-WL698/0.jpg)]([https://www.youtube.com/watch?v=StTqXEQ2l-Y](https://www.youtube.com/watch?v=9jRRZ-WL698))
|
82 |
+
|
YOLOv8_DeepSORT_TRACKING_SCRIPT.ipynb
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:c0918af0bfa0ef2e0e9d26d9a8b06e2d706f5a5685d4e19eb58877a8036092ac
|
3 |
+
size 16618677
|
YOLOv8_Detection_Tracking_CustomData_Complete.ipynb
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:3d514434f9b1d8f5f3a7fb72e782f82d3c136523a7fc7bb41c2a2a390f4aa783
|
3 |
+
size 22625415
|
figure/figure1.png
ADDED
Git LFS Details
|
figure/figure2.png
ADDED
Git LFS Details
|
figure/figure3.png
ADDED
Git LFS Details
|
mkdocs.yml
ADDED
@@ -0,0 +1,95 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
site_name: Ultralytics Docs
|
2 |
+
repo_url: https://github.com/ultralytics/ultralytics
|
3 |
+
repo_name: Ultralytics
|
4 |
+
|
5 |
+
theme:
|
6 |
+
name: "material"
|
7 |
+
logo: https://github.com/ultralytics/assets/raw/main/logo/Ultralytics-logomark-white.png
|
8 |
+
icon:
|
9 |
+
repo: fontawesome/brands/github
|
10 |
+
admonition:
|
11 |
+
note: octicons/tag-16
|
12 |
+
abstract: octicons/checklist-16
|
13 |
+
info: octicons/info-16
|
14 |
+
tip: octicons/squirrel-16
|
15 |
+
success: octicons/check-16
|
16 |
+
question: octicons/question-16
|
17 |
+
warning: octicons/alert-16
|
18 |
+
failure: octicons/x-circle-16
|
19 |
+
danger: octicons/zap-16
|
20 |
+
bug: octicons/bug-16
|
21 |
+
example: octicons/beaker-16
|
22 |
+
quote: octicons/quote-16
|
23 |
+
|
24 |
+
palette:
|
25 |
+
# Palette toggle for light mode
|
26 |
+
- scheme: default
|
27 |
+
toggle:
|
28 |
+
icon: material/brightness-7
|
29 |
+
name: Switch to dark mode
|
30 |
+
|
31 |
+
# Palette toggle for dark mode
|
32 |
+
- scheme: slate
|
33 |
+
toggle:
|
34 |
+
icon: material/brightness-4
|
35 |
+
name: Switch to light mode
|
36 |
+
features:
|
37 |
+
- content.code.annotate
|
38 |
+
- content.tooltips
|
39 |
+
- search.highlight
|
40 |
+
- search.share
|
41 |
+
- search.suggest
|
42 |
+
- toc.follow
|
43 |
+
|
44 |
+
extra_css:
|
45 |
+
- stylesheets/style.css
|
46 |
+
|
47 |
+
markdown_extensions:
|
48 |
+
# Div text decorators
|
49 |
+
- admonition
|
50 |
+
- pymdownx.details
|
51 |
+
- pymdownx.superfences
|
52 |
+
- tables
|
53 |
+
- attr_list
|
54 |
+
- def_list
|
55 |
+
# Syntax highlight
|
56 |
+
- pymdownx.highlight:
|
57 |
+
anchor_linenums: true
|
58 |
+
- pymdownx.inlinehilite
|
59 |
+
- pymdownx.snippets
|
60 |
+
|
61 |
+
# Button
|
62 |
+
- attr_list
|
63 |
+
|
64 |
+
# Content tabs
|
65 |
+
- pymdownx.superfences
|
66 |
+
- pymdownx.tabbed:
|
67 |
+
alternate_style: true
|
68 |
+
|
69 |
+
# Highlight
|
70 |
+
- pymdownx.critic
|
71 |
+
- pymdownx.caret
|
72 |
+
- pymdownx.keys
|
73 |
+
- pymdownx.mark
|
74 |
+
- pymdownx.tilde
|
75 |
+
plugins:
|
76 |
+
- mkdocstrings
|
77 |
+
|
78 |
+
# Primary navigation
|
79 |
+
nav:
|
80 |
+
- Quickstart: quickstart.md
|
81 |
+
- CLI: cli.md
|
82 |
+
- Python Interface: sdk.md
|
83 |
+
- Configuration: config.md
|
84 |
+
- Customization Guide: engine.md
|
85 |
+
- Ultralytics HUB: hub.md
|
86 |
+
- iOS and Android App: app.md
|
87 |
+
- Reference:
|
88 |
+
- Python Model interface: reference/model.md
|
89 |
+
- Engine:
|
90 |
+
- Trainer: reference/base_trainer.md
|
91 |
+
- Validator: reference/base_val.md
|
92 |
+
- Predictor: reference/base_pred.md
|
93 |
+
- Exporter: reference/exporter.md
|
94 |
+
- nn Module: reference/nn.md
|
95 |
+
- operations: reference/ops.md
|
requirements.txt
ADDED
@@ -0,0 +1,46 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Ultralytics requirements
|
2 |
+
# Usage: pip install -r requirements.txt
|
3 |
+
|
4 |
+
# Base ----------------------------------------
|
5 |
+
hydra-core>=1.2.0
|
6 |
+
matplotlib>=3.2.2
|
7 |
+
numpy>=1.18.5
|
8 |
+
opencv-python>=4.1.1
|
9 |
+
Pillow>=7.1.2
|
10 |
+
PyYAML>=5.3.1
|
11 |
+
requests>=2.23.0
|
12 |
+
scipy>=1.4.1
|
13 |
+
torch>=1.7.0
|
14 |
+
torchvision>=0.8.1
|
15 |
+
tqdm>=4.64.0
|
16 |
+
|
17 |
+
# Logging -------------------------------------
|
18 |
+
tensorboard>=2.4.1
|
19 |
+
# clearml
|
20 |
+
# comet
|
21 |
+
|
22 |
+
# Plotting ------------------------------------
|
23 |
+
pandas>=1.1.4
|
24 |
+
seaborn>=0.11.0
|
25 |
+
|
26 |
+
# Export --------------------------------------
|
27 |
+
# coremltools>=6.0 # CoreML export
|
28 |
+
# onnx>=1.12.0 # ONNX export
|
29 |
+
# onnx-simplifier>=0.4.1 # ONNX simplifier
|
30 |
+
# nvidia-pyindex # TensorRT export
|
31 |
+
# nvidia-tensorrt # TensorRT export
|
32 |
+
# scikit-learn==0.19.2 # CoreML quantization
|
33 |
+
# tensorflow>=2.4.1 # TF exports (-cpu, -aarch64, -macos)
|
34 |
+
# tensorflowjs>=3.9.0 # TF.js export
|
35 |
+
# openvino-dev # OpenVINO export
|
36 |
+
|
37 |
+
# Extras --------------------------------------
|
38 |
+
ipython # interactive notebook
|
39 |
+
psutil # system utilization
|
40 |
+
thop>=0.1.1 # FLOPs computation
|
41 |
+
# albumentations>=1.0.3
|
42 |
+
# pycocotools>=2.0.6 # COCO mAP
|
43 |
+
# roboflow
|
44 |
+
|
45 |
+
# HUB -----------------------------------------
|
46 |
+
GitPython>=3.1.24
|
setup.cfg
ADDED
@@ -0,0 +1,54 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Project-wide configuration file, can be used for package metadata and other toll configurations
|
2 |
+
# Example usage: global configuration for PEP8 (via flake8) setting or default pytest arguments
|
3 |
+
# Local usage: pip install pre-commit, pre-commit run --all-files
|
4 |
+
|
5 |
+
[metadata]
|
6 |
+
license_file = LICENSE
|
7 |
+
description_file = README.md
|
8 |
+
|
9 |
+
[tool:pytest]
|
10 |
+
norecursedirs =
|
11 |
+
.git
|
12 |
+
dist
|
13 |
+
build
|
14 |
+
addopts =
|
15 |
+
--doctest-modules
|
16 |
+
--durations=25
|
17 |
+
--color=yes
|
18 |
+
|
19 |
+
[flake8]
|
20 |
+
max-line-length = 120
|
21 |
+
exclude = .tox,*.egg,build,temp
|
22 |
+
select = E,W,F
|
23 |
+
doctests = True
|
24 |
+
verbose = 2
|
25 |
+
# https://pep8.readthedocs.io/en/latest/intro.html#error-codes
|
26 |
+
format = pylint
|
27 |
+
# see: https://www.flake8rules.com/
|
28 |
+
ignore = E731,F405,E402,F401,W504,E127,E231,E501,F403
|
29 |
+
# E731: Do not assign a lambda expression, use a def
|
30 |
+
# F405: name may be undefined, or defined from star imports: module
|
31 |
+
# E402: module level import not at top of file
|
32 |
+
# F401: module imported but unused
|
33 |
+
# W504: line break after binary operator
|
34 |
+
# E127: continuation line over-indented for visual indent
|
35 |
+
# E231: missing whitespace after ‘,’, ‘;’, or ‘:’
|
36 |
+
# E501: line too long
|
37 |
+
# F403: ‘from module import *’ used; unable to detect undefined names
|
38 |
+
|
39 |
+
[isort]
|
40 |
+
# https://pycqa.github.io/isort/docs/configuration/options.html
|
41 |
+
line_length = 120
|
42 |
+
# see: https://pycqa.github.io/isort/docs/configuration/multi_line_output_modes.html
|
43 |
+
multi_line_output = 0
|
44 |
+
|
45 |
+
[yapf]
|
46 |
+
based_on_style = pep8
|
47 |
+
spaces_before_comment = 2
|
48 |
+
COLUMN_LIMIT = 120
|
49 |
+
COALESCE_BRACKETS = True
|
50 |
+
SPACES_AROUND_POWER_OPERATOR = True
|
51 |
+
SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET = False
|
52 |
+
SPLIT_BEFORE_CLOSING_BRACKET = False
|
53 |
+
SPLIT_BEFORE_FIRST_ARGUMENT = False
|
54 |
+
# EACH_DICT_ENTRY_ON_SEPARATE_LINE = False
|
setup.py
ADDED
@@ -0,0 +1,53 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Ultralytics YOLO 🚀, GPL-3.0 license
|
2 |
+
|
3 |
+
import re
|
4 |
+
from pathlib import Path
|
5 |
+
|
6 |
+
import pkg_resources as pkg
|
7 |
+
from setuptools import find_packages, setup
|
8 |
+
|
9 |
+
# Settings
|
10 |
+
FILE = Path(__file__).resolve()
|
11 |
+
ROOT = FILE.parent # root directory
|
12 |
+
README = (ROOT / "README.md").read_text(encoding="utf-8")
|
13 |
+
REQUIREMENTS = [f'{x.name}{x.specifier}' for x in pkg.parse_requirements((ROOT / 'requirements.txt').read_text())]
|
14 |
+
|
15 |
+
|
16 |
+
def get_version():
|
17 |
+
file = ROOT / 'ultralytics/__init__.py'
|
18 |
+
return re.search(r'^__version__ = [\'"]([^\'"]*)[\'"]', file.read_text(), re.M)[1]
|
19 |
+
|
20 |
+
|
21 |
+
setup(
|
22 |
+
name="ultralytics", # name of pypi package
|
23 |
+
version=get_version(), # version of pypi package
|
24 |
+
python_requires=">=3.7.0",
|
25 |
+
license='GPL-3.0',
|
26 |
+
description='Ultralytics YOLOv8 and HUB',
|
27 |
+
long_description=README,
|
28 |
+
long_description_content_type="text/markdown",
|
29 |
+
url="https://github.com/ultralytics/ultralytics",
|
30 |
+
project_urls={
|
31 |
+
'Bug Reports': 'https://github.com/ultralytics/ultralytics/issues',
|
32 |
+
'Funding': 'https://ultralytics.com',
|
33 |
+
'Source': 'https://github.com/ultralytics/ultralytics',},
|
34 |
+
author="Ultralytics",
|
35 |
+
author_email='[email protected]',
|
36 |
+
packages=find_packages(), # required
|
37 |
+
include_package_data=True,
|
38 |
+
install_requires=REQUIREMENTS,
|
39 |
+
extras_require={
|
40 |
+
'dev':
|
41 |
+
['check-manifest', 'pytest', 'pytest-cov', 'coverage', 'mkdocs', 'mkdocstrings[python]', 'mkdocs-material'],},
|
42 |
+
classifiers=[
|
43 |
+
"Intended Audience :: Developers", "Intended Audience :: Science/Research",
|
44 |
+
"License :: OSI Approved :: GNU General Public License v3 (GPLv3)", "Programming Language :: Python :: 3",
|
45 |
+
"Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8",
|
46 |
+
"Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10",
|
47 |
+
"Topic :: Software Development", "Topic :: Scientific/Engineering",
|
48 |
+
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
49 |
+
"Topic :: Scientific/Engineering :: Image Recognition", "Operating System :: POSIX :: Linux",
|
50 |
+
"Operating System :: MacOS", "Operating System :: Microsoft :: Windows"],
|
51 |
+
keywords="machine-learning, deep-learning, vision, ML, DL, AI, YOLO, YOLOv3, YOLOv5, YOLOv8, HUB, Ultralytics",
|
52 |
+
entry_points={
|
53 |
+
'console_scripts': ['yolo = ultralytics.yolo.cli:cli', 'ultralytics = ultralytics.yolo.cli:cli'],})
|
ultralytics/__init__.py
ADDED
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Ultralytics YOLO 🚀, GPL-3.0 license
|
2 |
+
|
3 |
+
__version__ = "8.0.3"
|
4 |
+
|
5 |
+
from ultralytics.hub import checks
|
6 |
+
from ultralytics.yolo.engine.model import YOLO
|
7 |
+
from ultralytics.yolo.utils import ops
|
8 |
+
|
9 |
+
__all__ = ["__version__", "YOLO", "hub", "checks"] # allow simpler import
|
ultralytics/hub/__init__.py
ADDED
@@ -0,0 +1,133 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Ultralytics YOLO 🚀, GPL-3.0 license
|
2 |
+
|
3 |
+
import os
|
4 |
+
import shutil
|
5 |
+
|
6 |
+
import psutil
|
7 |
+
import requests
|
8 |
+
from IPython import display # to display images and clear console output
|
9 |
+
|
10 |
+
from ultralytics.hub.auth import Auth
|
11 |
+
from ultralytics.hub.session import HubTrainingSession
|
12 |
+
from ultralytics.hub.utils import PREFIX, split_key
|
13 |
+
from ultralytics.yolo.utils import LOGGER, emojis, is_colab
|
14 |
+
from ultralytics.yolo.utils.torch_utils import select_device
|
15 |
+
from ultralytics.yolo.v8.detect import DetectionTrainer
|
16 |
+
|
17 |
+
|
18 |
+
def checks(verbose=True):
|
19 |
+
if is_colab():
|
20 |
+
shutil.rmtree('sample_data', ignore_errors=True) # remove colab /sample_data directory
|
21 |
+
|
22 |
+
if verbose:
|
23 |
+
# System info
|
24 |
+
gib = 1 << 30 # bytes per GiB
|
25 |
+
ram = psutil.virtual_memory().total
|
26 |
+
total, used, free = shutil.disk_usage("/")
|
27 |
+
display.clear_output()
|
28 |
+
s = f'({os.cpu_count()} CPUs, {ram / gib:.1f} GB RAM, {(total - free) / gib:.1f}/{total / gib:.1f} GB disk)'
|
29 |
+
else:
|
30 |
+
s = ''
|
31 |
+
|
32 |
+
select_device(newline=False)
|
33 |
+
LOGGER.info(f'Setup complete ✅ {s}')
|
34 |
+
|
35 |
+
|
36 |
+
def start(key=''):
|
37 |
+
# Start training models with Ultralytics HUB. Usage: from src.ultralytics import start; start('API_KEY')
|
38 |
+
def request_api_key(attempts=0):
|
39 |
+
"""Prompt the user to input their API key"""
|
40 |
+
import getpass
|
41 |
+
|
42 |
+
max_attempts = 3
|
43 |
+
tries = f"Attempt {str(attempts + 1)} of {max_attempts}" if attempts > 0 else ""
|
44 |
+
LOGGER.info(f"{PREFIX}Login. {tries}")
|
45 |
+
input_key = getpass.getpass("Enter your Ultralytics HUB API key:\n")
|
46 |
+
auth.api_key, model_id = split_key(input_key)
|
47 |
+
if not auth.authenticate():
|
48 |
+
attempts += 1
|
49 |
+
LOGGER.warning(f"{PREFIX}Invalid API key ⚠️\n")
|
50 |
+
if attempts < max_attempts:
|
51 |
+
return request_api_key(attempts)
|
52 |
+
raise ConnectionError(emojis(f"{PREFIX}Failed to authenticate ❌"))
|
53 |
+
else:
|
54 |
+
return model_id
|
55 |
+
|
56 |
+
try:
|
57 |
+
api_key, model_id = split_key(key)
|
58 |
+
auth = Auth(api_key) # attempts cookie login if no api key is present
|
59 |
+
attempts = 1 if len(key) else 0
|
60 |
+
if not auth.get_state():
|
61 |
+
if len(key):
|
62 |
+
LOGGER.warning(f"{PREFIX}Invalid API key ⚠️\n")
|
63 |
+
model_id = request_api_key(attempts)
|
64 |
+
LOGGER.info(f"{PREFIX}Authenticated ✅")
|
65 |
+
if not model_id:
|
66 |
+
raise ConnectionError(emojis('Connecting with global API key is not currently supported. ❌'))
|
67 |
+
session = HubTrainingSession(model_id=model_id, auth=auth)
|
68 |
+
session.check_disk_space()
|
69 |
+
|
70 |
+
# TODO: refactor, hardcoded for v8
|
71 |
+
args = session.model.copy()
|
72 |
+
args.pop("id")
|
73 |
+
args.pop("status")
|
74 |
+
args.pop("weights")
|
75 |
+
args["data"] = "coco128.yaml"
|
76 |
+
args["model"] = "yolov8n.yaml"
|
77 |
+
args["batch_size"] = 16
|
78 |
+
args["imgsz"] = 64
|
79 |
+
|
80 |
+
trainer = DetectionTrainer(overrides=args)
|
81 |
+
session.register_callbacks(trainer)
|
82 |
+
setattr(trainer, 'hub_session', session)
|
83 |
+
trainer.train()
|
84 |
+
except Exception as e:
|
85 |
+
LOGGER.warning(f"{PREFIX}{e}")
|
86 |
+
|
87 |
+
|
88 |
+
def reset_model(key=''):
|
89 |
+
# Reset a trained model to an untrained state
|
90 |
+
api_key, model_id = split_key(key)
|
91 |
+
r = requests.post('https://api.ultralytics.com/model-reset', json={"apiKey": api_key, "modelId": model_id})
|
92 |
+
|
93 |
+
if r.status_code == 200:
|
94 |
+
LOGGER.info(f"{PREFIX}model reset successfully")
|
95 |
+
return
|
96 |
+
LOGGER.warning(f"{PREFIX}model reset failure {r.status_code} {r.reason}")
|
97 |
+
|
98 |
+
|
99 |
+
def export_model(key='', format='torchscript'):
|
100 |
+
# Export a model to all formats
|
101 |
+
api_key, model_id = split_key(key)
|
102 |
+
formats = ('torchscript', 'onnx', 'openvino', 'engine', 'coreml', 'saved_model', 'pb', 'tflite', 'edgetpu', 'tfjs',
|
103 |
+
'ultralytics_tflite', 'ultralytics_coreml')
|
104 |
+
assert format in formats, f"ERROR: Unsupported export format '{format}' passed, valid formats are {formats}"
|
105 |
+
|
106 |
+
r = requests.post('https://api.ultralytics.com/export',
|
107 |
+
json={
|
108 |
+
"apiKey": api_key,
|
109 |
+
"modelId": model_id,
|
110 |
+
"format": format})
|
111 |
+
assert r.status_code == 200, f"{PREFIX}{format} export failure {r.status_code} {r.reason}"
|
112 |
+
LOGGER.info(f"{PREFIX}{format} export started ✅")
|
113 |
+
|
114 |
+
|
115 |
+
def get_export(key='', format='torchscript'):
|
116 |
+
# Get an exported model dictionary with download URL
|
117 |
+
api_key, model_id = split_key(key)
|
118 |
+
formats = ('torchscript', 'onnx', 'openvino', 'engine', 'coreml', 'saved_model', 'pb', 'tflite', 'edgetpu', 'tfjs',
|
119 |
+
'ultralytics_tflite', 'ultralytics_coreml')
|
120 |
+
assert format in formats, f"ERROR: Unsupported export format '{format}' passed, valid formats are {formats}"
|
121 |
+
|
122 |
+
r = requests.post('https://api.ultralytics.com/get-export',
|
123 |
+
json={
|
124 |
+
"apiKey": api_key,
|
125 |
+
"modelId": model_id,
|
126 |
+
"format": format})
|
127 |
+
assert r.status_code == 200, f"{PREFIX}{format} get_export failure {r.status_code} {r.reason}"
|
128 |
+
return r.json()
|
129 |
+
|
130 |
+
|
131 |
+
# temp. For checking
|
132 |
+
if __name__ == "__main__":
|
133 |
+
start(key="b3fba421be84a20dbe68644e14436d1cce1b0a0aaa_HeMfHgvHsseMPhdq7Ylz")
|
ultralytics/hub/auth.py
ADDED
@@ -0,0 +1,70 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Ultralytics YOLO 🚀, GPL-3.0 license
|
2 |
+
|
3 |
+
import requests
|
4 |
+
|
5 |
+
from ultralytics.hub.utils import HUB_API_ROOT, request_with_credentials
|
6 |
+
from ultralytics.yolo.utils import is_colab
|
7 |
+
|
8 |
+
API_KEY_PATH = "https://hub.ultralytics.com/settings?tab=api+keys"
|
9 |
+
|
10 |
+
|
11 |
+
class Auth:
|
12 |
+
id_token = api_key = model_key = False
|
13 |
+
|
14 |
+
def __init__(self, api_key=None):
|
15 |
+
self.api_key = self._clean_api_key(api_key)
|
16 |
+
self.authenticate() if self.api_key else self.auth_with_cookies()
|
17 |
+
|
18 |
+
@staticmethod
|
19 |
+
def _clean_api_key(key: str) -> str:
|
20 |
+
"""Strip model from key if present"""
|
21 |
+
separator = "_"
|
22 |
+
return key.split(separator)[0] if separator in key else key
|
23 |
+
|
24 |
+
def authenticate(self) -> bool:
|
25 |
+
"""Attempt to authenticate with server"""
|
26 |
+
try:
|
27 |
+
header = self.get_auth_header()
|
28 |
+
if header:
|
29 |
+
r = requests.post(f"{HUB_API_ROOT}/v1/auth", headers=header)
|
30 |
+
if not r.json().get('success', False):
|
31 |
+
raise ConnectionError("Unable to authenticate.")
|
32 |
+
return True
|
33 |
+
raise ConnectionError("User has not authenticated locally.")
|
34 |
+
except ConnectionError:
|
35 |
+
self.id_token = self.api_key = False # reset invalid
|
36 |
+
return False
|
37 |
+
|
38 |
+
def auth_with_cookies(self) -> bool:
|
39 |
+
"""
|
40 |
+
Attempt to fetch authentication via cookies and set id_token.
|
41 |
+
User must be logged in to HUB and running in a supported browser.
|
42 |
+
"""
|
43 |
+
if not is_colab():
|
44 |
+
return False # Currently only works with Colab
|
45 |
+
try:
|
46 |
+
authn = request_with_credentials(f"{HUB_API_ROOT}/v1/auth/auto")
|
47 |
+
if authn.get("success", False):
|
48 |
+
self.id_token = authn.get("data", {}).get("idToken", None)
|
49 |
+
self.authenticate()
|
50 |
+
return True
|
51 |
+
raise ConnectionError("Unable to fetch browser authentication details.")
|
52 |
+
except ConnectionError:
|
53 |
+
self.id_token = False # reset invalid
|
54 |
+
return False
|
55 |
+
|
56 |
+
def get_auth_header(self):
|
57 |
+
if self.id_token:
|
58 |
+
return {"authorization": f"Bearer {self.id_token}"}
|
59 |
+
elif self.api_key:
|
60 |
+
return {"x-api-key": self.api_key}
|
61 |
+
else:
|
62 |
+
return None
|
63 |
+
|
64 |
+
def get_state(self) -> bool:
|
65 |
+
"""Get the authentication state"""
|
66 |
+
return self.id_token or self.api_key
|
67 |
+
|
68 |
+
def set_api_key(self, key: str):
|
69 |
+
"""Get the authentication state"""
|
70 |
+
self.api_key = key
|
ultralytics/hub/session.py
ADDED
@@ -0,0 +1,122 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Ultralytics YOLO 🚀, GPL-3.0 license
|
2 |
+
|
3 |
+
import signal
|
4 |
+
import sys
|
5 |
+
from pathlib import Path
|
6 |
+
from time import sleep
|
7 |
+
|
8 |
+
import requests
|
9 |
+
|
10 |
+
from ultralytics import __version__
|
11 |
+
from ultralytics.hub.utils import HUB_API_ROOT, check_dataset_disk_space, smart_request
|
12 |
+
from ultralytics.yolo.utils import LOGGER, is_colab, threaded
|
13 |
+
|
14 |
+
AGENT_NAME = f'python-{__version__}-colab' if is_colab() else f'python-{__version__}-local'
|
15 |
+
|
16 |
+
session = None
|
17 |
+
|
18 |
+
|
19 |
+
def signal_handler(signum, frame):
|
20 |
+
""" Confirm exit """
|
21 |
+
global hub_logger
|
22 |
+
LOGGER.info(f'Signal received. {signum} {frame}')
|
23 |
+
if isinstance(session, HubTrainingSession):
|
24 |
+
hub_logger.alive = False
|
25 |
+
del hub_logger
|
26 |
+
sys.exit(signum)
|
27 |
+
|
28 |
+
|
29 |
+
signal.signal(signal.SIGTERM, signal_handler)
|
30 |
+
signal.signal(signal.SIGINT, signal_handler)
|
31 |
+
|
32 |
+
|
33 |
+
class HubTrainingSession:
|
34 |
+
|
35 |
+
def __init__(self, model_id, auth):
|
36 |
+
self.agent_id = None # identifies which instance is communicating with server
|
37 |
+
self.model_id = model_id
|
38 |
+
self.api_url = f'{HUB_API_ROOT}/v1/models/{model_id}'
|
39 |
+
self.auth_header = auth.get_auth_header()
|
40 |
+
self.rate_limits = {'metrics': 3.0, 'ckpt': 900.0, 'heartbeat': 300.0} # rate limits (seconds)
|
41 |
+
self.t = {} # rate limit timers (seconds)
|
42 |
+
self.metrics_queue = {} # metrics queue
|
43 |
+
self.alive = True # for heartbeats
|
44 |
+
self.model = self._get_model()
|
45 |
+
self._heartbeats() # start heartbeats
|
46 |
+
|
47 |
+
def __del__(self):
|
48 |
+
# Class destructor
|
49 |
+
self.alive = False
|
50 |
+
|
51 |
+
def upload_metrics(self):
|
52 |
+
payload = {"metrics": self.metrics_queue.copy(), "type": "metrics"}
|
53 |
+
smart_request(f'{self.api_url}', json=payload, headers=self.auth_header, code=2)
|
54 |
+
|
55 |
+
def upload_model(self, epoch, weights, is_best=False, map=0.0, final=False):
|
56 |
+
# Upload a model to HUB
|
57 |
+
file = None
|
58 |
+
if Path(weights).is_file():
|
59 |
+
with open(weights, "rb") as f:
|
60 |
+
file = f.read()
|
61 |
+
if final:
|
62 |
+
smart_request(f'{self.api_url}/upload',
|
63 |
+
data={
|
64 |
+
"epoch": epoch,
|
65 |
+
"type": "final",
|
66 |
+
"map": map},
|
67 |
+
files={"best.pt": file},
|
68 |
+
headers=self.auth_header,
|
69 |
+
retry=10,
|
70 |
+
timeout=3600,
|
71 |
+
code=4)
|
72 |
+
else:
|
73 |
+
smart_request(f'{self.api_url}/upload',
|
74 |
+
data={
|
75 |
+
"epoch": epoch,
|
76 |
+
"type": "epoch",
|
77 |
+
"isBest": bool(is_best)},
|
78 |
+
headers=self.auth_header,
|
79 |
+
files={"last.pt": file},
|
80 |
+
code=3)
|
81 |
+
|
82 |
+
def _get_model(self):
|
83 |
+
# Returns model from database by id
|
84 |
+
api_url = f"{HUB_API_ROOT}/v1/models/{self.model_id}"
|
85 |
+
headers = self.auth_header
|
86 |
+
|
87 |
+
try:
|
88 |
+
r = smart_request(api_url, method="get", headers=headers, thread=False, code=0)
|
89 |
+
data = r.json().get("data", None)
|
90 |
+
if not data:
|
91 |
+
return
|
92 |
+
assert data['data'], 'ERROR: Dataset may still be processing. Please wait a minute and try again.' # RF fix
|
93 |
+
self.model_id = data["id"]
|
94 |
+
|
95 |
+
return data
|
96 |
+
except requests.exceptions.ConnectionError as e:
|
97 |
+
raise ConnectionRefusedError('ERROR: The HUB server is not online. Please try again later.') from e
|
98 |
+
|
99 |
+
def check_disk_space(self):
|
100 |
+
if not check_dataset_disk_space(self.model['data']):
|
101 |
+
raise MemoryError("Not enough disk space")
|
102 |
+
|
103 |
+
# COMMENT: Should not be needed as HUB is now considered an integration and is in integrations_callbacks
|
104 |
+
# import ultralytics.yolo.utils.callbacks.hub as hub_callbacks
|
105 |
+
# @staticmethod
|
106 |
+
# def register_callbacks(trainer):
|
107 |
+
# for k, v in hub_callbacks.callbacks.items():
|
108 |
+
# trainer.add_callback(k, v)
|
109 |
+
|
110 |
+
@threaded
|
111 |
+
def _heartbeats(self):
|
112 |
+
while self.alive:
|
113 |
+
r = smart_request(f'{HUB_API_ROOT}/v1/agent/heartbeat/models/{self.model_id}',
|
114 |
+
json={
|
115 |
+
"agent": AGENT_NAME,
|
116 |
+
"agentId": self.agent_id},
|
117 |
+
headers=self.auth_header,
|
118 |
+
retry=0,
|
119 |
+
code=5,
|
120 |
+
thread=False)
|
121 |
+
self.agent_id = r.json().get('data', {}).get('agentId', None)
|
122 |
+
sleep(self.rate_limits['heartbeat'])
|
ultralytics/hub/utils.py
ADDED
@@ -0,0 +1,150 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Ultralytics YOLO 🚀, GPL-3.0 license
|
2 |
+
|
3 |
+
import os
|
4 |
+
import shutil
|
5 |
+
import threading
|
6 |
+
import time
|
7 |
+
|
8 |
+
import requests
|
9 |
+
|
10 |
+
from ultralytics.yolo.utils import DEFAULT_CONFIG_DICT, LOGGER, RANK, SETTINGS, TryExcept, colorstr, emojis
|
11 |
+
|
12 |
+
PREFIX = colorstr('Ultralytics: ')
|
13 |
+
HELP_MSG = 'If this issue persists please visit https://github.com/ultralytics/hub/issues for assistance.'
|
14 |
+
HUB_API_ROOT = os.environ.get("ULTRALYTICS_HUB_API", "https://api.ultralytics.com")
|
15 |
+
|
16 |
+
|
17 |
+
def check_dataset_disk_space(url='https://github.com/ultralytics/yolov5/releases/download/v1.0/coco128.zip', sf=2.0):
|
18 |
+
# Check that url fits on disk with safety factor sf, i.e. require 2GB free if url size is 1GB with sf=2.0
|
19 |
+
gib = 1 << 30 # bytes per GiB
|
20 |
+
data = int(requests.head(url).headers['Content-Length']) / gib # dataset size (GB)
|
21 |
+
total, used, free = (x / gib for x in shutil.disk_usage("/")) # bytes
|
22 |
+
LOGGER.info(f'{PREFIX}{data:.3f} GB dataset, {free:.1f}/{total:.1f} GB free disk space')
|
23 |
+
if data * sf < free:
|
24 |
+
return True # sufficient space
|
25 |
+
LOGGER.warning(f'{PREFIX}WARNING: Insufficient free disk space {free:.1f} GB < {data * sf:.3f} GB required, '
|
26 |
+
f'training cancelled ❌. Please free {data * sf - free:.1f} GB additional disk space and try again.')
|
27 |
+
return False # insufficient space
|
28 |
+
|
29 |
+
|
30 |
+
def request_with_credentials(url: str) -> any:
|
31 |
+
""" Make an ajax request with cookies attached """
|
32 |
+
from google.colab import output # noqa
|
33 |
+
from IPython import display # noqa
|
34 |
+
display.display(
|
35 |
+
display.Javascript("""
|
36 |
+
window._hub_tmp = new Promise((resolve, reject) => {
|
37 |
+
const timeout = setTimeout(() => reject("Failed authenticating existing browser session"), 5000)
|
38 |
+
fetch("%s", {
|
39 |
+
method: 'POST',
|
40 |
+
credentials: 'include'
|
41 |
+
})
|
42 |
+
.then((response) => resolve(response.json()))
|
43 |
+
.then((json) => {
|
44 |
+
clearTimeout(timeout);
|
45 |
+
}).catch((err) => {
|
46 |
+
clearTimeout(timeout);
|
47 |
+
reject(err);
|
48 |
+
});
|
49 |
+
});
|
50 |
+
""" % url))
|
51 |
+
return output.eval_js("_hub_tmp")
|
52 |
+
|
53 |
+
|
54 |
+
# Deprecated TODO: eliminate this function?
|
55 |
+
def split_key(key=''):
|
56 |
+
"""
|
57 |
+
Verify and split a 'api_key[sep]model_id' string, sep is one of '.' or '_'
|
58 |
+
|
59 |
+
Args:
|
60 |
+
key (str): The model key to split. If not provided, the user will be prompted to enter it.
|
61 |
+
|
62 |
+
Returns:
|
63 |
+
Tuple[str, str]: A tuple containing the API key and model ID.
|
64 |
+
"""
|
65 |
+
|
66 |
+
import getpass
|
67 |
+
|
68 |
+
error_string = emojis(f'{PREFIX}Invalid API key ⚠️\n') # error string
|
69 |
+
if not key:
|
70 |
+
key = getpass.getpass('Enter model key: ')
|
71 |
+
sep = '_' if '_' in key else '.' if '.' in key else None # separator
|
72 |
+
assert sep, error_string
|
73 |
+
api_key, model_id = key.split(sep)
|
74 |
+
assert len(api_key) and len(model_id), error_string
|
75 |
+
return api_key, model_id
|
76 |
+
|
77 |
+
|
78 |
+
def smart_request(*args, retry=3, timeout=30, thread=True, code=-1, method="post", verbose=True, **kwargs):
|
79 |
+
"""
|
80 |
+
Makes an HTTP request using the 'requests' library, with exponential backoff retries up to a specified timeout.
|
81 |
+
|
82 |
+
Args:
|
83 |
+
*args: Positional arguments to be passed to the requests function specified in method.
|
84 |
+
retry (int, optional): Number of retries to attempt before giving up. Default is 3.
|
85 |
+
timeout (int, optional): Timeout in seconds after which the function will give up retrying. Default is 30.
|
86 |
+
thread (bool, optional): Whether to execute the request in a separate daemon thread. Default is True.
|
87 |
+
code (int, optional): An identifier for the request, used for logging purposes. Default is -1.
|
88 |
+
method (str, optional): The HTTP method to use for the request. Choices are 'post' and 'get'. Default is 'post'.
|
89 |
+
verbose (bool, optional): A flag to determine whether to print out to console or not. Default is True.
|
90 |
+
**kwargs: Keyword arguments to be passed to the requests function specified in method.
|
91 |
+
|
92 |
+
Returns:
|
93 |
+
requests.Response: The HTTP response object. If the request is executed in a separate thread, returns None.
|
94 |
+
"""
|
95 |
+
retry_codes = (408, 500) # retry only these codes
|
96 |
+
|
97 |
+
def func(*func_args, **func_kwargs):
|
98 |
+
r = None # response
|
99 |
+
t0 = time.time() # initial time for timer
|
100 |
+
for i in range(retry + 1):
|
101 |
+
if (time.time() - t0) > timeout:
|
102 |
+
break
|
103 |
+
if method == 'post':
|
104 |
+
r = requests.post(*func_args, **func_kwargs) # i.e. post(url, data, json, files)
|
105 |
+
elif method == 'get':
|
106 |
+
r = requests.get(*func_args, **func_kwargs) # i.e. get(url, data, json, files)
|
107 |
+
if r.status_code == 200:
|
108 |
+
break
|
109 |
+
try:
|
110 |
+
m = r.json().get('message', 'No JSON message.')
|
111 |
+
except AttributeError:
|
112 |
+
m = 'Unable to read JSON.'
|
113 |
+
if i == 0:
|
114 |
+
if r.status_code in retry_codes:
|
115 |
+
m += f' Retrying {retry}x for {timeout}s.' if retry else ''
|
116 |
+
elif r.status_code == 429: # rate limit
|
117 |
+
h = r.headers # response headers
|
118 |
+
m = f"Rate limit reached ({h['X-RateLimit-Remaining']}/{h['X-RateLimit-Limit']}). " \
|
119 |
+
f"Please retry after {h['Retry-After']}s."
|
120 |
+
if verbose:
|
121 |
+
LOGGER.warning(f"{PREFIX}{m} {HELP_MSG} ({r.status_code} #{code})")
|
122 |
+
if r.status_code not in retry_codes:
|
123 |
+
return r
|
124 |
+
time.sleep(2 ** i) # exponential standoff
|
125 |
+
return r
|
126 |
+
|
127 |
+
if thread:
|
128 |
+
threading.Thread(target=func, args=args, kwargs=kwargs, daemon=True).start()
|
129 |
+
else:
|
130 |
+
return func(*args, **kwargs)
|
131 |
+
|
132 |
+
|
133 |
+
@TryExcept()
|
134 |
+
def sync_analytics(cfg, all_keys=False, enabled=False):
|
135 |
+
"""
|
136 |
+
Sync analytics data if enabled in the global settings
|
137 |
+
|
138 |
+
Args:
|
139 |
+
cfg (DictConfig): Configuration for the task and mode.
|
140 |
+
all_keys (bool): Sync all items, not just non-default values.
|
141 |
+
enabled (bool): For debugging.
|
142 |
+
"""
|
143 |
+
if SETTINGS['sync'] and RANK in {-1, 0} and enabled:
|
144 |
+
cfg = dict(cfg) # convert type from DictConfig to dict
|
145 |
+
if not all_keys:
|
146 |
+
cfg = {k: v for k, v in cfg.items() if v != DEFAULT_CONFIG_DICT.get(k, None)} # retain non-default values
|
147 |
+
cfg['uuid'] = SETTINGS['uuid'] # add the device UUID to the configuration data
|
148 |
+
|
149 |
+
# Send a request to the HUB API to sync analytics
|
150 |
+
smart_request(f'{HUB_API_ROOT}/v1/usage/anonymous', json=cfg, headers=None, code=3, retry=0, verbose=False)
|
ultralytics/models/README.md
ADDED
@@ -0,0 +1,36 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
## Models
|
2 |
+
|
3 |
+
Welcome to the Ultralytics Models directory! Here you will find a wide variety of pre-configured model configuration
|
4 |
+
files (`*.yaml`s) that can be used to create custom YOLO models. The models in this directory have been expertly crafted
|
5 |
+
and fine-tuned by the Ultralytics team to provide the best performance for a wide range of object detection and image
|
6 |
+
segmentation tasks.
|
7 |
+
|
8 |
+
These model configurations cover a wide range of scenarios, from simple object detection to more complex tasks like
|
9 |
+
instance segmentation and object tracking. They are also designed to run efficiently on a variety of hardware platforms,
|
10 |
+
from CPUs to GPUs. Whether you are a seasoned machine learning practitioner or just getting started with YOLO, this
|
11 |
+
directory provides a great starting point for your custom model development needs.
|
12 |
+
|
13 |
+
To get started, simply browse through the models in this directory and find one that best suits your needs. Once you've
|
14 |
+
selected a model, you can use the provided `*.yaml` file to train and deploy your custom YOLO model with ease. See full
|
15 |
+
details at the Ultralytics [Docs](https://docs.ultralytics.com), and if you need help or have any questions, feel free
|
16 |
+
to reach out to the Ultralytics team for support. So, don't wait, start creating your custom YOLO model now!
|
17 |
+
|
18 |
+
### Usage
|
19 |
+
|
20 |
+
Model `*.yaml` files may be used directly in the Command Line Interface (CLI) with a `yolo` command:
|
21 |
+
|
22 |
+
```bash
|
23 |
+
yolo task=detect mode=train model=yolov8n.yaml data=coco128.yaml epochs=100
|
24 |
+
```
|
25 |
+
|
26 |
+
They may also be used directly in a Python environment, and accepts the same
|
27 |
+
[arguments](https://docs.ultralytics.com/config/) as in the CLI example above:
|
28 |
+
|
29 |
+
```python
|
30 |
+
from ultralytics import YOLO
|
31 |
+
|
32 |
+
model = YOLO("yolov8n.yaml") # build a YOLOv8n model from scratch
|
33 |
+
|
34 |
+
model.info() # display model information
|
35 |
+
model.train(data="coco128.yaml", epochs=100) # train the model
|
36 |
+
```
|
ultralytics/models/v3/yolov3-spp.yaml
ADDED
@@ -0,0 +1,47 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Ultralytics YOLO 🚀, GPL-3.0 license
|
2 |
+
|
3 |
+
# Parameters
|
4 |
+
nc: 80 # number of classes
|
5 |
+
depth_multiple: 1.0 # model depth multiple
|
6 |
+
width_multiple: 1.0 # layer channel multiple
|
7 |
+
|
8 |
+
# darknet53 backbone
|
9 |
+
backbone:
|
10 |
+
# [from, number, module, args]
|
11 |
+
[[-1, 1, Conv, [32, 3, 1]], # 0
|
12 |
+
[-1, 1, Conv, [64, 3, 2]], # 1-P1/2
|
13 |
+
[-1, 1, Bottleneck, [64]],
|
14 |
+
[-1, 1, Conv, [128, 3, 2]], # 3-P2/4
|
15 |
+
[-1, 2, Bottleneck, [128]],
|
16 |
+
[-1, 1, Conv, [256, 3, 2]], # 5-P3/8
|
17 |
+
[-1, 8, Bottleneck, [256]],
|
18 |
+
[-1, 1, Conv, [512, 3, 2]], # 7-P4/16
|
19 |
+
[-1, 8, Bottleneck, [512]],
|
20 |
+
[-1, 1, Conv, [1024, 3, 2]], # 9-P5/32
|
21 |
+
[-1, 4, Bottleneck, [1024]], # 10
|
22 |
+
]
|
23 |
+
|
24 |
+
# YOLOv3-SPP head
|
25 |
+
head:
|
26 |
+
[[-1, 1, Bottleneck, [1024, False]],
|
27 |
+
[-1, 1, SPP, [512, [5, 9, 13]]],
|
28 |
+
[-1, 1, Conv, [1024, 3, 1]],
|
29 |
+
[-1, 1, Conv, [512, 1, 1]],
|
30 |
+
[-1, 1, Conv, [1024, 3, 1]], # 15 (P5/32-large)
|
31 |
+
|
32 |
+
[-2, 1, Conv, [256, 1, 1]],
|
33 |
+
[-1, 1, nn.Upsample, [None, 2, 'nearest']],
|
34 |
+
[[-1, 8], 1, Concat, [1]], # cat backbone P4
|
35 |
+
[-1, 1, Bottleneck, [512, False]],
|
36 |
+
[-1, 1, Bottleneck, [512, False]],
|
37 |
+
[-1, 1, Conv, [256, 1, 1]],
|
38 |
+
[-1, 1, Conv, [512, 3, 1]], # 22 (P4/16-medium)
|
39 |
+
|
40 |
+
[-2, 1, Conv, [128, 1, 1]],
|
41 |
+
[-1, 1, nn.Upsample, [None, 2, 'nearest']],
|
42 |
+
[[-1, 6], 1, Concat, [1]], # cat backbone P3
|
43 |
+
[-1, 1, Bottleneck, [256, False]],
|
44 |
+
[-1, 2, Bottleneck, [256, False]], # 27 (P3/8-small)
|
45 |
+
|
46 |
+
[[27, 22, 15], 1, Detect, [nc]], # Detect(P3, P4, P5)
|
47 |
+
]
|
ultralytics/models/v3/yolov3-tiny.yaml
ADDED
@@ -0,0 +1,38 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Ultralytics YOLO 🚀, GPL-3.0 license
|
2 |
+
|
3 |
+
# Parameters
|
4 |
+
nc: 80 # number of classes
|
5 |
+
depth_multiple: 1.0 # model depth multiple
|
6 |
+
width_multiple: 1.0 # layer channel multiple
|
7 |
+
|
8 |
+
# YOLOv3-tiny backbone
|
9 |
+
backbone:
|
10 |
+
# [from, number, module, args]
|
11 |
+
[[-1, 1, Conv, [16, 3, 1]], # 0
|
12 |
+
[-1, 1, nn.MaxPool2d, [2, 2, 0]], # 1-P1/2
|
13 |
+
[-1, 1, Conv, [32, 3, 1]],
|
14 |
+
[-1, 1, nn.MaxPool2d, [2, 2, 0]], # 3-P2/4
|
15 |
+
[-1, 1, Conv, [64, 3, 1]],
|
16 |
+
[-1, 1, nn.MaxPool2d, [2, 2, 0]], # 5-P3/8
|
17 |
+
[-1, 1, Conv, [128, 3, 1]],
|
18 |
+
[-1, 1, nn.MaxPool2d, [2, 2, 0]], # 7-P4/16
|
19 |
+
[-1, 1, Conv, [256, 3, 1]],
|
20 |
+
[-1, 1, nn.MaxPool2d, [2, 2, 0]], # 9-P5/32
|
21 |
+
[-1, 1, Conv, [512, 3, 1]],
|
22 |
+
[-1, 1, nn.ZeroPad2d, [[0, 1, 0, 1]]], # 11
|
23 |
+
[-1, 1, nn.MaxPool2d, [2, 1, 0]], # 12
|
24 |
+
]
|
25 |
+
|
26 |
+
# YOLOv3-tiny head
|
27 |
+
head:
|
28 |
+
[[-1, 1, Conv, [1024, 3, 1]],
|
29 |
+
[-1, 1, Conv, [256, 1, 1]],
|
30 |
+
[-1, 1, Conv, [512, 3, 1]], # 15 (P5/32-large)
|
31 |
+
|
32 |
+
[-2, 1, Conv, [128, 1, 1]],
|
33 |
+
[-1, 1, nn.Upsample, [None, 2, 'nearest']],
|
34 |
+
[[-1, 8], 1, Concat, [1]], # cat backbone P4
|
35 |
+
[-1, 1, Conv, [256, 3, 1]], # 19 (P4/16-medium)
|
36 |
+
|
37 |
+
[[19, 15], 1, Detect, [nc]], # Detect(P4, P5)
|
38 |
+
]
|
ultralytics/models/v3/yolov3.yaml
ADDED
@@ -0,0 +1,47 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Ultralytics YOLO 🚀, GPL-3.0 license
|
2 |
+
|
3 |
+
# Parameters
|
4 |
+
nc: 80 # number of classes
|
5 |
+
depth_multiple: 1.0 # model depth multiple
|
6 |
+
width_multiple: 1.0 # layer channel multiple
|
7 |
+
|
8 |
+
# darknet53 backbone
|
9 |
+
backbone:
|
10 |
+
# [from, number, module, args]
|
11 |
+
[[-1, 1, Conv, [32, 3, 1]], # 0
|
12 |
+
[-1, 1, Conv, [64, 3, 2]], # 1-P1/2
|
13 |
+
[-1, 1, Bottleneck, [64]],
|
14 |
+
[-1, 1, Conv, [128, 3, 2]], # 3-P2/4
|
15 |
+
[-1, 2, Bottleneck, [128]],
|
16 |
+
[-1, 1, Conv, [256, 3, 2]], # 5-P3/8
|
17 |
+
[-1, 8, Bottleneck, [256]],
|
18 |
+
[-1, 1, Conv, [512, 3, 2]], # 7-P4/16
|
19 |
+
[-1, 8, Bottleneck, [512]],
|
20 |
+
[-1, 1, Conv, [1024, 3, 2]], # 9-P5/32
|
21 |
+
[-1, 4, Bottleneck, [1024]], # 10
|
22 |
+
]
|
23 |
+
|
24 |
+
# YOLOv3 head
|
25 |
+
head:
|
26 |
+
[[-1, 1, Bottleneck, [1024, False]],
|
27 |
+
[-1, 1, Conv, [512, 1, 1]],
|
28 |
+
[-1, 1, Conv, [1024, 3, 1]],
|
29 |
+
[-1, 1, Conv, [512, 1, 1]],
|
30 |
+
[-1, 1, Conv, [1024, 3, 1]], # 15 (P5/32-large)
|
31 |
+
|
32 |
+
[-2, 1, Conv, [256, 1, 1]],
|
33 |
+
[-1, 1, nn.Upsample, [None, 2, 'nearest']],
|
34 |
+
[[-1, 8], 1, Concat, [1]], # cat backbone P4
|
35 |
+
[-1, 1, Bottleneck, [512, False]],
|
36 |
+
[-1, 1, Bottleneck, [512, False]],
|
37 |
+
[-1, 1, Conv, [256, 1, 1]],
|
38 |
+
[-1, 1, Conv, [512, 3, 1]], # 22 (P4/16-medium)
|
39 |
+
|
40 |
+
[-2, 1, Conv, [128, 1, 1]],
|
41 |
+
[-1, 1, nn.Upsample, [None, 2, 'nearest']],
|
42 |
+
[[-1, 6], 1, Concat, [1]], # cat backbone P3
|
43 |
+
[-1, 1, Bottleneck, [256, False]],
|
44 |
+
[-1, 2, Bottleneck, [256, False]], # 27 (P3/8-small)
|
45 |
+
|
46 |
+
[[27, 22, 15], 1, Detect, [nc]], # Detect(P3, P4, P5)
|
47 |
+
]
|
ultralytics/models/v5/yolov5l.yaml
ADDED
@@ -0,0 +1,44 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Ultralytics YOLO 🚀, GPL-3.0 license
|
2 |
+
|
3 |
+
# Parameters
|
4 |
+
nc: 80 # number of classes
|
5 |
+
depth_multiple: 1.0 # model depth multiple
|
6 |
+
width_multiple: 1.0 # layer channel multiple
|
7 |
+
|
8 |
+
# YOLOv5 v6.0 backbone
|
9 |
+
backbone:
|
10 |
+
# [from, number, module, args]
|
11 |
+
[[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2
|
12 |
+
[-1, 1, Conv, [128, 3, 2]], # 1-P2/4
|
13 |
+
[-1, 3, C3, [128]],
|
14 |
+
[-1, 1, Conv, [256, 3, 2]], # 3-P3/8
|
15 |
+
[-1, 6, C3, [256]],
|
16 |
+
[-1, 1, Conv, [512, 3, 2]], # 5-P4/16
|
17 |
+
[-1, 9, C3, [512]],
|
18 |
+
[-1, 1, Conv, [1024, 3, 2]], # 7-P5/32
|
19 |
+
[-1, 3, C3, [1024]],
|
20 |
+
[-1, 1, SPPF, [1024, 5]], # 9
|
21 |
+
]
|
22 |
+
|
23 |
+
# YOLOv5 v6.0 head
|
24 |
+
head:
|
25 |
+
[[-1, 1, Conv, [512, 1, 1]],
|
26 |
+
[-1, 1, nn.Upsample, [None, 2, 'nearest']],
|
27 |
+
[[-1, 6], 1, Concat, [1]], # cat backbone P4
|
28 |
+
[-1, 3, C3, [512, False]], # 13
|
29 |
+
|
30 |
+
[-1, 1, Conv, [256, 1, 1]],
|
31 |
+
[-1, 1, nn.Upsample, [None, 2, 'nearest']],
|
32 |
+
[[-1, 4], 1, Concat, [1]], # cat backbone P3
|
33 |
+
[-1, 3, C3, [256, False]], # 17 (P3/8-small)
|
34 |
+
|
35 |
+
[-1, 1, Conv, [256, 3, 2]],
|
36 |
+
[[-1, 14], 1, Concat, [1]], # cat head P4
|
37 |
+
[-1, 3, C3, [512, False]], # 20 (P4/16-medium)
|
38 |
+
|
39 |
+
[-1, 1, Conv, [512, 3, 2]],
|
40 |
+
[[-1, 10], 1, Concat, [1]], # cat head P5
|
41 |
+
[-1, 3, C3, [1024, False]], # 23 (P5/32-large)
|
42 |
+
|
43 |
+
[[17, 20, 23], 1, Detect, [nc]], # Detect(P3, P4, P5)
|
44 |
+
]
|
ultralytics/models/v5/yolov5m.yaml
ADDED
@@ -0,0 +1,44 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Ultralytics YOLO 🚀, GPL-3.0 license
|
2 |
+
|
3 |
+
# Parameters
|
4 |
+
nc: 80 # number of classes
|
5 |
+
depth_multiple: 0.67 # model depth multiple
|
6 |
+
width_multiple: 0.75 # layer channel multiple
|
7 |
+
|
8 |
+
# YOLOv5 v6.0 backbone
|
9 |
+
backbone:
|
10 |
+
# [from, number, module, args]
|
11 |
+
[[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2
|
12 |
+
[-1, 1, Conv, [128, 3, 2]], # 1-P2/4
|
13 |
+
[-1, 3, C3, [128]],
|
14 |
+
[-1, 1, Conv, [256, 3, 2]], # 3-P3/8
|
15 |
+
[-1, 6, C3, [256]],
|
16 |
+
[-1, 1, Conv, [512, 3, 2]], # 5-P4/16
|
17 |
+
[-1, 9, C3, [512]],
|
18 |
+
[-1, 1, Conv, [1024, 3, 2]], # 7-P5/32
|
19 |
+
[-1, 3, C3, [1024]],
|
20 |
+
[-1, 1, SPPF, [1024, 5]], # 9
|
21 |
+
]
|
22 |
+
|
23 |
+
# YOLOv5 v6.0 head
|
24 |
+
head:
|
25 |
+
[[-1, 1, Conv, [512, 1, 1]],
|
26 |
+
[-1, 1, nn.Upsample, [None, 2, 'nearest']],
|
27 |
+
[[-1, 6], 1, Concat, [1]], # cat backbone P4
|
28 |
+
[-1, 3, C3, [512, False]], # 13
|
29 |
+
|
30 |
+
[-1, 1, Conv, [256, 1, 1]],
|
31 |
+
[-1, 1, nn.Upsample, [None, 2, 'nearest']],
|
32 |
+
[[-1, 4], 1, Concat, [1]], # cat backbone P3
|
33 |
+
[-1, 3, C3, [256, False]], # 17 (P3/8-small)
|
34 |
+
|
35 |
+
[-1, 1, Conv, [256, 3, 2]],
|
36 |
+
[[-1, 14], 1, Concat, [1]], # cat head P4
|
37 |
+
[-1, 3, C3, [512, False]], # 20 (P4/16-medium)
|
38 |
+
|
39 |
+
[-1, 1, Conv, [512, 3, 2]],
|
40 |
+
[[-1, 10], 1, Concat, [1]], # cat head P5
|
41 |
+
[-1, 3, C3, [1024, False]], # 23 (P5/32-large)
|
42 |
+
|
43 |
+
[[17, 20, 23], 1, Detect, [nc]], # Detect(P3, P4, P5)
|
44 |
+
]
|
ultralytics/models/v5/yolov5n.yaml
ADDED
@@ -0,0 +1,44 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Ultralytics YOLO 🚀, GPL-3.0 license
|
2 |
+
|
3 |
+
# Parameters
|
4 |
+
nc: 80 # number of classes
|
5 |
+
depth_multiple: 0.33 # model depth multiple
|
6 |
+
width_multiple: 0.25 # layer channel multiple
|
7 |
+
|
8 |
+
# YOLOv5 v6.0 backbone
|
9 |
+
backbone:
|
10 |
+
# [from, number, module, args]
|
11 |
+
[[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2
|
12 |
+
[-1, 1, Conv, [128, 3, 2]], # 1-P2/4
|
13 |
+
[-1, 3, C3, [128]],
|
14 |
+
[-1, 1, Conv, [256, 3, 2]], # 3-P3/8
|
15 |
+
[-1, 6, C3, [256]],
|
16 |
+
[-1, 1, Conv, [512, 3, 2]], # 5-P4/16
|
17 |
+
[-1, 9, C3, [512]],
|
18 |
+
[-1, 1, Conv, [1024, 3, 2]], # 7-P5/32
|
19 |
+
[-1, 3, C3, [1024]],
|
20 |
+
[-1, 1, SPPF, [1024, 5]], # 9
|
21 |
+
]
|
22 |
+
|
23 |
+
# YOLOv5 v6.0 head
|
24 |
+
head:
|
25 |
+
[[-1, 1, Conv, [512, 1, 1]],
|
26 |
+
[-1, 1, nn.Upsample, [None, 2, 'nearest']],
|
27 |
+
[[-1, 6], 1, Concat, [1]], # cat backbone P4
|
28 |
+
[-1, 3, C3, [512, False]], # 13
|
29 |
+
|
30 |
+
[-1, 1, Conv, [256, 1, 1]],
|
31 |
+
[-1, 1, nn.Upsample, [None, 2, 'nearest']],
|
32 |
+
[[-1, 4], 1, Concat, [1]], # cat backbone P3
|
33 |
+
[-1, 3, C3, [256, False]], # 17 (P3/8-small)
|
34 |
+
|
35 |
+
[-1, 1, Conv, [256, 3, 2]],
|
36 |
+
[[-1, 14], 1, Concat, [1]], # cat head P4
|
37 |
+
[-1, 3, C3, [512, False]], # 20 (P4/16-medium)
|
38 |
+
|
39 |
+
[-1, 1, Conv, [512, 3, 2]],
|
40 |
+
[[-1, 10], 1, Concat, [1]], # cat head P5
|
41 |
+
[-1, 3, C3, [1024, False]], # 23 (P5/32-large)
|
42 |
+
|
43 |
+
[[17, 20, 23], 1, Detect, [nc]], # Detect(P3, P4, P5)
|
44 |
+
]
|
ultralytics/models/v5/yolov5s.yaml
ADDED
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Ultralytics YOLO 🚀, GPL-3.0 license
|
2 |
+
|
3 |
+
# Parameters
|
4 |
+
nc: 80 # number of classes
|
5 |
+
depth_multiple: 0.33 # model depth multiple
|
6 |
+
width_multiple: 0.50 # layer channel multiple
|
7 |
+
|
8 |
+
|
9 |
+
# YOLOv5 v6.0 backbone
|
10 |
+
backbone:
|
11 |
+
# [from, number, module, args]
|
12 |
+
[[-1, 1, Conv, [64, 6, 2, 2]], # 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, 6, 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, 3, C3, [1024]],
|
21 |
+
[-1, 1, SPPF, [1024, 5]], # 9
|
22 |
+
]
|
23 |
+
|
24 |
+
# YOLOv5 v6.0 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, [256, 3, 2]],
|
37 |
+
[[-1, 14], 1, Concat, [1]], # cat head P4
|
38 |
+
[-1, 3, C3, [512, False]], # 20 (P4/16-medium)
|
39 |
+
|
40 |
+
[-1, 1, Conv, [512, 3, 2]],
|
41 |
+
[[-1, 10], 1, Concat, [1]], # cat head P5
|
42 |
+
[-1, 3, C3, [1024, False]], # 23 (P5/32-large)
|
43 |
+
|
44 |
+
[[17, 20, 23], 1, Detect, [nc]], # Detect(P3, P4, P5)
|
45 |
+
]
|
ultralytics/models/v5/yolov5x.yaml
ADDED
@@ -0,0 +1,44 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Ultralytics YOLO 🚀, GPL-3.0 license
|
2 |
+
|
3 |
+
# Parameters
|
4 |
+
nc: 80 # number of classes
|
5 |
+
depth_multiple: 1.33 # model depth multiple
|
6 |
+
width_multiple: 1.25 # layer channel multiple
|
7 |
+
|
8 |
+
# YOLOv5 v6.0 backbone
|
9 |
+
backbone:
|
10 |
+
# [from, number, module, args]
|
11 |
+
[[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2
|
12 |
+
[-1, 1, Conv, [128, 3, 2]], # 1-P2/4
|
13 |
+
[-1, 3, C3, [128]],
|
14 |
+
[-1, 1, Conv, [256, 3, 2]], # 3-P3/8
|
15 |
+
[-1, 6, C3, [256]],
|
16 |
+
[-1, 1, Conv, [512, 3, 2]], # 5-P4/16
|
17 |
+
[-1, 9, C3, [512]],
|
18 |
+
[-1, 1, Conv, [1024, 3, 2]], # 7-P5/32
|
19 |
+
[-1, 3, C3, [1024]],
|
20 |
+
[-1, 1, SPPF, [1024, 5]], # 9
|
21 |
+
]
|
22 |
+
|
23 |
+
# YOLOv5 v6.0 head
|
24 |
+
head:
|
25 |
+
[[-1, 1, Conv, [512, 1, 1]],
|
26 |
+
[-1, 1, nn.Upsample, [None, 2, 'nearest']],
|
27 |
+
[[-1, 6], 1, Concat, [1]], # cat backbone P4
|
28 |
+
[-1, 3, C3, [512, False]], # 13
|
29 |
+
|
30 |
+
[-1, 1, Conv, [256, 1, 1]],
|
31 |
+
[-1, 1, nn.Upsample, [None, 2, 'nearest']],
|
32 |
+
[[-1, 4], 1, Concat, [1]], # cat backbone P3
|
33 |
+
[-1, 3, C3, [256, False]], # 17 (P3/8-small)
|
34 |
+
|
35 |
+
[-1, 1, Conv, [256, 3, 2]],
|
36 |
+
[[-1, 14], 1, Concat, [1]], # cat head P4
|
37 |
+
[-1, 3, C3, [512, False]], # 20 (P4/16-medium)
|
38 |
+
|
39 |
+
[-1, 1, Conv, [512, 3, 2]],
|
40 |
+
[[-1, 10], 1, Concat, [1]], # cat head P5
|
41 |
+
[-1, 3, C3, [1024, False]], # 23 (P5/32-large)
|
42 |
+
|
43 |
+
[[17, 20, 23], 1, Detect, [nc]], # Detect(P3, P4, P5)
|
44 |
+
]
|
ultralytics/models/v8/cls/yolov8l-cls.yaml
ADDED
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Ultralytics YOLO 🚀, GPL-3.0 license
|
2 |
+
|
3 |
+
# Parameters
|
4 |
+
nc: 1000 # number of classes
|
5 |
+
depth_multiple: 1.00 # scales module repeats
|
6 |
+
width_multiple: 1.00 # scales convolution channels
|
7 |
+
|
8 |
+
# YOLOv8.0n backbone
|
9 |
+
backbone:
|
10 |
+
# [from, repeats, module, args]
|
11 |
+
- [-1, 1, Conv, [64, 3, 2]] # 0-P1/2
|
12 |
+
- [-1, 1, Conv, [128, 3, 2]] # 1-P2/4
|
13 |
+
- [-1, 3, C2f, [128, True]]
|
14 |
+
- [-1, 1, Conv, [256, 3, 2]] # 3-P3/8
|
15 |
+
- [-1, 6, C2f, [256, True]]
|
16 |
+
- [-1, 1, Conv, [512, 3, 2]] # 5-P4/16
|
17 |
+
- [-1, 6, C2f, [512, True]]
|
18 |
+
- [-1, 1, Conv, [1024, 3, 2]] # 7-P5/32
|
19 |
+
- [-1, 3, C2f, [1024, True]]
|
20 |
+
|
21 |
+
# YOLOv8.0n head
|
22 |
+
head:
|
23 |
+
- [-1, 1, Classify, [nc]]
|
ultralytics/models/v8/cls/yolov8m-cls.yaml
ADDED
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Ultralytics YOLO 🚀, GPL-3.0 license
|
2 |
+
|
3 |
+
# Parameters
|
4 |
+
nc: 1000 # number of classes
|
5 |
+
depth_multiple: 0.67 # scales module repeats
|
6 |
+
width_multiple: 0.75 # scales convolution channels
|
7 |
+
|
8 |
+
# YOLOv8.0n backbone
|
9 |
+
backbone:
|
10 |
+
# [from, repeats, module, args]
|
11 |
+
- [-1, 1, Conv, [64, 3, 2]] # 0-P1/2
|
12 |
+
- [-1, 1, Conv, [128, 3, 2]] # 1-P2/4
|
13 |
+
- [-1, 3, C2f, [128, True]]
|
14 |
+
- [-1, 1, Conv, [256, 3, 2]] # 3-P3/8
|
15 |
+
- [-1, 6, C2f, [256, True]]
|
16 |
+
- [-1, 1, Conv, [512, 3, 2]] # 5-P4/16
|
17 |
+
- [-1, 6, C2f, [512, True]]
|
18 |
+
- [-1, 1, Conv, [1024, 3, 2]] # 7-P5/32
|
19 |
+
- [-1, 3, C2f, [1024, True]]
|
20 |
+
|
21 |
+
# YOLOv8.0n head
|
22 |
+
head:
|
23 |
+
- [-1, 1, Classify, [nc]]
|
ultralytics/models/v8/cls/yolov8n-cls.yaml
ADDED
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Ultralytics YOLO 🚀, GPL-3.0 license
|
2 |
+
|
3 |
+
# Parameters
|
4 |
+
nc: 1000 # number of classes
|
5 |
+
depth_multiple: 0.33 # scales module repeats
|
6 |
+
width_multiple: 0.25 # scales convolution channels
|
7 |
+
|
8 |
+
# YOLOv8.0n backbone
|
9 |
+
backbone:
|
10 |
+
# [from, repeats, module, args]
|
11 |
+
- [-1, 1, Conv, [64, 3, 2]] # 0-P1/2
|
12 |
+
- [-1, 1, Conv, [128, 3, 2]] # 1-P2/4
|
13 |
+
- [-1, 3, C2f, [128, True]]
|
14 |
+
- [-1, 1, Conv, [256, 3, 2]] # 3-P3/8
|
15 |
+
- [-1, 6, C2f, [256, True]]
|
16 |
+
- [-1, 1, Conv, [512, 3, 2]] # 5-P4/16
|
17 |
+
- [-1, 6, C2f, [512, True]]
|
18 |
+
- [-1, 1, Conv, [1024, 3, 2]] # 7-P5/32
|
19 |
+
- [-1, 3, C2f, [1024, True]]
|
20 |
+
|
21 |
+
# YOLOv8.0n head
|
22 |
+
head:
|
23 |
+
- [-1, 1, Classify, [nc]]
|
ultralytics/models/v8/cls/yolov8s-cls.yaml
ADDED
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Ultralytics YOLO 🚀, GPL-3.0 license
|
2 |
+
|
3 |
+
# Parameters
|
4 |
+
nc: 1000 # number of classes
|
5 |
+
depth_multiple: 0.33 # scales module repeats
|
6 |
+
width_multiple: 0.50 # scales convolution channels
|
7 |
+
|
8 |
+
# YOLOv8.0n backbone
|
9 |
+
backbone:
|
10 |
+
# [from, repeats, module, args]
|
11 |
+
- [-1, 1, Conv, [64, 3, 2]] # 0-P1/2
|
12 |
+
- [-1, 1, Conv, [128, 3, 2]] # 1-P2/4
|
13 |
+
- [-1, 3, C2f, [128, True]]
|
14 |
+
- [-1, 1, Conv, [256, 3, 2]] # 3-P3/8
|
15 |
+
- [-1, 6, C2f, [256, True]]
|
16 |
+
- [-1, 1, Conv, [512, 3, 2]] # 5-P4/16
|
17 |
+
- [-1, 6, C2f, [512, True]]
|
18 |
+
- [-1, 1, Conv, [1024, 3, 2]] # 7-P5/32
|
19 |
+
- [-1, 3, C2f, [1024, True]]
|
20 |
+
|
21 |
+
# YOLOv8.0n head
|
22 |
+
head:
|
23 |
+
- [-1, 1, Classify, [nc]]
|
ultralytics/models/v8/cls/yolov8x-cls.yaml
ADDED
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Ultralytics YOLO 🚀, GPL-3.0 license
|
2 |
+
|
3 |
+
# Parameters
|
4 |
+
nc: 1000 # number of classes
|
5 |
+
depth_multiple: 1.00 # scales module repeats
|
6 |
+
width_multiple: 1.25 # scales convolution channels
|
7 |
+
|
8 |
+
# YOLOv8.0n backbone
|
9 |
+
backbone:
|
10 |
+
# [from, repeats, module, args]
|
11 |
+
- [-1, 1, Conv, [64, 3, 2]] # 0-P1/2
|
12 |
+
- [-1, 1, Conv, [128, 3, 2]] # 1-P2/4
|
13 |
+
- [-1, 3, C2f, [128, True]]
|
14 |
+
- [-1, 1, Conv, [256, 3, 2]] # 3-P3/8
|
15 |
+
- [-1, 6, C2f, [256, True]]
|
16 |
+
- [-1, 1, Conv, [512, 3, 2]] # 5-P4/16
|
17 |
+
- [-1, 6, C2f, [512, True]]
|
18 |
+
- [-1, 1, Conv, [1024, 3, 2]] # 7-P5/32
|
19 |
+
- [-1, 3, C2f, [1024, True]]
|
20 |
+
|
21 |
+
# YOLOv8.0n head
|
22 |
+
head:
|
23 |
+
- [-1, 1, Classify, [nc]]
|
ultralytics/models/v8/seg/yolov8l-seg.yaml
ADDED
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Ultralytics YOLO 🚀, GPL-3.0 license
|
2 |
+
|
3 |
+
# Parameters
|
4 |
+
nc: 80 # number of classes
|
5 |
+
depth_multiple: 1.00 # scales module repeats
|
6 |
+
width_multiple: 1.00 # scales convolution channels
|
7 |
+
|
8 |
+
# YOLOv8.0l backbone
|
9 |
+
backbone:
|
10 |
+
# [from, repeats, module, args]
|
11 |
+
- [-1, 1, Conv, [64, 3, 2]] # 0-P1/2
|
12 |
+
- [-1, 1, Conv, [128, 3, 2]] # 1-P2/4
|
13 |
+
- [-1, 3, C2f, [128, True]]
|
14 |
+
- [-1, 1, Conv, [256, 3, 2]] # 3-P3/8
|
15 |
+
- [-1, 6, C2f, [256, True]]
|
16 |
+
- [-1, 1, Conv, [512, 3, 2]] # 5-P4/16
|
17 |
+
- [-1, 6, C2f, [512, True]]
|
18 |
+
- [-1, 1, Conv, [512, 3, 2]] # 7-P5/32
|
19 |
+
- [-1, 3, C2f, [512, True]]
|
20 |
+
- [-1, 1, SPPF, [512, 5]] # 9
|
21 |
+
|
22 |
+
# YOLOv8.0l head
|
23 |
+
head:
|
24 |
+
- [-1, 1, nn.Upsample, [None, 2, 'nearest']]
|
25 |
+
- [[-1, 6], 1, Concat, [1]] # cat backbone P4
|
26 |
+
- [-1, 3, C2f, [512]] # 13
|
27 |
+
|
28 |
+
- [-1, 1, nn.Upsample, [None, 2, 'nearest']]
|
29 |
+
- [[-1, 4], 1, Concat, [1]] # cat backbone P3
|
30 |
+
- [-1, 3, C2f, [256]] # 17 (P3/8-small)
|
31 |
+
|
32 |
+
- [-1, 1, Conv, [256, 3, 2]]
|
33 |
+
- [[-1, 12], 1, Concat, [1]] # cat head P4
|
34 |
+
- [-1, 3, C2f, [512]] # 20 (P4/16-medium)
|
35 |
+
|
36 |
+
- [-1, 1, Conv, [512, 3, 2]]
|
37 |
+
- [[-1, 9], 1, Concat, [1]] # cat head P5
|
38 |
+
- [-1, 3, C2f, [512]] # 23 (P5/32-large)
|
39 |
+
|
40 |
+
- [[15, 18, 21], 1, Segment, [nc, 32, 256]] # Detect(P3, P4, P5)
|
ultralytics/models/v8/seg/yolov8m-seg.yaml
ADDED
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Ultralytics YOLO 🚀, GPL-3.0 license
|
2 |
+
|
3 |
+
# Parameters
|
4 |
+
nc: 80 # number of classes
|
5 |
+
depth_multiple: 0.67 # scales module repeats
|
6 |
+
width_multiple: 0.75 # scales convolution channels
|
7 |
+
|
8 |
+
# YOLOv8.0m backbone
|
9 |
+
backbone:
|
10 |
+
# [from, repeats, module, args]
|
11 |
+
- [-1, 1, Conv, [64, 3, 2]] # 0-P1/2
|
12 |
+
- [-1, 1, Conv, [128, 3, 2]] # 1-P2/4
|
13 |
+
- [-1, 3, C2f, [128, True]]
|
14 |
+
- [-1, 1, Conv, [256, 3, 2]] # 3-P3/8
|
15 |
+
- [-1, 6, C2f, [256, True]]
|
16 |
+
- [-1, 1, Conv, [512, 3, 2]] # 5-P4/16
|
17 |
+
- [-1, 6, C2f, [512, True]]
|
18 |
+
- [-1, 1, Conv, [768, 3, 2]] # 7-P5/32
|
19 |
+
- [-1, 3, C2f, [768, True]]
|
20 |
+
- [-1, 1, SPPF, [768, 5]] # 9
|
21 |
+
|
22 |
+
# YOLOv8.0m head
|
23 |
+
head:
|
24 |
+
- [-1, 1, nn.Upsample, [None, 2, 'nearest']]
|
25 |
+
- [[-1, 6], 1, Concat, [1]] # cat backbone P4
|
26 |
+
- [-1, 3, C2f, [512]] # 13
|
27 |
+
|
28 |
+
- [-1, 1, nn.Upsample, [None, 2, 'nearest']]
|
29 |
+
- [[-1, 4], 1, Concat, [1]] # cat backbone P3
|
30 |
+
- [-1, 3, C2f, [256]] # 17 (P3/8-small)
|
31 |
+
|
32 |
+
- [-1, 1, Conv, [256, 3, 2]]
|
33 |
+
- [[-1, 12], 1, Concat, [1]] # cat head P4
|
34 |
+
- [-1, 3, C2f, [512]] # 20 (P4/16-medium)
|
35 |
+
|
36 |
+
- [-1, 1, Conv, [512, 3, 2]]
|
37 |
+
- [[-1, 9], 1, Concat, [1]] # cat head P5
|
38 |
+
- [-1, 3, C2f, [768]] # 23 (P5/32-large)
|
39 |
+
|
40 |
+
- [[15, 18, 21], 1, Segment, [nc, 32, 256]] # Detect(P3, P4, P5)
|
ultralytics/models/v8/seg/yolov8n-seg.yaml
ADDED
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Ultralytics YOLO 🚀, GPL-3.0 license
|
2 |
+
|
3 |
+
# Parameters
|
4 |
+
nc: 80 # number of classes
|
5 |
+
depth_multiple: 0.33 # scales module repeats
|
6 |
+
width_multiple: 0.25 # scales convolution channels
|
7 |
+
|
8 |
+
# YOLOv8.0n backbone
|
9 |
+
backbone:
|
10 |
+
# [from, repeats, module, args]
|
11 |
+
- [-1, 1, Conv, [64, 3, 2]] # 0-P1/2
|
12 |
+
- [-1, 1, Conv, [128, 3, 2]] # 1-P2/4
|
13 |
+
- [-1, 3, C2f, [128, True]]
|
14 |
+
- [-1, 1, Conv, [256, 3, 2]] # 3-P3/8
|
15 |
+
- [-1, 6, C2f, [256, True]]
|
16 |
+
- [-1, 1, Conv, [512, 3, 2]] # 5-P4/16
|
17 |
+
- [-1, 6, C2f, [512, True]]
|
18 |
+
- [-1, 1, Conv, [1024, 3, 2]] # 7-P5/32
|
19 |
+
- [-1, 3, C2f, [1024, True]]
|
20 |
+
- [-1, 1, SPPF, [1024, 5]] # 9
|
21 |
+
|
22 |
+
# YOLOv8.0n head
|
23 |
+
head:
|
24 |
+
- [-1, 1, nn.Upsample, [None, 2, 'nearest']]
|
25 |
+
- [[-1, 6], 1, Concat, [1]] # cat backbone P4
|
26 |
+
- [-1, 3, C2f, [512]] # 13
|
27 |
+
|
28 |
+
- [-1, 1, nn.Upsample, [None, 2, 'nearest']]
|
29 |
+
- [[-1, 4], 1, Concat, [1]] # cat backbone P3
|
30 |
+
- [-1, 3, C2f, [256]] # 17 (P3/8-small)
|
31 |
+
|
32 |
+
- [-1, 1, Conv, [256, 3, 2]]
|
33 |
+
- [[-1, 12], 1, Concat, [1]] # cat head P4
|
34 |
+
- [-1, 3, C2f, [512]] # 20 (P4/16-medium)
|
35 |
+
|
36 |
+
- [-1, 1, Conv, [512, 3, 2]]
|
37 |
+
- [[-1, 9], 1, Concat, [1]] # cat head P5
|
38 |
+
- [-1, 3, C2f, [1024]] # 23 (P5/32-large)
|
39 |
+
|
40 |
+
- [[15, 18, 21], 1, Segment, [nc, 32, 256]] # Detect(P3, P4, P5)
|
ultralytics/models/v8/seg/yolov8s-seg.yaml
ADDED
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Ultralytics YOLO 🚀, GPL-3.0 license
|
2 |
+
|
3 |
+
# Parameters
|
4 |
+
nc: 80 # number of classes
|
5 |
+
depth_multiple: 0.33 # scales module repeats
|
6 |
+
width_multiple: 0.50 # scales convolution channels
|
7 |
+
|
8 |
+
# YOLOv8.0s backbone
|
9 |
+
backbone:
|
10 |
+
# [from, repeats, module, args]
|
11 |
+
- [-1, 1, Conv, [64, 3, 2]] # 0-P1/2
|
12 |
+
- [-1, 1, Conv, [128, 3, 2]] # 1-P2/4
|
13 |
+
- [-1, 3, C2f, [128, True]]
|
14 |
+
- [-1, 1, Conv, [256, 3, 2]] # 3-P3/8
|
15 |
+
- [-1, 6, C2f, [256, True]]
|
16 |
+
- [-1, 1, Conv, [512, 3, 2]] # 5-P4/16
|
17 |
+
- [-1, 6, C2f, [512, True]]
|
18 |
+
- [-1, 1, Conv, [1024, 3, 2]] # 7-P5/32
|
19 |
+
- [-1, 3, C2f, [1024, True]]
|
20 |
+
- [-1, 1, SPPF, [1024, 5]] # 9
|
21 |
+
|
22 |
+
# YOLOv8.0s head
|
23 |
+
head:
|
24 |
+
- [-1, 1, nn.Upsample, [None, 2, 'nearest']]
|
25 |
+
- [[-1, 6], 1, Concat, [1]] # cat backbone P4
|
26 |
+
- [-1, 3, C2f, [512]] # 13
|
27 |
+
|
28 |
+
- [-1, 1, nn.Upsample, [None, 2, 'nearest']]
|
29 |
+
- [[-1, 4], 1, Concat, [1]] # cat backbone P3
|
30 |
+
- [-1, 3, C2f, [256]] # 17 (P3/8-small)
|
31 |
+
|
32 |
+
- [-1, 1, Conv, [256, 3, 2]]
|
33 |
+
- [[-1, 12], 1, Concat, [1]] # cat head P4
|
34 |
+
- [-1, 3, C2f, [512]] # 20 (P4/16-medium)
|
35 |
+
|
36 |
+
- [-1, 1, Conv, [512, 3, 2]]
|
37 |
+
- [[-1, 9], 1, Concat, [1]] # cat head P5
|
38 |
+
- [-1, 3, C2f, [1024]] # 23 (P5/32-large)
|
39 |
+
|
40 |
+
- [[15, 18, 21], 1, Segment, [nc, 32, 256]] # Detect(P3, P4, P5)
|
ultralytics/models/v8/seg/yolov8x-seg.yaml
ADDED
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Ultralytics YOLO 🚀, GPL-3.0 license
|
2 |
+
|
3 |
+
# Parameters
|
4 |
+
nc: 80 # number of classes
|
5 |
+
depth_multiple: 1.00 # scales module repeats
|
6 |
+
width_multiple: 1.25 # scales convolution channels
|
7 |
+
|
8 |
+
# YOLOv8.0x backbone
|
9 |
+
backbone:
|
10 |
+
# [from, repeats, module, args]
|
11 |
+
- [-1, 1, Conv, [64, 3, 2]] # 0-P1/2
|
12 |
+
- [-1, 1, Conv, [128, 3, 2]] # 1-P2/4
|
13 |
+
- [-1, 3, C2f, [128, True]]
|
14 |
+
- [-1, 1, Conv, [256, 3, 2]] # 3-P3/8
|
15 |
+
- [-1, 6, C2f, [256, True]]
|
16 |
+
- [-1, 1, Conv, [512, 3, 2]] # 5-P4/16
|
17 |
+
- [-1, 6, C2f, [512, True]]
|
18 |
+
- [-1, 1, Conv, [512, 3, 2]] # 7-P5/32
|
19 |
+
- [-1, 3, C2f, [512, True]]
|
20 |
+
- [-1, 1, SPPF, [512, 5]] # 9
|
21 |
+
|
22 |
+
# YOLOv8.0x head
|
23 |
+
head:
|
24 |
+
- [-1, 1, nn.Upsample, [None, 2, 'nearest']]
|
25 |
+
- [[-1, 6], 1, Concat, [1]] # cat backbone P4
|
26 |
+
- [-1, 3, C2f, [512]] # 13
|
27 |
+
|
28 |
+
- [-1, 1, nn.Upsample, [None, 2, 'nearest']]
|
29 |
+
- [[-1, 4], 1, Concat, [1]] # cat backbone P3
|
30 |
+
- [-1, 3, C2f, [256]] # 17 (P3/8-small)
|
31 |
+
|
32 |
+
- [-1, 1, Conv, [256, 3, 2]]
|
33 |
+
- [[-1, 12], 1, Concat, [1]] # cat head P4
|
34 |
+
- [-1, 3, C2f, [512]] # 20 (P4/16-medium)
|
35 |
+
|
36 |
+
- [-1, 1, Conv, [512, 3, 2]]
|
37 |
+
- [[-1, 9], 1, Concat, [1]] # cat head P5
|
38 |
+
- [-1, 3, C2f, [512]] # 23 (P5/32-large)
|
39 |
+
|
40 |
+
- [[15, 18, 21], 1, Segment, [nc, 32, 256]] # Detect(P3, P4, P5)
|
ultralytics/models/v8/yolov8l.yaml
ADDED
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Ultralytics YOLO 🚀, GPL-3.0 license
|
2 |
+
|
3 |
+
# Parameters
|
4 |
+
nc: 80 # number of classes
|
5 |
+
depth_multiple: 1.00 # scales module repeats
|
6 |
+
width_multiple: 1.00 # scales convolution channels
|
7 |
+
|
8 |
+
# YOLOv8.0l backbone
|
9 |
+
backbone:
|
10 |
+
# [from, repeats, module, args]
|
11 |
+
- [-1, 1, Conv, [64, 3, 2]] # 0-P1/2
|
12 |
+
- [-1, 1, Conv, [128, 3, 2]] # 1-P2/4
|
13 |
+
- [-1, 3, C2f, [128, True]]
|
14 |
+
- [-1, 1, Conv, [256, 3, 2]] # 3-P3/8
|
15 |
+
- [-1, 6, C2f, [256, True]]
|
16 |
+
- [-1, 1, Conv, [512, 3, 2]] # 5-P4/16
|
17 |
+
- [-1, 6, C2f, [512, True]]
|
18 |
+
- [-1, 1, Conv, [512, 3, 2]] # 7-P5/32
|
19 |
+
- [-1, 3, C2f, [512, True]]
|
20 |
+
- [-1, 1, SPPF, [512, 5]] # 9
|
21 |
+
|
22 |
+
# YOLOv8.0l head
|
23 |
+
head:
|
24 |
+
- [-1, 1, nn.Upsample, [None, 2, 'nearest']]
|
25 |
+
- [[-1, 6], 1, Concat, [1]] # cat backbone P4
|
26 |
+
- [-1, 3, C2f, [512]] # 13
|
27 |
+
|
28 |
+
- [-1, 1, nn.Upsample, [None, 2, 'nearest']]
|
29 |
+
- [[-1, 4], 1, Concat, [1]] # cat backbone P3
|
30 |
+
- [-1, 3, C2f, [256]] # 17 (P3/8-small)
|
31 |
+
|
32 |
+
- [-1, 1, Conv, [256, 3, 2]]
|
33 |
+
- [[-1, 12], 1, Concat, [1]] # cat head P4
|
34 |
+
- [-1, 3, C2f, [512]] # 20 (P4/16-medium)
|
35 |
+
|
36 |
+
- [-1, 1, Conv, [512, 3, 2]]
|
37 |
+
- [[-1, 9], 1, Concat, [1]] # cat head P5
|
38 |
+
- [-1, 3, C2f, [512]] # 23 (P5/32-large)
|
39 |
+
|
40 |
+
- [[15, 18, 21], 1, Detect, [nc]] # Detect(P3, P4, P5)
|
ultralytics/models/v8/yolov8m.yaml
ADDED
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Ultralytics YOLO 🚀, GPL-3.0 license
|
2 |
+
|
3 |
+
# Parameters
|
4 |
+
nc: 80 # number of classes
|
5 |
+
depth_multiple: 0.67 # scales module repeats
|
6 |
+
width_multiple: 0.75 # scales convolution channels
|
7 |
+
|
8 |
+
# YOLOv8.0m backbone
|
9 |
+
backbone:
|
10 |
+
# [from, repeats, module, args]
|
11 |
+
- [-1, 1, Conv, [64, 3, 2]] # 0-P1/2
|
12 |
+
- [-1, 1, Conv, [128, 3, 2]] # 1-P2/4
|
13 |
+
- [-1, 3, C2f, [128, True]]
|
14 |
+
- [-1, 1, Conv, [256, 3, 2]] # 3-P3/8
|
15 |
+
- [-1, 6, C2f, [256, True]]
|
16 |
+
- [-1, 1, Conv, [512, 3, 2]] # 5-P4/16
|
17 |
+
- [-1, 6, C2f, [512, True]]
|
18 |
+
- [-1, 1, Conv, [768, 3, 2]] # 7-P5/32
|
19 |
+
- [-1, 3, C2f, [768, True]]
|
20 |
+
- [-1, 1, SPPF, [768, 5]] # 9
|
21 |
+
|
22 |
+
# YOLOv8.0m head
|
23 |
+
head:
|
24 |
+
- [-1, 1, nn.Upsample, [None, 2, 'nearest']]
|
25 |
+
- [[-1, 6], 1, Concat, [1]] # cat backbone P4
|
26 |
+
- [-1, 3, C2f, [512]] # 13
|
27 |
+
|
28 |
+
- [-1, 1, nn.Upsample, [None, 2, 'nearest']]
|
29 |
+
- [[-1, 4], 1, Concat, [1]] # cat backbone P3
|
30 |
+
- [-1, 3, C2f, [256]] # 17 (P3/8-small)
|
31 |
+
|
32 |
+
- [-1, 1, Conv, [256, 3, 2]]
|
33 |
+
- [[-1, 12], 1, Concat, [1]] # cat head P4
|
34 |
+
- [-1, 3, C2f, [512]] # 20 (P4/16-medium)
|
35 |
+
|
36 |
+
- [-1, 1, Conv, [512, 3, 2]]
|
37 |
+
- [[-1, 9], 1, Concat, [1]] # cat head P5
|
38 |
+
- [-1, 3, C2f, [768]] # 23 (P5/32-large)
|
39 |
+
|
40 |
+
- [[15, 18, 21], 1, Detect, [nc]] # Detect(P3, P4, P5)
|
ultralytics/models/v8/yolov8n.yaml
ADDED
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Ultralytics YOLO 🚀, GPL-3.0 license
|
2 |
+
|
3 |
+
# Parameters
|
4 |
+
nc: 80 # number of classes
|
5 |
+
depth_multiple: 0.33 # scales module repeats
|
6 |
+
width_multiple: 0.25 # scales convolution channels
|
7 |
+
|
8 |
+
# YOLOv8.0n backbone
|
9 |
+
backbone:
|
10 |
+
# [from, repeats, module, args]
|
11 |
+
- [-1, 1, Conv, [64, 3, 2]] # 0-P1/2
|
12 |
+
- [-1, 1, Conv, [128, 3, 2]] # 1-P2/4
|
13 |
+
- [-1, 3, C2f, [128, True]]
|
14 |
+
- [-1, 1, Conv, [256, 3, 2]] # 3-P3/8
|
15 |
+
- [-1, 6, C2f, [256, True]]
|
16 |
+
- [-1, 1, Conv, [512, 3, 2]] # 5-P4/16
|
17 |
+
- [-1, 6, C2f, [512, True]]
|
18 |
+
- [-1, 1, Conv, [1024, 3, 2]] # 7-P5/32
|
19 |
+
- [-1, 3, C2f, [1024, True]]
|
20 |
+
- [-1, 1, SPPF, [1024, 5]] # 9
|
21 |
+
|
22 |
+
# YOLOv8.0n head
|
23 |
+
head:
|
24 |
+
- [-1, 1, nn.Upsample, [None, 2, 'nearest']]
|
25 |
+
- [[-1, 6], 1, Concat, [1]] # cat backbone P4
|
26 |
+
- [-1, 3, C2f, [512]] # 13
|
27 |
+
|
28 |
+
- [-1, 1, nn.Upsample, [None, 2, 'nearest']]
|
29 |
+
- [[-1, 4], 1, Concat, [1]] # cat backbone P3
|
30 |
+
- [-1, 3, C2f, [256]] # 17 (P3/8-small)
|
31 |
+
|
32 |
+
- [-1, 1, Conv, [256, 3, 2]]
|
33 |
+
- [[-1, 12], 1, Concat, [1]] # cat head P4
|
34 |
+
- [-1, 3, C2f, [512]] # 20 (P4/16-medium)
|
35 |
+
|
36 |
+
- [-1, 1, Conv, [512, 3, 2]]
|
37 |
+
- [[-1, 9], 1, Concat, [1]] # cat head P5
|
38 |
+
- [-1, 3, C2f, [1024]] # 23 (P5/32-large)
|
39 |
+
|
40 |
+
- [[15, 18, 21], 1, Detect, [nc]] # Detect(P3, P4, P5)
|
ultralytics/models/v8/yolov8s.yaml
ADDED
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Ultralytics YOLO 🚀, GPL-3.0 license
|
2 |
+
|
3 |
+
# Parameters
|
4 |
+
nc: 80 # number of classes
|
5 |
+
depth_multiple: 0.33 # scales module repeats
|
6 |
+
width_multiple: 0.50 # scales convolution channels
|
7 |
+
|
8 |
+
# YOLOv8.0s backbone
|
9 |
+
backbone:
|
10 |
+
# [from, repeats, module, args]
|
11 |
+
- [-1, 1, Conv, [64, 3, 2]] # 0-P1/2
|
12 |
+
- [-1, 1, Conv, [128, 3, 2]] # 1-P2/4
|
13 |
+
- [-1, 3, C2f, [128, True]]
|
14 |
+
- [-1, 1, Conv, [256, 3, 2]] # 3-P3/8
|
15 |
+
- [-1, 6, C2f, [256, True]]
|
16 |
+
- [-1, 1, Conv, [512, 3, 2]] # 5-P4/16
|
17 |
+
- [-1, 6, C2f, [512, True]]
|
18 |
+
- [-1, 1, Conv, [1024, 3, 2]] # 7-P5/32
|
19 |
+
- [-1, 3, C2f, [1024, True]]
|
20 |
+
- [-1, 1, SPPF, [1024, 5]] # 9
|
21 |
+
|
22 |
+
# YOLOv8.0s head
|
23 |
+
head:
|
24 |
+
- [-1, 1, nn.Upsample, [None, 2, 'nearest']]
|
25 |
+
- [[-1, 6], 1, Concat, [1]] # cat backbone P4
|
26 |
+
- [-1, 3, C2f, [512]] # 13
|
27 |
+
|
28 |
+
- [-1, 1, nn.Upsample, [None, 2, 'nearest']]
|
29 |
+
- [[-1, 4], 1, Concat, [1]] # cat backbone P3
|
30 |
+
- [-1, 3, C2f, [256]] # 17 (P3/8-small)
|
31 |
+
|
32 |
+
- [-1, 1, Conv, [256, 3, 2]]
|
33 |
+
- [[-1, 12], 1, Concat, [1]] # cat head P4
|
34 |
+
- [-1, 3, C2f, [512]] # 20 (P4/16-medium)
|
35 |
+
|
36 |
+
- [-1, 1, Conv, [512, 3, 2]]
|
37 |
+
- [[-1, 9], 1, Concat, [1]] # cat head P5
|
38 |
+
- [-1, 3, C2f, [1024]] # 23 (P5/32-large)
|
39 |
+
|
40 |
+
- [[15, 18, 21], 1, Detect, [nc]] # Detect(P3, P4, P5)
|
ultralytics/models/v8/yolov8x.yaml
ADDED
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Ultralytics YOLO 🚀, GPL-3.0 license
|
2 |
+
|
3 |
+
# Parameters
|
4 |
+
nc: 80 # number of classes
|
5 |
+
depth_multiple: 1.00 # scales module repeats
|
6 |
+
width_multiple: 1.25 # scales convolution channels
|
7 |
+
|
8 |
+
# YOLOv8.0x backbone
|
9 |
+
backbone:
|
10 |
+
# [from, repeats, module, args]
|
11 |
+
- [-1, 1, Conv, [64, 3, 2]] # 0-P1/2
|
12 |
+
- [-1, 1, Conv, [128, 3, 2]] # 1-P2/4
|
13 |
+
- [-1, 3, C2f, [128, True]]
|
14 |
+
- [-1, 1, Conv, [256, 3, 2]] # 3-P3/8
|
15 |
+
- [-1, 6, C2f, [256, True]]
|
16 |
+
- [-1, 1, Conv, [512, 3, 2]] # 5-P4/16
|
17 |
+
- [-1, 6, C2f, [512, True]]
|
18 |
+
- [-1, 1, Conv, [512, 3, 2]] # 7-P5/32
|
19 |
+
- [-1, 3, C2f, [512, True]]
|
20 |
+
- [-1, 1, SPPF, [512, 5]] # 9
|
21 |
+
|
22 |
+
# YOLOv8.0x head
|
23 |
+
head:
|
24 |
+
- [-1, 1, nn.Upsample, [None, 2, 'nearest']]
|
25 |
+
- [[-1, 6], 1, Concat, [1]] # cat backbone P4
|
26 |
+
- [-1, 3, C2f, [512]] # 13
|
27 |
+
|
28 |
+
- [-1, 1, nn.Upsample, [None, 2, 'nearest']]
|
29 |
+
- [[-1, 4], 1, Concat, [1]] # cat backbone P3
|
30 |
+
- [-1, 3, C2f, [256]] # 17 (P3/8-small)
|
31 |
+
|
32 |
+
- [-1, 1, Conv, [256, 3, 2]]
|
33 |
+
- [[-1, 12], 1, Concat, [1]] # cat head P4
|
34 |
+
- [-1, 3, C2f, [512]] # 20 (P4/16-medium)
|
35 |
+
|
36 |
+
- [-1, 1, Conv, [512, 3, 2]]
|
37 |
+
- [[-1, 9], 1, Concat, [1]] # cat head P5
|
38 |
+
- [-1, 3, C2f, [512]] # 23 (P5/32-large)
|
39 |
+
|
40 |
+
- [[15, 18, 21], 1, Detect, [nc]] # Detect(P3, P4, P5)
|
ultralytics/models/v8/yolov8x6.yaml
ADDED
@@ -0,0 +1,50 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Ultralytics YOLO 🚀, GPL-3.0 license
|
2 |
+
|
3 |
+
# Parameters
|
4 |
+
nc: 80 # number of classes
|
5 |
+
depth_multiple: 1.00 # scales module repeats
|
6 |
+
width_multiple: 1.25 # scales convolution channels
|
7 |
+
|
8 |
+
# YOLOv8.0x6 backbone
|
9 |
+
backbone:
|
10 |
+
# [from, repeats, module, args]
|
11 |
+
- [-1, 1, Conv, [64, 3, 2]] # 0-P1/2
|
12 |
+
- [-1, 1, Conv, [128, 3, 2]] # 1-P2/4
|
13 |
+
- [-1, 3, C2f, [128, True]]
|
14 |
+
- [-1, 1, Conv, [256, 3, 2]] # 3-P3/8
|
15 |
+
- [-1, 6, C2f, [256, True]]
|
16 |
+
- [-1, 1, Conv, [512, 3, 2]] # 5-P4/16
|
17 |
+
- [-1, 6, C2f, [512, True]]
|
18 |
+
- [-1, 1, Conv, [512, 3, 2]] # 7-P5/32
|
19 |
+
- [-1, 3, C2f, [512, True]]
|
20 |
+
- [-1, 1, Conv, [512, 3, 2]] # 9-P6/64
|
21 |
+
- [-1, 3, C2f, [512, True]]
|
22 |
+
- [-1, 1, SPPF, [512, 5]] # 11
|
23 |
+
|
24 |
+
# YOLOv8.0x6 head
|
25 |
+
head:
|
26 |
+
- [-1, 1, nn.Upsample, [None, 2, 'nearest']]
|
27 |
+
- [[-1, 8], 1, Concat, [1]] # cat backbone P5
|
28 |
+
- [-1, 3, C2, [512, False]] # 14
|
29 |
+
|
30 |
+
- [-1, 1, nn.Upsample, [None, 2, 'nearest']]
|
31 |
+
- [[-1, 6], 1, Concat, [1]] # cat backbone P4
|
32 |
+
- [-1, 3, C2, [512, False]] # 17
|
33 |
+
|
34 |
+
- [-1, 1, nn.Upsample, [None, 2, 'nearest']]
|
35 |
+
- [[-1, 4], 1, Concat, [1]] # cat backbone P3
|
36 |
+
- [-1, 3, C2, [256, False]] # 20 (P3/8-small)
|
37 |
+
|
38 |
+
- [-1, 1, Conv, [256, 3, 2]]
|
39 |
+
- [[-1, 17], 1, Concat, [1]] # cat head P4
|
40 |
+
- [-1, 3, C2, [512, False]] # 23 (P4/16-medium)
|
41 |
+
|
42 |
+
- [-1, 1, Conv, [512, 3, 2]]
|
43 |
+
- [[-1, 14], 1, Concat, [1]] # cat head P5
|
44 |
+
- [-1, 3, C2, [512, False]] # 26 (P5/32-large)
|
45 |
+
|
46 |
+
- [-1, 1, Conv, [512, 3, 2]]
|
47 |
+
- [[-1, 11], 1, Concat, [1]] # cat head P6
|
48 |
+
- [-1, 3, C2, [512, False]] # 29 (P6/64-xlarge)
|
49 |
+
|
50 |
+
- [[20, 23, 26, 29], 1, Detect, [nc]] # Detect(P3, P4, P5, P6)
|
ultralytics/nn/__init__.py
ADDED
File without changes
|
ultralytics/nn/autobackend.py
ADDED
@@ -0,0 +1,381 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Ultralytics YOLO 🚀, GPL-3.0 license
|
2 |
+
|
3 |
+
import json
|
4 |
+
import platform
|
5 |
+
from collections import OrderedDict, namedtuple
|
6 |
+
from pathlib import Path
|
7 |
+
from urllib.parse import urlparse
|
8 |
+
|
9 |
+
import cv2
|
10 |
+
import numpy as np
|
11 |
+
import torch
|
12 |
+
import torch.nn as nn
|
13 |
+
from PIL import Image
|
14 |
+
|
15 |
+
from ultralytics.yolo.utils import LOGGER, ROOT, yaml_load
|
16 |
+
from ultralytics.yolo.utils.checks import check_requirements, check_suffix, check_version
|
17 |
+
from ultralytics.yolo.utils.downloads import attempt_download, is_url
|
18 |
+
from ultralytics.yolo.utils.ops import xywh2xyxy
|
19 |
+
|
20 |
+
|
21 |
+
class AutoBackend(nn.Module):
|
22 |
+
|
23 |
+
def __init__(self, weights='yolov8n.pt', device=torch.device('cpu'), dnn=False, data=None, fp16=False, fuse=True):
|
24 |
+
"""
|
25 |
+
Ultralytics YOLO MultiBackend class for python inference on various backends
|
26 |
+
|
27 |
+
Args:
|
28 |
+
weights: the path to the weights file. Defaults to yolov8n.pt
|
29 |
+
device: The device to run the model on.
|
30 |
+
dnn: If you want to use OpenCV's DNN module to run the inference, set this to True. Defaults to
|
31 |
+
False
|
32 |
+
data: a dictionary containing the following keys:
|
33 |
+
fp16: If true, will use half precision. Defaults to False
|
34 |
+
fuse: whether to fuse the model or not. Defaults to True
|
35 |
+
|
36 |
+
Supported format and their usage:
|
37 |
+
| Platform | weights |
|
38 |
+
|-----------------------|------------------|
|
39 |
+
| PyTorch | *.pt |
|
40 |
+
| TorchScript | *.torchscript |
|
41 |
+
| ONNX Runtime | *.onnx |
|
42 |
+
| ONNX OpenCV DNN | *.onnx --dnn |
|
43 |
+
| OpenVINO | *.xml |
|
44 |
+
| CoreML | *.mlmodel |
|
45 |
+
| TensorRT | *.engine |
|
46 |
+
| TensorFlow SavedModel | *_saved_model |
|
47 |
+
| TensorFlow GraphDef | *.pb |
|
48 |
+
| TensorFlow Lite | *.tflite |
|
49 |
+
| TensorFlow Edge TPU | *_edgetpu.tflite |
|
50 |
+
| PaddlePaddle | *_paddle_model |
|
51 |
+
"""
|
52 |
+
super().__init__()
|
53 |
+
w = str(weights[0] if isinstance(weights, list) else weights)
|
54 |
+
nn_module = isinstance(weights, torch.nn.Module)
|
55 |
+
pt, jit, onnx, xml, engine, coreml, saved_model, pb, tflite, edgetpu, tfjs, paddle, triton = self._model_type(w)
|
56 |
+
fp16 &= pt or jit or onnx or engine or nn_module # FP16
|
57 |
+
nhwc = coreml or saved_model or pb or tflite or edgetpu # BHWC formats (vs torch BCWH)
|
58 |
+
stride = 32 # default stride
|
59 |
+
cuda = torch.cuda.is_available() and device.type != 'cpu' # use CUDA
|
60 |
+
if not (pt or triton or nn_module):
|
61 |
+
w = attempt_download(w) # download if not local
|
62 |
+
|
63 |
+
# NOTE: special case: in-memory pytorch model
|
64 |
+
if nn_module:
|
65 |
+
model = weights.to(device)
|
66 |
+
model = model.fuse() if fuse else model
|
67 |
+
names = model.module.names if hasattr(model, 'module') else model.names # get class names
|
68 |
+
model.half() if fp16 else model.float()
|
69 |
+
self.model = model # explicitly assign for to(), cpu(), cuda(), half()
|
70 |
+
pt = True
|
71 |
+
elif pt: # PyTorch
|
72 |
+
from ultralytics.nn.tasks import attempt_load_weights
|
73 |
+
model = attempt_load_weights(weights if isinstance(weights, list) else w,
|
74 |
+
device=device,
|
75 |
+
inplace=True,
|
76 |
+
fuse=fuse)
|
77 |
+
stride = max(int(model.stride.max()), 32) # model stride
|
78 |
+
names = model.module.names if hasattr(model, 'module') else model.names # get class names
|
79 |
+
model.half() if fp16 else model.float()
|
80 |
+
self.model = model # explicitly assign for to(), cpu(), cuda(), half()
|
81 |
+
elif jit: # TorchScript
|
82 |
+
LOGGER.info(f'Loading {w} for TorchScript inference...')
|
83 |
+
extra_files = {'config.txt': ''} # model metadata
|
84 |
+
model = torch.jit.load(w, _extra_files=extra_files, map_location=device)
|
85 |
+
model.half() if fp16 else model.float()
|
86 |
+
if extra_files['config.txt']: # load metadata dict
|
87 |
+
d = json.loads(extra_files['config.txt'],
|
88 |
+
object_hook=lambda d: {int(k) if k.isdigit() else k: v
|
89 |
+
for k, v in d.items()})
|
90 |
+
stride, names = int(d['stride']), d['names']
|
91 |
+
elif dnn: # ONNX OpenCV DNN
|
92 |
+
LOGGER.info(f'Loading {w} for ONNX OpenCV DNN inference...')
|
93 |
+
check_requirements('opencv-python>=4.5.4')
|
94 |
+
net = cv2.dnn.readNetFromONNX(w)
|
95 |
+
elif onnx: # ONNX Runtime
|
96 |
+
LOGGER.info(f'Loading {w} for ONNX Runtime inference...')
|
97 |
+
check_requirements(('onnx', 'onnxruntime-gpu' if cuda else 'onnxruntime'))
|
98 |
+
import onnxruntime
|
99 |
+
providers = ['CUDAExecutionProvider', 'CPUExecutionProvider'] if cuda else ['CPUExecutionProvider']
|
100 |
+
session = onnxruntime.InferenceSession(w, providers=providers)
|
101 |
+
output_names = [x.name for x in session.get_outputs()]
|
102 |
+
meta = session.get_modelmeta().custom_metadata_map # metadata
|
103 |
+
if 'stride' in meta:
|
104 |
+
stride, names = int(meta['stride']), eval(meta['names'])
|
105 |
+
elif xml: # OpenVINO
|
106 |
+
LOGGER.info(f'Loading {w} for OpenVINO inference...')
|
107 |
+
check_requirements('openvino') # requires openvino-dev: https://pypi.org/project/openvino-dev/
|
108 |
+
from openvino.runtime import Core, Layout, get_batch # noqa
|
109 |
+
ie = Core()
|
110 |
+
if not Path(w).is_file(): # if not *.xml
|
111 |
+
w = next(Path(w).glob('*.xml')) # get *.xml file from *_openvino_model dir
|
112 |
+
network = ie.read_model(model=w, weights=Path(w).with_suffix('.bin'))
|
113 |
+
if network.get_parameters()[0].get_layout().empty:
|
114 |
+
network.get_parameters()[0].set_layout(Layout("NCHW"))
|
115 |
+
batch_dim = get_batch(network)
|
116 |
+
if batch_dim.is_static:
|
117 |
+
batch_size = batch_dim.get_length()
|
118 |
+
executable_network = ie.compile_model(network, device_name="CPU") # device_name="MYRIAD" for Intel NCS2
|
119 |
+
stride, names = self._load_metadata(Path(w).with_suffix('.yaml')) # load metadata
|
120 |
+
elif engine: # TensorRT
|
121 |
+
LOGGER.info(f'Loading {w} for TensorRT inference...')
|
122 |
+
import tensorrt as trt # https://developer.nvidia.com/nvidia-tensorrt-download
|
123 |
+
check_version(trt.__version__, '7.0.0', hard=True) # require tensorrt>=7.0.0
|
124 |
+
if device.type == 'cpu':
|
125 |
+
device = torch.device('cuda:0')
|
126 |
+
Binding = namedtuple('Binding', ('name', 'dtype', 'shape', 'data', 'ptr'))
|
127 |
+
logger = trt.Logger(trt.Logger.INFO)
|
128 |
+
with open(w, 'rb') as f, trt.Runtime(logger) as runtime:
|
129 |
+
model = runtime.deserialize_cuda_engine(f.read())
|
130 |
+
context = model.create_execution_context()
|
131 |
+
bindings = OrderedDict()
|
132 |
+
output_names = []
|
133 |
+
fp16 = False # default updated below
|
134 |
+
dynamic = False
|
135 |
+
for i in range(model.num_bindings):
|
136 |
+
name = model.get_binding_name(i)
|
137 |
+
dtype = trt.nptype(model.get_binding_dtype(i))
|
138 |
+
if model.binding_is_input(i):
|
139 |
+
if -1 in tuple(model.get_binding_shape(i)): # dynamic
|
140 |
+
dynamic = True
|
141 |
+
context.set_binding_shape(i, tuple(model.get_profile_shape(0, i)[2]))
|
142 |
+
if dtype == np.float16:
|
143 |
+
fp16 = True
|
144 |
+
else: # output
|
145 |
+
output_names.append(name)
|
146 |
+
shape = tuple(context.get_binding_shape(i))
|
147 |
+
im = torch.from_numpy(np.empty(shape, dtype=dtype)).to(device)
|
148 |
+
bindings[name] = Binding(name, dtype, shape, im, int(im.data_ptr()))
|
149 |
+
binding_addrs = OrderedDict((n, d.ptr) for n, d in bindings.items())
|
150 |
+
batch_size = bindings['images'].shape[0] # if dynamic, this is instead max batch size
|
151 |
+
elif coreml: # CoreML
|
152 |
+
LOGGER.info(f'Loading {w} for CoreML inference...')
|
153 |
+
import coremltools as ct
|
154 |
+
model = ct.models.MLModel(w)
|
155 |
+
elif saved_model: # TF SavedModel
|
156 |
+
LOGGER.info(f'Loading {w} for TensorFlow SavedModel inference...')
|
157 |
+
import tensorflow as tf
|
158 |
+
keras = False # assume TF1 saved_model
|
159 |
+
model = tf.keras.models.load_model(w) if keras else tf.saved_model.load(w)
|
160 |
+
elif pb: # GraphDef https://www.tensorflow.org/guide/migrate#a_graphpb_or_graphpbtxt
|
161 |
+
LOGGER.info(f'Loading {w} for TensorFlow GraphDef inference...')
|
162 |
+
import tensorflow as tf
|
163 |
+
|
164 |
+
def wrap_frozen_graph(gd, inputs, outputs):
|
165 |
+
x = tf.compat.v1.wrap_function(lambda: tf.compat.v1.import_graph_def(gd, name=""), []) # wrapped
|
166 |
+
ge = x.graph.as_graph_element
|
167 |
+
return x.prune(tf.nest.map_structure(ge, inputs), tf.nest.map_structure(ge, outputs))
|
168 |
+
|
169 |
+
def gd_outputs(gd):
|
170 |
+
name_list, input_list = [], []
|
171 |
+
for node in gd.node: # tensorflow.core.framework.node_def_pb2.NodeDef
|
172 |
+
name_list.append(node.name)
|
173 |
+
input_list.extend(node.input)
|
174 |
+
return sorted(f'{x}:0' for x in list(set(name_list) - set(input_list)) if not x.startswith('NoOp'))
|
175 |
+
|
176 |
+
gd = tf.Graph().as_graph_def() # TF GraphDef
|
177 |
+
with open(w, 'rb') as f:
|
178 |
+
gd.ParseFromString(f.read())
|
179 |
+
frozen_func = wrap_frozen_graph(gd, inputs="x:0", outputs=gd_outputs(gd))
|
180 |
+
elif tflite or edgetpu: # https://www.tensorflow.org/lite/guide/python#install_tensorflow_lite_for_python
|
181 |
+
try: # https://coral.ai/docs/edgetpu/tflite-python/#update-existing-tf-lite-code-for-the-edge-tpu
|
182 |
+
from tflite_runtime.interpreter import Interpreter, load_delegate
|
183 |
+
except ImportError:
|
184 |
+
import tensorflow as tf
|
185 |
+
Interpreter, load_delegate = tf.lite.Interpreter, tf.lite.experimental.load_delegate,
|
186 |
+
if edgetpu: # TF Edge TPU https://coral.ai/software/#edgetpu-runtime
|
187 |
+
LOGGER.info(f'Loading {w} for TensorFlow Lite Edge TPU inference...')
|
188 |
+
delegate = {
|
189 |
+
'Linux': 'libedgetpu.so.1',
|
190 |
+
'Darwin': 'libedgetpu.1.dylib',
|
191 |
+
'Windows': 'edgetpu.dll'}[platform.system()]
|
192 |
+
interpreter = Interpreter(model_path=w, experimental_delegates=[load_delegate(delegate)])
|
193 |
+
else: # TFLite
|
194 |
+
LOGGER.info(f'Loading {w} for TensorFlow Lite inference...')
|
195 |
+
interpreter = Interpreter(model_path=w) # load TFLite model
|
196 |
+
interpreter.allocate_tensors() # allocate
|
197 |
+
input_details = interpreter.get_input_details() # inputs
|
198 |
+
output_details = interpreter.get_output_details() # outputs
|
199 |
+
elif tfjs: # TF.js
|
200 |
+
raise NotImplementedError('ERROR: YOLOv5 TF.js inference is not supported')
|
201 |
+
elif paddle: # PaddlePaddle
|
202 |
+
LOGGER.info(f'Loading {w} for PaddlePaddle inference...')
|
203 |
+
check_requirements('paddlepaddle-gpu' if cuda else 'paddlepaddle')
|
204 |
+
import paddle.inference as pdi
|
205 |
+
if not Path(w).is_file(): # if not *.pdmodel
|
206 |
+
w = next(Path(w).rglob('*.pdmodel')) # get *.xml file from *_openvino_model dir
|
207 |
+
weights = Path(w).with_suffix('.pdiparams')
|
208 |
+
config = pdi.Config(str(w), str(weights))
|
209 |
+
if cuda:
|
210 |
+
config.enable_use_gpu(memory_pool_init_size_mb=2048, device_id=0)
|
211 |
+
predictor = pdi.create_predictor(config)
|
212 |
+
input_handle = predictor.get_input_handle(predictor.get_input_names()[0])
|
213 |
+
output_names = predictor.get_output_names()
|
214 |
+
elif triton: # NVIDIA Triton Inference Server
|
215 |
+
LOGGER.info('Triton Inference Server not supported...')
|
216 |
+
'''
|
217 |
+
TODO:
|
218 |
+
check_requirements('tritonclient[all]')
|
219 |
+
from utils.triton import TritonRemoteModel
|
220 |
+
model = TritonRemoteModel(url=w)
|
221 |
+
nhwc = model.runtime.startswith("tensorflow")
|
222 |
+
'''
|
223 |
+
else:
|
224 |
+
raise NotImplementedError(f'ERROR: {w} is not a supported format')
|
225 |
+
|
226 |
+
# class names
|
227 |
+
if 'names' not in locals():
|
228 |
+
names = yaml_load(data)['names'] if data else {i: f'class{i}' for i in range(999)}
|
229 |
+
if names[0] == 'n01440764' and len(names) == 1000: # ImageNet
|
230 |
+
names = yaml_load(ROOT / 'yolo/data/datasets/ImageNet.yaml')['names'] # human-readable names
|
231 |
+
|
232 |
+
self.__dict__.update(locals()) # assign all variables to self
|
233 |
+
|
234 |
+
def forward(self, im, augment=False, visualize=False):
|
235 |
+
"""
|
236 |
+
Runs inference on the given model
|
237 |
+
|
238 |
+
Args:
|
239 |
+
im: the image tensor
|
240 |
+
augment: whether to augment the image. Defaults to False
|
241 |
+
visualize: if True, then the network will output the feature maps of the last convolutional layer.
|
242 |
+
Defaults to False
|
243 |
+
"""
|
244 |
+
# YOLOv5 MultiBackend inference
|
245 |
+
b, ch, h, w = im.shape # batch, channel, height, width
|
246 |
+
if self.fp16 and im.dtype != torch.float16:
|
247 |
+
im = im.half() # to FP16
|
248 |
+
if self.nhwc:
|
249 |
+
im = im.permute(0, 2, 3, 1) # torch BCHW to numpy BHWC shape(1,320,192,3)
|
250 |
+
|
251 |
+
if self.pt or self.nn_module: # PyTorch
|
252 |
+
y = self.model(im, augment=augment, visualize=visualize) if augment or visualize else self.model(im)
|
253 |
+
elif self.jit: # TorchScript
|
254 |
+
y = self.model(im)
|
255 |
+
elif self.dnn: # ONNX OpenCV DNN
|
256 |
+
im = im.cpu().numpy() # torch to numpy
|
257 |
+
self.net.setInput(im)
|
258 |
+
y = self.net.forward()
|
259 |
+
elif self.onnx: # ONNX Runtime
|
260 |
+
im = im.cpu().numpy() # torch to numpy
|
261 |
+
y = self.session.run(self.output_names, {self.session.get_inputs()[0].name: im})
|
262 |
+
elif self.xml: # OpenVINO
|
263 |
+
im = im.cpu().numpy() # FP32
|
264 |
+
y = list(self.executable_network([im]).values())
|
265 |
+
elif self.engine: # TensorRT
|
266 |
+
if self.dynamic and im.shape != self.bindings['images'].shape:
|
267 |
+
i = self.model.get_binding_index('images')
|
268 |
+
self.context.set_binding_shape(i, im.shape) # reshape if dynamic
|
269 |
+
self.bindings['images'] = self.bindings['images']._replace(shape=im.shape)
|
270 |
+
for name in self.output_names:
|
271 |
+
i = self.model.get_binding_index(name)
|
272 |
+
self.bindings[name].data.resize_(tuple(self.context.get_binding_shape(i)))
|
273 |
+
s = self.bindings['images'].shape
|
274 |
+
assert im.shape == s, f"input size {im.shape} {'>' if self.dynamic else 'not equal to'} max model size {s}"
|
275 |
+
self.binding_addrs['images'] = int(im.data_ptr())
|
276 |
+
self.context.execute_v2(list(self.binding_addrs.values()))
|
277 |
+
y = [self.bindings[x].data for x in sorted(self.output_names)]
|
278 |
+
elif self.coreml: # CoreML
|
279 |
+
im = im.cpu().numpy()
|
280 |
+
im = Image.fromarray((im[0] * 255).astype('uint8'))
|
281 |
+
# im = im.resize((192, 320), Image.ANTIALIAS)
|
282 |
+
y = self.model.predict({'image': im}) # coordinates are xywh normalized
|
283 |
+
if 'confidence' in y:
|
284 |
+
box = xywh2xyxy(y['coordinates'] * [[w, h, w, h]]) # xyxy pixels
|
285 |
+
conf, cls = y['confidence'].max(1), y['confidence'].argmax(1).astype(np.float)
|
286 |
+
y = np.concatenate((box, conf.reshape(-1, 1), cls.reshape(-1, 1)), 1)
|
287 |
+
else:
|
288 |
+
y = list(reversed(y.values())) # reversed for segmentation models (pred, proto)
|
289 |
+
elif self.paddle: # PaddlePaddle
|
290 |
+
im = im.cpu().numpy().astype(np.float32)
|
291 |
+
self.input_handle.copy_from_cpu(im)
|
292 |
+
self.predictor.run()
|
293 |
+
y = [self.predictor.get_output_handle(x).copy_to_cpu() for x in self.output_names]
|
294 |
+
elif self.triton: # NVIDIA Triton Inference Server
|
295 |
+
y = self.model(im)
|
296 |
+
else: # TensorFlow (SavedModel, GraphDef, Lite, Edge TPU)
|
297 |
+
im = im.cpu().numpy()
|
298 |
+
if self.saved_model: # SavedModel
|
299 |
+
y = self.model(im, training=False) if self.keras else self.model(im)
|
300 |
+
elif self.pb: # GraphDef
|
301 |
+
y = self.frozen_func(x=self.tf.constant(im))
|
302 |
+
else: # Lite or Edge TPU
|
303 |
+
input = self.input_details[0]
|
304 |
+
int8 = input['dtype'] == np.uint8 # is TFLite quantized uint8 model
|
305 |
+
if int8:
|
306 |
+
scale, zero_point = input['quantization']
|
307 |
+
im = (im / scale + zero_point).astype(np.uint8) # de-scale
|
308 |
+
self.interpreter.set_tensor(input['index'], im)
|
309 |
+
self.interpreter.invoke()
|
310 |
+
y = []
|
311 |
+
for output in self.output_details:
|
312 |
+
x = self.interpreter.get_tensor(output['index'])
|
313 |
+
if int8:
|
314 |
+
scale, zero_point = output['quantization']
|
315 |
+
x = (x.astype(np.float32) - zero_point) * scale # re-scale
|
316 |
+
y.append(x)
|
317 |
+
y = [x if isinstance(x, np.ndarray) else x.numpy() for x in y]
|
318 |
+
y[0][..., :4] *= [w, h, w, h] # xywh normalized to pixels
|
319 |
+
|
320 |
+
if isinstance(y, (list, tuple)):
|
321 |
+
return self.from_numpy(y[0]) if len(y) == 1 else [self.from_numpy(x) for x in y]
|
322 |
+
else:
|
323 |
+
return self.from_numpy(y)
|
324 |
+
|
325 |
+
def from_numpy(self, x):
|
326 |
+
"""
|
327 |
+
`from_numpy` converts a numpy array to a tensor
|
328 |
+
|
329 |
+
Args:
|
330 |
+
x: the numpy array to convert
|
331 |
+
"""
|
332 |
+
return torch.from_numpy(x).to(self.device) if isinstance(x, np.ndarray) else x
|
333 |
+
|
334 |
+
def warmup(self, imgsz=(1, 3, 640, 640)):
|
335 |
+
"""
|
336 |
+
Warmup model by running inference once
|
337 |
+
|
338 |
+
Args:
|
339 |
+
imgsz: the size of the image you want to run inference on.
|
340 |
+
"""
|
341 |
+
warmup_types = self.pt, self.jit, self.onnx, self.engine, self.saved_model, self.pb, self.triton, self.nn_module
|
342 |
+
if any(warmup_types) and (self.device.type != 'cpu' or self.triton):
|
343 |
+
im = torch.empty(*imgsz, dtype=torch.half if self.fp16 else torch.float, device=self.device) # input
|
344 |
+
for _ in range(2 if self.jit else 1): #
|
345 |
+
self.forward(im) # warmup
|
346 |
+
|
347 |
+
@staticmethod
|
348 |
+
def _model_type(p='path/to/model.pt'):
|
349 |
+
"""
|
350 |
+
This function takes a path to a model file and returns the model type
|
351 |
+
|
352 |
+
Args:
|
353 |
+
p: path to the model file. Defaults to path/to/model.pt
|
354 |
+
"""
|
355 |
+
# Return model type from model path, i.e. path='path/to/model.onnx' -> type=onnx
|
356 |
+
# types = [pt, jit, onnx, xml, engine, coreml, saved_model, pb, tflite, edgetpu, tfjs, paddle]
|
357 |
+
from ultralytics.yolo.engine.exporter import export_formats
|
358 |
+
sf = list(export_formats().Suffix) # export suffixes
|
359 |
+
if not is_url(p, check=False) and not isinstance(p, str):
|
360 |
+
check_suffix(p, sf) # checks
|
361 |
+
url = urlparse(p) # if url may be Triton inference server
|
362 |
+
types = [s in Path(p).name for s in sf]
|
363 |
+
types[8] &= not types[9] # tflite &= not edgetpu
|
364 |
+
triton = not any(types) and all([any(s in url.scheme for s in ["http", "grpc"]), url.netloc])
|
365 |
+
return types + [triton]
|
366 |
+
|
367 |
+
@staticmethod
|
368 |
+
def _load_metadata(f=Path('path/to/meta.yaml')):
|
369 |
+
"""
|
370 |
+
> Loads the metadata from a yaml file
|
371 |
+
|
372 |
+
Args:
|
373 |
+
f: The path to the metadata file.
|
374 |
+
"""
|
375 |
+
from ultralytics.yolo.utils.files import yaml_load
|
376 |
+
|
377 |
+
# Load metadata from meta.yaml if it exists
|
378 |
+
if f.exists():
|
379 |
+
d = yaml_load(f)
|
380 |
+
return d['stride'], d['names'] # assign stride, names
|
381 |
+
return None, None
|
ultralytics/nn/modules.py
ADDED
@@ -0,0 +1,688 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Ultralytics YOLO 🚀, GPL-3.0 license
|
2 |
+
"""
|
3 |
+
Common modules
|
4 |
+
"""
|
5 |
+
|
6 |
+
import math
|
7 |
+
import warnings
|
8 |
+
from copy import copy
|
9 |
+
from pathlib import Path
|
10 |
+
|
11 |
+
import cv2
|
12 |
+
import numpy as np
|
13 |
+
import pandas as pd
|
14 |
+
import requests
|
15 |
+
import torch
|
16 |
+
import torch.nn as nn
|
17 |
+
from PIL import Image, ImageOps
|
18 |
+
from torch.cuda import amp
|
19 |
+
|
20 |
+
from ultralytics.nn.autobackend import AutoBackend
|
21 |
+
from ultralytics.yolo.data.augment import LetterBox
|
22 |
+
from ultralytics.yolo.utils import LOGGER, colorstr
|
23 |
+
from ultralytics.yolo.utils.files import increment_path
|
24 |
+
from ultralytics.yolo.utils.ops import Profile, make_divisible, non_max_suppression, scale_boxes, xyxy2xywh
|
25 |
+
from ultralytics.yolo.utils.plotting import Annotator, colors, save_one_box
|
26 |
+
from ultralytics.yolo.utils.tal import dist2bbox, make_anchors
|
27 |
+
from ultralytics.yolo.utils.torch_utils import copy_attr, smart_inference_mode
|
28 |
+
|
29 |
+
# from utils.plots import feature_visualization TODO
|
30 |
+
|
31 |
+
|
32 |
+
def autopad(k, p=None, d=1): # kernel, padding, dilation
|
33 |
+
# Pad to 'same' shape outputs
|
34 |
+
if d > 1:
|
35 |
+
k = d * (k - 1) + 1 if isinstance(k, int) else [d * (x - 1) + 1 for x in k] # actual kernel-size
|
36 |
+
if p is None:
|
37 |
+
p = k // 2 if isinstance(k, int) else [x // 2 for x in k] # auto-pad
|
38 |
+
return p
|
39 |
+
|
40 |
+
|
41 |
+
class Conv(nn.Module):
|
42 |
+
# Standard convolution with args(ch_in, ch_out, kernel, stride, padding, groups, dilation, activation)
|
43 |
+
default_act = nn.SiLU() # default activation
|
44 |
+
|
45 |
+
def __init__(self, c1, c2, k=1, s=1, p=None, g=1, d=1, act=True):
|
46 |
+
super().__init__()
|
47 |
+
self.conv = nn.Conv2d(c1, c2, k, s, autopad(k, p, d), groups=g, dilation=d, bias=False)
|
48 |
+
self.bn = nn.BatchNorm2d(c2)
|
49 |
+
self.act = self.default_act if act is True else act if isinstance(act, nn.Module) else nn.Identity()
|
50 |
+
|
51 |
+
def forward(self, x):
|
52 |
+
return self.act(self.bn(self.conv(x)))
|
53 |
+
|
54 |
+
def forward_fuse(self, x):
|
55 |
+
return self.act(self.conv(x))
|
56 |
+
|
57 |
+
|
58 |
+
class DWConv(Conv):
|
59 |
+
# Depth-wise convolution
|
60 |
+
def __init__(self, c1, c2, k=1, s=1, d=1, act=True): # ch_in, ch_out, kernel, stride, dilation, activation
|
61 |
+
super().__init__(c1, c2, k, s, g=math.gcd(c1, c2), d=d, act=act)
|
62 |
+
|
63 |
+
|
64 |
+
class DWConvTranspose2d(nn.ConvTranspose2d):
|
65 |
+
# Depth-wise transpose convolution
|
66 |
+
def __init__(self, c1, c2, k=1, s=1, p1=0, p2=0): # ch_in, ch_out, kernel, stride, padding, padding_out
|
67 |
+
super().__init__(c1, c2, k, s, p1, p2, groups=math.gcd(c1, c2))
|
68 |
+
|
69 |
+
|
70 |
+
class ConvTranspose(nn.Module):
|
71 |
+
# Convolution transpose 2d layer
|
72 |
+
default_act = nn.SiLU() # default activation
|
73 |
+
|
74 |
+
def __init__(self, c1, c2, k=2, s=2, p=0, bn=True, act=True):
|
75 |
+
super().__init__()
|
76 |
+
self.conv_transpose = nn.ConvTranspose2d(c1, c2, k, s, p, bias=not bn)
|
77 |
+
self.bn = nn.BatchNorm2d(c2) if bn else nn.Identity()
|
78 |
+
self.act = self.default_act if act is True else act if isinstance(act, nn.Module) else nn.Identity()
|
79 |
+
|
80 |
+
def forward(self, x):
|
81 |
+
return self.act(self.bn(self.conv_transpose(x)))
|
82 |
+
|
83 |
+
|
84 |
+
class DFL(nn.Module):
|
85 |
+
# DFL module
|
86 |
+
def __init__(self, c1=16):
|
87 |
+
super().__init__()
|
88 |
+
self.conv = nn.Conv2d(c1, 1, 1, bias=False).requires_grad_(False)
|
89 |
+
x = torch.arange(c1, dtype=torch.float)
|
90 |
+
self.conv.weight.data[:] = nn.Parameter(x.view(1, c1, 1, 1))
|
91 |
+
self.c1 = c1
|
92 |
+
|
93 |
+
def forward(self, x):
|
94 |
+
b, c, a = x.shape # batch, channels, anchors
|
95 |
+
return self.conv(x.view(b, 4, self.c1, a).transpose(2, 1).softmax(1)).view(b, 4, a)
|
96 |
+
# return self.conv(x.view(b, self.c1, 4, a).softmax(1)).view(b, 4, a)
|
97 |
+
|
98 |
+
|
99 |
+
class TransformerLayer(nn.Module):
|
100 |
+
# Transformer layer https://arxiv.org/abs/2010.11929 (LayerNorm layers removed for better performance)
|
101 |
+
def __init__(self, c, num_heads):
|
102 |
+
super().__init__()
|
103 |
+
self.q = nn.Linear(c, c, bias=False)
|
104 |
+
self.k = nn.Linear(c, c, bias=False)
|
105 |
+
self.v = nn.Linear(c, c, bias=False)
|
106 |
+
self.ma = nn.MultiheadAttention(embed_dim=c, num_heads=num_heads)
|
107 |
+
self.fc1 = nn.Linear(c, c, bias=False)
|
108 |
+
self.fc2 = nn.Linear(c, c, bias=False)
|
109 |
+
|
110 |
+
def forward(self, x):
|
111 |
+
x = self.ma(self.q(x), self.k(x), self.v(x))[0] + x
|
112 |
+
x = self.fc2(self.fc1(x)) + x
|
113 |
+
return x
|
114 |
+
|
115 |
+
|
116 |
+
class TransformerBlock(nn.Module):
|
117 |
+
# Vision Transformer https://arxiv.org/abs/2010.11929
|
118 |
+
def __init__(self, c1, c2, num_heads, num_layers):
|
119 |
+
super().__init__()
|
120 |
+
self.conv = None
|
121 |
+
if c1 != c2:
|
122 |
+
self.conv = Conv(c1, c2)
|
123 |
+
self.linear = nn.Linear(c2, c2) # learnable position embedding
|
124 |
+
self.tr = nn.Sequential(*(TransformerLayer(c2, num_heads) for _ in range(num_layers)))
|
125 |
+
self.c2 = c2
|
126 |
+
|
127 |
+
def forward(self, x):
|
128 |
+
if self.conv is not None:
|
129 |
+
x = self.conv(x)
|
130 |
+
b, _, w, h = x.shape
|
131 |
+
p = x.flatten(2).permute(2, 0, 1)
|
132 |
+
return self.tr(p + self.linear(p)).permute(1, 2, 0).reshape(b, self.c2, w, h)
|
133 |
+
|
134 |
+
|
135 |
+
class Bottleneck(nn.Module):
|
136 |
+
# Standard bottleneck
|
137 |
+
def __init__(self, c1, c2, shortcut=True, g=1, k=(3, 3), e=0.5): # ch_in, ch_out, shortcut, kernels, groups, expand
|
138 |
+
super().__init__()
|
139 |
+
c_ = int(c2 * e) # hidden channels
|
140 |
+
self.cv1 = Conv(c1, c_, k[0], 1)
|
141 |
+
self.cv2 = Conv(c_, c2, k[1], 1, g=g)
|
142 |
+
self.add = shortcut and c1 == c2
|
143 |
+
|
144 |
+
def forward(self, x):
|
145 |
+
return x + self.cv2(self.cv1(x)) if self.add else self.cv2(self.cv1(x))
|
146 |
+
|
147 |
+
|
148 |
+
class BottleneckCSP(nn.Module):
|
149 |
+
# CSP Bottleneck https://github.com/WongKinYiu/CrossStagePartialNetworks
|
150 |
+
def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5): # ch_in, ch_out, number, shortcut, groups, expansion
|
151 |
+
super().__init__()
|
152 |
+
c_ = int(c2 * e) # hidden channels
|
153 |
+
self.cv1 = Conv(c1, c_, 1, 1)
|
154 |
+
self.cv2 = nn.Conv2d(c1, c_, 1, 1, bias=False)
|
155 |
+
self.cv3 = nn.Conv2d(c_, c_, 1, 1, bias=False)
|
156 |
+
self.cv4 = Conv(2 * c_, c2, 1, 1)
|
157 |
+
self.bn = nn.BatchNorm2d(2 * c_) # applied to cat(cv2, cv3)
|
158 |
+
self.act = nn.SiLU()
|
159 |
+
self.m = nn.Sequential(*(Bottleneck(c_, c_, shortcut, g, e=1.0) for _ in range(n)))
|
160 |
+
|
161 |
+
def forward(self, x):
|
162 |
+
y1 = self.cv3(self.m(self.cv1(x)))
|
163 |
+
y2 = self.cv2(x)
|
164 |
+
return self.cv4(self.act(self.bn(torch.cat((y1, y2), 1))))
|
165 |
+
|
166 |
+
|
167 |
+
class C3(nn.Module):
|
168 |
+
# CSP Bottleneck with 3 convolutions
|
169 |
+
def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5): # ch_in, ch_out, number, shortcut, groups, expansion
|
170 |
+
super().__init__()
|
171 |
+
c_ = int(c2 * e) # hidden channels
|
172 |
+
self.cv1 = Conv(c1, c_, 1, 1)
|
173 |
+
self.cv2 = Conv(c1, c_, 1, 1)
|
174 |
+
self.cv3 = Conv(2 * c_, c2, 1) # optional act=FReLU(c2)
|
175 |
+
self.m = nn.Sequential(*(Bottleneck(c_, c_, shortcut, g, e=1.0) for _ in range(n)))
|
176 |
+
|
177 |
+
def forward(self, x):
|
178 |
+
return self.cv3(torch.cat((self.m(self.cv1(x)), self.cv2(x)), 1))
|
179 |
+
|
180 |
+
|
181 |
+
class C2(nn.Module):
|
182 |
+
# CSP Bottleneck with 2 convolutions
|
183 |
+
def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5): # ch_in, ch_out, number, shortcut, groups, expansion
|
184 |
+
super().__init__()
|
185 |
+
self.c = int(c2 * e) # hidden channels
|
186 |
+
self.cv1 = Conv(c1, 2 * self.c, 1, 1)
|
187 |
+
self.cv2 = Conv(2 * self.c, c2, 1) # optional act=FReLU(c2)
|
188 |
+
# self.attention = ChannelAttention(2 * self.c) # or SpatialAttention()
|
189 |
+
self.m = nn.Sequential(*(Bottleneck(self.c, self.c, shortcut, g, k=((3, 3), (3, 3)), e=1.0) for _ in range(n)))
|
190 |
+
|
191 |
+
def forward(self, x):
|
192 |
+
a, b = self.cv1(x).split((self.c, self.c), 1)
|
193 |
+
return self.cv2(torch.cat((self.m(a), b), 1))
|
194 |
+
|
195 |
+
|
196 |
+
class C2f(nn.Module):
|
197 |
+
# CSP Bottleneck with 2 convolutions
|
198 |
+
def __init__(self, c1, c2, n=1, shortcut=False, g=1, e=0.5): # ch_in, ch_out, number, shortcut, groups, expansion
|
199 |
+
super().__init__()
|
200 |
+
self.c = int(c2 * e) # hidden channels
|
201 |
+
self.cv1 = Conv(c1, 2 * self.c, 1, 1)
|
202 |
+
self.cv2 = Conv((2 + n) * self.c, c2, 1) # optional act=FReLU(c2)
|
203 |
+
self.m = nn.ModuleList(Bottleneck(self.c, self.c, shortcut, g, k=((3, 3), (3, 3)), e=1.0) for _ in range(n))
|
204 |
+
|
205 |
+
def forward(self, x):
|
206 |
+
y = list(self.cv1(x).split((self.c, self.c), 1))
|
207 |
+
y.extend(m(y[-1]) for m in self.m)
|
208 |
+
return self.cv2(torch.cat(y, 1))
|
209 |
+
|
210 |
+
|
211 |
+
class ChannelAttention(nn.Module):
|
212 |
+
# Channel-attention module https://github.com/open-mmlab/mmdetection/tree/v3.0.0rc1/configs/rtmdet
|
213 |
+
def __init__(self, channels: int) -> None:
|
214 |
+
super().__init__()
|
215 |
+
self.pool = nn.AdaptiveAvgPool2d(1)
|
216 |
+
self.fc = nn.Conv2d(channels, channels, 1, 1, 0, bias=True)
|
217 |
+
self.act = nn.Sigmoid()
|
218 |
+
|
219 |
+
def forward(self, x: torch.Tensor) -> torch.Tensor:
|
220 |
+
return x * self.act(self.fc(self.pool(x)))
|
221 |
+
|
222 |
+
|
223 |
+
class SpatialAttention(nn.Module):
|
224 |
+
# Spatial-attention module
|
225 |
+
def __init__(self, kernel_size=7):
|
226 |
+
super().__init__()
|
227 |
+
assert kernel_size in (3, 7), 'kernel size must be 3 or 7'
|
228 |
+
padding = 3 if kernel_size == 7 else 1
|
229 |
+
self.cv1 = nn.Conv2d(2, 1, kernel_size, padding=padding, bias=False)
|
230 |
+
self.act = nn.Sigmoid()
|
231 |
+
|
232 |
+
def forward(self, x):
|
233 |
+
return x * self.act(self.cv1(torch.cat([torch.mean(x, 1, keepdim=True), torch.max(x, 1, keepdim=True)[0]], 1)))
|
234 |
+
|
235 |
+
|
236 |
+
class CBAM(nn.Module):
|
237 |
+
# CSP Bottleneck with 3 convolutions
|
238 |
+
def __init__(self, c1, ratio=16, kernel_size=7): # ch_in, ch_out, number, shortcut, groups, expansion
|
239 |
+
super().__init__()
|
240 |
+
self.channel_attention = ChannelAttention(c1)
|
241 |
+
self.spatial_attention = SpatialAttention(kernel_size)
|
242 |
+
|
243 |
+
def forward(self, x):
|
244 |
+
return self.spatial_attention(self.channel_attention(x))
|
245 |
+
|
246 |
+
|
247 |
+
class C1(nn.Module):
|
248 |
+
# CSP Bottleneck with 3 convolutions
|
249 |
+
def __init__(self, c1, c2, n=1): # ch_in, ch_out, number, shortcut, groups, expansion
|
250 |
+
super().__init__()
|
251 |
+
self.cv1 = Conv(c1, c2, 1, 1)
|
252 |
+
self.m = nn.Sequential(*(Conv(c2, c2, 3) for _ in range(n)))
|
253 |
+
|
254 |
+
def forward(self, x):
|
255 |
+
y = self.cv1(x)
|
256 |
+
return self.m(y) + y
|
257 |
+
|
258 |
+
|
259 |
+
class C3x(C3):
|
260 |
+
# C3 module with cross-convolutions
|
261 |
+
def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5):
|
262 |
+
super().__init__(c1, c2, n, shortcut, g, e)
|
263 |
+
self.c_ = int(c2 * e)
|
264 |
+
self.m = nn.Sequential(*(Bottleneck(self.c_, self.c_, shortcut, g, k=((1, 3), (3, 1)), e=1) for _ in range(n)))
|
265 |
+
|
266 |
+
|
267 |
+
class C3TR(C3):
|
268 |
+
# C3 module with TransformerBlock()
|
269 |
+
def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5):
|
270 |
+
super().__init__(c1, c2, n, shortcut, g, e)
|
271 |
+
c_ = int(c2 * e)
|
272 |
+
self.m = TransformerBlock(c_, c_, 4, n)
|
273 |
+
|
274 |
+
|
275 |
+
class C3Ghost(C3):
|
276 |
+
# C3 module with GhostBottleneck()
|
277 |
+
def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5):
|
278 |
+
super().__init__(c1, c2, n, shortcut, g, e)
|
279 |
+
c_ = int(c2 * e) # hidden channels
|
280 |
+
self.m = nn.Sequential(*(GhostBottleneck(c_, c_) for _ in range(n)))
|
281 |
+
|
282 |
+
|
283 |
+
class SPP(nn.Module):
|
284 |
+
# Spatial Pyramid Pooling (SPP) layer https://arxiv.org/abs/1406.4729
|
285 |
+
def __init__(self, c1, c2, k=(5, 9, 13)):
|
286 |
+
super().__init__()
|
287 |
+
c_ = c1 // 2 # hidden channels
|
288 |
+
self.cv1 = Conv(c1, c_, 1, 1)
|
289 |
+
self.cv2 = Conv(c_ * (len(k) + 1), c2, 1, 1)
|
290 |
+
self.m = nn.ModuleList([nn.MaxPool2d(kernel_size=x, stride=1, padding=x // 2) for x in k])
|
291 |
+
|
292 |
+
def forward(self, x):
|
293 |
+
x = self.cv1(x)
|
294 |
+
with warnings.catch_warnings():
|
295 |
+
warnings.simplefilter('ignore') # suppress torch 1.9.0 max_pool2d() warning
|
296 |
+
return self.cv2(torch.cat([x] + [m(x) for m in self.m], 1))
|
297 |
+
|
298 |
+
|
299 |
+
class SPPF(nn.Module):
|
300 |
+
# Spatial Pyramid Pooling - Fast (SPPF) layer for YOLOv5 by Glenn Jocher
|
301 |
+
def __init__(self, c1, c2, k=5): # equivalent to SPP(k=(5, 9, 13))
|
302 |
+
super().__init__()
|
303 |
+
c_ = c1 // 2 # hidden channels
|
304 |
+
self.cv1 = Conv(c1, c_, 1, 1)
|
305 |
+
self.cv2 = Conv(c_ * 4, c2, 1, 1)
|
306 |
+
self.m = nn.MaxPool2d(kernel_size=k, stride=1, padding=k // 2)
|
307 |
+
|
308 |
+
def forward(self, x):
|
309 |
+
x = self.cv1(x)
|
310 |
+
with warnings.catch_warnings():
|
311 |
+
warnings.simplefilter('ignore') # suppress torch 1.9.0 max_pool2d() warning
|
312 |
+
y1 = self.m(x)
|
313 |
+
y2 = self.m(y1)
|
314 |
+
return self.cv2(torch.cat((x, y1, y2, self.m(y2)), 1))
|
315 |
+
|
316 |
+
|
317 |
+
class Focus(nn.Module):
|
318 |
+
# Focus wh information into c-space
|
319 |
+
def __init__(self, c1, c2, k=1, s=1, p=None, g=1, act=True): # ch_in, ch_out, kernel, stride, padding, groups
|
320 |
+
super().__init__()
|
321 |
+
self.conv = Conv(c1 * 4, c2, k, s, p, g, act=act)
|
322 |
+
# self.contract = Contract(gain=2)
|
323 |
+
|
324 |
+
def forward(self, x): # x(b,c,w,h) -> y(b,4c,w/2,h/2)
|
325 |
+
return self.conv(torch.cat((x[..., ::2, ::2], x[..., 1::2, ::2], x[..., ::2, 1::2], x[..., 1::2, 1::2]), 1))
|
326 |
+
# return self.conv(self.contract(x))
|
327 |
+
|
328 |
+
|
329 |
+
class GhostConv(nn.Module):
|
330 |
+
# Ghost Convolution https://github.com/huawei-noah/ghostnet
|
331 |
+
def __init__(self, c1, c2, k=1, s=1, g=1, act=True): # ch_in, ch_out, kernel, stride, groups
|
332 |
+
super().__init__()
|
333 |
+
c_ = c2 // 2 # hidden channels
|
334 |
+
self.cv1 = Conv(c1, c_, k, s, None, g, act=act)
|
335 |
+
self.cv2 = Conv(c_, c_, 5, 1, None, c_, act=act)
|
336 |
+
|
337 |
+
def forward(self, x):
|
338 |
+
y = self.cv1(x)
|
339 |
+
return torch.cat((y, self.cv2(y)), 1)
|
340 |
+
|
341 |
+
|
342 |
+
class GhostBottleneck(nn.Module):
|
343 |
+
# Ghost Bottleneck https://github.com/huawei-noah/ghostnet
|
344 |
+
def __init__(self, c1, c2, k=3, s=1): # ch_in, ch_out, kernel, stride
|
345 |
+
super().__init__()
|
346 |
+
c_ = c2 // 2
|
347 |
+
self.conv = nn.Sequential(
|
348 |
+
GhostConv(c1, c_, 1, 1), # pw
|
349 |
+
DWConv(c_, c_, k, s, act=False) if s == 2 else nn.Identity(), # dw
|
350 |
+
GhostConv(c_, c2, 1, 1, act=False)) # pw-linear
|
351 |
+
self.shortcut = nn.Sequential(DWConv(c1, c1, k, s, act=False), Conv(c1, c2, 1, 1,
|
352 |
+
act=False)) if s == 2 else nn.Identity()
|
353 |
+
|
354 |
+
def forward(self, x):
|
355 |
+
return self.conv(x) + self.shortcut(x)
|
356 |
+
|
357 |
+
|
358 |
+
class Concat(nn.Module):
|
359 |
+
# Concatenate a list of tensors along dimension
|
360 |
+
def __init__(self, dimension=1):
|
361 |
+
super().__init__()
|
362 |
+
self.d = dimension
|
363 |
+
|
364 |
+
def forward(self, x):
|
365 |
+
return torch.cat(x, self.d)
|
366 |
+
|
367 |
+
|
368 |
+
class AutoShape(nn.Module):
|
369 |
+
# YOLOv5 input-robust model wrapper for passing cv2/np/PIL/torch inputs. Includes preprocessing, inference and NMS
|
370 |
+
conf = 0.25 # NMS confidence threshold
|
371 |
+
iou = 0.45 # NMS IoU threshold
|
372 |
+
agnostic = False # NMS class-agnostic
|
373 |
+
multi_label = False # NMS multiple labels per box
|
374 |
+
classes = None # (optional list) filter by class, i.e. = [0, 15, 16] for COCO persons, cats and dogs
|
375 |
+
max_det = 1000 # maximum number of detections per image
|
376 |
+
amp = False # Automatic Mixed Precision (AMP) inference
|
377 |
+
|
378 |
+
def __init__(self, model, verbose=True):
|
379 |
+
super().__init__()
|
380 |
+
if verbose:
|
381 |
+
LOGGER.info('Adding AutoShape... ')
|
382 |
+
copy_attr(self, model, include=('yaml', 'nc', 'hyp', 'names', 'stride', 'abc'), exclude=()) # copy attributes
|
383 |
+
self.dmb = isinstance(model, AutoBackend) # DetectMultiBackend() instance
|
384 |
+
self.pt = not self.dmb or model.pt # PyTorch model
|
385 |
+
self.model = model.eval()
|
386 |
+
if self.pt:
|
387 |
+
m = self.model.model.model[-1] if self.dmb else self.model.model[-1] # Detect()
|
388 |
+
m.inplace = False # Detect.inplace=False for safe multithread inference
|
389 |
+
m.export = True # do not output loss values
|
390 |
+
|
391 |
+
def _apply(self, fn):
|
392 |
+
# Apply to(), cpu(), cuda(), half() to model tensors that are not parameters or registered buffers
|
393 |
+
self = super()._apply(fn)
|
394 |
+
if self.pt:
|
395 |
+
m = self.model.model.model[-1] if self.dmb else self.model.model[-1] # Detect()
|
396 |
+
m.stride = fn(m.stride)
|
397 |
+
m.grid = list(map(fn, m.grid))
|
398 |
+
if isinstance(m.anchor_grid, list):
|
399 |
+
m.anchor_grid = list(map(fn, m.anchor_grid))
|
400 |
+
return self
|
401 |
+
|
402 |
+
@smart_inference_mode()
|
403 |
+
def forward(self, ims, size=640, augment=False, profile=False):
|
404 |
+
# Inference from various sources. For size(height=640, width=1280), RGB images example inputs are:
|
405 |
+
# file: ims = 'data/images/zidane.jpg' # str or PosixPath
|
406 |
+
# URI: = 'https://ultralytics.com/images/zidane.jpg'
|
407 |
+
# OpenCV: = cv2.imread('image.jpg')[:,:,::-1] # HWC BGR to RGB x(640,1280,3)
|
408 |
+
# PIL: = Image.open('image.jpg') or ImageGrab.grab() # HWC x(640,1280,3)
|
409 |
+
# numpy: = np.zeros((640,1280,3)) # HWC
|
410 |
+
# torch: = torch.zeros(16,3,320,640) # BCHW (scaled to size=640, 0-1 values)
|
411 |
+
# multiple: = [Image.open('image1.jpg'), Image.open('image2.jpg'), ...] # list of images
|
412 |
+
|
413 |
+
dt = (Profile(), Profile(), Profile())
|
414 |
+
with dt[0]:
|
415 |
+
if isinstance(size, int): # expand
|
416 |
+
size = (size, size)
|
417 |
+
p = next(self.model.parameters()) if self.pt else torch.empty(1, device=self.model.device) # param
|
418 |
+
autocast = self.amp and (p.device.type != 'cpu') # Automatic Mixed Precision (AMP) inference
|
419 |
+
if isinstance(ims, torch.Tensor): # torch
|
420 |
+
with amp.autocast(autocast):
|
421 |
+
return self.model(ims.to(p.device).type_as(p), augment=augment) # inference
|
422 |
+
|
423 |
+
# Pre-process
|
424 |
+
n, ims = (len(ims), list(ims)) if isinstance(ims, (list, tuple)) else (1, [ims]) # number, list of images
|
425 |
+
shape0, shape1, files = [], [], [] # image and inference shapes, filenames
|
426 |
+
for i, im in enumerate(ims):
|
427 |
+
f = f'image{i}' # filename
|
428 |
+
if isinstance(im, (str, Path)): # filename or uri
|
429 |
+
im, f = Image.open(requests.get(im, stream=True).raw if str(im).startswith('http') else im), im
|
430 |
+
im = np.asarray(ImageOps.exif_transpose(im))
|
431 |
+
elif isinstance(im, Image.Image): # PIL Image
|
432 |
+
im, f = np.asarray(ImageOps.exif_transpose(im)), getattr(im, 'filename', f) or f
|
433 |
+
files.append(Path(f).with_suffix('.jpg').name)
|
434 |
+
if im.shape[0] < 5: # image in CHW
|
435 |
+
im = im.transpose((1, 2, 0)) # reverse dataloader .transpose(2, 0, 1)
|
436 |
+
im = im[..., :3] if im.ndim == 3 else cv2.cvtColor(im, cv2.COLOR_GRAY2BGR) # enforce 3ch input
|
437 |
+
s = im.shape[:2] # HWC
|
438 |
+
shape0.append(s) # image shape
|
439 |
+
g = max(size) / max(s) # gain
|
440 |
+
shape1.append([y * g for y in s])
|
441 |
+
ims[i] = im if im.data.contiguous else np.ascontiguousarray(im) # update
|
442 |
+
shape1 = [make_divisible(x, self.stride) for x in np.array(shape1).max(0)] if self.pt else size # inf shape
|
443 |
+
x = [LetterBox(shape1, auto=False)(image=im)["img"] for im in ims] # pad
|
444 |
+
x = np.ascontiguousarray(np.array(x).transpose((0, 3, 1, 2))) # stack and BHWC to BCHW
|
445 |
+
x = torch.from_numpy(x).to(p.device).type_as(p) / 255 # uint8 to fp16/32
|
446 |
+
|
447 |
+
with amp.autocast(autocast):
|
448 |
+
# Inference
|
449 |
+
with dt[1]:
|
450 |
+
y = self.model(x, augment=augment) # forward
|
451 |
+
|
452 |
+
# Post-process
|
453 |
+
with dt[2]:
|
454 |
+
y = non_max_suppression(y if self.dmb else y[0],
|
455 |
+
self.conf,
|
456 |
+
self.iou,
|
457 |
+
self.classes,
|
458 |
+
self.agnostic,
|
459 |
+
self.multi_label,
|
460 |
+
max_det=self.max_det) # NMS
|
461 |
+
for i in range(n):
|
462 |
+
scale_boxes(shape1, y[i][:, :4], shape0[i])
|
463 |
+
|
464 |
+
return Detections(ims, y, files, dt, self.names, x.shape)
|
465 |
+
|
466 |
+
|
467 |
+
class Detections:
|
468 |
+
# YOLOv5 detections class for inference results
|
469 |
+
def __init__(self, ims, pred, files, times=(0, 0, 0), names=None, shape=None):
|
470 |
+
super().__init__()
|
471 |
+
d = pred[0].device # device
|
472 |
+
gn = [torch.tensor([*(im.shape[i] for i in [1, 0, 1, 0]), 1, 1], device=d) for im in ims] # normalizations
|
473 |
+
self.ims = ims # list of images as numpy arrays
|
474 |
+
self.pred = pred # list of tensors pred[0] = (xyxy, conf, cls)
|
475 |
+
self.names = names # class names
|
476 |
+
self.files = files # image filenames
|
477 |
+
self.times = times # profiling times
|
478 |
+
self.xyxy = pred # xyxy pixels
|
479 |
+
self.xywh = [xyxy2xywh(x) for x in pred] # xywh pixels
|
480 |
+
self.xyxyn = [x / g for x, g in zip(self.xyxy, gn)] # xyxy normalized
|
481 |
+
self.xywhn = [x / g for x, g in zip(self.xywh, gn)] # xywh normalized
|
482 |
+
self.n = len(self.pred) # number of images (batch size)
|
483 |
+
self.t = tuple(x.t / self.n * 1E3 for x in times) # timestamps (ms)
|
484 |
+
self.s = tuple(shape) # inference BCHW shape
|
485 |
+
|
486 |
+
def _run(self, pprint=False, show=False, save=False, crop=False, render=False, labels=True, save_dir=Path('')):
|
487 |
+
s, crops = '', []
|
488 |
+
for i, (im, pred) in enumerate(zip(self.ims, self.pred)):
|
489 |
+
s += f'\nimage {i + 1}/{len(self.pred)}: {im.shape[0]}x{im.shape[1]} ' # string
|
490 |
+
if pred.shape[0]:
|
491 |
+
for c in pred[:, -1].unique():
|
492 |
+
n = (pred[:, -1] == c).sum() # detections per class
|
493 |
+
s += f"{n} {self.names[int(c)]}{'s' * (n > 1)}, " # add to string
|
494 |
+
s = s.rstrip(', ')
|
495 |
+
if show or save or render or crop:
|
496 |
+
annotator = Annotator(im, example=str(self.names))
|
497 |
+
for *box, conf, cls in reversed(pred): # xyxy, confidence, class
|
498 |
+
label = f'{self.names[int(cls)]} {conf:.2f}'
|
499 |
+
if crop:
|
500 |
+
file = save_dir / 'crops' / self.names[int(cls)] / self.files[i] if save else None
|
501 |
+
crops.append({
|
502 |
+
'box': box,
|
503 |
+
'conf': conf,
|
504 |
+
'cls': cls,
|
505 |
+
'label': label,
|
506 |
+
'im': save_one_box(box, im, file=file, save=save)})
|
507 |
+
else: # all others
|
508 |
+
annotator.box_label(box, label if labels else '', color=colors(cls))
|
509 |
+
im = annotator.im
|
510 |
+
else:
|
511 |
+
s += '(no detections)'
|
512 |
+
|
513 |
+
im = Image.fromarray(im.astype(np.uint8)) if isinstance(im, np.ndarray) else im # from np
|
514 |
+
if show:
|
515 |
+
im.show(self.files[i]) # show
|
516 |
+
if save:
|
517 |
+
f = self.files[i]
|
518 |
+
im.save(save_dir / f) # save
|
519 |
+
if i == self.n - 1:
|
520 |
+
LOGGER.info(f"Saved {self.n} image{'s' * (self.n > 1)} to {colorstr('bold', save_dir)}")
|
521 |
+
if render:
|
522 |
+
self.ims[i] = np.asarray(im)
|
523 |
+
if pprint:
|
524 |
+
s = s.lstrip('\n')
|
525 |
+
return f'{s}\nSpeed: %.1fms pre-process, %.1fms inference, %.1fms NMS per image at shape {self.s}' % self.t
|
526 |
+
if crop:
|
527 |
+
if save:
|
528 |
+
LOGGER.info(f'Saved results to {save_dir}\n')
|
529 |
+
return crops
|
530 |
+
|
531 |
+
def show(self, labels=True):
|
532 |
+
self._run(show=True, labels=labels) # show results
|
533 |
+
|
534 |
+
def save(self, labels=True, save_dir='runs/detect/exp', exist_ok=False):
|
535 |
+
save_dir = increment_path(save_dir, exist_ok, mkdir=True) # increment save_dir
|
536 |
+
self._run(save=True, labels=labels, save_dir=save_dir) # save results
|
537 |
+
|
538 |
+
def crop(self, save=True, save_dir='runs/detect/exp', exist_ok=False):
|
539 |
+
save_dir = increment_path(save_dir, exist_ok, mkdir=True) if save else None
|
540 |
+
return self._run(crop=True, save=save, save_dir=save_dir) # crop results
|
541 |
+
|
542 |
+
def render(self, labels=True):
|
543 |
+
self._run(render=True, labels=labels) # render results
|
544 |
+
return self.ims
|
545 |
+
|
546 |
+
def pandas(self):
|
547 |
+
# return detections as pandas DataFrames, i.e. print(results.pandas().xyxy[0])
|
548 |
+
new = copy(self) # return copy
|
549 |
+
ca = 'xmin', 'ymin', 'xmax', 'ymax', 'confidence', 'class', 'name' # xyxy columns
|
550 |
+
cb = 'xcenter', 'ycenter', 'width', 'height', 'confidence', 'class', 'name' # xywh columns
|
551 |
+
for k, c in zip(['xyxy', 'xyxyn', 'xywh', 'xywhn'], [ca, ca, cb, cb]):
|
552 |
+
a = [[x[:5] + [int(x[5]), self.names[int(x[5])]] for x in x.tolist()] for x in getattr(self, k)] # update
|
553 |
+
setattr(new, k, [pd.DataFrame(x, columns=c) for x in a])
|
554 |
+
return new
|
555 |
+
|
556 |
+
def tolist(self):
|
557 |
+
# return a list of Detections objects, i.e. 'for result in results.tolist():'
|
558 |
+
r = range(self.n) # iterable
|
559 |
+
x = [Detections([self.ims[i]], [self.pred[i]], [self.files[i]], self.times, self.names, self.s) for i in r]
|
560 |
+
# for d in x:
|
561 |
+
# for k in ['ims', 'pred', 'xyxy', 'xyxyn', 'xywh', 'xywhn']:
|
562 |
+
# setattr(d, k, getattr(d, k)[0]) # pop out of list
|
563 |
+
return x
|
564 |
+
|
565 |
+
def print(self):
|
566 |
+
LOGGER.info(self.__str__())
|
567 |
+
|
568 |
+
def __len__(self): # override len(results)
|
569 |
+
return self.n
|
570 |
+
|
571 |
+
def __str__(self): # override print(results)
|
572 |
+
return self._run(pprint=True) # print results
|
573 |
+
|
574 |
+
def __repr__(self):
|
575 |
+
return f'YOLOv5 {self.__class__} instance\n' + self.__str__()
|
576 |
+
|
577 |
+
|
578 |
+
class Proto(nn.Module):
|
579 |
+
# YOLOv8 mask Proto module for segmentation models
|
580 |
+
def __init__(self, c1, c_=256, c2=32): # ch_in, number of protos, number of masks
|
581 |
+
super().__init__()
|
582 |
+
self.cv1 = Conv(c1, c_, k=3)
|
583 |
+
self.upsample = nn.ConvTranspose2d(c_, c_, 2, 2, 0, bias=True) # nn.Upsample(scale_factor=2, mode='nearest')
|
584 |
+
self.cv2 = Conv(c_, c_, k=3)
|
585 |
+
self.cv3 = Conv(c_, c2)
|
586 |
+
|
587 |
+
def forward(self, x):
|
588 |
+
return self.cv3(self.cv2(self.upsample(self.cv1(x))))
|
589 |
+
|
590 |
+
|
591 |
+
class Ensemble(nn.ModuleList):
|
592 |
+
# Ensemble of models
|
593 |
+
def __init__(self):
|
594 |
+
super().__init__()
|
595 |
+
|
596 |
+
def forward(self, x, augment=False, profile=False, visualize=False):
|
597 |
+
y = [module(x, augment, profile, visualize)[0] for module in self]
|
598 |
+
# y = torch.stack(y).max(0)[0] # max ensemble
|
599 |
+
# y = torch.stack(y).mean(0) # mean ensemble
|
600 |
+
y = torch.cat(y, 1) # nms ensemble
|
601 |
+
return y, None # inference, train output
|
602 |
+
|
603 |
+
|
604 |
+
# heads
|
605 |
+
class Detect(nn.Module):
|
606 |
+
# YOLOv5 Detect head for detection models
|
607 |
+
dynamic = False # force grid reconstruction
|
608 |
+
export = False # export mode
|
609 |
+
shape = None
|
610 |
+
anchors = torch.empty(0) # init
|
611 |
+
strides = torch.empty(0) # init
|
612 |
+
|
613 |
+
def __init__(self, nc=80, ch=()): # detection layer
|
614 |
+
super().__init__()
|
615 |
+
self.nc = nc # number of classes
|
616 |
+
self.nl = len(ch) # number of detection layers
|
617 |
+
self.reg_max = 16 # DFL channels (ch[0] // 16 to scale 4/8/12/16/20 for n/s/m/l/x)
|
618 |
+
self.no = nc + self.reg_max * 4 # number of outputs per anchor
|
619 |
+
self.stride = torch.zeros(self.nl) # strides computed during build
|
620 |
+
|
621 |
+
c2, c3 = max((16, ch[0] // 4, self.reg_max * 4)), max(ch[0], self.nc) # channels
|
622 |
+
self.cv2 = nn.ModuleList(
|
623 |
+
nn.Sequential(Conv(x, c2, 3), Conv(c2, c2, 3), nn.Conv2d(c2, 4 * self.reg_max, 1)) for x in ch)
|
624 |
+
self.cv3 = nn.ModuleList(nn.Sequential(Conv(x, c3, 3), Conv(c3, c3, 3), nn.Conv2d(c3, self.nc, 1)) for x in ch)
|
625 |
+
self.dfl = DFL(self.reg_max) if self.reg_max > 1 else nn.Identity()
|
626 |
+
|
627 |
+
def forward(self, x):
|
628 |
+
shape = x[0].shape # BCHW
|
629 |
+
for i in range(self.nl):
|
630 |
+
x[i] = torch.cat((self.cv2[i](x[i]), self.cv3[i](x[i])), 1)
|
631 |
+
if self.training:
|
632 |
+
return x
|
633 |
+
elif self.dynamic or self.shape != shape:
|
634 |
+
self.anchors, self.strides = (x.transpose(0, 1) for x in make_anchors(x, self.stride, 0.5))
|
635 |
+
self.shape = shape
|
636 |
+
|
637 |
+
box, cls = torch.cat([xi.view(shape[0], self.no, -1) for xi in x], 2).split((self.reg_max * 4, self.nc), 1)
|
638 |
+
dbox = dist2bbox(self.dfl(box), self.anchors.unsqueeze(0), xywh=True, dim=1) * self.strides
|
639 |
+
y = torch.cat((dbox, cls.sigmoid()), 1)
|
640 |
+
return y if self.export else (y, x)
|
641 |
+
|
642 |
+
def bias_init(self):
|
643 |
+
# Initialize Detect() biases, WARNING: requires stride availability
|
644 |
+
m = self # self.model[-1] # Detect() module
|
645 |
+
# cf = torch.bincount(torch.tensor(np.concatenate(dataset.labels, 0)[:, 0]).long(), minlength=nc) + 1
|
646 |
+
# ncf = math.log(0.6 / (m.nc - 0.999999)) if cf is None else torch.log(cf / cf.sum()) # nominal class frequency
|
647 |
+
for a, b, s in zip(m.cv2, m.cv3, m.stride): # from
|
648 |
+
a[-1].bias.data[:] = 1.0 # box
|
649 |
+
b[-1].bias.data[:m.nc] = math.log(5 / m.nc / (640 / s) ** 2) # cls (.01 objects, 80 classes, 640 img)
|
650 |
+
|
651 |
+
|
652 |
+
class Segment(Detect):
|
653 |
+
# YOLOv5 Segment head for segmentation models
|
654 |
+
def __init__(self, nc=80, nm=32, npr=256, ch=()):
|
655 |
+
super().__init__(nc, ch)
|
656 |
+
self.nm = nm # number of masks
|
657 |
+
self.npr = npr # number of protos
|
658 |
+
self.proto = Proto(ch[0], self.npr, self.nm) # protos
|
659 |
+
self.detect = Detect.forward
|
660 |
+
|
661 |
+
c4 = max(ch[0] // 4, self.nm)
|
662 |
+
self.cv4 = nn.ModuleList(nn.Sequential(Conv(x, c4, 3), Conv(c4, c4, 3), nn.Conv2d(c4, self.nm, 1)) for x in ch)
|
663 |
+
|
664 |
+
def forward(self, x):
|
665 |
+
p = self.proto(x[0]) # mask protos
|
666 |
+
bs = p.shape[0] # batch size
|
667 |
+
|
668 |
+
mc = torch.cat([self.cv4[i](x[i]).view(bs, self.nm, -1) for i in range(self.nl)], 2) # mask coefficients
|
669 |
+
x = self.detect(self, x)
|
670 |
+
if self.training:
|
671 |
+
return x, mc, p
|
672 |
+
return (torch.cat([x, mc], 1), p) if self.export else (torch.cat([x[0], mc], 1), (x[1], mc, p))
|
673 |
+
|
674 |
+
|
675 |
+
class Classify(nn.Module):
|
676 |
+
# YOLOv5 classification head, i.e. x(b,c1,20,20) to x(b,c2)
|
677 |
+
def __init__(self, c1, c2, k=1, s=1, p=None, g=1): # ch_in, ch_out, kernel, stride, padding, groups
|
678 |
+
super().__init__()
|
679 |
+
c_ = 1280 # efficientnet_b0 size
|
680 |
+
self.conv = Conv(c1, c_, k, s, autopad(k, p), g)
|
681 |
+
self.pool = nn.AdaptiveAvgPool2d(1) # to x(b,c_,1,1)
|
682 |
+
self.drop = nn.Dropout(p=0.0, inplace=True)
|
683 |
+
self.linear = nn.Linear(c_, c2) # to x(b,c2)
|
684 |
+
|
685 |
+
def forward(self, x):
|
686 |
+
if isinstance(x, list):
|
687 |
+
x = torch.cat(x, 1)
|
688 |
+
return self.linear(self.drop(self.pool(self.conv(x)).flatten(1)))
|
ultralytics/nn/tasks.py
ADDED
@@ -0,0 +1,416 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Ultralytics YOLO 🚀, GPL-3.0 license
|
2 |
+
|
3 |
+
import contextlib
|
4 |
+
from copy import deepcopy
|
5 |
+
|
6 |
+
import thop
|
7 |
+
import torch
|
8 |
+
import torch.nn as nn
|
9 |
+
|
10 |
+
from ultralytics.nn.modules import (C1, C2, C3, C3TR, SPP, SPPF, Bottleneck, BottleneckCSP, C2f, C3Ghost, C3x, Classify,
|
11 |
+
Concat, Conv, ConvTranspose, Detect, DWConv, DWConvTranspose2d, Ensemble, Focus,
|
12 |
+
GhostBottleneck, GhostConv, Segment)
|
13 |
+
from ultralytics.yolo.utils import DEFAULT_CONFIG_DICT, DEFAULT_CONFIG_KEYS, LOGGER, colorstr, yaml_load
|
14 |
+
from ultralytics.yolo.utils.checks import check_yaml
|
15 |
+
from ultralytics.yolo.utils.torch_utils import (fuse_conv_and_bn, initialize_weights, intersect_dicts, make_divisible,
|
16 |
+
model_info, scale_img, time_sync)
|
17 |
+
|
18 |
+
|
19 |
+
class BaseModel(nn.Module):
|
20 |
+
'''
|
21 |
+
The BaseModel class is a base class for all the models in the Ultralytics YOLO family.
|
22 |
+
'''
|
23 |
+
|
24 |
+
def forward(self, x, profile=False, visualize=False):
|
25 |
+
"""
|
26 |
+
> `forward` is a wrapper for `_forward_once` that runs the model on a single scale
|
27 |
+
|
28 |
+
Args:
|
29 |
+
x: the input image
|
30 |
+
profile: whether to profile the model. Defaults to False
|
31 |
+
visualize: if True, will return the intermediate feature maps. Defaults to False
|
32 |
+
|
33 |
+
Returns:
|
34 |
+
The output of the network.
|
35 |
+
"""
|
36 |
+
return self._forward_once(x, profile, visualize)
|
37 |
+
|
38 |
+
def _forward_once(self, x, profile=False, visualize=False):
|
39 |
+
"""
|
40 |
+
> Forward pass of the network
|
41 |
+
|
42 |
+
Args:
|
43 |
+
x: input to the model
|
44 |
+
profile: if True, the time taken for each layer will be printed. Defaults to False
|
45 |
+
visualize: If True, it will save the feature maps of the model. Defaults to False
|
46 |
+
|
47 |
+
Returns:
|
48 |
+
The last layer of the model.
|
49 |
+
"""
|
50 |
+
y, dt = [], [] # outputs
|
51 |
+
for m in self.model:
|
52 |
+
if m.f != -1: # if not from previous layer
|
53 |
+
x = y[m.f] if isinstance(m.f, int) else [x if j == -1 else y[j] for j in m.f] # from earlier layers
|
54 |
+
if profile:
|
55 |
+
self._profile_one_layer(m, x, dt)
|
56 |
+
x = m(x) # run
|
57 |
+
y.append(x if m.i in self.save else None) # save output
|
58 |
+
if visualize:
|
59 |
+
pass
|
60 |
+
# TODO: feature_visualization(x, m.type, m.i, save_dir=visualize)
|
61 |
+
return x
|
62 |
+
|
63 |
+
def _profile_one_layer(self, m, x, dt):
|
64 |
+
"""
|
65 |
+
It takes a model, an input, and a list of times, and it profiles the model on the input, appending
|
66 |
+
the time to the list
|
67 |
+
|
68 |
+
Args:
|
69 |
+
m: the model
|
70 |
+
x: the input image
|
71 |
+
dt: list of time taken for each layer
|
72 |
+
"""
|
73 |
+
c = m == self.model[-1] # is final layer, copy input as inplace fix
|
74 |
+
o = thop.profile(m, inputs=(x.copy() if c else x,), verbose=False)[0] / 1E9 * 2 if thop else 0 # FLOPs
|
75 |
+
t = time_sync()
|
76 |
+
for _ in range(10):
|
77 |
+
m(x.copy() if c else x)
|
78 |
+
dt.append((time_sync() - t) * 100)
|
79 |
+
if m == self.model[0]:
|
80 |
+
LOGGER.info(f"{'time (ms)':>10s} {'GFLOPs':>10s} {'params':>10s} module")
|
81 |
+
LOGGER.info(f'{dt[-1]:10.2f} {o:10.2f} {m.np:10.0f} {m.type}')
|
82 |
+
if c:
|
83 |
+
LOGGER.info(f"{sum(dt):10.2f} {'-':>10s} {'-':>10s} Total")
|
84 |
+
|
85 |
+
def fuse(self):
|
86 |
+
"""
|
87 |
+
> It takes a model and fuses the Conv2d() and BatchNorm2d() layers into a single layer
|
88 |
+
|
89 |
+
Returns:
|
90 |
+
The model is being returned.
|
91 |
+
"""
|
92 |
+
LOGGER.info('Fusing layers... ')
|
93 |
+
for m in self.model.modules():
|
94 |
+
if isinstance(m, (Conv, DWConv)) and hasattr(m, 'bn'):
|
95 |
+
m.conv = fuse_conv_and_bn(m.conv, m.bn) # update conv
|
96 |
+
delattr(m, 'bn') # remove batchnorm
|
97 |
+
m.forward = m.forward_fuse # update forward
|
98 |
+
self.info()
|
99 |
+
return self
|
100 |
+
|
101 |
+
def info(self, verbose=False, imgsz=640):
|
102 |
+
"""
|
103 |
+
Prints model information
|
104 |
+
|
105 |
+
Args:
|
106 |
+
verbose: if True, prints out the model information. Defaults to False
|
107 |
+
imgsz: the size of the image that the model will be trained on. Defaults to 640
|
108 |
+
"""
|
109 |
+
model_info(self, verbose, imgsz)
|
110 |
+
|
111 |
+
def _apply(self, fn):
|
112 |
+
"""
|
113 |
+
`_apply()` is a function that applies a function to all the tensors in the model that are not
|
114 |
+
parameters or registered buffers
|
115 |
+
|
116 |
+
Args:
|
117 |
+
fn: the function to apply to the model
|
118 |
+
|
119 |
+
Returns:
|
120 |
+
A model that is a Detect() object.
|
121 |
+
"""
|
122 |
+
self = super()._apply(fn)
|
123 |
+
m = self.model[-1] # Detect()
|
124 |
+
if isinstance(m, (Detect, Segment)):
|
125 |
+
m.stride = fn(m.stride)
|
126 |
+
m.anchors = fn(m.anchors)
|
127 |
+
m.strides = fn(m.strides)
|
128 |
+
return self
|
129 |
+
|
130 |
+
def load(self, weights):
|
131 |
+
"""
|
132 |
+
> This function loads the weights of the model from a file
|
133 |
+
|
134 |
+
Args:
|
135 |
+
weights: The weights to load into the model.
|
136 |
+
"""
|
137 |
+
# Force all tasks to implement this function
|
138 |
+
raise NotImplementedError("This function needs to be implemented by derived classes!")
|
139 |
+
|
140 |
+
|
141 |
+
class DetectionModel(BaseModel):
|
142 |
+
# YOLOv5 detection model
|
143 |
+
def __init__(self, cfg='yolov8n.yaml', ch=3, nc=None, verbose=True): # model, input channels, number of classes
|
144 |
+
super().__init__()
|
145 |
+
self.yaml = cfg if isinstance(cfg, dict) else yaml_load(check_yaml(cfg), append_filename=True) # cfg dict
|
146 |
+
|
147 |
+
# Define model
|
148 |
+
ch = self.yaml['ch'] = self.yaml.get('ch', ch) # input channels
|
149 |
+
if nc and nc != self.yaml['nc']:
|
150 |
+
LOGGER.info(f"Overriding model.yaml nc={self.yaml['nc']} with nc={nc}")
|
151 |
+
self.yaml['nc'] = nc # override yaml value
|
152 |
+
self.model, self.save = parse_model(deepcopy(self.yaml), ch=[ch], verbose=verbose) # model, savelist
|
153 |
+
self.names = {i: f'{i}' for i in range(self.yaml['nc'])} # default names dict
|
154 |
+
self.inplace = self.yaml.get('inplace', True)
|
155 |
+
|
156 |
+
# Build strides
|
157 |
+
m = self.model[-1] # Detect()
|
158 |
+
if isinstance(m, (Detect, Segment)):
|
159 |
+
s = 256 # 2x min stride
|
160 |
+
m.inplace = self.inplace
|
161 |
+
forward = lambda x: self.forward(x)[0] if isinstance(m, Segment) else self.forward(x)
|
162 |
+
m.stride = torch.tensor([s / x.shape[-2] for x in forward(torch.zeros(1, ch, s, s))]) # forward
|
163 |
+
self.stride = m.stride
|
164 |
+
m.bias_init() # only run once
|
165 |
+
|
166 |
+
# Init weights, biases
|
167 |
+
initialize_weights(self)
|
168 |
+
if verbose:
|
169 |
+
self.info()
|
170 |
+
LOGGER.info('')
|
171 |
+
|
172 |
+
def forward(self, x, augment=False, profile=False, visualize=False):
|
173 |
+
if augment:
|
174 |
+
return self._forward_augment(x) # augmented inference, None
|
175 |
+
return self._forward_once(x, profile, visualize) # single-scale inference, train
|
176 |
+
|
177 |
+
def _forward_augment(self, x):
|
178 |
+
img_size = x.shape[-2:] # height, width
|
179 |
+
s = [1, 0.83, 0.67] # scales
|
180 |
+
f = [None, 3, None] # flips (2-ud, 3-lr)
|
181 |
+
y = [] # outputs
|
182 |
+
for si, fi in zip(s, f):
|
183 |
+
xi = scale_img(x.flip(fi) if fi else x, si, gs=int(self.stride.max()))
|
184 |
+
yi = self._forward_once(xi)[0] # forward
|
185 |
+
# cv2.imwrite(f'img_{si}.jpg', 255 * xi[0].cpu().numpy().transpose((1, 2, 0))[:, :, ::-1]) # save
|
186 |
+
yi = self._descale_pred(yi, fi, si, img_size)
|
187 |
+
y.append(yi)
|
188 |
+
y = self._clip_augmented(y) # clip augmented tails
|
189 |
+
return torch.cat(y, -1), None # augmented inference, train
|
190 |
+
|
191 |
+
@staticmethod
|
192 |
+
def _descale_pred(p, flips, scale, img_size, dim=1):
|
193 |
+
# de-scale predictions following augmented inference (inverse operation)
|
194 |
+
p[:, :4] /= scale # de-scale
|
195 |
+
x, y, wh, cls = p.split((1, 1, 2, p.shape[dim] - 4), dim)
|
196 |
+
if flips == 2:
|
197 |
+
y = img_size[0] - y # de-flip ud
|
198 |
+
elif flips == 3:
|
199 |
+
x = img_size[1] - x # de-flip lr
|
200 |
+
return torch.cat((x, y, wh, cls), dim)
|
201 |
+
|
202 |
+
def _clip_augmented(self, y):
|
203 |
+
# Clip YOLOv5 augmented inference tails
|
204 |
+
nl = self.model[-1].nl # number of detection layers (P3-P5)
|
205 |
+
g = sum(4 ** x for x in range(nl)) # grid points
|
206 |
+
e = 1 # exclude layer count
|
207 |
+
i = (y[0].shape[-1] // g) * sum(4 ** x for x in range(e)) # indices
|
208 |
+
y[0] = y[0][..., :-i] # large
|
209 |
+
i = (y[-1].shape[-1] // g) * sum(4 ** (nl - 1 - x) for x in range(e)) # indices
|
210 |
+
y[-1] = y[-1][..., i:] # small
|
211 |
+
return y
|
212 |
+
|
213 |
+
def load(self, weights, verbose=True):
|
214 |
+
csd = weights.float().state_dict() # checkpoint state_dict as FP32
|
215 |
+
csd = intersect_dicts(csd, self.state_dict()) # intersect
|
216 |
+
self.load_state_dict(csd, strict=False) # load
|
217 |
+
if verbose:
|
218 |
+
LOGGER.info(f'Transferred {len(csd)}/{len(self.model.state_dict())} items from pretrained weights')
|
219 |
+
|
220 |
+
|
221 |
+
class SegmentationModel(DetectionModel):
|
222 |
+
# YOLOv5 segmentation model
|
223 |
+
def __init__(self, cfg='yolov8n-seg.yaml', ch=3, nc=None, verbose=True):
|
224 |
+
super().__init__(cfg, ch, nc, verbose)
|
225 |
+
|
226 |
+
|
227 |
+
class ClassificationModel(BaseModel):
|
228 |
+
# YOLOv5 classification model
|
229 |
+
def __init__(self,
|
230 |
+
cfg=None,
|
231 |
+
model=None,
|
232 |
+
ch=3,
|
233 |
+
nc=1000,
|
234 |
+
cutoff=10,
|
235 |
+
verbose=True): # yaml, model, number of classes, cutoff index
|
236 |
+
super().__init__()
|
237 |
+
self._from_detection_model(model, nc, cutoff) if model is not None else self._from_yaml(cfg, ch, nc, verbose)
|
238 |
+
|
239 |
+
def _from_detection_model(self, model, nc=1000, cutoff=10):
|
240 |
+
# Create a YOLOv5 classification model from a YOLOv5 detection model
|
241 |
+
from ultralytics.nn.autobackend import AutoBackend
|
242 |
+
if isinstance(model, AutoBackend):
|
243 |
+
model = model.model # unwrap DetectMultiBackend
|
244 |
+
model.model = model.model[:cutoff] # backbone
|
245 |
+
m = model.model[-1] # last layer
|
246 |
+
ch = m.conv.in_channels if hasattr(m, 'conv') else m.cv1.conv.in_channels # ch into module
|
247 |
+
c = Classify(ch, nc) # Classify()
|
248 |
+
c.i, c.f, c.type = m.i, m.f, 'models.common.Classify' # index, from, type
|
249 |
+
model.model[-1] = c # replace
|
250 |
+
self.model = model.model
|
251 |
+
self.stride = model.stride
|
252 |
+
self.save = []
|
253 |
+
self.nc = nc
|
254 |
+
|
255 |
+
def _from_yaml(self, cfg, ch, nc, verbose):
|
256 |
+
self.yaml = cfg if isinstance(cfg, dict) else yaml_load(check_yaml(cfg), append_filename=True) # cfg dict
|
257 |
+
# Define model
|
258 |
+
ch = self.yaml['ch'] = self.yaml.get('ch', ch) # input channels
|
259 |
+
if nc and nc != self.yaml['nc']:
|
260 |
+
LOGGER.info(f"Overriding model.yaml nc={self.yaml['nc']} with nc={nc}")
|
261 |
+
self.yaml['nc'] = nc # override yaml value
|
262 |
+
self.model, self.save = parse_model(deepcopy(self.yaml), ch=[ch], verbose=verbose) # model, savelist
|
263 |
+
self.names = {i: f'{i}' for i in range(self.yaml['nc'])} # default names dict
|
264 |
+
self.info()
|
265 |
+
|
266 |
+
def load(self, weights):
|
267 |
+
model = weights["model"] if isinstance(weights, dict) else weights # torchvision models are not dicts
|
268 |
+
csd = model.float().state_dict()
|
269 |
+
csd = intersect_dicts(csd, self.state_dict()) # intersect
|
270 |
+
self.load_state_dict(csd, strict=False) # load
|
271 |
+
|
272 |
+
@staticmethod
|
273 |
+
def reshape_outputs(model, nc):
|
274 |
+
# Update a TorchVision classification model to class count 'n' if required
|
275 |
+
name, m = list((model.model if hasattr(model, 'model') else model).named_children())[-1] # last module
|
276 |
+
if isinstance(m, Classify): # YOLO Classify() head
|
277 |
+
if m.linear.out_features != nc:
|
278 |
+
m.linear = nn.Linear(m.linear.in_features, nc)
|
279 |
+
elif isinstance(m, nn.Linear): # ResNet, EfficientNet
|
280 |
+
if m.out_features != nc:
|
281 |
+
setattr(model, name, nn.Linear(m.in_features, nc))
|
282 |
+
elif isinstance(m, nn.Sequential):
|
283 |
+
types = [type(x) for x in m]
|
284 |
+
if nn.Linear in types:
|
285 |
+
i = types.index(nn.Linear) # nn.Linear index
|
286 |
+
if m[i].out_features != nc:
|
287 |
+
m[i] = nn.Linear(m[i].in_features, nc)
|
288 |
+
elif nn.Conv2d in types:
|
289 |
+
i = types.index(nn.Conv2d) # nn.Conv2d index
|
290 |
+
if m[i].out_channels != nc:
|
291 |
+
m[i] = nn.Conv2d(m[i].in_channels, nc, m[i].kernel_size, m[i].stride, bias=m[i].bias is not None)
|
292 |
+
|
293 |
+
|
294 |
+
# Functions ------------------------------------------------------------------------------------------------------------
|
295 |
+
|
296 |
+
|
297 |
+
def attempt_load_weights(weights, device=None, inplace=True, fuse=False):
|
298 |
+
# Loads an ensemble of models weights=[a,b,c] or a single model weights=[a] or weights=a
|
299 |
+
from ultralytics.yolo.utils.downloads import attempt_download
|
300 |
+
|
301 |
+
model = Ensemble()
|
302 |
+
for w in weights if isinstance(weights, list) else [weights]:
|
303 |
+
ckpt = torch.load(attempt_download(w), map_location='cpu') # load
|
304 |
+
args = {**DEFAULT_CONFIG_DICT, **ckpt['train_args']} # combine model and default args, preferring model args
|
305 |
+
ckpt = (ckpt.get('ema') or ckpt['model']).to(device).float() # FP32 model
|
306 |
+
|
307 |
+
# Model compatibility updates
|
308 |
+
ckpt.args = {k: v for k, v in args.items() if k in DEFAULT_CONFIG_KEYS} # attach args to model
|
309 |
+
ckpt.pt_path = weights # attach *.pt file path to model
|
310 |
+
if not hasattr(ckpt, 'stride'):
|
311 |
+
ckpt.stride = torch.tensor([32.])
|
312 |
+
|
313 |
+
# Append
|
314 |
+
model.append(ckpt.fuse().eval() if fuse and hasattr(ckpt, 'fuse') else ckpt.eval()) # model in eval mode
|
315 |
+
|
316 |
+
# Module compatibility updates
|
317 |
+
for m in model.modules():
|
318 |
+
t = type(m)
|
319 |
+
if t in (nn.Hardswish, nn.LeakyReLU, nn.ReLU, nn.ReLU6, nn.SiLU, Detect, Segment):
|
320 |
+
m.inplace = inplace # torch 1.7.0 compatibility
|
321 |
+
elif t is nn.Upsample and not hasattr(m, 'recompute_scale_factor'):
|
322 |
+
m.recompute_scale_factor = None # torch 1.11.0 compatibility
|
323 |
+
|
324 |
+
# Return model
|
325 |
+
if len(model) == 1:
|
326 |
+
return model[-1]
|
327 |
+
|
328 |
+
# Return ensemble
|
329 |
+
print(f'Ensemble created with {weights}\n')
|
330 |
+
for k in 'names', 'nc', 'yaml':
|
331 |
+
setattr(model, k, getattr(model[0], k))
|
332 |
+
model.stride = model[torch.argmax(torch.tensor([m.stride.max() for m in model])).int()].stride # max stride
|
333 |
+
assert all(model[0].nc == m.nc for m in model), f'Models have different class counts: {[m.nc for m in model]}'
|
334 |
+
return model
|
335 |
+
|
336 |
+
|
337 |
+
def attempt_load_one_weight(weight, device=None, inplace=True, fuse=False):
|
338 |
+
# Loads a single model weights
|
339 |
+
from ultralytics.yolo.utils.downloads import attempt_download
|
340 |
+
|
341 |
+
ckpt = torch.load(attempt_download(weight), map_location='cpu') # load
|
342 |
+
args = {**DEFAULT_CONFIG_DICT, **ckpt['train_args']} # combine model and default args, preferring model args
|
343 |
+
model = (ckpt.get('ema') or ckpt['model']).to(device).float() # FP32 model
|
344 |
+
|
345 |
+
# Model compatibility updates
|
346 |
+
model.args = {k: v for k, v in args.items() if k in DEFAULT_CONFIG_KEYS} # attach args to model
|
347 |
+
model.pt_path = weight # attach *.pt file path to model
|
348 |
+
if not hasattr(model, 'stride'):
|
349 |
+
model.stride = torch.tensor([32.])
|
350 |
+
|
351 |
+
model = model.fuse().eval() if fuse and hasattr(model, 'fuse') else model.eval() # model in eval mode
|
352 |
+
|
353 |
+
# Module compatibility updates
|
354 |
+
for m in model.modules():
|
355 |
+
t = type(m)
|
356 |
+
if t in (nn.Hardswish, nn.LeakyReLU, nn.ReLU, nn.ReLU6, nn.SiLU, Detect, Segment):
|
357 |
+
m.inplace = inplace # torch 1.7.0 compatibility
|
358 |
+
elif t is nn.Upsample and not hasattr(m, 'recompute_scale_factor'):
|
359 |
+
m.recompute_scale_factor = None # torch 1.11.0 compatibility
|
360 |
+
|
361 |
+
# Return model and ckpt
|
362 |
+
return model, ckpt
|
363 |
+
|
364 |
+
|
365 |
+
def parse_model(d, ch, verbose=True): # model_dict, input_channels(3)
|
366 |
+
# Parse a YOLO model.yaml dictionary
|
367 |
+
if verbose:
|
368 |
+
LOGGER.info(f"\n{'':>3}{'from':>20}{'n':>3}{'params':>10} {'module':<45}{'arguments':<30}")
|
369 |
+
nc, gd, gw, act = d['nc'], d['depth_multiple'], d['width_multiple'], d.get('activation')
|
370 |
+
if act:
|
371 |
+
Conv.default_act = eval(act) # redefine default activation, i.e. Conv.default_act = nn.SiLU()
|
372 |
+
if verbose:
|
373 |
+
LOGGER.info(f"{colorstr('activation:')} {act}") # print
|
374 |
+
|
375 |
+
layers, save, c2 = [], [], ch[-1] # layers, savelist, ch out
|
376 |
+
for i, (f, n, m, args) in enumerate(d['backbone'] + d['head']): # from, number, module, args
|
377 |
+
m = eval(m) if isinstance(m, str) else m # eval strings
|
378 |
+
for j, a in enumerate(args):
|
379 |
+
with contextlib.suppress(NameError):
|
380 |
+
args[j] = eval(a) if isinstance(a, str) else a # eval strings
|
381 |
+
|
382 |
+
n = n_ = max(round(n * gd), 1) if n > 1 else n # depth gain
|
383 |
+
if m in {
|
384 |
+
Classify, Conv, ConvTranspose, GhostConv, Bottleneck, GhostBottleneck, SPP, SPPF, DWConv, Focus,
|
385 |
+
BottleneckCSP, C1, C2, C2f, C3, C3TR, C3Ghost, nn.ConvTranspose2d, DWConvTranspose2d, C3x}:
|
386 |
+
c1, c2 = ch[f], args[0]
|
387 |
+
if c2 != nc: # if c2 not equal to number of classes (i.e. for Classify() output)
|
388 |
+
c2 = make_divisible(c2 * gw, 8)
|
389 |
+
|
390 |
+
args = [c1, c2, *args[1:]]
|
391 |
+
if m in {BottleneckCSP, C1, C2, C2f, C3, C3TR, C3Ghost, C3x}:
|
392 |
+
args.insert(2, n) # number of repeats
|
393 |
+
n = 1
|
394 |
+
elif m is nn.BatchNorm2d:
|
395 |
+
args = [ch[f]]
|
396 |
+
elif m is Concat:
|
397 |
+
c2 = sum(ch[x] for x in f)
|
398 |
+
elif m in {Detect, Segment}:
|
399 |
+
args.append([ch[x] for x in f])
|
400 |
+
if m is Segment:
|
401 |
+
args[2] = make_divisible(args[2] * gw, 8)
|
402 |
+
else:
|
403 |
+
c2 = ch[f]
|
404 |
+
|
405 |
+
m_ = nn.Sequential(*(m(*args) for _ in range(n))) if n > 1 else m(*args) # module
|
406 |
+
t = str(m)[8:-2].replace('__main__.', '') # module type
|
407 |
+
m.np = sum(x.numel() for x in m_.parameters()) # number params
|
408 |
+
m_.i, m_.f, m_.type = i, f, t # attach index, 'from' index, type
|
409 |
+
if verbose:
|
410 |
+
LOGGER.info(f'{i:>3}{str(f):>20}{n_:>3}{m.np:10.0f} {t:<45}{str(args):<30}') # print
|
411 |
+
save.extend(x % i for x in ([f] if isinstance(f, int) else f) if x != -1) # append to savelist
|
412 |
+
layers.append(m_)
|
413 |
+
if i == 0:
|
414 |
+
ch = []
|
415 |
+
ch.append(c2)
|
416 |
+
return nn.Sequential(*layers), sorted(save)
|
ultralytics/yolo/cli.py
ADDED
@@ -0,0 +1,52 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Ultralytics YOLO 🚀, GPL-3.0 license
|
2 |
+
|
3 |
+
import shutil
|
4 |
+
from pathlib import Path
|
5 |
+
|
6 |
+
import hydra
|
7 |
+
|
8 |
+
from ultralytics import hub, yolo
|
9 |
+
from ultralytics.yolo.utils import DEFAULT_CONFIG, LOGGER, colorstr
|
10 |
+
|
11 |
+
DIR = Path(__file__).parent
|
12 |
+
|
13 |
+
|
14 |
+
@hydra.main(version_base=None, config_path=str(DEFAULT_CONFIG.parent.relative_to(DIR)), config_name=DEFAULT_CONFIG.name)
|
15 |
+
def cli(cfg):
|
16 |
+
"""
|
17 |
+
Run a specified task and mode with the given configuration.
|
18 |
+
|
19 |
+
Args:
|
20 |
+
cfg (DictConfig): Configuration for the task and mode.
|
21 |
+
"""
|
22 |
+
# LOGGER.info(f"{colorstr(f'Ultralytics YOLO v{ultralytics.__version__}')}")
|
23 |
+
task, mode = cfg.task.lower(), cfg.mode.lower()
|
24 |
+
|
25 |
+
# Special case for initializing the configuration
|
26 |
+
if task == "init":
|
27 |
+
shutil.copy2(DEFAULT_CONFIG, Path.cwd())
|
28 |
+
LOGGER.info(f"""
|
29 |
+
{colorstr("YOLO:")} configuration saved to {Path.cwd() / DEFAULT_CONFIG.name}.
|
30 |
+
To run experiments using custom configuration:
|
31 |
+
yolo task='task' mode='mode' --config-name config_file.yaml
|
32 |
+
""")
|
33 |
+
return
|
34 |
+
|
35 |
+
# Mapping from task to module
|
36 |
+
task_module_map = {"detect": yolo.v8.detect, "segment": yolo.v8.segment, "classify": yolo.v8.classify}
|
37 |
+
module = task_module_map.get(task)
|
38 |
+
if not module:
|
39 |
+
raise SyntaxError(f"task not recognized. Choices are {', '.join(task_module_map.keys())}")
|
40 |
+
|
41 |
+
# Mapping from mode to function
|
42 |
+
mode_func_map = {
|
43 |
+
"train": module.train,
|
44 |
+
"val": module.val,
|
45 |
+
"predict": module.predict,
|
46 |
+
"export": yolo.engine.exporter.export,
|
47 |
+
"checks": hub.checks}
|
48 |
+
func = mode_func_map.get(mode)
|
49 |
+
if not func:
|
50 |
+
raise SyntaxError(f"mode not recognized. Choices are {', '.join(mode_func_map.keys())}")
|
51 |
+
|
52 |
+
func(cfg)
|