From 8947bed4135d7ccdf6de89b63bb6390289dc7085 Mon Sep 17 00:00:00 2001 From: "shengquan.nian" Date: Thu, 18 Apr 2024 13:49:28 +0800 Subject: [PATCH] add yolov9 model --- cv/3d_detection/yolov9/pytorch/LICENSE.md | 674 +++++++++ cv/3d_detection/yolov9/pytorch/README.md | 31 + .../yolov9/pytorch/README_origin.md | 327 +++++ cv/3d_detection/yolov9/pytorch/benchmarks.py | 142 ++ .../yolov9/pytorch/classify/predict.py | 224 +++ .../yolov9/pytorch/classify/train.py | 333 +++++ .../yolov9/pytorch/classify/val.py | 170 +++ cv/3d_detection/yolov9/pytorch/data/coco.yaml | 125 ++ .../pytorch/data/hyps/hyp.scratch-high.yaml | 30 + .../yolov9/pytorch/data/images/horses.jpg | Bin 0 -> 133495 bytes cv/3d_detection/yolov9/pytorch/detect.py | 231 ++++ cv/3d_detection/yolov9/pytorch/detect_dual.py | 232 ++++ cv/3d_detection/yolov9/pytorch/export.py | 686 ++++++++++ .../pytorch/figure/horses_prediction.jpg | Bin 0 -> 158176 bytes .../yolov9/pytorch/figure/multitask.png | Bin 0 -> 1292320 bytes .../yolov9/pytorch/figure/performance.png | Bin 0 -> 356076 bytes cv/3d_detection/yolov9/pytorch/hubconf.py | 107 ++ .../yolov9/pytorch/models/__init__.py | 1 + .../yolov9/pytorch/models/common.py | 1212 ++++++++++++++++ .../yolov9/pytorch/models/detect/gelan-c.yaml | 80 ++ .../yolov9/pytorch/models/detect/gelan-e.yaml | 121 ++ .../yolov9/pytorch/models/detect/gelan.yaml | 80 ++ .../pytorch/models/detect/yolov7-af.yaml | 137 ++ .../pytorch/models/detect/yolov9-c.yaml | 124 ++ .../pytorch/models/detect/yolov9-e.yaml | 144 ++ .../yolov9/pytorch/models/detect/yolov9.yaml | 117 ++ .../yolov9/pytorch/models/experimental.py | 275 ++++ .../yolov9/pytorch/models/hub/anchors.yaml | 59 + .../yolov9/pytorch/models/hub/yolov3-spp.yaml | 51 + .../pytorch/models/hub/yolov3-tiny.yaml | 41 + .../yolov9/pytorch/models/hub/yolov3.yaml | 51 + .../pytorch/models/panoptic/gelan-c-pan.yaml | 80 ++ .../models/panoptic/yolov7-af-pan.yaml | 137 ++ .../pytorch/models/segment/gelan-c-dseg.yaml | 84 ++ .../pytorch/models/segment/gelan-c-seg.yaml | 80 ++ .../pytorch/models/segment/yolov7-af-seg.yaml | 136 ++ .../pytorch/models/segment/yolov9-c-dseg.yaml | 130 ++ cv/3d_detection/yolov9/pytorch/models/tf.py | 596 ++++++++ cv/3d_detection/yolov9/pytorch/models/yolo.py | 818 +++++++++++ .../yolov9/pytorch/panoptic/predict.py | 246 ++++ .../yolov9/pytorch/panoptic/train.py | 662 +++++++++ .../yolov9/pytorch/panoptic/val.py | 597 ++++++++ .../yolov9/pytorch/requirements.txt | 47 + .../yolov9/pytorch/scripts/get_coco.sh | 22 + .../yolov9/pytorch/segment/predict.py | 246 ++++ .../yolov9/pytorch/segment/train.py | 646 +++++++++ .../yolov9/pytorch/segment/train_dual.py | 647 +++++++++ cv/3d_detection/yolov9/pytorch/segment/val.py | 457 +++++++ .../yolov9/pytorch/segment/val_dual.py | 458 +++++++ .../pytorch/tools/reparameterization.ipynb | 244 ++++ cv/3d_detection/yolov9/pytorch/train.py | 634 +++++++++ cv/3d_detection/yolov9/pytorch/train_dual.py | 644 +++++++++ .../yolov9/pytorch/train_triple.py | 636 +++++++++ .../yolov9/pytorch/utils/__init__.py | 75 + .../yolov9/pytorch/utils/activations.py | 98 ++ .../yolov9/pytorch/utils/augmentations.py | 395 ++++++ .../yolov9/pytorch/utils/autoanchor.py | 164 +++ .../yolov9/pytorch/utils/autobatch.py | 67 + .../yolov9/pytorch/utils/callbacks.py | 71 + .../yolov9/pytorch/utils/coco_utils.py | 108 ++ .../yolov9/pytorch/utils/dataloaders.py | 1217 +++++++++++++++++ .../yolov9/pytorch/utils/downloads.py | 103 ++ .../yolov9/pytorch/utils/general.py | 1135 +++++++++++++++ cv/3d_detection/yolov9/pytorch/utils/lion.py | 67 + .../yolov9/pytorch/utils/loggers/__init__.py | 399 ++++++ .../pytorch/utils/loggers/clearml/__init__.py | 1 + .../utils/loggers/clearml/clearml_utils.py | 157 +++ .../pytorch/utils/loggers/clearml/hpo.py | 84 ++ .../pytorch/utils/loggers/comet/__init__.py | 508 +++++++ .../utils/loggers/comet/comet_utils.py | 150 ++ .../yolov9/pytorch/utils/loggers/comet/hpo.py | 118 ++ .../utils/loggers/comet/optimizer_config.json | 209 +++ .../pytorch/utils/loggers/wandb/__init__.py | 1 + .../utils/loggers/wandb/log_dataset.py | 27 + .../pytorch/utils/loggers/wandb/sweep.py | 41 + .../pytorch/utils/loggers/wandb/sweep.yaml | 143 ++ .../utils/loggers/wandb/wandb_utils.py | 589 ++++++++ cv/3d_detection/yolov9/pytorch/utils/loss.py | 363 +++++ .../yolov9/pytorch/utils/loss_tal.py | 215 +++ .../yolov9/pytorch/utils/loss_tal_dual.py | 385 ++++++ .../yolov9/pytorch/utils/loss_tal_triple.py | 282 ++++ .../yolov9/pytorch/utils/metrics.py | 397 ++++++ .../yolov9/pytorch/utils/panoptic/__init__.py | 1 + .../pytorch/utils/panoptic/augmentations.py | 183 +++ .../pytorch/utils/panoptic/dataloaders.py | 478 +++++++ .../yolov9/pytorch/utils/panoptic/general.py | 137 ++ .../yolov9/pytorch/utils/panoptic/loss.py | 186 +++ .../yolov9/pytorch/utils/panoptic/loss_tal.py | 285 ++++ .../yolov9/pytorch/utils/panoptic/metrics.py | 272 ++++ .../yolov9/pytorch/utils/panoptic/plots.py | 164 +++ .../pytorch/utils/panoptic/tal/__init__.py | 1 + .../utils/panoptic/tal/anchor_generator.py | 38 + .../pytorch/utils/panoptic/tal/assigner.py | 181 +++ cv/3d_detection/yolov9/pytorch/utils/plots.py | 570 ++++++++ .../yolov9/pytorch/utils/segment/__init__.py | 1 + .../pytorch/utils/segment/augmentations.py | 99 ++ .../pytorch/utils/segment/dataloaders.py | 328 +++++ .../yolov9/pytorch/utils/segment/general.py | 137 ++ .../yolov9/pytorch/utils/segment/loss.py | 186 +++ .../yolov9/pytorch/utils/segment/loss_tal.py | 261 ++++ .../pytorch/utils/segment/loss_tal_dual.py | 727 ++++++++++ .../yolov9/pytorch/utils/segment/metrics.py | 205 +++ .../yolov9/pytorch/utils/segment/plots.py | 143 ++ .../pytorch/utils/segment/tal/__init__.py | 1 + .../utils/segment/tal/anchor_generator.py | 38 + .../pytorch/utils/segment/tal/assigner.py | 180 +++ .../yolov9/pytorch/utils/tal/__init__.py | 1 + .../pytorch/utils/tal/anchor_generator.py | 38 + .../yolov9/pytorch/utils/tal/assigner.py | 179 +++ .../yolov9/pytorch/utils/torch_utils.py | 529 +++++++ .../yolov9/pytorch/utils/triton.py | 81 ++ cv/3d_detection/yolov9/pytorch/val.py | 389 ++++++ cv/3d_detection/yolov9/pytorch/val_dual.py | 393 ++++++ cv/3d_detection/yolov9/pytorch/val_triple.py | 391 ++++++ 114 files changed, 28424 insertions(+) create mode 100644 cv/3d_detection/yolov9/pytorch/LICENSE.md create mode 100644 cv/3d_detection/yolov9/pytorch/README.md create mode 100644 cv/3d_detection/yolov9/pytorch/README_origin.md create mode 100644 cv/3d_detection/yolov9/pytorch/benchmarks.py create mode 100644 cv/3d_detection/yolov9/pytorch/classify/predict.py create mode 100644 cv/3d_detection/yolov9/pytorch/classify/train.py create mode 100644 cv/3d_detection/yolov9/pytorch/classify/val.py create mode 100644 cv/3d_detection/yolov9/pytorch/data/coco.yaml create mode 100644 cv/3d_detection/yolov9/pytorch/data/hyps/hyp.scratch-high.yaml create mode 100644 cv/3d_detection/yolov9/pytorch/data/images/horses.jpg create mode 100644 cv/3d_detection/yolov9/pytorch/detect.py create mode 100644 cv/3d_detection/yolov9/pytorch/detect_dual.py create mode 100644 cv/3d_detection/yolov9/pytorch/export.py create mode 100644 cv/3d_detection/yolov9/pytorch/figure/horses_prediction.jpg create mode 100644 cv/3d_detection/yolov9/pytorch/figure/multitask.png create mode 100644 cv/3d_detection/yolov9/pytorch/figure/performance.png create mode 100644 cv/3d_detection/yolov9/pytorch/hubconf.py create mode 100644 cv/3d_detection/yolov9/pytorch/models/__init__.py create mode 100644 cv/3d_detection/yolov9/pytorch/models/common.py create mode 100644 cv/3d_detection/yolov9/pytorch/models/detect/gelan-c.yaml create mode 100644 cv/3d_detection/yolov9/pytorch/models/detect/gelan-e.yaml create mode 100644 cv/3d_detection/yolov9/pytorch/models/detect/gelan.yaml create mode 100644 cv/3d_detection/yolov9/pytorch/models/detect/yolov7-af.yaml create mode 100644 cv/3d_detection/yolov9/pytorch/models/detect/yolov9-c.yaml create mode 100644 cv/3d_detection/yolov9/pytorch/models/detect/yolov9-e.yaml create mode 100644 cv/3d_detection/yolov9/pytorch/models/detect/yolov9.yaml create mode 100644 cv/3d_detection/yolov9/pytorch/models/experimental.py create mode 100644 cv/3d_detection/yolov9/pytorch/models/hub/anchors.yaml create mode 100644 cv/3d_detection/yolov9/pytorch/models/hub/yolov3-spp.yaml create mode 100644 cv/3d_detection/yolov9/pytorch/models/hub/yolov3-tiny.yaml create mode 100644 cv/3d_detection/yolov9/pytorch/models/hub/yolov3.yaml create mode 100644 cv/3d_detection/yolov9/pytorch/models/panoptic/gelan-c-pan.yaml create mode 100644 cv/3d_detection/yolov9/pytorch/models/panoptic/yolov7-af-pan.yaml create mode 100644 cv/3d_detection/yolov9/pytorch/models/segment/gelan-c-dseg.yaml create mode 100644 cv/3d_detection/yolov9/pytorch/models/segment/gelan-c-seg.yaml create mode 100644 cv/3d_detection/yolov9/pytorch/models/segment/yolov7-af-seg.yaml create mode 100644 cv/3d_detection/yolov9/pytorch/models/segment/yolov9-c-dseg.yaml create mode 100644 cv/3d_detection/yolov9/pytorch/models/tf.py create mode 100644 cv/3d_detection/yolov9/pytorch/models/yolo.py create mode 100644 cv/3d_detection/yolov9/pytorch/panoptic/predict.py create mode 100644 cv/3d_detection/yolov9/pytorch/panoptic/train.py create mode 100644 cv/3d_detection/yolov9/pytorch/panoptic/val.py create mode 100644 cv/3d_detection/yolov9/pytorch/requirements.txt create mode 100644 cv/3d_detection/yolov9/pytorch/scripts/get_coco.sh create mode 100644 cv/3d_detection/yolov9/pytorch/segment/predict.py create mode 100644 cv/3d_detection/yolov9/pytorch/segment/train.py create mode 100644 cv/3d_detection/yolov9/pytorch/segment/train_dual.py create mode 100644 cv/3d_detection/yolov9/pytorch/segment/val.py create mode 100644 cv/3d_detection/yolov9/pytorch/segment/val_dual.py create mode 100644 cv/3d_detection/yolov9/pytorch/tools/reparameterization.ipynb create mode 100644 cv/3d_detection/yolov9/pytorch/train.py create mode 100644 cv/3d_detection/yolov9/pytorch/train_dual.py create mode 100644 cv/3d_detection/yolov9/pytorch/train_triple.py create mode 100644 cv/3d_detection/yolov9/pytorch/utils/__init__.py create mode 100644 cv/3d_detection/yolov9/pytorch/utils/activations.py create mode 100644 cv/3d_detection/yolov9/pytorch/utils/augmentations.py create mode 100644 cv/3d_detection/yolov9/pytorch/utils/autoanchor.py create mode 100644 cv/3d_detection/yolov9/pytorch/utils/autobatch.py create mode 100644 cv/3d_detection/yolov9/pytorch/utils/callbacks.py create mode 100644 cv/3d_detection/yolov9/pytorch/utils/coco_utils.py create mode 100644 cv/3d_detection/yolov9/pytorch/utils/dataloaders.py create mode 100644 cv/3d_detection/yolov9/pytorch/utils/downloads.py create mode 100644 cv/3d_detection/yolov9/pytorch/utils/general.py create mode 100644 cv/3d_detection/yolov9/pytorch/utils/lion.py create mode 100644 cv/3d_detection/yolov9/pytorch/utils/loggers/__init__.py create mode 100644 cv/3d_detection/yolov9/pytorch/utils/loggers/clearml/__init__.py create mode 100644 cv/3d_detection/yolov9/pytorch/utils/loggers/clearml/clearml_utils.py create mode 100644 cv/3d_detection/yolov9/pytorch/utils/loggers/clearml/hpo.py create mode 100644 cv/3d_detection/yolov9/pytorch/utils/loggers/comet/__init__.py create mode 100644 cv/3d_detection/yolov9/pytorch/utils/loggers/comet/comet_utils.py create mode 100644 cv/3d_detection/yolov9/pytorch/utils/loggers/comet/hpo.py create mode 100644 cv/3d_detection/yolov9/pytorch/utils/loggers/comet/optimizer_config.json create mode 100644 cv/3d_detection/yolov9/pytorch/utils/loggers/wandb/__init__.py create mode 100644 cv/3d_detection/yolov9/pytorch/utils/loggers/wandb/log_dataset.py create mode 100644 cv/3d_detection/yolov9/pytorch/utils/loggers/wandb/sweep.py create mode 100644 cv/3d_detection/yolov9/pytorch/utils/loggers/wandb/sweep.yaml create mode 100644 cv/3d_detection/yolov9/pytorch/utils/loggers/wandb/wandb_utils.py create mode 100644 cv/3d_detection/yolov9/pytorch/utils/loss.py create mode 100644 cv/3d_detection/yolov9/pytorch/utils/loss_tal.py create mode 100644 cv/3d_detection/yolov9/pytorch/utils/loss_tal_dual.py create mode 100644 cv/3d_detection/yolov9/pytorch/utils/loss_tal_triple.py create mode 100644 cv/3d_detection/yolov9/pytorch/utils/metrics.py create mode 100644 cv/3d_detection/yolov9/pytorch/utils/panoptic/__init__.py create mode 100644 cv/3d_detection/yolov9/pytorch/utils/panoptic/augmentations.py create mode 100644 cv/3d_detection/yolov9/pytorch/utils/panoptic/dataloaders.py create mode 100644 cv/3d_detection/yolov9/pytorch/utils/panoptic/general.py create mode 100644 cv/3d_detection/yolov9/pytorch/utils/panoptic/loss.py create mode 100644 cv/3d_detection/yolov9/pytorch/utils/panoptic/loss_tal.py create mode 100644 cv/3d_detection/yolov9/pytorch/utils/panoptic/metrics.py create mode 100644 cv/3d_detection/yolov9/pytorch/utils/panoptic/plots.py create mode 100644 cv/3d_detection/yolov9/pytorch/utils/panoptic/tal/__init__.py create mode 100644 cv/3d_detection/yolov9/pytorch/utils/panoptic/tal/anchor_generator.py create mode 100644 cv/3d_detection/yolov9/pytorch/utils/panoptic/tal/assigner.py create mode 100644 cv/3d_detection/yolov9/pytorch/utils/plots.py create mode 100644 cv/3d_detection/yolov9/pytorch/utils/segment/__init__.py create mode 100644 cv/3d_detection/yolov9/pytorch/utils/segment/augmentations.py create mode 100644 cv/3d_detection/yolov9/pytorch/utils/segment/dataloaders.py create mode 100644 cv/3d_detection/yolov9/pytorch/utils/segment/general.py create mode 100644 cv/3d_detection/yolov9/pytorch/utils/segment/loss.py create mode 100644 cv/3d_detection/yolov9/pytorch/utils/segment/loss_tal.py create mode 100644 cv/3d_detection/yolov9/pytorch/utils/segment/loss_tal_dual.py create mode 100644 cv/3d_detection/yolov9/pytorch/utils/segment/metrics.py create mode 100644 cv/3d_detection/yolov9/pytorch/utils/segment/plots.py create mode 100644 cv/3d_detection/yolov9/pytorch/utils/segment/tal/__init__.py create mode 100644 cv/3d_detection/yolov9/pytorch/utils/segment/tal/anchor_generator.py create mode 100644 cv/3d_detection/yolov9/pytorch/utils/segment/tal/assigner.py create mode 100644 cv/3d_detection/yolov9/pytorch/utils/tal/__init__.py create mode 100644 cv/3d_detection/yolov9/pytorch/utils/tal/anchor_generator.py create mode 100644 cv/3d_detection/yolov9/pytorch/utils/tal/assigner.py create mode 100644 cv/3d_detection/yolov9/pytorch/utils/torch_utils.py create mode 100644 cv/3d_detection/yolov9/pytorch/utils/triton.py create mode 100644 cv/3d_detection/yolov9/pytorch/val.py create mode 100644 cv/3d_detection/yolov9/pytorch/val_dual.py create mode 100644 cv/3d_detection/yolov9/pytorch/val_triple.py diff --git a/cv/3d_detection/yolov9/pytorch/LICENSE.md b/cv/3d_detection/yolov9/pytorch/LICENSE.md new file mode 100644 index 000000000..f288702d2 --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/LICENSE.md @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/cv/3d_detection/yolov9/pytorch/README.md b/cv/3d_detection/yolov9/pytorch/README.md new file mode 100644 index 000000000..edb2b65ab --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/README.md @@ -0,0 +1,31 @@ +# YOLOv9 + +## Model description +YOLOv9 is a state-of-the-art object detection algorithm that belongs to the YOLO (You Only Look Once) family of models. It is an improved version of the original YOLO algorithm with better accuracy and performance. + +## Step 1: Installation +``` +pip3 install -r requirements.txt +``` + +## Step 2: Preparing datasets +``` +bash scripts/get_coco.sh +``` +Download MS COCO dataset images ([train](http://images.cocodataset.org/zips/train2017.zip), [val](http://images.cocodataset.org/zips/val2017.zip), [test](http://images.cocodataset.org/zips/test2017.zip)) and [labels](https://github.com/WongKinYiu/yolov7/releases/download/v0.1/coco2017labels-segments.zip). If you have previously used a different version of YOLO, we strongly recommend that you delete train2017.cache and val2017.cache files, and redownload [labels](https://github.com/WongKinYiu/yolov7/releases/download/v0.1/coco2017labels-segments.zip) + +## Step 3: Training +### Training on a Single GPU +``` +python3 train_dual.py --workers 8 --device 0 --batch 16 --data data/coco.yaml --img 640 --cfg models/detect/yolov9-c.yaml --weights '' --name yolov9-c --hyp hyp.scratch-high.yaml --min-items 0 --epochs 1 --close-mosaic 15 +``` + +### Multiple GPU training +``` +python3 -m torch.distributed.launch --nproc_per_node 8 --master_port 9527 train_dual.py --workers 8 --device 0,1,2,3,4,5,6,7 --sync-bn --batch 128 --data data/coco.yaml --img 640 --cfg models/detect/yolov9-c.yaml --weights '' --name yolov9-c --hyp hyp.scratch-high.yaml --min-items 0 --epochs 1 --close-mosaic 15 +``` + +## Results + +## Reference +[YOLOv9](https://github.com/WongKinYiu/yolov9?tab=readme-ov-file) diff --git a/cv/3d_detection/yolov9/pytorch/README_origin.md b/cv/3d_detection/yolov9/pytorch/README_origin.md new file mode 100644 index 000000000..478383b63 --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/README_origin.md @@ -0,0 +1,327 @@ +# YOLOv9 + +Implementation of paper - [YOLOv9: Learning What You Want to Learn Using Programmable Gradient Information](https://arxiv.org/abs/2402.13616) + +[![arxiv.org](http://img.shields.io/badge/cs.CV-arXiv%3A2402.13616-B31B1B.svg)](https://arxiv.org/abs/2402.13616) +[![Hugging Face Spaces](https://img.shields.io/badge/%F0%9F%A4%97%20Hugging%20Face-Spaces-blue)](https://huggingface.co/spaces/kadirnar/Yolov9) +[![Hugging Face Spaces](https://img.shields.io/badge/%F0%9F%A4%97%20Hugging%20Face-Spaces-blue)](https://huggingface.co/merve/yolov9) +[![Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/roboflow-ai/notebooks/blob/main/notebooks/train-yolov9-object-detection-on-custom-dataset.ipynb) +[![OpenCV](https://img.shields.io/badge/OpenCV-BlogPost-black?logo=opencv&labelColor=blue&color=black)](https://learnopencv.com/yolov9-advancing-the-yolo-legacy/) + + + + +## Performance + +MS COCO + +| Model | Test Size | APval | AP50val | AP75val | Param. | FLOPs | +| :-- | :-: | :-: | :-: | :-: | :-: | :-: | +| [**YOLOv9-T**]() | 640 | **38.3%** | **53.1%** | **41.3%** | **2.0M** | **7.7G** | +| [**YOLOv9-S**]() | 640 | **46.8%** | **63.4%** | **50.7%** | **7.1M** | **26.4G** | +| [**YOLOv9-M**]() | 640 | **51.4%** | **68.1%** | **56.1%** | **20.0M** | **76.3G** | +| [**YOLOv9-C**](https://github.com/WongKinYiu/yolov9/releases/download/v0.1/yolov9-c-converted.pt) | 640 | **53.0%** | **70.2%** | **57.8%** | **25.3M** | **102.1G** | +| [**YOLOv9-E**](https://github.com/WongKinYiu/yolov9/releases/download/v0.1/yolov9-e-converted.pt) | 640 | **55.6%** | **72.8%** | **60.6%** | **57.3M** | **189.0G** | + + + + +## Useful Links + +
Expand + +Custom training: https://github.com/WongKinYiu/yolov9/issues/30#issuecomment-1960955297 + +ONNX export: https://github.com/WongKinYiu/yolov9/issues/2#issuecomment-1960519506 https://github.com/WongKinYiu/yolov9/issues/40#issue-2150697688 https://github.com/WongKinYiu/yolov9/issues/130#issue-2162045461 + +ONNX export for segmentation: https://github.com/WongKinYiu/yolov9/issues/260#issue-2191162150 + +TensorRT inference: https://github.com/WongKinYiu/yolov9/issues/143#issuecomment-1975049660 https://github.com/WongKinYiu/yolov9/issues/34#issue-2150393690 https://github.com/WongKinYiu/yolov9/issues/79#issue-2153547004 https://github.com/WongKinYiu/yolov9/issues/143#issue-2164002309 + +QAT TensorRT: https://github.com/WongKinYiu/yolov9/issues/327#issue-2229284136 https://github.com/WongKinYiu/yolov9/issues/253#issue-2189520073 + +OpenVINO: https://github.com/WongKinYiu/yolov9/issues/164#issue-2168540003 + +C# ONNX inference: https://github.com/WongKinYiu/yolov9/issues/95#issue-2155974619 + +C# OpenVINO inference: https://github.com/WongKinYiu/yolov9/issues/95#issuecomment-1968131244 + +OpenCV: https://github.com/WongKinYiu/yolov9/issues/113#issuecomment-1971327672 + +Hugging Face demo: https://github.com/WongKinYiu/yolov9/issues/45#issuecomment-1961496943 + +CoLab demo: https://github.com/WongKinYiu/yolov9/pull/18 + +ONNXSlim export: https://github.com/WongKinYiu/yolov9/pull/37 + +YOLOv9 ROS: https://github.com/WongKinYiu/yolov9/issues/144#issue-2164210644 + +YOLOv9 ROS TensorRT: https://github.com/WongKinYiu/yolov9/issues/145#issue-2164218595 + +YOLOv9 Julia: https://github.com/WongKinYiu/yolov9/issues/141#issuecomment-1973710107 + +YOLOv9 MLX: https://github.com/WongKinYiu/yolov9/issues/258#issue-2190586540 + +YOLOv9 StrongSORT with OSNet: https://github.com/WongKinYiu/yolov9/issues/299#issue-2212093340 + +YOLOv9 ByteTrack: https://github.com/WongKinYiu/yolov9/issues/78#issue-2153512879 + +YOLOv9 DeepSORT: https://github.com/WongKinYiu/yolov9/issues/98#issue-2156172319 + +YOLOv9 counting: https://github.com/WongKinYiu/yolov9/issues/84#issue-2153904804 + +YOLOv9 face detection: https://github.com/WongKinYiu/yolov9/issues/121#issue-2160218766 + +YOLOv9 segmentation onnxruntime: https://github.com/WongKinYiu/yolov9/issues/151#issue-2165667350 + +Comet logging: https://github.com/WongKinYiu/yolov9/pull/110 + +MLflow logging: https://github.com/WongKinYiu/yolov9/pull/87 + +AnyLabeling tool: https://github.com/WongKinYiu/yolov9/issues/48#issue-2152139662 + +AX650N deploy: https://github.com/WongKinYiu/yolov9/issues/96#issue-2156115760 + +Conda environment: https://github.com/WongKinYiu/yolov9/pull/93 + +AutoDL docker environment: https://github.com/WongKinYiu/yolov9/issues/112#issue-2158203480 + +
+ + +## Installation + +Docker environment (recommended) +
Expand + +``` shell +# create the docker container, you can change the share memory size if you have more. +nvidia-docker run --name yolov9 -it -v your_coco_path/:/coco/ -v your_code_path/:/yolov9 --shm-size=64g nvcr.io/nvidia/pytorch:21.11-py3 + +# apt install required packages +apt update +apt install -y zip htop screen libgl1-mesa-glx + +# pip install required packages +pip install seaborn thop + +# go to code folder +cd /yolov9 +``` + +
+ + +## Evaluation + +[`yolov9-c-converted.pt`](https://github.com/WongKinYiu/yolov9/releases/download/v0.1/yolov9-c-converted.pt) [`yolov9-e-converted.pt`](https://github.com/WongKinYiu/yolov9/releases/download/v0.1/yolov9-e-converted.pt) [`yolov9-c.pt`](https://github.com/WongKinYiu/yolov9/releases/download/v0.1/yolov9-c.pt) [`yolov9-e.pt`](https://github.com/WongKinYiu/yolov9/releases/download/v0.1/yolov9-e.pt) [`gelan-c.pt`](https://github.com/WongKinYiu/yolov9/releases/download/v0.1/gelan-c.pt) [`gelan-e.pt`](https://github.com/WongKinYiu/yolov9/releases/download/v0.1/gelan-e.pt) + +``` shell +# evaluate converted yolov9 models +python val.py --data data/coco.yaml --img 640 --batch 32 --conf 0.001 --iou 0.7 --device 0 --weights './yolov9-c-converted.pt' --save-json --name yolov9_c_c_640_val + +# evaluate yolov9 models +# python val_dual.py --data data/coco.yaml --img 640 --batch 32 --conf 0.001 --iou 0.7 --device 0 --weights './yolov9-c.pt' --save-json --name yolov9_c_640_val + +# evaluate gelan models +# python val.py --data data/coco.yaml --img 640 --batch 32 --conf 0.001 --iou 0.7 --device 0 --weights './gelan-c.pt' --save-json --name gelan_c_640_val +``` + +You will get the results: + +``` + Average Precision (AP) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.530 + Average Precision (AP) @[ IoU=0.50 | area= all | maxDets=100 ] = 0.702 + Average Precision (AP) @[ IoU=0.75 | area= all | maxDets=100 ] = 0.578 + Average Precision (AP) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.362 + Average Precision (AP) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.585 + Average Precision (AP) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.693 + Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 1 ] = 0.392 + Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 10 ] = 0.652 + Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.702 + Average Recall (AR) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.541 + Average Recall (AR) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.760 + Average Recall (AR) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.844 +``` + + +## Training + +Data preparation + +``` shell +bash scripts/get_coco.sh +``` + +* Download MS COCO dataset images ([train](http://images.cocodataset.org/zips/train2017.zip), [val](http://images.cocodataset.org/zips/val2017.zip), [test](http://images.cocodataset.org/zips/test2017.zip)) and [labels](https://github.com/WongKinYiu/yolov7/releases/download/v0.1/coco2017labels-segments.zip). If you have previously used a different version of YOLO, we strongly recommend that you delete `train2017.cache` and `val2017.cache` files, and redownload [labels](https://github.com/WongKinYiu/yolov7/releases/download/v0.1/coco2017labels-segments.zip) + +Single GPU training + +``` shell +# train yolov9 models +python train_dual.py --workers 8 --device 0 --batch 16 --data data/coco.yaml --img 640 --cfg models/detect/yolov9-c.yaml --weights '' --name yolov9-c --hyp hyp.scratch-high.yaml --min-items 0 --epochs 500 --close-mosaic 15 + +# train gelan models +# python train.py --workers 8 --device 0 --batch 32 --data data/coco.yaml --img 640 --cfg models/detect/gelan-c.yaml --weights '' --name gelan-c --hyp hyp.scratch-high.yaml --min-items 0 --epochs 500 --close-mosaic 15 +``` + +Multiple GPU training + +``` shell +# train yolov9 models +python -m torch.distributed.launch --nproc_per_node 8 --master_port 9527 train_dual.py --workers 8 --device 0,1,2,3,4,5,6,7 --sync-bn --batch 128 --data data/coco.yaml --img 640 --cfg models/detect/yolov9-c.yaml --weights '' --name yolov9-c --hyp hyp.scratch-high.yaml --min-items 0 --epochs 500 --close-mosaic 15 + +# train gelan models +# python -m torch.distributed.launch --nproc_per_node 4 --master_port 9527 train.py --workers 8 --device 0,1,2,3 --sync-bn --batch 128 --data data/coco.yaml --img 640 --cfg models/detect/gelan-c.yaml --weights '' --name gelan-c --hyp hyp.scratch-high.yaml --min-items 0 --epochs 500 --close-mosaic 15 +``` + + +## Re-parameterization + +See [reparameterization.ipynb](https://github.com/WongKinYiu/yolov9/blob/main/tools/reparameterization.ipynb). + + +## Inference + + + +``` shell +# inference converted yolov9 models +python detect.py --source './data/images/horses.jpg' --img 640 --device 0 --weights './yolov9-c-converted.pt' --name yolov9_c_c_640_detect + +# inference yolov9 models +# python detect_dual.py --source './data/images/horses.jpg' --img 640 --device 0 --weights './yolov9-c.pt' --name yolov9_c_640_detect + +# inference gelan models +# python detect.py --source './data/images/horses.jpg' --img 640 --device 0 --weights './gelan-c.pt' --name gelan_c_c_640_detect +``` + + +## Citation + +``` +@article{wang2024yolov9, + title={{YOLOv9}: Learning What You Want to Learn Using Programmable Gradient Information}, + author={Wang, Chien-Yao and Liao, Hong-Yuan Mark}, + booktitle={arXiv preprint arXiv:2402.13616}, + year={2024} +} +``` + +``` +@article{chang2023yolor, + title={{YOLOR}-Based Multi-Task Learning}, + author={Chang, Hung-Shuo and Wang, Chien-Yao and Wang, Richard Robert and Chou, Gene and Liao, Hong-Yuan Mark}, + journal={arXiv preprint arXiv:2309.16921}, + year={2023} +} +``` + + +## Teaser + +Parts of code of [YOLOR-Based Multi-Task Learning](https://arxiv.org/abs/2309.16921) are released in the repository. + + + +#### Object Detection + +[`gelan-c-det.pt`](https://github.com/WongKinYiu/yolov9/releases/download/v0.1/gelan-c-det.pt) + +`object detection` + +``` shell +# coco/labels/{split}/*.txt +# bbox or polygon (1 instance 1 line) +python train.py --workers 8 --device 0 --batch 32 --data data/coco.yaml --img 640 --cfg models/detect/gelan-c.yaml --weights '' --name gelan-c-det --hyp hyp.scratch-high.yaml --min-items 0 --epochs 300 --close-mosaic 10 +``` + +| Model | Test Size | Param. | FLOPs | APbox | +| :-- | :-: | :-: | :-: | :-: | +| [**GELAN-C-DET**](https://github.com/WongKinYiu/yolov9/releases/download/v0.1/gelan-c-det.pt) | 640 | 25.3M | 102.1G |**52.3%** | +| [**YOLOv9-C-DET**]() | 640 | 25.3M | 102.1G | **53.0%** | + +#### Instance Segmentation + +[`gelan-c-seg.pt`](https://github.com/WongKinYiu/yolov9/releases/download/v0.1/gelan-c-seg.pt) + +`object detection` `instance segmentation` + +``` shell +# coco/labels/{split}/*.txt +# polygon (1 instance 1 line) +python segment/train.py --workers 8 --device 0 --batch 32 --data coco.yaml --img 640 --cfg models/segment/gelan-c-seg.yaml --weights '' --name gelan-c-seg --hyp hyp.scratch-high.yaml --no-overlap --epochs 300 --close-mosaic 10 +``` + +| Model | Test Size | Param. | FLOPs | APbox | APmask | +| :-- | :-: | :-: | :-: | :-: | :-: | +| [**GELAN-C-SEG**](https://github.com/WongKinYiu/yolov9/releases/download/v0.1/gelan-c-seg.pt) | 640 | 27.4M | 144.6G | **52.3%** | **42.4%** | +| [**YOLOv9-C-SEG**]() | 640 | 27.4M | 145.5G | **53.3%** | **43.5%** | + +#### Panoptic Segmentation + +[`gelan-c-pan.pt`](https://github.com/WongKinYiu/yolov9/releases/download/v0.1/gelan-c-pan.pt) + +`object detection` `instance segmentation` `semantic segmentation` `stuff segmentation` `panoptic segmentation` + +``` shell +# coco/labels/{split}/*.txt +# polygon (1 instance 1 line) +# coco/stuff/{split}/*.txt +# polygon (1 semantic 1 line) +python panoptic/train.py --workers 8 --device 0 --batch 32 --data coco.yaml --img 640 --cfg models/panoptic/gelan-c-pan.yaml --weights '' --name gelan-c-pan --hyp hyp.scratch-high.yaml --no-overlap --epochs 300 --close-mosaic 10 +``` + +| Model | Test Size | Param. | FLOPs | APbox | APmask | mIoU164k/10ksemantic | mIoUstuff | PQpanoptic | +| :-- | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | +| [**GELAN-C-PAN**](https://github.com/WongKinYiu/yolov9/releases/download/v0.1/gelan-c-pan.pt) | 640 | 27.6M | 146.7G | **52.6%** | **42.5%** | **39.0%/48.3%** | **52.7%** | **39.4%** | +| [**YOLOv9-C-PAN**]() | 640 | 28.8M | 187.0G | **52.7%** | **43.0%** | **39.8%/-** | **52.2%** | **40.5%** | + +#### Image Captioning (not yet released) + + + +`object detection` `instance segmentation` `semantic segmentation` `stuff segmentation` `panoptic segmentation` `image captioning` + +``` shell +# coco/labels/{split}/*.txt +# polygon (1 instance 1 line) +# coco/stuff/{split}/*.txt +# polygon (1 semantic 1 line) +# coco/annotations/*.json +# json (1 split 1 file) +python caption/train.py --workers 8 --device 0 --batch 32 --data coco.yaml --img 640 --cfg models/caption/gelan-c-cap.yaml --weights '' --name gelan-c-cap --hyp hyp.scratch-high.yaml --no-overlap --epochs 300 --close-mosaic 10 +``` + +| Model | Test Size | Param. | FLOPs | APbox | APmask | mIoU164k/10ksemantic | mIoUstuff | PQpanoptic | BLEU@4caption | CIDErcaption | +| :-- | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | +| [**GELAN-C-CAP**]() | 640 | 47.5M | - | **51.9%** | **42.6%** | **42.5%/-** | **56.5%** | **41.7%** | **38.8** | **122.3** | + + + + +## Acknowledgements + +
Expand + +* [https://github.com/AlexeyAB/darknet](https://github.com/AlexeyAB/darknet) +* [https://github.com/WongKinYiu/yolor](https://github.com/WongKinYiu/yolor) +* [https://github.com/WongKinYiu/yolov7](https://github.com/WongKinYiu/yolov7) +* [https://github.com/VDIGPKU/DynamicDet](https://github.com/VDIGPKU/DynamicDet) +* [https://github.com/DingXiaoH/RepVGG](https://github.com/DingXiaoH/RepVGG) +* [https://github.com/ultralytics/yolov5](https://github.com/ultralytics/yolov5) +* [https://github.com/meituan/YOLOv6](https://github.com/meituan/YOLOv6) + +
diff --git a/cv/3d_detection/yolov9/pytorch/benchmarks.py b/cv/3d_detection/yolov9/pytorch/benchmarks.py new file mode 100644 index 000000000..462636b25 --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/benchmarks.py @@ -0,0 +1,142 @@ +import argparse +import platform +import sys +import time +from pathlib import Path + +import pandas as pd + +FILE = Path(__file__).resolve() +ROOT = FILE.parents[0] # YOLO root directory +if str(ROOT) not in sys.path: + sys.path.append(str(ROOT)) # add ROOT to PATH +# ROOT = ROOT.relative_to(Path.cwd()) # relative + +import export +from models.experimental import attempt_load +from models.yolo import SegmentationModel +from segment.val import run as val_seg +from utils import notebook_init +from utils.general import LOGGER, check_yaml, file_size, print_args +from utils.torch_utils import select_device +from val import run as val_det + + +def run( + weights=ROOT / 'yolo.pt', # weights path + imgsz=640, # inference size (pixels) + batch_size=1, # batch size + data=ROOT / 'data/coco.yaml', # dataset.yaml path + device='', # cuda device, i.e. 0 or 0,1,2,3 or cpu + half=False, # use FP16 half-precision inference + test=False, # test exports only + pt_only=False, # test PyTorch only + hard_fail=False, # throw error on benchmark failure +): + y, t = [], time.time() + device = select_device(device) + model_type = type(attempt_load(weights, fuse=False)) # DetectionModel, SegmentationModel, etc. + for i, (name, f, suffix, cpu, gpu) in export.export_formats().iterrows(): # index, (name, file, suffix, CPU, GPU) + try: + assert i not in (9, 10), 'inference not supported' # Edge TPU and TF.js are unsupported + assert i != 5 or platform.system() == 'Darwin', 'inference only supported on macOS>=10.13' # CoreML + if 'cpu' in device.type: + assert cpu, 'inference not supported on CPU' + if 'cuda' in device.type: + assert gpu, 'inference not supported on GPU' + + # Export + if f == '-': + w = weights # PyTorch format + else: + w = export.run(weights=weights, imgsz=[imgsz], include=[f], device=device, half=half)[-1] # all others + assert suffix in str(w), 'export failed' + + # Validate + if model_type == SegmentationModel: + result = val_seg(data, w, batch_size, imgsz, plots=False, device=device, task='speed', half=half) + metric = result[0][7] # (box(p, r, map50, map), mask(p, r, map50, map), *loss(box, obj, cls)) + else: # DetectionModel: + result = val_det(data, w, batch_size, imgsz, plots=False, device=device, task='speed', half=half) + metric = result[0][3] # (p, r, map50, map, *loss(box, obj, cls)) + speed = result[2][1] # times (preprocess, inference, postprocess) + y.append([name, round(file_size(w), 1), round(metric, 4), round(speed, 2)]) # MB, mAP, t_inference + except Exception as e: + if hard_fail: + assert type(e) is AssertionError, f'Benchmark --hard-fail for {name}: {e}' + LOGGER.warning(f'WARNING ⚠️ Benchmark failure for {name}: {e}') + y.append([name, None, None, None]) # mAP, t_inference + if pt_only and i == 0: + break # break after PyTorch + + # Print results + LOGGER.info('\n') + parse_opt() + notebook_init() # print system info + c = ['Format', 'Size (MB)', 'mAP50-95', 'Inference time (ms)'] if map else ['Format', 'Export', '', ''] + py = pd.DataFrame(y, columns=c) + LOGGER.info(f'\nBenchmarks complete ({time.time() - t:.2f}s)') + LOGGER.info(str(py if map else py.iloc[:, :2])) + if hard_fail and isinstance(hard_fail, str): + metrics = py['mAP50-95'].array # values to compare to floor + floor = eval(hard_fail) # minimum metric floor to pass + assert all(x > floor for x in metrics if pd.notna(x)), f'HARD FAIL: mAP50-95 < floor {floor}' + return py + + +def test( + weights=ROOT / 'yolo.pt', # weights path + imgsz=640, # inference size (pixels) + batch_size=1, # batch size + data=ROOT / 'data/coco128.yaml', # dataset.yaml path + device='', # cuda device, i.e. 0 or 0,1,2,3 or cpu + half=False, # use FP16 half-precision inference + test=False, # test exports only + pt_only=False, # test PyTorch only + hard_fail=False, # throw error on benchmark failure +): + y, t = [], time.time() + device = select_device(device) + for i, (name, f, suffix, gpu) in export.export_formats().iterrows(): # index, (name, file, suffix, gpu-capable) + try: + w = weights if f == '-' else \ + export.run(weights=weights, imgsz=[imgsz], include=[f], device=device, half=half)[-1] # weights + assert suffix in str(w), 'export failed' + y.append([name, True]) + except Exception: + y.append([name, False]) # mAP, t_inference + + # Print results + LOGGER.info('\n') + parse_opt() + notebook_init() # print system info + py = pd.DataFrame(y, columns=['Format', 'Export']) + LOGGER.info(f'\nExports complete ({time.time() - t:.2f}s)') + LOGGER.info(str(py)) + return py + + +def parse_opt(): + parser = argparse.ArgumentParser() + parser.add_argument('--weights', type=str, default=ROOT / 'yolo.pt', help='weights path') + parser.add_argument('--imgsz', '--img', '--img-size', type=int, default=640, help='inference size (pixels)') + parser.add_argument('--batch-size', type=int, default=1, help='batch size') + parser.add_argument('--data', type=str, default=ROOT / 'data/coco128.yaml', help='dataset.yaml path') + parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu') + parser.add_argument('--half', action='store_true', help='use FP16 half-precision inference') + parser.add_argument('--test', action='store_true', help='test exports only') + parser.add_argument('--pt-only', action='store_true', help='test PyTorch only') + parser.add_argument('--hard-fail', nargs='?', const=True, default=False, help='Exception on error or < min metric') + opt = parser.parse_args() + opt.data = check_yaml(opt.data) # check YAML + print_args(vars(opt)) + return opt + + +def main(opt): + test(**vars(opt)) if opt.test else run(**vars(opt)) + + +if __name__ == "__main__": + opt = parse_opt() + main(opt) diff --git a/cv/3d_detection/yolov9/pytorch/classify/predict.py b/cv/3d_detection/yolov9/pytorch/classify/predict.py new file mode 100644 index 000000000..9a6b00062 --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/classify/predict.py @@ -0,0 +1,224 @@ +# YOLOv5 🚀 by Ultralytics, GPL-3.0 license +""" +Run YOLOv5 classification inference on images, videos, directories, globs, YouTube, webcam, streams, etc. + +Usage - sources: + $ python classify/predict.py --weights yolov5s-cls.pt --source 0 # webcam + img.jpg # image + vid.mp4 # video + screen # screenshot + path/ # directory + 'path/*.jpg' # glob + 'https://youtu.be/Zgi9g1ksQHc' # YouTube + 'rtsp://example.com/media.mp4' # RTSP, RTMP, HTTP stream + +Usage - formats: + $ python classify/predict.py --weights yolov5s-cls.pt # PyTorch + yolov5s-cls.torchscript # TorchScript + yolov5s-cls.onnx # ONNX Runtime or OpenCV DNN with --dnn + yolov5s-cls_openvino_model # OpenVINO + yolov5s-cls.engine # TensorRT + yolov5s-cls.mlmodel # CoreML (macOS-only) + yolov5s-cls_saved_model # TensorFlow SavedModel + yolov5s-cls.pb # TensorFlow GraphDef + yolov5s-cls.tflite # TensorFlow Lite + yolov5s-cls_edgetpu.tflite # TensorFlow Edge TPU + yolov5s-cls_paddle_model # PaddlePaddle +""" + +import argparse +import os +import platform +import sys +from pathlib import Path + +import torch +import torch.nn.functional as F + +FILE = Path(__file__).resolve() +ROOT = FILE.parents[1] # YOLOv5 root directory +if str(ROOT) not in sys.path: + sys.path.append(str(ROOT)) # add ROOT to PATH +ROOT = Path(os.path.relpath(ROOT, Path.cwd())) # relative + +from models.common import DetectMultiBackend +from utils.augmentations import classify_transforms +from utils.dataloaders import IMG_FORMATS, VID_FORMATS, LoadImages, LoadScreenshots, LoadStreams +from utils.general import (LOGGER, Profile, check_file, check_img_size, check_imshow, check_requirements, colorstr, cv2, + increment_path, print_args, strip_optimizer) +from utils.plots import Annotator +from utils.torch_utils import select_device, smart_inference_mode + + +@smart_inference_mode() +def run( + weights=ROOT / 'yolov5s-cls.pt', # model.pt path(s) + source=ROOT / 'data/images', # file/dir/URL/glob/screen/0(webcam) + data=ROOT / 'data/coco128.yaml', # dataset.yaml path + imgsz=(224, 224), # inference size (height, width) + device='', # cuda device, i.e. 0 or 0,1,2,3 or cpu + view_img=False, # show results + save_txt=False, # save results to *.txt + nosave=False, # do not save images/videos + augment=False, # augmented inference + visualize=False, # visualize features + update=False, # update all models + project=ROOT / 'runs/predict-cls', # save results to project/name + name='exp', # save results to project/name + exist_ok=False, # existing project/name ok, do not increment + half=False, # use FP16 half-precision inference + dnn=False, # use OpenCV DNN for ONNX inference + vid_stride=1, # video frame-rate stride +): + source = str(source) + save_img = not nosave and not source.endswith('.txt') # save inference images + is_file = Path(source).suffix[1:] in (IMG_FORMATS + VID_FORMATS) + is_url = source.lower().startswith(('rtsp://', 'rtmp://', 'http://', 'https://')) + webcam = source.isnumeric() or source.endswith('.txt') or (is_url and not is_file) + screenshot = source.lower().startswith('screen') + if is_url and is_file: + source = check_file(source) # download + + # Directories + save_dir = increment_path(Path(project) / name, exist_ok=exist_ok) # increment run + (save_dir / 'labels' if save_txt else save_dir).mkdir(parents=True, exist_ok=True) # make dir + + # Load model + device = select_device(device) + model = DetectMultiBackend(weights, device=device, dnn=dnn, data=data, fp16=half) + stride, names, pt = model.stride, model.names, model.pt + imgsz = check_img_size(imgsz, s=stride) # check image size + + # Dataloader + bs = 1 # batch_size + if webcam: + view_img = check_imshow(warn=True) + dataset = LoadStreams(source, img_size=imgsz, transforms=classify_transforms(imgsz[0]), vid_stride=vid_stride) + bs = len(dataset) + elif screenshot: + dataset = LoadScreenshots(source, img_size=imgsz, stride=stride, auto=pt) + else: + dataset = LoadImages(source, img_size=imgsz, transforms=classify_transforms(imgsz[0]), vid_stride=vid_stride) + vid_path, vid_writer = [None] * bs, [None] * bs + + # Run inference + model.warmup(imgsz=(1 if pt else bs, 3, *imgsz)) # warmup + seen, windows, dt = 0, [], (Profile(), Profile(), Profile()) + for path, im, im0s, vid_cap, s in dataset: + with dt[0]: + im = torch.Tensor(im).to(model.device) + im = im.half() if model.fp16 else im.float() # uint8 to fp16/32 + if len(im.shape) == 3: + im = im[None] # expand for batch dim + + # Inference + with dt[1]: + results = model(im) + + # Post-process + with dt[2]: + pred = F.softmax(results, dim=1) # probabilities + + # Process predictions + for i, prob in enumerate(pred): # per image + seen += 1 + if webcam: # batch_size >= 1 + p, im0, frame = path[i], im0s[i].copy(), dataset.count + s += f'{i}: ' + else: + p, im0, frame = path, im0s.copy(), getattr(dataset, 'frame', 0) + + p = Path(p) # to Path + save_path = str(save_dir / p.name) # im.jpg + txt_path = str(save_dir / 'labels' / p.stem) + ('' if dataset.mode == 'image' else f'_{frame}') # im.txt + + s += '%gx%g ' % im.shape[2:] # print string + annotator = Annotator(im0, example=str(names), pil=True) + + # Print results + top5i = prob.argsort(0, descending=True)[:5].tolist() # top 5 indices + s += f"{', '.join(f'{names[j]} {prob[j]:.2f}' for j in top5i)}, " + + # Write results + text = '\n'.join(f'{prob[j]:.2f} {names[j]}' for j in top5i) + if save_img or view_img: # Add bbox to image + annotator.text((32, 32), text, txt_color=(255, 255, 255)) + if save_txt: # Write to file + with open(f'{txt_path}.txt', 'a') as f: + f.write(text + '\n') + + # Stream results + im0 = annotator.result() + if view_img: + if platform.system() == 'Linux' and p not in windows: + windows.append(p) + cv2.namedWindow(str(p), cv2.WINDOW_NORMAL | cv2.WINDOW_KEEPRATIO) # allow window resize (Linux) + cv2.resizeWindow(str(p), im0.shape[1], im0.shape[0]) + cv2.imshow(str(p), im0) + cv2.waitKey(1) # 1 millisecond + + # Save results (image with detections) + if save_img: + if dataset.mode == 'image': + cv2.imwrite(save_path, im0) + else: # 'video' or 'stream' + if vid_path[i] != save_path: # new video + vid_path[i] = save_path + if isinstance(vid_writer[i], cv2.VideoWriter): + vid_writer[i].release() # release previous video writer + if vid_cap: # video + fps = vid_cap.get(cv2.CAP_PROP_FPS) + w = int(vid_cap.get(cv2.CAP_PROP_FRAME_WIDTH)) + h = int(vid_cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) + else: # stream + fps, w, h = 30, im0.shape[1], im0.shape[0] + save_path = str(Path(save_path).with_suffix('.mp4')) # force *.mp4 suffix on results videos + vid_writer[i] = cv2.VideoWriter(save_path, cv2.VideoWriter_fourcc(*'mp4v'), fps, (w, h)) + vid_writer[i].write(im0) + + # Print time (inference-only) + LOGGER.info(f"{s}{dt[1].dt * 1E3:.1f}ms") + + # Print results + t = tuple(x.t / seen * 1E3 for x in dt) # speeds per image + LOGGER.info(f'Speed: %.1fms pre-process, %.1fms inference, %.1fms NMS per image at shape {(1, 3, *imgsz)}' % t) + if save_txt or save_img: + s = f"\n{len(list(save_dir.glob('labels/*.txt')))} labels saved to {save_dir / 'labels'}" if save_txt else '' + LOGGER.info(f"Results saved to {colorstr('bold', save_dir)}{s}") + if update: + strip_optimizer(weights[0]) # update model (to fix SourceChangeWarning) + + +def parse_opt(): + parser = argparse.ArgumentParser() + parser.add_argument('--weights', nargs='+', type=str, default=ROOT / 'yolov5s-cls.pt', help='model path(s)') + parser.add_argument('--source', type=str, default=ROOT / 'data/images', help='file/dir/URL/glob/screen/0(webcam)') + parser.add_argument('--data', type=str, default=ROOT / 'data/coco128.yaml', help='(optional) dataset.yaml path') + parser.add_argument('--imgsz', '--img', '--img-size', nargs='+', type=int, default=[224], help='inference size h,w') + parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu') + parser.add_argument('--view-img', action='store_true', help='show results') + parser.add_argument('--save-txt', action='store_true', help='save results to *.txt') + parser.add_argument('--nosave', action='store_true', help='do not save images/videos') + parser.add_argument('--augment', action='store_true', help='augmented inference') + parser.add_argument('--visualize', action='store_true', help='visualize features') + parser.add_argument('--update', action='store_true', help='update all models') + parser.add_argument('--project', default=ROOT / 'runs/predict-cls', help='save results to project/name') + parser.add_argument('--name', default='exp', help='save results to project/name') + parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment') + parser.add_argument('--half', action='store_true', help='use FP16 half-precision inference') + parser.add_argument('--dnn', action='store_true', help='use OpenCV DNN for ONNX inference') + parser.add_argument('--vid-stride', type=int, default=1, help='video frame-rate stride') + opt = parser.parse_args() + opt.imgsz *= 2 if len(opt.imgsz) == 1 else 1 # expand + print_args(vars(opt)) + return opt + + +def main(opt): + check_requirements(exclude=('tensorboard', 'thop')) + run(**vars(opt)) + + +if __name__ == "__main__": + opt = parse_opt() + main(opt) diff --git a/cv/3d_detection/yolov9/pytorch/classify/train.py b/cv/3d_detection/yolov9/pytorch/classify/train.py new file mode 100644 index 000000000..a50845a4f --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/classify/train.py @@ -0,0 +1,333 @@ +# YOLOv5 🚀 by Ultralytics, GPL-3.0 license +""" +Train a YOLOv5 classifier model on a classification dataset + +Usage - Single-GPU training: + $ python classify/train.py --model yolov5s-cls.pt --data imagenette160 --epochs 5 --img 224 + +Usage - Multi-GPU DDP training: + $ python -m torch.distributed.run --nproc_per_node 4 --master_port 1 classify/train.py --model yolov5s-cls.pt --data imagenet --epochs 5 --img 224 --device 0,1,2,3 + +Datasets: --data mnist, fashion-mnist, cifar10, cifar100, imagenette, imagewoof, imagenet, or 'path/to/data' +YOLOv5-cls models: --model yolov5n-cls.pt, yolov5s-cls.pt, yolov5m-cls.pt, yolov5l-cls.pt, yolov5x-cls.pt +Torchvision models: --model resnet50, efficientnet_b0, etc. See https://pytorch.org/vision/stable/models.html +""" + +import argparse +import os +import subprocess +import sys +import time +from copy import deepcopy +from datetime import datetime +from pathlib import Path + +import torch +import torch.distributed as dist +import torch.hub as hub +import torch.optim.lr_scheduler as lr_scheduler +import torchvision +from torch.cuda import amp +from tqdm import tqdm + +FILE = Path(__file__).resolve() +ROOT = FILE.parents[1] # YOLOv5 root directory +if str(ROOT) not in sys.path: + sys.path.append(str(ROOT)) # add ROOT to PATH +ROOT = Path(os.path.relpath(ROOT, Path.cwd())) # relative + +from classify import val as validate +from models.experimental import attempt_load +from models.yolo import ClassificationModel, DetectionModel +from utils.dataloaders import create_classification_dataloader +from utils.general import (DATASETS_DIR, LOGGER, TQDM_BAR_FORMAT, WorkingDirectory, check_git_info, check_git_status, + check_requirements, colorstr, download, increment_path, init_seeds, print_args, yaml_save) +from utils.loggers import GenericLogger +from utils.plots import imshow_cls +from utils.torch_utils import (ModelEMA, model_info, reshape_classifier_output, select_device, smart_DDP, + smart_optimizer, smartCrossEntropyLoss, torch_distributed_zero_first) + +LOCAL_RANK = int(os.getenv('LOCAL_RANK', -1)) # https://pytorch.org/docs/stable/elastic/run.html +RANK = int(os.getenv('RANK', -1)) +WORLD_SIZE = int(os.getenv('WORLD_SIZE', 1)) +GIT_INFO = check_git_info() + + +def train(opt, device): + init_seeds(opt.seed + 1 + RANK, deterministic=True) + save_dir, data, bs, epochs, nw, imgsz, pretrained = \ + opt.save_dir, Path(opt.data), opt.batch_size, opt.epochs, min(os.cpu_count() - 1, opt.workers), \ + opt.imgsz, str(opt.pretrained).lower() == 'true' + cuda = device.type != 'cpu' + + # Directories + wdir = save_dir / 'weights' + wdir.mkdir(parents=True, exist_ok=True) # make dir + last, best = wdir / 'last.pt', wdir / 'best.pt' + + # Save run settings + yaml_save(save_dir / 'opt.yaml', vars(opt)) + + # Logger + logger = GenericLogger(opt=opt, console_logger=LOGGER) if RANK in {-1, 0} else None + + # Download Dataset + with torch_distributed_zero_first(LOCAL_RANK), WorkingDirectory(ROOT): + data_dir = data if data.is_dir() else (DATASETS_DIR / data) + if not data_dir.is_dir(): + LOGGER.info(f'\nDataset not found ⚠️, missing path {data_dir}, attempting download...') + t = time.time() + if str(data) == 'imagenet': + subprocess.run(f"bash {ROOT / 'data/scripts/get_imagenet.sh'}", shell=True, check=True) + else: + url = f'https://github.com/ultralytics/yolov5/releases/download/v1.0/{data}.zip' + download(url, dir=data_dir.parent) + s = f"Dataset download success ✅ ({time.time() - t:.1f}s), saved to {colorstr('bold', data_dir)}\n" + LOGGER.info(s) + + # Dataloaders + nc = len([x for x in (data_dir / 'train').glob('*') if x.is_dir()]) # number of classes + trainloader = create_classification_dataloader(path=data_dir / 'train', + imgsz=imgsz, + batch_size=bs // WORLD_SIZE, + augment=True, + cache=opt.cache, + rank=LOCAL_RANK, + workers=nw) + + test_dir = data_dir / 'test' if (data_dir / 'test').exists() else data_dir / 'val' # data/test or data/val + if RANK in {-1, 0}: + testloader = create_classification_dataloader(path=test_dir, + imgsz=imgsz, + batch_size=bs // WORLD_SIZE * 2, + augment=False, + cache=opt.cache, + rank=-1, + workers=nw) + + # Model + with torch_distributed_zero_first(LOCAL_RANK), WorkingDirectory(ROOT): + if Path(opt.model).is_file() or opt.model.endswith('.pt'): + model = attempt_load(opt.model, device='cpu', fuse=False) + elif opt.model in torchvision.models.__dict__: # TorchVision models i.e. resnet50, efficientnet_b0 + model = torchvision.models.__dict__[opt.model](weights='IMAGENET1K_V1' if pretrained else None) + else: + m = hub.list('ultralytics/yolov5') # + hub.list('pytorch/vision') # models + raise ModuleNotFoundError(f'--model {opt.model} not found. Available models are: \n' + '\n'.join(m)) + if isinstance(model, DetectionModel): + LOGGER.warning("WARNING ⚠️ pass YOLOv5 classifier model with '-cls' suffix, i.e. '--model yolov5s-cls.pt'") + model = ClassificationModel(model=model, nc=nc, cutoff=opt.cutoff or 10) # convert to classification model + reshape_classifier_output(model, nc) # update class count + for m in model.modules(): + if not pretrained and hasattr(m, 'reset_parameters'): + m.reset_parameters() + if isinstance(m, torch.nn.Dropout) and opt.dropout is not None: + m.p = opt.dropout # set dropout + for p in model.parameters(): + p.requires_grad = True # for training + model = model.to(device) + + # Info + if RANK in {-1, 0}: + model.names = trainloader.dataset.classes # attach class names + model.transforms = testloader.dataset.torch_transforms # attach inference transforms + model_info(model) + if opt.verbose: + LOGGER.info(model) + images, labels = next(iter(trainloader)) + file = imshow_cls(images[:25], labels[:25], names=model.names, f=save_dir / 'train_images.jpg') + logger.log_images(file, name='Train Examples') + logger.log_graph(model, imgsz) # log model + + # Optimizer + optimizer = smart_optimizer(model, opt.optimizer, opt.lr0, momentum=0.9, decay=opt.decay) + + # Scheduler + lrf = 0.01 # final lr (fraction of lr0) + # lf = lambda x: ((1 + math.cos(x * math.pi / epochs)) / 2) * (1 - lrf) + lrf # cosine + lf = lambda x: (1 - x / epochs) * (1 - lrf) + lrf # linear + scheduler = lr_scheduler.LambdaLR(optimizer, lr_lambda=lf) + # scheduler = lr_scheduler.OneCycleLR(optimizer, max_lr=lr0, total_steps=epochs, pct_start=0.1, + # final_div_factor=1 / 25 / lrf) + + # EMA + ema = ModelEMA(model) if RANK in {-1, 0} else None + + # DDP mode + if cuda and RANK != -1: + model = smart_DDP(model) + + # Train + t0 = time.time() + criterion = smartCrossEntropyLoss(label_smoothing=opt.label_smoothing) # loss function + best_fitness = 0.0 + scaler = amp.GradScaler(enabled=cuda) + val = test_dir.stem # 'val' or 'test' + LOGGER.info(f'Image sizes {imgsz} train, {imgsz} test\n' + f'Using {nw * WORLD_SIZE} dataloader workers\n' + f"Logging results to {colorstr('bold', save_dir)}\n" + f'Starting {opt.model} training on {data} dataset with {nc} classes for {epochs} epochs...\n\n' + f"{'Epoch':>10}{'GPU_mem':>10}{'train_loss':>12}{f'{val}_loss':>12}{'top1_acc':>12}{'top5_acc':>12}") + for epoch in range(epochs): # loop over the dataset multiple times + tloss, vloss, fitness = 0.0, 0.0, 0.0 # train loss, val loss, fitness + model.train() + if RANK != -1: + trainloader.sampler.set_epoch(epoch) + pbar = enumerate(trainloader) + if RANK in {-1, 0}: + pbar = tqdm(enumerate(trainloader), total=len(trainloader), bar_format=TQDM_BAR_FORMAT) + for i, (images, labels) in pbar: # progress bar + images, labels = images.to(device, non_blocking=True), labels.to(device) + + # Forward + with amp.autocast(enabled=cuda): # stability issues when enabled + loss = criterion(model(images), labels) + + # Backward + scaler.scale(loss).backward() + + # Optimize + scaler.unscale_(optimizer) # unscale gradients + torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=10.0) # clip gradients + scaler.step(optimizer) + scaler.update() + optimizer.zero_grad() + if ema: + ema.update(model) + + if RANK in {-1, 0}: + # Print + tloss = (tloss * i + loss.item()) / (i + 1) # update mean losses + mem = '%.3gG' % (torch.cuda.memory_reserved() / 1E9 if torch.cuda.is_available() else 0) # (GB) + pbar.desc = f"{f'{epoch + 1}/{epochs}':>10}{mem:>10}{tloss:>12.3g}" + ' ' * 36 + + # Test + if i == len(pbar) - 1: # last batch + top1, top5, vloss = validate.run(model=ema.ema, + dataloader=testloader, + criterion=criterion, + pbar=pbar) # test accuracy, loss + fitness = top1 # define fitness as top1 accuracy + + # Scheduler + scheduler.step() + + # Log metrics + if RANK in {-1, 0}: + # Best fitness + if fitness > best_fitness: + best_fitness = fitness + + # Log + metrics = { + "train/loss": tloss, + f"{val}/loss": vloss, + "metrics/accuracy_top1": top1, + "metrics/accuracy_top5": top5, + "lr/0": optimizer.param_groups[0]['lr']} # learning rate + logger.log_metrics(metrics, epoch) + + # Save model + final_epoch = epoch + 1 == epochs + if (not opt.nosave) or final_epoch: + ckpt = { + 'epoch': epoch, + 'best_fitness': best_fitness, + 'model': deepcopy(ema.ema).half(), # deepcopy(de_parallel(model)).half(), + 'ema': None, # deepcopy(ema.ema).half(), + 'updates': ema.updates, + 'optimizer': None, # optimizer.state_dict(), + 'opt': vars(opt), + 'git': GIT_INFO, # {remote, branch, commit} if a git repo + 'date': datetime.now().isoformat()} + + # Save last, best and delete + torch.save(ckpt, last) + if best_fitness == fitness: + torch.save(ckpt, best) + del ckpt + + # Train complete + if RANK in {-1, 0} and final_epoch: + LOGGER.info(f'\nTraining complete ({(time.time() - t0) / 3600:.3f} hours)' + f"\nResults saved to {colorstr('bold', save_dir)}" + f"\nPredict: python classify/predict.py --weights {best} --source im.jpg" + f"\nValidate: python classify/val.py --weights {best} --data {data_dir}" + f"\nExport: python export.py --weights {best} --include onnx" + f"\nPyTorch Hub: model = torch.hub.load('ultralytics/yolov5', 'custom', '{best}')" + f"\nVisualize: https://netron.app\n") + + # Plot examples + images, labels = (x[:25] for x in next(iter(testloader))) # first 25 images and labels + pred = torch.max(ema.ema(images.to(device)), 1)[1] + file = imshow_cls(images, labels, pred, model.names, verbose=False, f=save_dir / 'test_images.jpg') + + # Log results + meta = {"epochs": epochs, "top1_acc": best_fitness, "date": datetime.now().isoformat()} + logger.log_images(file, name='Test Examples (true-predicted)', epoch=epoch) + logger.log_model(best, epochs, metadata=meta) + + +def parse_opt(known=False): + parser = argparse.ArgumentParser() + parser.add_argument('--model', type=str, default='yolov5s-cls.pt', help='initial weights path') + parser.add_argument('--data', type=str, default='imagenette160', help='cifar10, cifar100, mnist, imagenet, ...') + parser.add_argument('--epochs', type=int, default=10, help='total training epochs') + parser.add_argument('--batch-size', type=int, default=64, help='total batch size for all GPUs') + parser.add_argument('--imgsz', '--img', '--img-size', type=int, default=224, help='train, val image size (pixels)') + parser.add_argument('--nosave', action='store_true', help='only save final checkpoint') + parser.add_argument('--cache', type=str, nargs='?', const='ram', help='--cache images in "ram" (default) or "disk"') + parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu') + parser.add_argument('--workers', type=int, default=8, help='max dataloader workers (per RANK in DDP mode)') + parser.add_argument('--project', default=ROOT / 'runs/train-cls', help='save to project/name') + parser.add_argument('--name', default='exp', help='save to project/name') + parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment') + parser.add_argument('--pretrained', nargs='?', const=True, default=True, help='start from i.e. --pretrained False') + parser.add_argument('--optimizer', choices=['SGD', 'Adam', 'AdamW', 'RMSProp'], default='Adam', help='optimizer') + parser.add_argument('--lr0', type=float, default=0.001, help='initial learning rate') + parser.add_argument('--decay', type=float, default=5e-5, help='weight decay') + parser.add_argument('--label-smoothing', type=float, default=0.1, help='Label smoothing epsilon') + parser.add_argument('--cutoff', type=int, default=None, help='Model layer cutoff index for Classify() head') + parser.add_argument('--dropout', type=float, default=None, help='Dropout (fraction)') + parser.add_argument('--verbose', action='store_true', help='Verbose mode') + parser.add_argument('--seed', type=int, default=0, help='Global training seed') + parser.add_argument('--local_rank', type=int, default=-1, help='Automatic DDP Multi-GPU argument, do not modify') + return parser.parse_known_args()[0] if known else parser.parse_args() + + +def main(opt): + # Checks + if RANK in {-1, 0}: + print_args(vars(opt)) + check_git_status() + check_requirements() + + # DDP mode + device = select_device(opt.device, batch_size=opt.batch_size) + if LOCAL_RANK != -1: + assert opt.batch_size != -1, 'AutoBatch is coming soon for classification, please pass a valid --batch-size' + assert opt.batch_size % WORLD_SIZE == 0, f'--batch-size {opt.batch_size} must be multiple of WORLD_SIZE' + assert torch.cuda.device_count() > LOCAL_RANK, 'insufficient CUDA devices for DDP command' + torch.cuda.set_device(LOCAL_RANK) + device = torch.device('cuda', LOCAL_RANK) + dist.init_process_group(backend="nccl" if dist.is_nccl_available() else "gloo") + + # Parameters + opt.save_dir = increment_path(Path(opt.project) / opt.name, exist_ok=opt.exist_ok) # increment run + + # Train + train(opt, device) + + +def run(**kwargs): + # Usage: from yolov5 import classify; classify.train.run(data=mnist, imgsz=320, model='yolov5m') + opt = parse_opt(True) + for k, v in kwargs.items(): + setattr(opt, k, v) + main(opt) + return opt + + +if __name__ == "__main__": + opt = parse_opt() + main(opt) diff --git a/cv/3d_detection/yolov9/pytorch/classify/val.py b/cv/3d_detection/yolov9/pytorch/classify/val.py new file mode 100644 index 000000000..8657036fb --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/classify/val.py @@ -0,0 +1,170 @@ +# YOLOv5 🚀 by Ultralytics, GPL-3.0 license +""" +Validate a trained YOLOv5 classification model on a classification dataset + +Usage: + $ bash data/scripts/get_imagenet.sh --val # download ImageNet val split (6.3G, 50000 images) + $ python classify/val.py --weights yolov5m-cls.pt --data ../datasets/imagenet --img 224 # validate ImageNet + +Usage - formats: + $ python classify/val.py --weights yolov5s-cls.pt # PyTorch + yolov5s-cls.torchscript # TorchScript + yolov5s-cls.onnx # ONNX Runtime or OpenCV DNN with --dnn + yolov5s-cls_openvino_model # OpenVINO + yolov5s-cls.engine # TensorRT + yolov5s-cls.mlmodel # CoreML (macOS-only) + yolov5s-cls_saved_model # TensorFlow SavedModel + yolov5s-cls.pb # TensorFlow GraphDef + yolov5s-cls.tflite # TensorFlow Lite + yolov5s-cls_edgetpu.tflite # TensorFlow Edge TPU + yolov5s-cls_paddle_model # PaddlePaddle +""" + +import argparse +import os +import sys +from pathlib import Path + +import torch +from tqdm import tqdm + +FILE = Path(__file__).resolve() +ROOT = FILE.parents[1] # YOLOv5 root directory +if str(ROOT) not in sys.path: + sys.path.append(str(ROOT)) # add ROOT to PATH +ROOT = Path(os.path.relpath(ROOT, Path.cwd())) # relative + +from models.common import DetectMultiBackend +from utils.dataloaders import create_classification_dataloader +from utils.general import (LOGGER, TQDM_BAR_FORMAT, Profile, check_img_size, check_requirements, colorstr, + increment_path, print_args) +from utils.torch_utils import select_device, smart_inference_mode + + +@smart_inference_mode() +def run( + data=ROOT / '../datasets/mnist', # dataset dir + weights=ROOT / 'yolov5s-cls.pt', # model.pt path(s) + batch_size=128, # batch size + imgsz=224, # inference size (pixels) + device='', # cuda device, i.e. 0 or 0,1,2,3 or cpu + workers=8, # max dataloader workers (per RANK in DDP mode) + verbose=False, # verbose output + project=ROOT / 'runs/val-cls', # save to project/name + name='exp', # save to project/name + exist_ok=False, # existing project/name ok, do not increment + half=False, # use FP16 half-precision inference + dnn=False, # use OpenCV DNN for ONNX inference + model=None, + dataloader=None, + criterion=None, + pbar=None, +): + # Initialize/load model and set device + training = model is not None + if training: # called by train.py + device, pt, jit, engine = next(model.parameters()).device, True, False, False # get model device, PyTorch model + half &= device.type != 'cpu' # half precision only supported on CUDA + model.half() if half else model.float() + else: # called directly + device = select_device(device, batch_size=batch_size) + + # Directories + save_dir = increment_path(Path(project) / name, exist_ok=exist_ok) # increment run + save_dir.mkdir(parents=True, exist_ok=True) # make dir + + # Load model + model = DetectMultiBackend(weights, device=device, dnn=dnn, fp16=half) + stride, pt, jit, engine = model.stride, model.pt, model.jit, model.engine + imgsz = check_img_size(imgsz, s=stride) # check image size + half = model.fp16 # FP16 supported on limited backends with CUDA + if engine: + batch_size = model.batch_size + else: + device = model.device + if not (pt or jit): + batch_size = 1 # export.py models default to batch-size 1 + LOGGER.info(f'Forcing --batch-size 1 square inference (1,3,{imgsz},{imgsz}) for non-PyTorch models') + + # Dataloader + data = Path(data) + test_dir = data / 'test' if (data / 'test').exists() else data / 'val' # data/test or data/val + dataloader = create_classification_dataloader(path=test_dir, + imgsz=imgsz, + batch_size=batch_size, + augment=False, + rank=-1, + workers=workers) + + model.eval() + pred, targets, loss, dt = [], [], 0, (Profile(), Profile(), Profile()) + n = len(dataloader) # number of batches + action = 'validating' if dataloader.dataset.root.stem == 'val' else 'testing' + desc = f"{pbar.desc[:-36]}{action:>36}" if pbar else f"{action}" + bar = tqdm(dataloader, desc, n, not training, bar_format=TQDM_BAR_FORMAT, position=0) + with torch.cuda.amp.autocast(enabled=device.type != 'cpu'): + for images, labels in bar: + with dt[0]: + images, labels = images.to(device, non_blocking=True), labels.to(device) + + with dt[1]: + y = model(images) + + with dt[2]: + pred.append(y.argsort(1, descending=True)[:, :5]) + targets.append(labels) + if criterion: + loss += criterion(y, labels) + + loss /= n + pred, targets = torch.cat(pred), torch.cat(targets) + correct = (targets[:, None] == pred).float() + acc = torch.stack((correct[:, 0], correct.max(1).values), dim=1) # (top1, top5) accuracy + top1, top5 = acc.mean(0).tolist() + + if pbar: + pbar.desc = f"{pbar.desc[:-36]}{loss:>12.3g}{top1:>12.3g}{top5:>12.3g}" + if verbose: # all classes + LOGGER.info(f"{'Class':>24}{'Images':>12}{'top1_acc':>12}{'top5_acc':>12}") + LOGGER.info(f"{'all':>24}{targets.shape[0]:>12}{top1:>12.3g}{top5:>12.3g}") + for i, c in model.names.items(): + aci = acc[targets == i] + top1i, top5i = aci.mean(0).tolist() + LOGGER.info(f"{c:>24}{aci.shape[0]:>12}{top1i:>12.3g}{top5i:>12.3g}") + + # Print results + t = tuple(x.t / len(dataloader.dataset.samples) * 1E3 for x in dt) # speeds per image + shape = (1, 3, imgsz, imgsz) + LOGGER.info(f'Speed: %.1fms pre-process, %.1fms inference, %.1fms post-process per image at shape {shape}' % t) + LOGGER.info(f"Results saved to {colorstr('bold', save_dir)}") + + return top1, top5, loss + + +def parse_opt(): + parser = argparse.ArgumentParser() + parser.add_argument('--data', type=str, default=ROOT / '../datasets/mnist', help='dataset path') + parser.add_argument('--weights', nargs='+', type=str, default=ROOT / 'yolov5s-cls.pt', help='model.pt path(s)') + parser.add_argument('--batch-size', type=int, default=128, help='batch size') + parser.add_argument('--imgsz', '--img', '--img-size', type=int, default=224, help='inference size (pixels)') + parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu') + parser.add_argument('--workers', type=int, default=8, help='max dataloader workers (per RANK in DDP mode)') + parser.add_argument('--verbose', nargs='?', const=True, default=True, help='verbose output') + parser.add_argument('--project', default=ROOT / 'runs/val-cls', help='save to project/name') + parser.add_argument('--name', default='exp', help='save to project/name') + parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment') + parser.add_argument('--half', action='store_true', help='use FP16 half-precision inference') + parser.add_argument('--dnn', action='store_true', help='use OpenCV DNN for ONNX inference') + opt = parser.parse_args() + print_args(vars(opt)) + return opt + + +def main(opt): + check_requirements(exclude=('tensorboard', 'thop')) + run(**vars(opt)) + + +if __name__ == "__main__": + opt = parse_opt() + main(opt) diff --git a/cv/3d_detection/yolov9/pytorch/data/coco.yaml b/cv/3d_detection/yolov9/pytorch/data/coco.yaml new file mode 100644 index 000000000..721772552 --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/data/coco.yaml @@ -0,0 +1,125 @@ +path: ./coco # dataset root dir +train: train2017.txt # train images (relative to 'path') 118287 images +val: val2017.txt # val images (relative to 'path') 5000 images +test: test-dev2017.txt # 20288 of 40670 images, submit to https://competitions.codalab.org/competitions/20794 + +# Classes +names: + 0: person + 1: bicycle + 2: car + 3: motorcycle + 4: airplane + 5: bus + 6: train + 7: truck + 8: boat + 9: traffic light + 10: fire hydrant + 11: stop sign + 12: parking meter + 13: bench + 14: bird + 15: cat + 16: dog + 17: horse + 18: sheep + 19: cow + 20: elephant + 21: bear + 22: zebra + 23: giraffe + 24: backpack + 25: umbrella + 26: handbag + 27: tie + 28: suitcase + 29: frisbee + 30: skis + 31: snowboard + 32: sports ball + 33: kite + 34: baseball bat + 35: baseball glove + 36: skateboard + 37: surfboard + 38: tennis racket + 39: bottle + 40: wine glass + 41: cup + 42: fork + 43: knife + 44: spoon + 45: bowl + 46: banana + 47: apple + 48: sandwich + 49: orange + 50: broccoli + 51: carrot + 52: hot dog + 53: pizza + 54: donut + 55: cake + 56: chair + 57: couch + 58: potted plant + 59: bed + 60: dining table + 61: toilet + 62: tv + 63: laptop + 64: mouse + 65: remote + 66: keyboard + 67: cell phone + 68: microwave + 69: oven + 70: toaster + 71: sink + 72: refrigerator + 73: book + 74: clock + 75: vase + 76: scissors + 77: teddy bear + 78: hair drier + 79: toothbrush + + +# stuff names +stuff_names: [ + 'banner', 'blanket', 'branch', 'bridge', 'building-other', 'bush', 'cabinet', 'cage', + 'cardboard', 'carpet', 'ceiling-other', 'ceiling-tile', 'cloth', 'clothes', 'clouds', 'counter', 'cupboard', + 'curtain', 'desk-stuff', 'dirt', 'door-stuff', 'fence', 'floor-marble', 'floor-other', 'floor-stone', 'floor-tile', + 'floor-wood', 'flower', 'fog', 'food-other', 'fruit', 'furniture-other', 'grass', 'gravel', 'ground-other', 'hill', + 'house', 'leaves', 'light', 'mat', 'metal', 'mirror-stuff', 'moss', 'mountain', 'mud', 'napkin', 'net', 'paper', + 'pavement', 'pillow', 'plant-other', 'plastic', 'platform', 'playingfield', 'railing', 'railroad', 'river', 'road', + 'rock', 'roof', 'rug', 'salad', 'sand', 'sea', 'shelf', 'sky-other', 'skyscraper', 'snow', 'solid-other', 'stairs', + 'stone', 'straw', 'structural-other', 'table', 'tent', 'textile-other', 'towel', 'tree', 'vegetable', 'wall-brick', + 'wall-concrete', 'wall-other', 'wall-panel', 'wall-stone', 'wall-tile', 'wall-wood', 'water-other', 'waterdrops', + 'window-blind', 'window-other', 'wood', + # other + 'other', + # unlabeled + 'unlabeled' +] + + +# Download script/URL (optional) +download: | + from utils.general import download, Path + + + # Download labels + #segments = True # segment or box labels + #dir = Path(yaml['path']) # dataset root dir + #url = 'https://github.com/WongKinYiu/yolov7/releases/download/v0.1/' + #urls = [url + ('coco2017labels-segments.zip' if segments else 'coco2017labels.zip')] # labels + #download(urls, dir=dir.parent) + + # Download data + #urls = ['http://images.cocodataset.org/zips/train2017.zip', # 19G, 118k images + # 'http://images.cocodataset.org/zips/val2017.zip', # 1G, 5k images + # 'http://images.cocodataset.org/zips/test2017.zip'] # 7G, 41k images (optional) + #download(urls, dir=dir / 'images', threads=3) diff --git a/cv/3d_detection/yolov9/pytorch/data/hyps/hyp.scratch-high.yaml b/cv/3d_detection/yolov9/pytorch/data/hyps/hyp.scratch-high.yaml new file mode 100644 index 000000000..fdb2c3788 --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/data/hyps/hyp.scratch-high.yaml @@ -0,0 +1,30 @@ +lr0: 0.01 # initial learning rate (SGD=1E-2, Adam=1E-3) +lrf: 0.01 # final OneCycleLR learning rate (lr0 * lrf) +momentum: 0.937 # SGD momentum/Adam beta1 +weight_decay: 0.0005 # optimizer weight decay 5e-4 +warmup_epochs: 3.0 # warmup epochs (fractions ok) +warmup_momentum: 0.8 # warmup initial momentum +warmup_bias_lr: 0.1 # warmup initial bias lr +box: 7.5 # box loss gain +cls: 0.5 # cls loss gain +cls_pw: 1.0 # cls BCELoss positive_weight +obj: 0.7 # obj loss gain (scale with pixels) +obj_pw: 1.0 # obj BCELoss positive_weight +dfl: 1.5 # dfl loss gain +iou_t: 0.20 # IoU training threshold +anchor_t: 5.0 # anchor-multiple threshold +# anchors: 3 # anchors per output layer (0 to ignore) +fl_gamma: 0.0 # focal loss gamma (efficientDet default gamma=1.5) +hsv_h: 0.015 # image HSV-Hue augmentation (fraction) +hsv_s: 0.7 # image HSV-Saturation augmentation (fraction) +hsv_v: 0.4 # image HSV-Value augmentation (fraction) +degrees: 0.0 # image rotation (+/- deg) +translate: 0.1 # image translation (+/- fraction) +scale: 0.9 # image scale (+/- gain) +shear: 0.0 # image shear (+/- deg) +perspective: 0.0 # image perspective (+/- fraction), range 0-0.001 +flipud: 0.0 # image flip up-down (probability) +fliplr: 0.5 # image flip left-right (probability) +mosaic: 1.0 # image mosaic (probability) +mixup: 0.15 # image mixup (probability) +copy_paste: 0.3 # segment copy-paste (probability) diff --git a/cv/3d_detection/yolov9/pytorch/data/images/horses.jpg b/cv/3d_detection/yolov9/pytorch/data/images/horses.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3a761f46ba08ed459af026b59f6b91b6fa597dd1 GIT binary patch literal 133495 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 j`h%HPf?GiIOe8@u` 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

JO)KMKE!d5KDD`bqhGuc!({?n!6J;4 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�!nQVmgH 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 C;nJ-D literal 0 HcmV?d00001 diff --git a/cv/3d_detection/yolov9/pytorch/detect.py b/cv/3d_detection/yolov9/pytorch/detect.py new file mode 100644 index 000000000..6dbb6e7ef --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/detect.py @@ -0,0 +1,231 @@ +import argparse +import os +import platform +import sys +from pathlib import Path + +import torch + +FILE = Path(__file__).resolve() +ROOT = FILE.parents[0] # YOLO root directory +if str(ROOT) not in sys.path: + sys.path.append(str(ROOT)) # add ROOT to PATH +ROOT = Path(os.path.relpath(ROOT, Path.cwd())) # relative + +from models.common import DetectMultiBackend +from utils.dataloaders import IMG_FORMATS, VID_FORMATS, LoadImages, LoadScreenshots, LoadStreams +from utils.general import (LOGGER, Profile, check_file, check_img_size, check_imshow, check_requirements, colorstr, cv2, + increment_path, non_max_suppression, print_args, scale_boxes, strip_optimizer, xyxy2xywh) +from utils.plots import Annotator, colors, save_one_box +from utils.torch_utils import select_device, smart_inference_mode + + +@smart_inference_mode() +def run( + weights=ROOT / 'yolo.pt', # model path or triton URL + source=ROOT / 'data/images', # file/dir/URL/glob/screen/0(webcam) + data=ROOT / 'data/coco.yaml', # dataset.yaml path + imgsz=(640, 640), # inference size (height, width) + conf_thres=0.25, # confidence threshold + iou_thres=0.45, # NMS IOU threshold + max_det=1000, # maximum detections per image + device='', # cuda device, i.e. 0 or 0,1,2,3 or cpu + view_img=False, # show results + save_txt=False, # save results to *.txt + save_conf=False, # save confidences in --save-txt labels + save_crop=False, # save cropped prediction boxes + nosave=False, # do not save images/videos + classes=None, # filter by class: --class 0, or --class 0 2 3 + agnostic_nms=False, # class-agnostic NMS + augment=False, # augmented inference + visualize=False, # visualize features + update=False, # update all models + project=ROOT / 'runs/detect', # save results to project/name + name='exp', # save results to project/name + exist_ok=False, # existing project/name ok, do not increment + line_thickness=3, # bounding box thickness (pixels) + hide_labels=False, # hide labels + hide_conf=False, # hide confidences + half=False, # use FP16 half-precision inference + dnn=False, # use OpenCV DNN for ONNX inference + vid_stride=1, # video frame-rate stride +): + source = str(source) + save_img = not nosave and not source.endswith('.txt') # save inference images + is_file = Path(source).suffix[1:] in (IMG_FORMATS + VID_FORMATS) + is_url = source.lower().startswith(('rtsp://', 'rtmp://', 'http://', 'https://')) + webcam = source.isnumeric() or source.endswith('.txt') or (is_url and not is_file) + screenshot = source.lower().startswith('screen') + if is_url and is_file: + source = check_file(source) # download + + # Directories + save_dir = increment_path(Path(project) / name, exist_ok=exist_ok) # increment run + (save_dir / 'labels' if save_txt else save_dir).mkdir(parents=True, exist_ok=True) # make dir + + # Load model + device = select_device(device) + model = DetectMultiBackend(weights, device=device, dnn=dnn, data=data, fp16=half) + stride, names, pt = model.stride, model.names, model.pt + imgsz = check_img_size(imgsz, s=stride) # check image size + + # Dataloader + bs = 1 # batch_size + if webcam: + view_img = check_imshow(warn=True) + dataset = LoadStreams(source, img_size=imgsz, stride=stride, auto=pt, vid_stride=vid_stride) + bs = len(dataset) + elif screenshot: + dataset = LoadScreenshots(source, img_size=imgsz, stride=stride, auto=pt) + else: + dataset = LoadImages(source, img_size=imgsz, stride=stride, auto=pt, vid_stride=vid_stride) + vid_path, vid_writer = [None] * bs, [None] * bs + + # Run inference + model.warmup(imgsz=(1 if pt or model.triton else bs, 3, *imgsz)) # warmup + seen, windows, dt = 0, [], (Profile(), Profile(), Profile()) + for path, im, im0s, vid_cap, s in dataset: + with dt[0]: + im = torch.from_numpy(im).to(model.device) + im = im.half() if model.fp16 else im.float() # uint8 to fp16/32 + im /= 255 # 0 - 255 to 0.0 - 1.0 + if len(im.shape) == 3: + im = im[None] # expand for batch dim + + # Inference + with dt[1]: + visualize = increment_path(save_dir / Path(path).stem, mkdir=True) if visualize else False + pred = model(im, augment=augment, visualize=visualize) + + # NMS + with dt[2]: + pred = non_max_suppression(pred, conf_thres, iou_thres, classes, agnostic_nms, max_det=max_det) + + # Second-stage classifier (optional) + # pred = utils.general.apply_classifier(pred, classifier_model, im, im0s) + + # Process predictions + for i, det in enumerate(pred): # per image + seen += 1 + if webcam: # batch_size >= 1 + p, im0, frame = path[i], im0s[i].copy(), dataset.count + s += f'{i}: ' + else: + p, im0, frame = path, im0s.copy(), getattr(dataset, 'frame', 0) + + p = Path(p) # to Path + save_path = str(save_dir / p.name) # im.jpg + txt_path = str(save_dir / 'labels' / p.stem) + ('' if dataset.mode == 'image' else f'_{frame}') # im.txt + s += '%gx%g ' % im.shape[2:] # print string + gn = torch.tensor(im0.shape)[[1, 0, 1, 0]] # normalization gain whwh + imc = im0.copy() if save_crop else im0 # for save_crop + annotator = Annotator(im0, line_width=line_thickness, example=str(names)) + if len(det): + # Rescale boxes from img_size to im0 size + det[:, :4] = scale_boxes(im.shape[2:], det[:, :4], im0.shape).round() + + # Print results + for c in det[:, 5].unique(): + n = (det[:, 5] == c).sum() # detections per class + s += f"{n} {names[int(c)]}{'s' * (n > 1)}, " # add to string + + # Write results + for *xyxy, conf, cls in reversed(det): + if save_txt: # Write to file + xywh = (xyxy2xywh(torch.tensor(xyxy).view(1, 4)) / gn).view(-1).tolist() # normalized xywh + line = (cls, *xywh, conf) if save_conf else (cls, *xywh) # label format + with open(f'{txt_path}.txt', 'a') as f: + f.write(('%g ' * len(line)).rstrip() % line + '\n') + + if save_img or save_crop or view_img: # Add bbox to image + c = int(cls) # integer class + label = None if hide_labels else (names[c] if hide_conf else f'{names[c]} {conf:.2f}') + annotator.box_label(xyxy, label, color=colors(c, True)) + if save_crop: + save_one_box(xyxy, imc, file=save_dir / 'crops' / names[c] / f'{p.stem}.jpg', BGR=True) + + # Stream results + im0 = annotator.result() + if view_img: + if platform.system() == 'Linux' and p not in windows: + windows.append(p) + cv2.namedWindow(str(p), cv2.WINDOW_NORMAL | cv2.WINDOW_KEEPRATIO) # allow window resize (Linux) + cv2.resizeWindow(str(p), im0.shape[1], im0.shape[0]) + cv2.imshow(str(p), im0) + cv2.waitKey(1) # 1 millisecond + + # Save results (image with detections) + if save_img: + if dataset.mode == 'image': + cv2.imwrite(save_path, im0) + else: # 'video' or 'stream' + if vid_path[i] != save_path: # new video + vid_path[i] = save_path + if isinstance(vid_writer[i], cv2.VideoWriter): + vid_writer[i].release() # release previous video writer + if vid_cap: # video + fps = vid_cap.get(cv2.CAP_PROP_FPS) + w = int(vid_cap.get(cv2.CAP_PROP_FRAME_WIDTH)) + h = int(vid_cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) + else: # stream + fps, w, h = 30, im0.shape[1], im0.shape[0] + save_path = str(Path(save_path).with_suffix('.mp4')) # force *.mp4 suffix on results videos + vid_writer[i] = cv2.VideoWriter(save_path, cv2.VideoWriter_fourcc(*'mp4v'), fps, (w, h)) + vid_writer[i].write(im0) + + # Print time (inference-only) + LOGGER.info(f"{s}{'' if len(det) else '(no detections), '}{dt[1].dt * 1E3:.1f}ms") + + # Print results + t = tuple(x.t / seen * 1E3 for x in dt) # speeds per image + LOGGER.info(f'Speed: %.1fms pre-process, %.1fms inference, %.1fms NMS per image at shape {(1, 3, *imgsz)}' % t) + if save_txt or save_img: + s = f"\n{len(list(save_dir.glob('labels/*.txt')))} labels saved to {save_dir / 'labels'}" if save_txt else '' + LOGGER.info(f"Results saved to {colorstr('bold', save_dir)}{s}") + if update: + strip_optimizer(weights[0]) # update model (to fix SourceChangeWarning) + + +def parse_opt(): + parser = argparse.ArgumentParser() + parser.add_argument('--weights', nargs='+', type=str, default=ROOT / 'yolo.pt', help='model path or triton URL') + parser.add_argument('--source', type=str, default=ROOT / 'data/images', help='file/dir/URL/glob/screen/0(webcam)') + parser.add_argument('--data', type=str, default=ROOT / 'data/coco128.yaml', help='(optional) dataset.yaml path') + parser.add_argument('--imgsz', '--img', '--img-size', nargs='+', type=int, default=[640], help='inference size h,w') + parser.add_argument('--conf-thres', type=float, default=0.25, help='confidence threshold') + parser.add_argument('--iou-thres', type=float, default=0.45, help='NMS IoU threshold') + parser.add_argument('--max-det', type=int, default=1000, help='maximum detections per image') + parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu') + parser.add_argument('--view-img', action='store_true', help='show results') + parser.add_argument('--save-txt', action='store_true', help='save results to *.txt') + parser.add_argument('--save-conf', action='store_true', help='save confidences in --save-txt labels') + parser.add_argument('--save-crop', action='store_true', help='save cropped prediction boxes') + parser.add_argument('--nosave', action='store_true', help='do not save images/videos') + parser.add_argument('--classes', nargs='+', type=int, help='filter by class: --classes 0, or --classes 0 2 3') + parser.add_argument('--agnostic-nms', action='store_true', help='class-agnostic NMS') + parser.add_argument('--augment', action='store_true', help='augmented inference') + parser.add_argument('--visualize', action='store_true', help='visualize features') + parser.add_argument('--update', action='store_true', help='update all models') + parser.add_argument('--project', default=ROOT / 'runs/detect', help='save results to project/name') + parser.add_argument('--name', default='exp', help='save results to project/name') + parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment') + parser.add_argument('--line-thickness', default=3, type=int, help='bounding box thickness (pixels)') + parser.add_argument('--hide-labels', default=False, action='store_true', help='hide labels') + parser.add_argument('--hide-conf', default=False, action='store_true', help='hide confidences') + parser.add_argument('--half', action='store_true', help='use FP16 half-precision inference') + parser.add_argument('--dnn', action='store_true', help='use OpenCV DNN for ONNX inference') + parser.add_argument('--vid-stride', type=int, default=1, help='video frame-rate stride') + opt = parser.parse_args() + opt.imgsz *= 2 if len(opt.imgsz) == 1 else 1 # expand + print_args(vars(opt)) + return opt + + +def main(opt): + # check_requirements(exclude=('tensorboard', 'thop')) + run(**vars(opt)) + + +if __name__ == "__main__": + opt = parse_opt() + main(opt) diff --git a/cv/3d_detection/yolov9/pytorch/detect_dual.py b/cv/3d_detection/yolov9/pytorch/detect_dual.py new file mode 100644 index 000000000..a6c6eec6d --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/detect_dual.py @@ -0,0 +1,232 @@ +import argparse +import os +import platform +import sys +from pathlib import Path + +import torch + +FILE = Path(__file__).resolve() +ROOT = FILE.parents[0] # YOLO root directory +if str(ROOT) not in sys.path: + sys.path.append(str(ROOT)) # add ROOT to PATH +ROOT = Path(os.path.relpath(ROOT, Path.cwd())) # relative + +from models.common import DetectMultiBackend +from utils.dataloaders import IMG_FORMATS, VID_FORMATS, LoadImages, LoadScreenshots, LoadStreams +from utils.general import (LOGGER, Profile, check_file, check_img_size, check_imshow, check_requirements, colorstr, cv2, + increment_path, non_max_suppression, print_args, scale_boxes, strip_optimizer, xyxy2xywh) +from utils.plots import Annotator, colors, save_one_box +from utils.torch_utils import select_device, smart_inference_mode + + +@smart_inference_mode() +def run( + weights=ROOT / 'yolo.pt', # model path or triton URL + source=ROOT / 'data/images', # file/dir/URL/glob/screen/0(webcam) + data=ROOT / 'data/coco.yaml', # dataset.yaml path + imgsz=(640, 640), # inference size (height, width) + conf_thres=0.25, # confidence threshold + iou_thres=0.45, # NMS IOU threshold + max_det=1000, # maximum detections per image + device='', # cuda device, i.e. 0 or 0,1,2,3 or cpu + view_img=False, # show results + save_txt=False, # save results to *.txt + save_conf=False, # save confidences in --save-txt labels + save_crop=False, # save cropped prediction boxes + nosave=False, # do not save images/videos + classes=None, # filter by class: --class 0, or --class 0 2 3 + agnostic_nms=False, # class-agnostic NMS + augment=False, # augmented inference + visualize=False, # visualize features + update=False, # update all models + project=ROOT / 'runs/detect', # save results to project/name + name='exp', # save results to project/name + exist_ok=False, # existing project/name ok, do not increment + line_thickness=3, # bounding box thickness (pixels) + hide_labels=False, # hide labels + hide_conf=False, # hide confidences + half=False, # use FP16 half-precision inference + dnn=False, # use OpenCV DNN for ONNX inference + vid_stride=1, # video frame-rate stride +): + source = str(source) + save_img = not nosave and not source.endswith('.txt') # save inference images + is_file = Path(source).suffix[1:] in (IMG_FORMATS + VID_FORMATS) + is_url = source.lower().startswith(('rtsp://', 'rtmp://', 'http://', 'https://')) + webcam = source.isnumeric() or source.endswith('.txt') or (is_url and not is_file) + screenshot = source.lower().startswith('screen') + if is_url and is_file: + source = check_file(source) # download + + # Directories + save_dir = increment_path(Path(project) / name, exist_ok=exist_ok) # increment run + (save_dir / 'labels' if save_txt else save_dir).mkdir(parents=True, exist_ok=True) # make dir + + # Load model + device = select_device(device) + model = DetectMultiBackend(weights, device=device, dnn=dnn, data=data, fp16=half) + stride, names, pt = model.stride, model.names, model.pt + imgsz = check_img_size(imgsz, s=stride) # check image size + + # Dataloader + bs = 1 # batch_size + if webcam: + view_img = check_imshow(warn=True) + dataset = LoadStreams(source, img_size=imgsz, stride=stride, auto=pt, vid_stride=vid_stride) + bs = len(dataset) + elif screenshot: + dataset = LoadScreenshots(source, img_size=imgsz, stride=stride, auto=pt) + else: + dataset = LoadImages(source, img_size=imgsz, stride=stride, auto=pt, vid_stride=vid_stride) + vid_path, vid_writer = [None] * bs, [None] * bs + + # Run inference + model.warmup(imgsz=(1 if pt or model.triton else bs, 3, *imgsz)) # warmup + seen, windows, dt = 0, [], (Profile(), Profile(), Profile()) + for path, im, im0s, vid_cap, s in dataset: + with dt[0]: + im = torch.from_numpy(im).to(model.device) + im = im.half() if model.fp16 else im.float() # uint8 to fp16/32 + im /= 255 # 0 - 255 to 0.0 - 1.0 + if len(im.shape) == 3: + im = im[None] # expand for batch dim + + # Inference + with dt[1]: + visualize = increment_path(save_dir / Path(path).stem, mkdir=True) if visualize else False + pred = model(im, augment=augment, visualize=visualize) + pred = pred[0][1] + + # NMS + with dt[2]: + pred = non_max_suppression(pred, conf_thres, iou_thres, classes, agnostic_nms, max_det=max_det) + + # Second-stage classifier (optional) + # pred = utils.general.apply_classifier(pred, classifier_model, im, im0s) + + # Process predictions + for i, det in enumerate(pred): # per image + seen += 1 + if webcam: # batch_size >= 1 + p, im0, frame = path[i], im0s[i].copy(), dataset.count + s += f'{i}: ' + else: + p, im0, frame = path, im0s.copy(), getattr(dataset, 'frame', 0) + + p = Path(p) # to Path + save_path = str(save_dir / p.name) # im.jpg + txt_path = str(save_dir / 'labels' / p.stem) + ('' if dataset.mode == 'image' else f'_{frame}') # im.txt + s += '%gx%g ' % im.shape[2:] # print string + gn = torch.tensor(im0.shape)[[1, 0, 1, 0]] # normalization gain whwh + imc = im0.copy() if save_crop else im0 # for save_crop + annotator = Annotator(im0, line_width=line_thickness, example=str(names)) + if len(det): + # Rescale boxes from img_size to im0 size + det[:, :4] = scale_boxes(im.shape[2:], det[:, :4], im0.shape).round() + + # Print results + for c in det[:, 5].unique(): + n = (det[:, 5] == c).sum() # detections per class + s += f"{n} {names[int(c)]}{'s' * (n > 1)}, " # add to string + + # Write results + for *xyxy, conf, cls in reversed(det): + if save_txt: # Write to file + xywh = (xyxy2xywh(torch.tensor(xyxy).view(1, 4)) / gn).view(-1).tolist() # normalized xywh + line = (cls, *xywh, conf) if save_conf else (cls, *xywh) # label format + with open(f'{txt_path}.txt', 'a') as f: + f.write(('%g ' * len(line)).rstrip() % line + '\n') + + if save_img or save_crop or view_img: # Add bbox to image + c = int(cls) # integer class + label = None if hide_labels else (names[c] if hide_conf else f'{names[c]} {conf:.2f}') + annotator.box_label(xyxy, label, color=colors(c, True)) + if save_crop: + save_one_box(xyxy, imc, file=save_dir / 'crops' / names[c] / f'{p.stem}.jpg', BGR=True) + + # Stream results + im0 = annotator.result() + if view_img: + if platform.system() == 'Linux' and p not in windows: + windows.append(p) + cv2.namedWindow(str(p), cv2.WINDOW_NORMAL | cv2.WINDOW_KEEPRATIO) # allow window resize (Linux) + cv2.resizeWindow(str(p), im0.shape[1], im0.shape[0]) + cv2.imshow(str(p), im0) + cv2.waitKey(1) # 1 millisecond + + # Save results (image with detections) + if save_img: + if dataset.mode == 'image': + cv2.imwrite(save_path, im0) + else: # 'video' or 'stream' + if vid_path[i] != save_path: # new video + vid_path[i] = save_path + if isinstance(vid_writer[i], cv2.VideoWriter): + vid_writer[i].release() # release previous video writer + if vid_cap: # video + fps = vid_cap.get(cv2.CAP_PROP_FPS) + w = int(vid_cap.get(cv2.CAP_PROP_FRAME_WIDTH)) + h = int(vid_cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) + else: # stream + fps, w, h = 30, im0.shape[1], im0.shape[0] + save_path = str(Path(save_path).with_suffix('.mp4')) # force *.mp4 suffix on results videos + vid_writer[i] = cv2.VideoWriter(save_path, cv2.VideoWriter_fourcc(*'mp4v'), fps, (w, h)) + vid_writer[i].write(im0) + + # Print time (inference-only) + LOGGER.info(f"{s}{'' if len(det) else '(no detections), '}{dt[1].dt * 1E3:.1f}ms") + + # Print results + t = tuple(x.t / seen * 1E3 for x in dt) # speeds per image + LOGGER.info(f'Speed: %.1fms pre-process, %.1fms inference, %.1fms NMS per image at shape {(1, 3, *imgsz)}' % t) + if save_txt or save_img: + s = f"\n{len(list(save_dir.glob('labels/*.txt')))} labels saved to {save_dir / 'labels'}" if save_txt else '' + LOGGER.info(f"Results saved to {colorstr('bold', save_dir)}{s}") + if update: + strip_optimizer(weights[0]) # update model (to fix SourceChangeWarning) + + +def parse_opt(): + parser = argparse.ArgumentParser() + parser.add_argument('--weights', nargs='+', type=str, default=ROOT / 'yolo.pt', help='model path or triton URL') + parser.add_argument('--source', type=str, default=ROOT / 'data/images', help='file/dir/URL/glob/screen/0(webcam)') + parser.add_argument('--data', type=str, default=ROOT / 'data/coco128.yaml', help='(optional) dataset.yaml path') + parser.add_argument('--imgsz', '--img', '--img-size', nargs='+', type=int, default=[640], help='inference size h,w') + parser.add_argument('--conf-thres', type=float, default=0.25, help='confidence threshold') + parser.add_argument('--iou-thres', type=float, default=0.45, help='NMS IoU threshold') + parser.add_argument('--max-det', type=int, default=1000, help='maximum detections per image') + parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu') + parser.add_argument('--view-img', action='store_true', help='show results') + parser.add_argument('--save-txt', action='store_true', help='save results to *.txt') + parser.add_argument('--save-conf', action='store_true', help='save confidences in --save-txt labels') + parser.add_argument('--save-crop', action='store_true', help='save cropped prediction boxes') + parser.add_argument('--nosave', action='store_true', help='do not save images/videos') + parser.add_argument('--classes', nargs='+', type=int, help='filter by class: --classes 0, or --classes 0 2 3') + parser.add_argument('--agnostic-nms', action='store_true', help='class-agnostic NMS') + parser.add_argument('--augment', action='store_true', help='augmented inference') + parser.add_argument('--visualize', action='store_true', help='visualize features') + parser.add_argument('--update', action='store_true', help='update all models') + parser.add_argument('--project', default=ROOT / 'runs/detect', help='save results to project/name') + parser.add_argument('--name', default='exp', help='save results to project/name') + parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment') + parser.add_argument('--line-thickness', default=3, type=int, help='bounding box thickness (pixels)') + parser.add_argument('--hide-labels', default=False, action='store_true', help='hide labels') + parser.add_argument('--hide-conf', default=False, action='store_true', help='hide confidences') + parser.add_argument('--half', action='store_true', help='use FP16 half-precision inference') + parser.add_argument('--dnn', action='store_true', help='use OpenCV DNN for ONNX inference') + parser.add_argument('--vid-stride', type=int, default=1, help='video frame-rate stride') + opt = parser.parse_args() + opt.imgsz *= 2 if len(opt.imgsz) == 1 else 1 # expand + print_args(vars(opt)) + return opt + + +def main(opt): + # check_requirements(exclude=('tensorboard', 'thop')) + run(**vars(opt)) + + +if __name__ == "__main__": + opt = parse_opt() + main(opt) diff --git a/cv/3d_detection/yolov9/pytorch/export.py b/cv/3d_detection/yolov9/pytorch/export.py new file mode 100644 index 000000000..2ef415c1a --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/export.py @@ -0,0 +1,686 @@ +import argparse +import contextlib +import json +import os +import platform +import re +import subprocess +import sys +import time +import warnings +from pathlib import Path + +import pandas as pd +import torch +from torch.utils.mobile_optimizer import optimize_for_mobile + +FILE = Path(__file__).resolve() +ROOT = FILE.parents[0] # YOLO root directory +if str(ROOT) not in sys.path: + sys.path.append(str(ROOT)) # add ROOT to PATH +if platform.system() != 'Windows': + ROOT = Path(os.path.relpath(ROOT, Path.cwd())) # relative + +from models.experimental import attempt_load, End2End +from models.yolo import ClassificationModel, Detect, DDetect, DualDetect, DualDDetect, DetectionModel, SegmentationModel +from utils.dataloaders import LoadImages +from utils.general import (LOGGER, Profile, check_dataset, check_img_size, check_requirements, check_version, + check_yaml, colorstr, file_size, get_default_args, print_args, url2file, yaml_save) +from utils.torch_utils import select_device, smart_inference_mode + +MACOS = platform.system() == 'Darwin' # macOS environment + + +def export_formats(): + # YOLO export formats + x = [ + ['PyTorch', '-', '.pt', True, True], + ['TorchScript', 'torchscript', '.torchscript', True, True], + ['ONNX', 'onnx', '.onnx', True, True], + ['ONNX END2END', 'onnx_end2end', '_end2end.onnx', True, True], + ['OpenVINO', 'openvino', '_openvino_model', True, False], + ['TensorRT', 'engine', '.engine', False, True], + ['CoreML', 'coreml', '.mlmodel', True, False], + ['TensorFlow SavedModel', 'saved_model', '_saved_model', True, True], + ['TensorFlow GraphDef', 'pb', '.pb', True, True], + ['TensorFlow Lite', 'tflite', '.tflite', True, False], + ['TensorFlow Edge TPU', 'edgetpu', '_edgetpu.tflite', False, False], + ['TensorFlow.js', 'tfjs', '_web_model', False, False], + ['PaddlePaddle', 'paddle', '_paddle_model', True, True],] + return pd.DataFrame(x, columns=['Format', 'Argument', 'Suffix', 'CPU', 'GPU']) + + +def try_export(inner_func): + # YOLO export decorator, i..e @try_export + inner_args = get_default_args(inner_func) + + def outer_func(*args, **kwargs): + prefix = inner_args['prefix'] + try: + with Profile() as dt: + f, model = inner_func(*args, **kwargs) + LOGGER.info(f'{prefix} export success ✅ {dt.t:.1f}s, saved as {f} ({file_size(f):.1f} MB)') + return f, model + except Exception as e: + LOGGER.info(f'{prefix} export failure ❌ {dt.t:.1f}s: {e}') + return None, None + + return outer_func + + +@try_export +def export_torchscript(model, im, file, optimize, prefix=colorstr('TorchScript:')): + # YOLO TorchScript model export + LOGGER.info(f'\n{prefix} starting export with torch {torch.__version__}...') + f = file.with_suffix('.torchscript') + + ts = torch.jit.trace(model, im, strict=False) + d = {"shape": im.shape, "stride": int(max(model.stride)), "names": model.names} + extra_files = {'config.txt': json.dumps(d)} # torch._C.ExtraFilesMap() + if optimize: # https://pytorch.org/tutorials/recipes/mobile_interpreter.html + optimize_for_mobile(ts)._save_for_lite_interpreter(str(f), _extra_files=extra_files) + else: + ts.save(str(f), _extra_files=extra_files) + return f, None + + +@try_export +def export_onnx(model, im, file, opset, dynamic, simplify, prefix=colorstr('ONNX:')): + # YOLO ONNX export + check_requirements('onnx') + import onnx + + LOGGER.info(f'\n{prefix} starting export with onnx {onnx.__version__}...') + f = file.with_suffix('.onnx') + + output_names = ['output0', 'output1'] if isinstance(model, SegmentationModel) else ['output0'] + if dynamic: + dynamic = {'images': {0: 'batch', 2: 'height', 3: 'width'}} # shape(1,3,640,640) + if isinstance(model, SegmentationModel): + dynamic['output0'] = {0: 'batch', 1: 'anchors'} # shape(1,25200,85) + dynamic['output1'] = {0: 'batch', 2: 'mask_height', 3: 'mask_width'} # shape(1,32,160,160) + elif isinstance(model, DetectionModel): + dynamic['output0'] = {0: 'batch', 1: 'anchors'} # shape(1,25200,85) + + torch.onnx.export( + model.cpu() if dynamic else model, # --dynamic only compatible with cpu + im.cpu() if dynamic else im, + f, + verbose=False, + opset_version=opset, + do_constant_folding=True, + input_names=['images'], + output_names=output_names, + dynamic_axes=dynamic or None) + + # Checks + model_onnx = onnx.load(f) # load onnx model + onnx.checker.check_model(model_onnx) # check onnx model + + # Metadata + d = {'stride': int(max(model.stride)), 'names': model.names} + for k, v in d.items(): + meta = model_onnx.metadata_props.add() + meta.key, meta.value = k, str(v) + onnx.save(model_onnx, f) + + # Simplify + if simplify: + try: + cuda = torch.cuda.is_available() + check_requirements(('onnxruntime-gpu' if cuda else 'onnxruntime', 'onnx-simplifier>=0.4.1')) + import onnxsim + + LOGGER.info(f'{prefix} simplifying with onnx-simplifier {onnxsim.__version__}...') + model_onnx, check = onnxsim.simplify(model_onnx) + assert check, 'assert check failed' + onnx.save(model_onnx, f) + except Exception as e: + LOGGER.info(f'{prefix} simplifier failure: {e}') + return f, model_onnx + + +@try_export +def export_onnx_end2end(model, im, file, simplify, topk_all, iou_thres, conf_thres, device, labels, prefix=colorstr('ONNX END2END:')): + # YOLO ONNX export + check_requirements('onnx') + import onnx + LOGGER.info(f'\n{prefix} starting export with onnx {onnx.__version__}...') + f = os.path.splitext(file)[0] + "-end2end.onnx" + batch_size = 'batch' + + dynamic_axes = {'images': {0 : 'batch', 2: 'height', 3:'width'}, } # variable length axes + + output_axes = { + 'num_dets': {0: 'batch'}, + 'det_boxes': {0: 'batch'}, + 'det_scores': {0: 'batch'}, + 'det_classes': {0: 'batch'}, + } + dynamic_axes.update(output_axes) + model = End2End(model, topk_all, iou_thres, conf_thres, None ,device, labels) + + output_names = ['num_dets', 'det_boxes', 'det_scores', 'det_classes'] + shapes = [ batch_size, 1, batch_size, topk_all, 4, + batch_size, topk_all, batch_size, topk_all] + + torch.onnx.export(model, + im, + f, + verbose=False, + export_params=True, # store the trained parameter weights inside the model file + opset_version=12, + do_constant_folding=True, # whether to execute constant folding for optimization + input_names=['images'], + output_names=output_names, + dynamic_axes=dynamic_axes) + + # Checks + model_onnx = onnx.load(f) # load onnx model + onnx.checker.check_model(model_onnx) # check onnx model + for i in model_onnx.graph.output: + for j in i.type.tensor_type.shape.dim: + j.dim_param = str(shapes.pop(0)) + + if simplify: + try: + import onnxsim + + print('\nStarting to simplify ONNX...') + model_onnx, check = onnxsim.simplify(model_onnx) + assert check, 'assert check failed' + except Exception as e: + print(f'Simplifier failure: {e}') + + # print(onnx.helper.printable_graph(onnx_model.graph)) # print a human readable model + onnx.save(model_onnx,f) + print('ONNX export success, saved as %s' % f) + return f, model_onnx + + +@try_export +def export_openvino(file, metadata, half, prefix=colorstr('OpenVINO:')): + # YOLO OpenVINO export + check_requirements('openvino-dev') # requires openvino-dev: https://pypi.org/project/openvino-dev/ + import openvino.inference_engine as ie + + LOGGER.info(f'\n{prefix} starting export with openvino {ie.__version__}...') + f = str(file).replace('.pt', f'_openvino_model{os.sep}') + + #cmd = f"mo --input_model {file.with_suffix('.onnx')} --output_dir {f} --data_type {'FP16' if half else 'FP32'}" + #cmd = f"mo --input_model {file.with_suffix('.onnx')} --output_dir {f} {"--compress_to_fp16" if half else ""}" + half_arg = "--compress_to_fp16" if half else "" + cmd = f"mo --input_model {file.with_suffix('.onnx')} --output_dir {f} {half_arg}" + subprocess.run(cmd.split(), check=True, env=os.environ) # export + yaml_save(Path(f) / file.with_suffix('.yaml').name, metadata) # add metadata.yaml + return f, None + + +@try_export +def export_paddle(model, im, file, metadata, prefix=colorstr('PaddlePaddle:')): + # YOLO Paddle export + check_requirements(('paddlepaddle', 'x2paddle')) + import x2paddle + from x2paddle.convert import pytorch2paddle + + LOGGER.info(f'\n{prefix} starting export with X2Paddle {x2paddle.__version__}...') + f = str(file).replace('.pt', f'_paddle_model{os.sep}') + + pytorch2paddle(module=model, save_dir=f, jit_type='trace', input_examples=[im]) # export + yaml_save(Path(f) / file.with_suffix('.yaml').name, metadata) # add metadata.yaml + return f, None + + +@try_export +def export_coreml(model, im, file, int8, half, prefix=colorstr('CoreML:')): + # YOLO CoreML export + check_requirements('coremltools') + import coremltools as ct + + LOGGER.info(f'\n{prefix} starting export with coremltools {ct.__version__}...') + f = file.with_suffix('.mlmodel') + + ts = torch.jit.trace(model, im, strict=False) # TorchScript model + ct_model = ct.convert(ts, inputs=[ct.ImageType('image', shape=im.shape, scale=1 / 255, bias=[0, 0, 0])]) + bits, mode = (8, 'kmeans_lut') if int8 else (16, 'linear') if half else (32, None) + if bits < 32: + if MACOS: # quantization only supported on macOS + with warnings.catch_warnings(): + warnings.filterwarnings("ignore", category=DeprecationWarning) # suppress numpy==1.20 float warning + ct_model = ct.models.neural_network.quantization_utils.quantize_weights(ct_model, bits, mode) + else: + print(f'{prefix} quantization only supported on macOS, skipping...') + ct_model.save(f) + return f, ct_model + + +@try_export +def export_engine(model, im, file, half, dynamic, simplify, workspace=4, verbose=False, prefix=colorstr('TensorRT:')): + # YOLO TensorRT export https://developer.nvidia.com/tensorrt + assert im.device.type != 'cpu', 'export running on CPU but must be on GPU, i.e. `python export.py --device 0`' + try: + import tensorrt as trt + except Exception: + if platform.system() == 'Linux': + check_requirements('nvidia-tensorrt', cmds='-U --index-url https://pypi.ngc.nvidia.com') + import tensorrt as trt + + if trt.__version__[0] == '7': # TensorRT 7 handling https://github.com/ultralytics/yolov5/issues/6012 + grid = model.model[-1].anchor_grid + model.model[-1].anchor_grid = [a[..., :1, :1, :] for a in grid] + export_onnx(model, im, file, 12, dynamic, simplify) # opset 12 + model.model[-1].anchor_grid = grid + else: # TensorRT >= 8 + check_version(trt.__version__, '8.0.0', hard=True) # require tensorrt>=8.0.0 + export_onnx(model, im, file, 12, dynamic, simplify) # opset 12 + onnx = file.with_suffix('.onnx') + + LOGGER.info(f'\n{prefix} starting export with TensorRT {trt.__version__}...') + assert onnx.exists(), f'failed to export ONNX file: {onnx}' + f = file.with_suffix('.engine') # TensorRT engine file + logger = trt.Logger(trt.Logger.INFO) + if verbose: + logger.min_severity = trt.Logger.Severity.VERBOSE + + builder = trt.Builder(logger) + config = builder.create_builder_config() + config.max_workspace_size = workspace * 1 << 30 + # config.set_memory_pool_limit(trt.MemoryPoolType.WORKSPACE, workspace << 30) # fix TRT 8.4 deprecation notice + + flag = (1 << int(trt.NetworkDefinitionCreationFlag.EXPLICIT_BATCH)) + network = builder.create_network(flag) + parser = trt.OnnxParser(network, logger) + if not parser.parse_from_file(str(onnx)): + raise RuntimeError(f'failed to load ONNX file: {onnx}') + + inputs = [network.get_input(i) for i in range(network.num_inputs)] + outputs = [network.get_output(i) for i in range(network.num_outputs)] + for inp in inputs: + LOGGER.info(f'{prefix} input "{inp.name}" with shape{inp.shape} {inp.dtype}') + for out in outputs: + LOGGER.info(f'{prefix} output "{out.name}" with shape{out.shape} {out.dtype}') + + if dynamic: + if im.shape[0] <= 1: + LOGGER.warning(f"{prefix} WARNING ⚠️ --dynamic model requires maximum --batch-size argument") + profile = builder.create_optimization_profile() + for inp in inputs: + profile.set_shape(inp.name, (1, *im.shape[1:]), (max(1, im.shape[0] // 2), *im.shape[1:]), im.shape) + config.add_optimization_profile(profile) + + LOGGER.info(f'{prefix} building FP{16 if builder.platform_has_fast_fp16 and half else 32} engine as {f}') + if builder.platform_has_fast_fp16 and half: + config.set_flag(trt.BuilderFlag.FP16) + with builder.build_engine(network, config) as engine, open(f, 'wb') as t: + t.write(engine.serialize()) + return f, None + + +@try_export +def export_saved_model(model, + im, + file, + dynamic, + tf_nms=False, + agnostic_nms=False, + topk_per_class=100, + topk_all=100, + iou_thres=0.45, + conf_thres=0.25, + keras=False, + prefix=colorstr('TensorFlow SavedModel:')): + # YOLO TensorFlow SavedModel export + try: + import tensorflow as tf + except Exception: + check_requirements(f"tensorflow{'' if torch.cuda.is_available() else '-macos' if MACOS else '-cpu'}") + import tensorflow as tf + from tensorflow.python.framework.convert_to_constants import convert_variables_to_constants_v2 + + from models.tf import TFModel + + LOGGER.info(f'\n{prefix} starting export with tensorflow {tf.__version__}...') + f = str(file).replace('.pt', '_saved_model') + batch_size, ch, *imgsz = list(im.shape) # BCHW + + tf_model = TFModel(cfg=model.yaml, model=model, nc=model.nc, imgsz=imgsz) + im = tf.zeros((batch_size, *imgsz, ch)) # BHWC order for TensorFlow + _ = tf_model.predict(im, tf_nms, agnostic_nms, topk_per_class, topk_all, iou_thres, conf_thres) + inputs = tf.keras.Input(shape=(*imgsz, ch), batch_size=None if dynamic else batch_size) + outputs = tf_model.predict(inputs, tf_nms, agnostic_nms, topk_per_class, topk_all, iou_thres, conf_thres) + keras_model = tf.keras.Model(inputs=inputs, outputs=outputs) + keras_model.trainable = False + keras_model.summary() + if keras: + keras_model.save(f, save_format='tf') + else: + spec = tf.TensorSpec(keras_model.inputs[0].shape, keras_model.inputs[0].dtype) + m = tf.function(lambda x: keras_model(x)) # full model + m = m.get_concrete_function(spec) + frozen_func = convert_variables_to_constants_v2(m) + tfm = tf.Module() + tfm.__call__ = tf.function(lambda x: frozen_func(x)[:4] if tf_nms else frozen_func(x), [spec]) + tfm.__call__(im) + tf.saved_model.save(tfm, + f, + options=tf.saved_model.SaveOptions(experimental_custom_gradients=False) if check_version( + tf.__version__, '2.6') else tf.saved_model.SaveOptions()) + return f, keras_model + + +@try_export +def export_pb(keras_model, file, prefix=colorstr('TensorFlow GraphDef:')): + # YOLO TensorFlow GraphDef *.pb export https://github.com/leimao/Frozen_Graph_TensorFlow + import tensorflow as tf + from tensorflow.python.framework.convert_to_constants import convert_variables_to_constants_v2 + + LOGGER.info(f'\n{prefix} starting export with tensorflow {tf.__version__}...') + f = file.with_suffix('.pb') + + m = tf.function(lambda x: keras_model(x)) # full model + m = m.get_concrete_function(tf.TensorSpec(keras_model.inputs[0].shape, keras_model.inputs[0].dtype)) + frozen_func = convert_variables_to_constants_v2(m) + frozen_func.graph.as_graph_def() + tf.io.write_graph(graph_or_graph_def=frozen_func.graph, logdir=str(f.parent), name=f.name, as_text=False) + return f, None + + +@try_export +def export_tflite(keras_model, im, file, int8, data, nms, agnostic_nms, prefix=colorstr('TensorFlow Lite:')): + # YOLOv5 TensorFlow Lite export + import tensorflow as tf + + LOGGER.info(f'\n{prefix} starting export with tensorflow {tf.__version__}...') + batch_size, ch, *imgsz = list(im.shape) # BCHW + f = str(file).replace('.pt', '-fp16.tflite') + + converter = tf.lite.TFLiteConverter.from_keras_model(keras_model) + converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS] + converter.target_spec.supported_types = [tf.float16] + converter.optimizations = [tf.lite.Optimize.DEFAULT] + if int8: + from models.tf import representative_dataset_gen + dataset = LoadImages(check_dataset(check_yaml(data))['train'], img_size=imgsz, auto=False) + converter.representative_dataset = lambda: representative_dataset_gen(dataset, ncalib=100) + converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS_INT8] + converter.target_spec.supported_types = [] + converter.inference_input_type = tf.uint8 # or tf.int8 + converter.inference_output_type = tf.uint8 # or tf.int8 + converter.experimental_new_quantizer = True + f = str(file).replace('.pt', '-int8.tflite') + if nms or agnostic_nms: + converter.target_spec.supported_ops.append(tf.lite.OpsSet.SELECT_TF_OPS) + + tflite_model = converter.convert() + open(f, "wb").write(tflite_model) + return f, None + + +@try_export +def export_edgetpu(file, prefix=colorstr('Edge TPU:')): + # YOLO Edge TPU export https://coral.ai/docs/edgetpu/models-intro/ + cmd = 'edgetpu_compiler --version' + help_url = 'https://coral.ai/docs/edgetpu/compiler/' + assert platform.system() == 'Linux', f'export only supported on Linux. See {help_url}' + if subprocess.run(f'{cmd} >/dev/null', shell=True).returncode != 0: + LOGGER.info(f'\n{prefix} export requires Edge TPU compiler. Attempting install from {help_url}') + sudo = subprocess.run('sudo --version >/dev/null', shell=True).returncode == 0 # sudo installed on system + for c in ( + 'curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -', + 'echo "deb https://packages.cloud.google.com/apt coral-edgetpu-stable main" | sudo tee /etc/apt/sources.list.d/coral-edgetpu.list', + 'sudo apt-get update', 'sudo apt-get install edgetpu-compiler'): + subprocess.run(c if sudo else c.replace('sudo ', ''), shell=True, check=True) + ver = subprocess.run(cmd, shell=True, capture_output=True, check=True).stdout.decode().split()[-1] + + LOGGER.info(f'\n{prefix} starting export with Edge TPU compiler {ver}...') + f = str(file).replace('.pt', '-int8_edgetpu.tflite') # Edge TPU model + f_tfl = str(file).replace('.pt', '-int8.tflite') # TFLite model + + cmd = f"edgetpu_compiler -s -d -k 10 --out_dir {file.parent} {f_tfl}" + subprocess.run(cmd.split(), check=True) + return f, None + + +@try_export +def export_tfjs(file, prefix=colorstr('TensorFlow.js:')): + # YOLO TensorFlow.js export + check_requirements('tensorflowjs') + import tensorflowjs as tfjs + + LOGGER.info(f'\n{prefix} starting export with tensorflowjs {tfjs.__version__}...') + f = str(file).replace('.pt', '_web_model') # js dir + f_pb = file.with_suffix('.pb') # *.pb path + f_json = f'{f}/model.json' # *.json path + + cmd = f'tensorflowjs_converter --input_format=tf_frozen_model ' \ + f'--output_node_names=Identity,Identity_1,Identity_2,Identity_3 {f_pb} {f}' + subprocess.run(cmd.split()) + + json = Path(f_json).read_text() + with open(f_json, 'w') as j: # sort JSON Identity_* in ascending order + subst = re.sub( + r'{"outputs": {"Identity.?.?": {"name": "Identity.?.?"}, ' + r'"Identity.?.?": {"name": "Identity.?.?"}, ' + r'"Identity.?.?": {"name": "Identity.?.?"}, ' + r'"Identity.?.?": {"name": "Identity.?.?"}}}', r'{"outputs": {"Identity": {"name": "Identity"}, ' + r'"Identity_1": {"name": "Identity_1"}, ' + r'"Identity_2": {"name": "Identity_2"}, ' + r'"Identity_3": {"name": "Identity_3"}}}', json) + j.write(subst) + return f, None + + +def add_tflite_metadata(file, metadata, num_outputs): + # Add metadata to *.tflite models per https://www.tensorflow.org/lite/models/convert/metadata + with contextlib.suppress(ImportError): + # check_requirements('tflite_support') + from tflite_support import flatbuffers + from tflite_support import metadata as _metadata + from tflite_support import metadata_schema_py_generated as _metadata_fb + + tmp_file = Path('/tmp/meta.txt') + with open(tmp_file, 'w') as meta_f: + meta_f.write(str(metadata)) + + model_meta = _metadata_fb.ModelMetadataT() + label_file = _metadata_fb.AssociatedFileT() + label_file.name = tmp_file.name + model_meta.associatedFiles = [label_file] + + subgraph = _metadata_fb.SubGraphMetadataT() + subgraph.inputTensorMetadata = [_metadata_fb.TensorMetadataT()] + subgraph.outputTensorMetadata = [_metadata_fb.TensorMetadataT()] * num_outputs + model_meta.subgraphMetadata = [subgraph] + + b = flatbuffers.Builder(0) + b.Finish(model_meta.Pack(b), _metadata.MetadataPopulator.METADATA_FILE_IDENTIFIER) + metadata_buf = b.Output() + + populator = _metadata.MetadataPopulator.with_model_file(file) + populator.load_metadata_buffer(metadata_buf) + populator.load_associated_files([str(tmp_file)]) + populator.populate() + tmp_file.unlink() + + +@smart_inference_mode() +def run( + data=ROOT / 'data/coco.yaml', # 'dataset.yaml path' + weights=ROOT / 'yolo.pt', # weights path + imgsz=(640, 640), # image (height, width) + batch_size=1, # batch size + device='cpu', # cuda device, i.e. 0 or 0,1,2,3 or cpu + include=('torchscript', 'onnx'), # include formats + half=False, # FP16 half-precision export + inplace=False, # set YOLO Detect() inplace=True + keras=False, # use Keras + optimize=False, # TorchScript: optimize for mobile + int8=False, # CoreML/TF INT8 quantization + dynamic=False, # ONNX/TF/TensorRT: dynamic axes + simplify=False, # ONNX: simplify model + opset=12, # ONNX: opset version + verbose=False, # TensorRT: verbose log + workspace=4, # TensorRT: workspace size (GB) + nms=False, # TF: add NMS to model + agnostic_nms=False, # TF: add agnostic NMS to model + topk_per_class=100, # TF.js NMS: topk per class to keep + topk_all=100, # TF.js NMS: topk for all classes to keep + iou_thres=0.45, # TF.js NMS: IoU threshold + conf_thres=0.25, # TF.js NMS: confidence threshold +): + t = time.time() + include = [x.lower() for x in include] # to lowercase + fmts = tuple(export_formats()['Argument'][1:]) # --include arguments + flags = [x in include for x in fmts] + assert sum(flags) == len(include), f'ERROR: Invalid --include {include}, valid --include arguments are {fmts}' + jit, onnx, onnx_end2end, xml, engine, coreml, saved_model, pb, tflite, edgetpu, tfjs, paddle = flags # export booleans + file = Path(url2file(weights) if str(weights).startswith(('http:/', 'https:/')) else weights) # PyTorch weights + + # Load PyTorch model + device = select_device(device) + if half: + assert device.type != 'cpu' or coreml, '--half only compatible with GPU export, i.e. use --device 0' + assert not dynamic, '--half not compatible with --dynamic, i.e. use either --half or --dynamic but not both' + model = attempt_load(weights, device=device, inplace=True, fuse=True) # load FP32 model + + # Checks + imgsz *= 2 if len(imgsz) == 1 else 1 # expand + if optimize: + assert device.type == 'cpu', '--optimize not compatible with cuda devices, i.e. use --device cpu' + + # Input + gs = int(max(model.stride)) # grid size (max stride) + imgsz = [check_img_size(x, gs) for x in imgsz] # verify img_size are gs-multiples + im = torch.zeros(batch_size, 3, *imgsz).to(device) # image size(1,3,320,192) BCHW iDetection + + # Update model + model.eval() + for k, m in model.named_modules(): + if isinstance(m, (Detect, DDetect, DualDetect, DualDDetect)): + m.inplace = inplace + m.dynamic = dynamic + m.export = True + + for _ in range(2): + y = model(im) # dry runs + if half and not coreml: + im, model = im.half(), model.half() # to FP16 + shape = tuple((y[0] if isinstance(y, (tuple, list)) else y).shape) # model output shape + metadata = {'stride': int(max(model.stride)), 'names': model.names} # model metadata + LOGGER.info(f"\n{colorstr('PyTorch:')} starting from {file} with output shape {shape} ({file_size(file):.1f} MB)") + + # Exports + f = [''] * len(fmts) # exported filenames + warnings.filterwarnings(action='ignore', category=torch.jit.TracerWarning) # suppress TracerWarning + if jit: # TorchScript + f[0], _ = export_torchscript(model, im, file, optimize) + if engine: # TensorRT required before ONNX + f[1], _ = export_engine(model, im, file, half, dynamic, simplify, workspace, verbose) + if onnx or xml: # OpenVINO requires ONNX + f[2], _ = export_onnx(model, im, file, opset, dynamic, simplify) + if onnx_end2end: + if isinstance(model, DetectionModel): + labels = model.names + f[2], _ = export_onnx_end2end(model, im, file, simplify, topk_all, iou_thres, conf_thres, device, len(labels)) + else: + raise RuntimeError("The model is not a DetectionModel.") + if xml: # OpenVINO + f[3], _ = export_openvino(file, metadata, half) + if coreml: # CoreML + f[4], _ = export_coreml(model, im, file, int8, half) + if any((saved_model, pb, tflite, edgetpu, tfjs)): # TensorFlow formats + assert not tflite or not tfjs, 'TFLite and TF.js models must be exported separately, please pass only one type.' + assert not isinstance(model, ClassificationModel), 'ClassificationModel export to TF formats not yet supported.' + f[5], s_model = export_saved_model(model.cpu(), + im, + file, + dynamic, + tf_nms=nms or agnostic_nms or tfjs, + agnostic_nms=agnostic_nms or tfjs, + topk_per_class=topk_per_class, + topk_all=topk_all, + iou_thres=iou_thres, + conf_thres=conf_thres, + keras=keras) + if pb or tfjs: # pb prerequisite to tfjs + f[6], _ = export_pb(s_model, file) + if tflite or edgetpu: + f[7], _ = export_tflite(s_model, im, file, int8 or edgetpu, data=data, nms=nms, agnostic_nms=agnostic_nms) + if edgetpu: + f[8], _ = export_edgetpu(file) + add_tflite_metadata(f[8] or f[7], metadata, num_outputs=len(s_model.outputs)) + if tfjs: + f[9], _ = export_tfjs(file) + if paddle: # PaddlePaddle + f[10], _ = export_paddle(model, im, file, metadata) + + # Finish + f = [str(x) for x in f if x] # filter out '' and None + if any(f): + cls, det, seg = (isinstance(model, x) for x in (ClassificationModel, DetectionModel, SegmentationModel)) # type + dir = Path('segment' if seg else 'classify' if cls else '') + h = '--half' if half else '' # --half FP16 inference arg + s = "# WARNING ⚠️ ClassificationModel not yet supported for PyTorch Hub AutoShape inference" if cls else \ + "# WARNING ⚠️ SegmentationModel not yet supported for PyTorch Hub AutoShape inference" if seg else '' + if onnx_end2end: + LOGGER.info(f'\nExport complete ({time.time() - t:.1f}s)' + f"\nResults saved to {colorstr('bold', file.parent.resolve())}" + f"\nVisualize: https://netron.app") + else: + LOGGER.info(f'\nExport complete ({time.time() - t:.1f}s)' + f"\nResults saved to {colorstr('bold', file.parent.resolve())}" + f"\nDetect: python {dir / ('detect.py' if det else 'predict.py')} --weights {f[-1]} {h}" + f"\nValidate: python {dir / 'val.py'} --weights {f[-1]} {h}" + f"\nPyTorch Hub: model = torch.hub.load('ultralytics/yolov5', 'custom', '{f[-1]}') {s}" + f"\nVisualize: https://netron.app") + return f # return list of exported files/dirs + + +def parse_opt(): + parser = argparse.ArgumentParser() + parser.add_argument('--data', type=str, default=ROOT / 'data/coco.yaml', help='dataset.yaml path') + parser.add_argument('--weights', nargs='+', type=str, default=ROOT / 'yolo.pt', help='model.pt path(s)') + parser.add_argument('--imgsz', '--img', '--img-size', nargs='+', type=int, default=[640, 640], help='image (h, w)') + parser.add_argument('--batch-size', type=int, default=1, help='batch size') + parser.add_argument('--device', default='cpu', help='cuda device, i.e. 0 or 0,1,2,3 or cpu') + parser.add_argument('--half', action='store_true', help='FP16 half-precision export') + parser.add_argument('--inplace', action='store_true', help='set YOLO Detect() inplace=True') + parser.add_argument('--keras', action='store_true', help='TF: use Keras') + parser.add_argument('--optimize', action='store_true', help='TorchScript: optimize for mobile') + parser.add_argument('--int8', action='store_true', help='CoreML/TF INT8 quantization') + parser.add_argument('--dynamic', action='store_true', help='ONNX/TF/TensorRT: dynamic axes') + parser.add_argument('--simplify', action='store_true', help='ONNX: simplify model') + parser.add_argument('--opset', type=int, default=12, help='ONNX: opset version') + parser.add_argument('--verbose', action='store_true', help='TensorRT: verbose log') + parser.add_argument('--workspace', type=int, default=4, help='TensorRT: workspace size (GB)') + parser.add_argument('--nms', action='store_true', help='TF: add NMS to model') + parser.add_argument('--agnostic-nms', action='store_true', help='TF: add agnostic NMS to model') + parser.add_argument('--topk-per-class', type=int, default=100, help='TF.js NMS: topk per class to keep') + parser.add_argument('--topk-all', type=int, default=100, help='ONNX END2END/TF.js NMS: topk for all classes to keep') + parser.add_argument('--iou-thres', type=float, default=0.45, help='ONNX END2END/TF.js NMS: IoU threshold') + parser.add_argument('--conf-thres', type=float, default=0.25, help='ONNX END2END/TF.js NMS: confidence threshold') + parser.add_argument( + '--include', + nargs='+', + default=['torchscript'], + help='torchscript, onnx, onnx_end2end, openvino, engine, coreml, saved_model, pb, tflite, edgetpu, tfjs, paddle') + opt = parser.parse_args() + + if 'onnx_end2end' in opt.include: + opt.simplify = True + opt.dynamic = True + opt.inplace = True + opt.half = False + + print_args(vars(opt)) + return opt + + +def main(opt): + for opt.weights in (opt.weights if isinstance(opt.weights, list) else [opt.weights]): + run(**vars(opt)) + + +if __name__ == "__main__": + opt = parse_opt() + main(opt) diff --git a/cv/3d_detection/yolov9/pytorch/figure/horses_prediction.jpg b/cv/3d_detection/yolov9/pytorch/figure/horses_prediction.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0fbfc83f8ef44a6e6ef170d70a73980de078e5db GIT binary patch literal 158176 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

BVP4eXXFh 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

yZBd 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 Q$2p>xvgX#~yIl|e*{|`^MgRZ+ literal 0 HcmV?d00001 diff --git a/cv/3d_detection/yolov9/pytorch/figure/multitask.png b/cv/3d_detection/yolov9/pytorch/figure/multitask.png new file mode 100644 index 0000000000000000000000000000000000000000..5bf893cb8e3e5bd288ef035fd67b22474b908039 GIT binary patch literal 1292320 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%0As@dD(ePOS4*q! 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%0A%3lxciXRk|B9})pj#JNSI7Ky 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

(tQiLs(MtCUq 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

    ^f+3I@}t%JUVkYAS6|7)wbzR9#+4Gh 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

    9vH*dFO1=9 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%0AaLr0xqQQ^J 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%0D75NE@&Q%!Js$C0MhW>KB9y9^_^x4IDdh& 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 WGEFBj=nu|n%moMqLSY2{JP|o*r#qRDWIz> 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 Y9a`!V%`$mGx!n;XeN%LWu2b}X0p)#AD*ylh literal 0 HcmV?d00001 diff --git a/cv/3d_detection/yolov9/pytorch/hubconf.py b/cv/3d_detection/yolov9/pytorch/hubconf.py new file mode 100644 index 000000000..b4d6b6e41 --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/hubconf.py @@ -0,0 +1,107 @@ +import torch + + +def _create(name, pretrained=True, channels=3, classes=80, autoshape=True, verbose=True, device=None): + """Creates or loads a YOLO model + + Arguments: + name (str): model name 'yolov3' or path 'path/to/best.pt' + pretrained (bool): load pretrained weights into the model + channels (int): number of input channels + classes (int): number of model classes + autoshape (bool): apply YOLO .autoshape() wrapper to model + verbose (bool): print all information to screen + device (str, torch.device, None): device to use for model parameters + + Returns: + YOLO model + """ + from pathlib import Path + + from models.common import AutoShape, DetectMultiBackend + from models.experimental import attempt_load + from models.yolo import ClassificationModel, DetectionModel, SegmentationModel + from utils.downloads import attempt_download + from utils.general import LOGGER, check_requirements, intersect_dicts, logging + from utils.torch_utils import select_device + + if not verbose: + LOGGER.setLevel(logging.WARNING) + check_requirements(exclude=('opencv-python', 'tensorboard', 'thop')) + name = Path(name) + path = name.with_suffix('.pt') if name.suffix == '' and not name.is_dir() else name # checkpoint path + try: + device = select_device(device) + if pretrained and channels == 3 and classes == 80: + try: + model = DetectMultiBackend(path, device=device, fuse=autoshape) # detection model + if autoshape: + if model.pt and isinstance(model.model, ClassificationModel): + LOGGER.warning('WARNING ⚠️ YOLO ClassificationModel is not yet AutoShape compatible. ' + 'You must pass torch tensors in BCHW to this model, i.e. shape(1,3,224,224).') + elif model.pt and isinstance(model.model, SegmentationModel): + LOGGER.warning('WARNING ⚠️ YOLO SegmentationModel is not yet AutoShape compatible. ' + 'You will not be able to run inference with this model.') + else: + model = AutoShape(model) # for file/URI/PIL/cv2/np inputs and NMS + except Exception: + model = attempt_load(path, device=device, fuse=False) # arbitrary model + else: + cfg = list((Path(__file__).parent / 'models').rglob(f'{path.stem}.yaml'))[0] # model.yaml path + model = DetectionModel(cfg, channels, classes) # create model + if pretrained: + ckpt = torch.load(attempt_download(path), map_location=device) # load + csd = ckpt['model'].float().state_dict() # checkpoint state_dict as FP32 + csd = intersect_dicts(csd, model.state_dict(), exclude=['anchors']) # intersect + model.load_state_dict(csd, strict=False) # load + if len(ckpt['model'].names) == classes: + model.names = ckpt['model'].names # set class names attribute + if not verbose: + LOGGER.setLevel(logging.INFO) # reset to default + return model.to(device) + + except Exception as e: + help_url = 'https://github.com/ultralytics/yolov5/issues/36' + s = f'{e}. Cache may be out of date, try `force_reload=True` or see {help_url} for help.' + raise Exception(s) from e + + +def custom(path='path/to/model.pt', autoshape=True, _verbose=True, device=None): + # YOLO custom or local model + return _create(path, autoshape=autoshape, verbose=_verbose, device=device) + + +if __name__ == '__main__': + import argparse + from pathlib import Path + + import numpy as np + from PIL import Image + + from utils.general import cv2, print_args + + # Argparser + parser = argparse.ArgumentParser() + parser.add_argument('--model', type=str, default='yolo', help='model name') + opt = parser.parse_args() + print_args(vars(opt)) + + # Model + model = _create(name=opt.model, pretrained=True, channels=3, classes=80, autoshape=True, verbose=True) + # model = custom(path='path/to/model.pt') # custom + + # Images + imgs = [ + 'data/images/zidane.jpg', # filename + Path('data/images/zidane.jpg'), # Path + 'https://ultralytics.com/images/zidane.jpg', # URI + cv2.imread('data/images/bus.jpg')[:, :, ::-1], # OpenCV + Image.open('data/images/bus.jpg'), # PIL + np.zeros((320, 640, 3))] # numpy + + # Inference + results = model(imgs, size=320) # batched inference + + # Results + results.print() + results.save() diff --git a/cv/3d_detection/yolov9/pytorch/models/__init__.py b/cv/3d_detection/yolov9/pytorch/models/__init__.py new file mode 100644 index 000000000..84952a816 --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/models/__init__.py @@ -0,0 +1 @@ +# init \ No newline at end of file diff --git a/cv/3d_detection/yolov9/pytorch/models/common.py b/cv/3d_detection/yolov9/pytorch/models/common.py new file mode 100644 index 000000000..c7fbbe322 --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/models/common.py @@ -0,0 +1,1212 @@ +import ast +import contextlib +import json +import math +import platform +import warnings +import zipfile +from collections import OrderedDict, namedtuple +from copy import copy +from pathlib import Path +from urllib.parse import urlparse + +from typing import Optional + +import cv2 +import numpy as np +import pandas as pd +import requests +import torch +import torch.nn as nn +from IPython.display import display +from PIL import Image +from torch.cuda import amp + +from utils import TryExcept +from utils.dataloaders import exif_transpose, letterbox +from utils.general import (LOGGER, ROOT, Profile, check_requirements, check_suffix, check_version, colorstr, + increment_path, is_notebook, make_divisible, non_max_suppression, scale_boxes, + xywh2xyxy, xyxy2xywh, yaml_load) +from utils.plots import Annotator, colors, save_one_box +from utils.torch_utils import copy_attr, smart_inference_mode + + +def autopad(k, p=None, d=1): # kernel, padding, dilation + # Pad to 'same' shape outputs + if d > 1: + k = d * (k - 1) + 1 if isinstance(k, int) else [d * (x - 1) + 1 for x in k] # actual kernel-size + if p is None: + p = k // 2 if isinstance(k, int) else [x // 2 for x in k] # auto-pad + return p + + +class Conv(nn.Module): + # Standard convolution with args(ch_in, ch_out, kernel, stride, padding, groups, dilation, activation) + default_act = nn.SiLU() # default activation + + def __init__(self, c1, c2, k=1, s=1, p=None, g=1, d=1, act=True): + super().__init__() + self.conv = nn.Conv2d(c1, c2, k, s, autopad(k, p, d), groups=g, dilation=d, bias=False) + self.bn = nn.BatchNorm2d(c2) + self.act = self.default_act if act is True else act if isinstance(act, nn.Module) else nn.Identity() + + def forward(self, x): + return self.act(self.bn(self.conv(x))) + + def forward_fuse(self, x): + return self.act(self.conv(x)) + + +class AConv(nn.Module): + def __init__(self, c1, c2): # ch_in, ch_out, shortcut, kernels, groups, expand + super().__init__() + self.cv1 = Conv(c1, c2, 3, 2, 1) + + def forward(self, x): + x = torch.nn.functional.avg_pool2d(x, 2, 1, 0, False, True) + return self.cv1(x) + + +class ADown(nn.Module): + def __init__(self, c1, c2): # ch_in, ch_out, shortcut, kernels, groups, expand + super().__init__() + self.c = c2 // 2 + self.cv1 = Conv(c1 // 2, self.c, 3, 2, 1) + self.cv2 = Conv(c1 // 2, self.c, 1, 1, 0) + + def forward(self, x): + x = torch.nn.functional.avg_pool2d(x, 2, 1, 0, False, True) + x1,x2 = x.chunk(2, 1) + x1 = self.cv1(x1) + x2 = torch.nn.functional.max_pool2d(x2, 3, 2, 1) + x2 = self.cv2(x2) + return torch.cat((x1, x2), 1) + + +class RepConvN(nn.Module): + """RepConv is a basic rep-style block, including training and deploy status + This code is based on https://github.com/DingXiaoH/RepVGG/blob/main/repvgg.py + """ + default_act = nn.SiLU() # default activation + + def __init__(self, c1, c2, k=3, s=1, p=1, g=1, d=1, act=True, bn=False, deploy=False): + super().__init__() + assert k == 3 and p == 1 + self.g = g + self.c1 = c1 + self.c2 = c2 + self.act = self.default_act if act is True else act if isinstance(act, nn.Module) else nn.Identity() + + self.bn = None + self.conv1 = Conv(c1, c2, k, s, p=p, g=g, act=False) + self.conv2 = Conv(c1, c2, 1, s, p=(p - k // 2), g=g, act=False) + + def forward_fuse(self, x): + """Forward process""" + return self.act(self.conv(x)) + + def forward(self, x): + """Forward process""" + id_out = 0 if self.bn is None else self.bn(x) + return self.act(self.conv1(x) + self.conv2(x) + id_out) + + def get_equivalent_kernel_bias(self): + kernel3x3, bias3x3 = self._fuse_bn_tensor(self.conv1) + kernel1x1, bias1x1 = self._fuse_bn_tensor(self.conv2) + kernelid, biasid = self._fuse_bn_tensor(self.bn) + return kernel3x3 + self._pad_1x1_to_3x3_tensor(kernel1x1) + kernelid, bias3x3 + bias1x1 + biasid + + def _avg_to_3x3_tensor(self, avgp): + channels = self.c1 + groups = self.g + kernel_size = avgp.kernel_size + input_dim = channels // groups + k = torch.zeros((channels, input_dim, kernel_size, kernel_size)) + k[np.arange(channels), np.tile(np.arange(input_dim), groups), :, :] = 1.0 / kernel_size ** 2 + return k + + def _pad_1x1_to_3x3_tensor(self, kernel1x1): + if kernel1x1 is None: + return 0 + else: + return torch.nn.functional.pad(kernel1x1, [1, 1, 1, 1]) + + def _fuse_bn_tensor(self, branch): + if branch is None: + return 0, 0 + if isinstance(branch, Conv): + kernel = branch.conv.weight + running_mean = branch.bn.running_mean + running_var = branch.bn.running_var + gamma = branch.bn.weight + beta = branch.bn.bias + eps = branch.bn.eps + elif isinstance(branch, nn.BatchNorm2d): + if not hasattr(self, 'id_tensor'): + input_dim = self.c1 // self.g + kernel_value = np.zeros((self.c1, input_dim, 3, 3), dtype=np.float32) + for i in range(self.c1): + kernel_value[i, i % input_dim, 1, 1] = 1 + self.id_tensor = torch.from_numpy(kernel_value).to(branch.weight.device) + kernel = self.id_tensor + running_mean = branch.running_mean + running_var = branch.running_var + gamma = branch.weight + beta = branch.bias + eps = branch.eps + std = (running_var + eps).sqrt() + t = (gamma / std).reshape(-1, 1, 1, 1) + return kernel * t, beta - running_mean * gamma / std + + def fuse_convs(self): + if hasattr(self, 'conv'): + return + kernel, bias = self.get_equivalent_kernel_bias() + self.conv = nn.Conv2d(in_channels=self.conv1.conv.in_channels, + out_channels=self.conv1.conv.out_channels, + kernel_size=self.conv1.conv.kernel_size, + stride=self.conv1.conv.stride, + padding=self.conv1.conv.padding, + dilation=self.conv1.conv.dilation, + groups=self.conv1.conv.groups, + bias=True).requires_grad_(False) + self.conv.weight.data = kernel + self.conv.bias.data = bias + for para in self.parameters(): + para.detach_() + self.__delattr__('conv1') + self.__delattr__('conv2') + if hasattr(self, 'nm'): + self.__delattr__('nm') + if hasattr(self, 'bn'): + self.__delattr__('bn') + if hasattr(self, 'id_tensor'): + self.__delattr__('id_tensor') + + +class SP(nn.Module): + def __init__(self, k=3, s=1): + super(SP, self).__init__() + self.m = nn.MaxPool2d(kernel_size=k, stride=s, padding=k // 2) + + def forward(self, x): + return self.m(x) + + +class MP(nn.Module): + # Max pooling + def __init__(self, k=2): + super(MP, self).__init__() + self.m = nn.MaxPool2d(kernel_size=k, stride=k) + + def forward(self, x): + return self.m(x) + + +class ConvTranspose(nn.Module): + # Convolution transpose 2d layer + default_act = nn.SiLU() # default activation + + def __init__(self, c1, c2, k=2, s=2, p=0, bn=True, act=True): + super().__init__() + self.conv_transpose = nn.ConvTranspose2d(c1, c2, k, s, p, bias=not bn) + self.bn = nn.BatchNorm2d(c2) if bn else nn.Identity() + self.act = self.default_act if act is True else act if isinstance(act, nn.Module) else nn.Identity() + + def forward(self, x): + return self.act(self.bn(self.conv_transpose(x))) + + +class DWConv(Conv): + # Depth-wise convolution + def __init__(self, c1, c2, k=1, s=1, d=1, act=True): # ch_in, ch_out, kernel, stride, dilation, activation + super().__init__(c1, c2, k, s, g=math.gcd(c1, c2), d=d, act=act) + + +class DWConvTranspose2d(nn.ConvTranspose2d): + # Depth-wise transpose convolution + def __init__(self, c1, c2, k=1, s=1, p1=0, p2=0): # ch_in, ch_out, kernel, stride, padding, padding_out + super().__init__(c1, c2, k, s, p1, p2, groups=math.gcd(c1, c2)) + + +class DFL(nn.Module): + # DFL module + def __init__(self, c1=17): + super().__init__() + self.conv = nn.Conv2d(c1, 1, 1, bias=False).requires_grad_(False) + self.conv.weight.data[:] = nn.Parameter(torch.arange(c1, dtype=torch.float).view(1, c1, 1, 1)) # / 120.0 + self.c1 = c1 + # self.bn = nn.BatchNorm2d(4) + + def forward(self, x): + b, c, a = x.shape # batch, channels, anchors + return self.conv(x.view(b, 4, self.c1, a).transpose(2, 1).softmax(1)).view(b, 4, a) + # return self.conv(x.view(b, self.c1, 4, a).softmax(1)).view(b, 4, a) + + +class BottleneckBase(nn.Module): + # Standard bottleneck + def __init__(self, c1, c2, shortcut=True, g=1, k=(1, 3), e=0.5): # ch_in, ch_out, shortcut, kernels, groups, expand + super().__init__() + c_ = int(c2 * e) # hidden channels + self.cv1 = Conv(c1, c_, k[0], 1) + self.cv2 = Conv(c_, c2, k[1], 1, g=g) + self.add = shortcut and c1 == c2 + + def forward(self, x): + return x + self.cv2(self.cv1(x)) if self.add else self.cv2(self.cv1(x)) + + +class RBottleneckBase(nn.Module): + # Standard bottleneck + def __init__(self, c1, c2, shortcut=True, g=1, k=(3, 1), e=0.5): # ch_in, ch_out, shortcut, kernels, groups, expand + super().__init__() + c_ = int(c2 * e) # hidden channels + self.cv1 = Conv(c1, c_, k[0], 1) + self.cv2 = Conv(c_, c2, k[1], 1, g=g) + self.add = shortcut and c1 == c2 + + def forward(self, x): + return x + self.cv2(self.cv1(x)) if self.add else self.cv2(self.cv1(x)) + + +class RepNRBottleneckBase(nn.Module): + # Standard bottleneck + def __init__(self, c1, c2, shortcut=True, g=1, k=(3, 1), e=0.5): # ch_in, ch_out, shortcut, kernels, groups, expand + super().__init__() + c_ = int(c2 * e) # hidden channels + self.cv1 = RepConvN(c1, c_, k[0], 1) + self.cv2 = Conv(c_, c2, k[1], 1, g=g) + self.add = shortcut and c1 == c2 + + def forward(self, x): + return x + self.cv2(self.cv1(x)) if self.add else self.cv2(self.cv1(x)) + + +class Bottleneck(nn.Module): + # Standard bottleneck + def __init__(self, c1, c2, shortcut=True, g=1, k=(3, 3), e=0.5): # ch_in, ch_out, shortcut, kernels, groups, expand + super().__init__() + c_ = int(c2 * e) # hidden channels + self.cv1 = Conv(c1, c_, k[0], 1) + self.cv2 = Conv(c_, c2, k[1], 1, g=g) + self.add = shortcut and c1 == c2 + + def forward(self, x): + return x + self.cv2(self.cv1(x)) if self.add else self.cv2(self.cv1(x)) + + +class RepNBottleneck(nn.Module): + # Standard bottleneck + def __init__(self, c1, c2, shortcut=True, g=1, k=(3, 3), e=0.5): # ch_in, ch_out, shortcut, kernels, groups, expand + super().__init__() + c_ = int(c2 * e) # hidden channels + self.cv1 = RepConvN(c1, c_, k[0], 1) + self.cv2 = Conv(c_, c2, k[1], 1, g=g) + self.add = shortcut and c1 == c2 + + def forward(self, x): + return x + self.cv2(self.cv1(x)) if self.add else self.cv2(self.cv1(x)) + + +class Res(nn.Module): + # ResNet bottleneck + def __init__(self, c1, c2, shortcut=True, g=1, e=0.5): # ch_in, ch_out, shortcut, groups, expansion + super(Res, self).__init__() + c_ = int(c2 * e) # hidden channels + self.cv1 = Conv(c1, c_, 1, 1) + self.cv2 = Conv(c_, c_, 3, 1, g=g) + self.cv3 = Conv(c_, c2, 1, 1) + self.add = shortcut and c1 == c2 + + def forward(self, x): + return x + self.cv3(self.cv2(self.cv1(x))) if self.add else self.cv3(self.cv2(self.cv1(x))) + + +class RepNRes(nn.Module): + # ResNet bottleneck + def __init__(self, c1, c2, shortcut=True, g=1, e=0.5): # ch_in, ch_out, shortcut, groups, expansion + super(RepNRes, self).__init__() + c_ = int(c2 * e) # hidden channels + self.cv1 = Conv(c1, c_, 1, 1) + self.cv2 = RepConvN(c_, c_, 3, 1, g=g) + self.cv3 = Conv(c_, c2, 1, 1) + self.add = shortcut and c1 == c2 + + def forward(self, x): + return x + self.cv3(self.cv2(self.cv1(x))) if self.add else self.cv3(self.cv2(self.cv1(x))) + + +class BottleneckCSP(nn.Module): + # CSP Bottleneck https://github.com/WongKinYiu/CrossStagePartialNetworks + def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5): # ch_in, ch_out, number, shortcut, groups, expansion + super().__init__() + c_ = int(c2 * e) # hidden channels + self.cv1 = Conv(c1, c_, 1, 1) + self.cv2 = nn.Conv2d(c1, c_, 1, 1, bias=False) + self.cv3 = nn.Conv2d(c_, c_, 1, 1, bias=False) + self.cv4 = Conv(2 * c_, c2, 1, 1) + self.bn = nn.BatchNorm2d(2 * c_) # applied to cat(cv2, cv3) + self.act = nn.SiLU() + self.m = nn.Sequential(*(Bottleneck(c_, c_, shortcut, g, e=1.0) for _ in range(n))) + + def forward(self, x): + y1 = self.cv3(self.m(self.cv1(x))) + y2 = self.cv2(x) + return self.cv4(self.act(self.bn(torch.cat((y1, y2), 1)))) + + +class CSP(nn.Module): + # CSP Bottleneck with 3 convolutions + def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5): # ch_in, ch_out, number, shortcut, groups, expansion + super().__init__() + c_ = int(c2 * e) # hidden channels + self.cv1 = Conv(c1, c_, 1, 1) + self.cv2 = Conv(c1, c_, 1, 1) + self.cv3 = Conv(2 * c_, c2, 1) # optional act=FReLU(c2) + self.m = nn.Sequential(*(Bottleneck(c_, c_, shortcut, g, e=1.0) for _ in range(n))) + + def forward(self, x): + return self.cv3(torch.cat((self.m(self.cv1(x)), self.cv2(x)), 1)) + + +class RepNCSP(nn.Module): + # CSP Bottleneck with 3 convolutions + def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5): # ch_in, ch_out, number, shortcut, groups, expansion + super().__init__() + c_ = int(c2 * e) # hidden channels + self.cv1 = Conv(c1, c_, 1, 1) + self.cv2 = Conv(c1, c_, 1, 1) + self.cv3 = Conv(2 * c_, c2, 1) # optional act=FReLU(c2) + self.m = nn.Sequential(*(RepNBottleneck(c_, c_, shortcut, g, e=1.0) for _ in range(n))) + + def forward(self, x): + return self.cv3(torch.cat((self.m(self.cv1(x)), self.cv2(x)), 1)) + + +class CSPBase(nn.Module): + # CSP Bottleneck with 3 convolutions + def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5): # ch_in, ch_out, number, shortcut, groups, expansion + super().__init__() + c_ = int(c2 * e) # hidden channels + self.cv1 = Conv(c1, c_, 1, 1) + self.cv2 = Conv(c1, c_, 1, 1) + self.cv3 = Conv(2 * c_, c2, 1) # optional act=FReLU(c2) + self.m = nn.Sequential(*(BottleneckBase(c_, c_, shortcut, g, e=1.0) for _ in range(n))) + + def forward(self, x): + return self.cv3(torch.cat((self.m(self.cv1(x)), self.cv2(x)), 1)) + + +class SPP(nn.Module): + # Spatial Pyramid Pooling (SPP) layer https://arxiv.org/abs/1406.4729 + def __init__(self, c1, c2, k=(5, 9, 13)): + super().__init__() + c_ = c1 // 2 # hidden channels + self.cv1 = Conv(c1, c_, 1, 1) + self.cv2 = Conv(c_ * (len(k) + 1), c2, 1, 1) + self.m = nn.ModuleList([nn.MaxPool2d(kernel_size=x, stride=1, padding=x // 2) for x in k]) + + def forward(self, x): + x = self.cv1(x) + with warnings.catch_warnings(): + warnings.simplefilter('ignore') # suppress torch 1.9.0 max_pool2d() warning + return self.cv2(torch.cat([x] + [m(x) for m in self.m], 1)) + + +class ASPP(torch.nn.Module): + + def __init__(self, in_channels, out_channels): + super().__init__() + kernel_sizes = [1, 3, 3, 1] + dilations = [1, 3, 6, 1] + paddings = [0, 3, 6, 0] + self.aspp = torch.nn.ModuleList() + for aspp_idx in range(len(kernel_sizes)): + conv = torch.nn.Conv2d( + in_channels, + out_channels, + kernel_size=kernel_sizes[aspp_idx], + stride=1, + dilation=dilations[aspp_idx], + padding=paddings[aspp_idx], + bias=True) + self.aspp.append(conv) + self.gap = torch.nn.AdaptiveAvgPool2d(1) + self.aspp_num = len(kernel_sizes) + for m in self.modules(): + if isinstance(m, torch.nn.Conv2d): + n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels + m.weight.data.normal_(0, math.sqrt(2. / n)) + m.bias.data.fill_(0) + + def forward(self, x): + avg_x = self.gap(x) + out = [] + for aspp_idx in range(self.aspp_num): + inp = avg_x if (aspp_idx == self.aspp_num - 1) else x + out.append(F.relu_(self.aspp[aspp_idx](inp))) + out[-1] = out[-1].expand_as(out[-2]) + out = torch.cat(out, dim=1) + return out + + +class SPPCSPC(nn.Module): + # CSP SPP https://github.com/WongKinYiu/CrossStagePartialNetworks + def __init__(self, c1, c2, n=1, shortcut=False, g=1, e=0.5, k=(5, 9, 13)): + super(SPPCSPC, self).__init__() + c_ = int(2 * c2 * e) # hidden channels + self.cv1 = Conv(c1, c_, 1, 1) + self.cv2 = Conv(c1, c_, 1, 1) + self.cv3 = Conv(c_, c_, 3, 1) + self.cv4 = Conv(c_, c_, 1, 1) + self.m = nn.ModuleList([nn.MaxPool2d(kernel_size=x, stride=1, padding=x // 2) for x in k]) + self.cv5 = Conv(4 * c_, c_, 1, 1) + self.cv6 = Conv(c_, c_, 3, 1) + self.cv7 = Conv(2 * c_, c2, 1, 1) + + def forward(self, x): + x1 = self.cv4(self.cv3(self.cv1(x))) + y1 = self.cv6(self.cv5(torch.cat([x1] + [m(x1) for m in self.m], 1))) + y2 = self.cv2(x) + return self.cv7(torch.cat((y1, y2), dim=1)) + + +class SPPF(nn.Module): + # Spatial Pyramid Pooling - Fast (SPPF) layer by Glenn Jocher + def __init__(self, c1, c2, k=5): # equivalent to SPP(k=(5, 9, 13)) + super().__init__() + c_ = c1 // 2 # hidden channels + self.cv1 = Conv(c1, c_, 1, 1) + self.cv2 = Conv(c_ * 4, c2, 1, 1) + self.m = nn.MaxPool2d(kernel_size=k, stride=1, padding=k // 2) + # self.m = SoftPool2d(kernel_size=k, stride=1, padding=k // 2) + + def forward(self, x): + x = self.cv1(x) + with warnings.catch_warnings(): + warnings.simplefilter('ignore') # suppress torch 1.9.0 max_pool2d() warning + y1 = self.m(x) + y2 = self.m(y1) + return self.cv2(torch.cat((x, y1, y2, self.m(y2)), 1)) + + +import torch.nn.functional as F +from torch.nn.modules.utils import _pair + + +class ReOrg(nn.Module): + # yolo + def __init__(self): + super(ReOrg, self).__init__() + + def forward(self, x): # x(b,c,w,h) -> y(b,4c,w/2,h/2) + return torch.cat([x[..., ::2, ::2], x[..., 1::2, ::2], x[..., ::2, 1::2], x[..., 1::2, 1::2]], 1) + + +class Contract(nn.Module): + # Contract width-height into channels, i.e. x(1,64,80,80) to x(1,256,40,40) + def __init__(self, gain=2): + super().__init__() + self.gain = gain + + def forward(self, x): + b, c, h, w = x.size() # assert (h / s == 0) and (W / s == 0), 'Indivisible gain' + s = self.gain + x = x.view(b, c, h // s, s, w // s, s) # x(1,64,40,2,40,2) + x = x.permute(0, 3, 5, 1, 2, 4).contiguous() # x(1,2,2,64,40,40) + return x.view(b, c * s * s, h // s, w // s) # x(1,256,40,40) + + +class Expand(nn.Module): + # Expand channels into width-height, i.e. x(1,64,80,80) to x(1,16,160,160) + def __init__(self, gain=2): + super().__init__() + self.gain = gain + + def forward(self, x): + b, c, h, w = x.size() # assert C / s ** 2 == 0, 'Indivisible gain' + s = self.gain + x = x.view(b, s, s, c // s ** 2, h, w) # x(1,2,2,16,80,80) + x = x.permute(0, 3, 4, 1, 5, 2).contiguous() # x(1,16,80,2,80,2) + return x.view(b, c // s ** 2, h * s, w * s) # x(1,16,160,160) + + +class Concat(nn.Module): + # Concatenate a list of tensors along dimension + def __init__(self, dimension=1): + super().__init__() + self.d = dimension + + def forward(self, x): + return torch.cat(x, self.d) + + +class Shortcut(nn.Module): + def __init__(self, dimension=0): + super(Shortcut, self).__init__() + self.d = dimension + + def forward(self, x): + return x[0]+x[1] + + +class Silence(nn.Module): + def __init__(self): + super(Silence, self).__init__() + def forward(self, x): + return x + + +##### GELAN ##### + +class SPPELAN(nn.Module): + # spp-elan + def __init__(self, c1, c2, c3): # ch_in, ch_out, number, shortcut, groups, expansion + super().__init__() + self.c = c3 + self.cv1 = Conv(c1, c3, 1, 1) + self.cv2 = SP(5) + self.cv3 = SP(5) + self.cv4 = SP(5) + self.cv5 = Conv(4*c3, c2, 1, 1) + + def forward(self, x): + y = [self.cv1(x)] + y.extend(m(y[-1]) for m in [self.cv2, self.cv3, self.cv4]) + return self.cv5(torch.cat(y, 1)) + + +class RepNCSPELAN4(nn.Module): + # csp-elan + def __init__(self, c1, c2, c3, c4, c5=1): # ch_in, ch_out, number, shortcut, groups, expansion + super().__init__() + self.c = c3//2 + self.cv1 = Conv(c1, c3, 1, 1) + self.cv2 = nn.Sequential(RepNCSP(c3//2, c4, c5), Conv(c4, c4, 3, 1)) + self.cv3 = nn.Sequential(RepNCSP(c4, c4, c5), Conv(c4, c4, 3, 1)) + self.cv4 = Conv(c3+(2*c4), c2, 1, 1) + + def forward(self, x): + y = list(self.cv1(x).chunk(2, 1)) + y.extend((m(y[-1])) for m in [self.cv2, self.cv3]) + return self.cv4(torch.cat(y, 1)) + + def forward_split(self, x): + y = list(self.cv1(x).split((self.c, self.c), 1)) + y.extend(m(y[-1]) for m in [self.cv2, self.cv3]) + return self.cv4(torch.cat(y, 1)) + +################# + + +##### YOLOR ##### + +class ImplicitA(nn.Module): + def __init__(self, channel): + super(ImplicitA, self).__init__() + self.channel = channel + self.implicit = nn.Parameter(torch.zeros(1, channel, 1, 1)) + nn.init.normal_(self.implicit, std=.02) + + def forward(self, x): + return self.implicit + x + + +class ImplicitM(nn.Module): + def __init__(self, channel): + super(ImplicitM, self).__init__() + self.channel = channel + self.implicit = nn.Parameter(torch.ones(1, channel, 1, 1)) + nn.init.normal_(self.implicit, mean=1., std=.02) + + def forward(self, x): + return self.implicit * x + +################# + + +##### CBNet ##### + +class CBLinear(nn.Module): + def __init__(self, c1, c2s, k=1, s=1, p=None, g=1): # ch_in, ch_outs, kernel, stride, padding, groups + super(CBLinear, self).__init__() + self.c2s = c2s + self.conv = nn.Conv2d(c1, sum(c2s), k, s, autopad(k, p), groups=g, bias=True) + + def forward(self, x): + outs = self.conv(x).split(self.c2s, dim=1) + return outs + +class CBFuse(nn.Module): + def __init__(self, idx): + super(CBFuse, self).__init__() + self.idx = idx + + def forward(self, xs): + target_size = xs[-1].shape[2:] + res = [F.interpolate(x[self.idx[i]], size=target_size, mode='nearest') for i, x in enumerate(xs[:-1])] + out = torch.sum(torch.stack(res + xs[-1:]), dim=0) + return out + +################# + + +class DetectMultiBackend(nn.Module): + # YOLO MultiBackend class for python inference on various backends + def __init__(self, weights='yolo.pt', device=torch.device('cpu'), dnn=False, data=None, fp16=False, fuse=True): + # Usage: + # PyTorch: weights = *.pt + # TorchScript: *.torchscript + # ONNX Runtime: *.onnx + # ONNX OpenCV DNN: *.onnx --dnn + # OpenVINO: *_openvino_model + # CoreML: *.mlmodel + # TensorRT: *.engine + # TensorFlow SavedModel: *_saved_model + # TensorFlow GraphDef: *.pb + # TensorFlow Lite: *.tflite + # TensorFlow Edge TPU: *_edgetpu.tflite + # PaddlePaddle: *_paddle_model + from models.experimental import attempt_download, attempt_load # scoped to avoid circular import + + super().__init__() + w = str(weights[0] if isinstance(weights, list) else weights) + pt, jit, onnx, onnx_end2end, xml, engine, coreml, saved_model, pb, tflite, edgetpu, tfjs, paddle, triton = self._model_type(w) + fp16 &= pt or jit or onnx or engine # FP16 + nhwc = coreml or saved_model or pb or tflite or edgetpu # BHWC formats (vs torch BCWH) + stride = 32 # default stride + cuda = torch.cuda.is_available() and device.type != 'cpu' # use CUDA + if not (pt or triton): + w = attempt_download(w) # download if not local + + if pt: # PyTorch + model = attempt_load(weights if isinstance(weights, list) else w, device=device, inplace=True, fuse=fuse) + stride = max(int(model.stride.max()), 32) # model stride + names = model.module.names if hasattr(model, 'module') else model.names # get class names + model.half() if fp16 else model.float() + self.model = model # explicitly assign for to(), cpu(), cuda(), half() + elif jit: # TorchScript + LOGGER.info(f'Loading {w} for TorchScript inference...') + extra_files = {'config.txt': ''} # model metadata + model = torch.jit.load(w, _extra_files=extra_files, map_location=device) + model.half() if fp16 else model.float() + if extra_files['config.txt']: # load metadata dict + d = json.loads(extra_files['config.txt'], + object_hook=lambda d: {int(k) if k.isdigit() else k: v + for k, v in d.items()}) + stride, names = int(d['stride']), d['names'] + elif dnn: # ONNX OpenCV DNN + LOGGER.info(f'Loading {w} for ONNX OpenCV DNN inference...') + check_requirements('opencv-python>=4.5.4') + net = cv2.dnn.readNetFromONNX(w) + elif onnx: # ONNX Runtime + LOGGER.info(f'Loading {w} for ONNX Runtime inference...') + check_requirements(('onnx', 'onnxruntime-gpu' if cuda else 'onnxruntime')) + import onnxruntime + providers = ['CUDAExecutionProvider', 'CPUExecutionProvider'] if cuda else ['CPUExecutionProvider'] + session = onnxruntime.InferenceSession(w, providers=providers) + output_names = [x.name for x in session.get_outputs()] + meta = session.get_modelmeta().custom_metadata_map # metadata + if 'stride' in meta: + stride, names = int(meta['stride']), eval(meta['names']) + elif xml: # OpenVINO + LOGGER.info(f'Loading {w} for OpenVINO inference...') + check_requirements('openvino') # requires openvino-dev: https://pypi.org/project/openvino-dev/ + from openvino.runtime import Core, Layout, get_batch + ie = Core() + if not Path(w).is_file(): # if not *.xml + w = next(Path(w).glob('*.xml')) # get *.xml file from *_openvino_model dir + network = ie.read_model(model=w, weights=Path(w).with_suffix('.bin')) + if network.get_parameters()[0].get_layout().empty: + network.get_parameters()[0].set_layout(Layout("NCHW")) + batch_dim = get_batch(network) + if batch_dim.is_static: + batch_size = batch_dim.get_length() + executable_network = ie.compile_model(network, device_name="CPU") # device_name="MYRIAD" for Intel NCS2 + stride, names = self._load_metadata(Path(w).with_suffix('.yaml')) # load metadata + elif engine: # TensorRT + LOGGER.info(f'Loading {w} for TensorRT inference...') + import tensorrt as trt # https://developer.nvidia.com/nvidia-tensorrt-download + check_version(trt.__version__, '7.0.0', hard=True) # require tensorrt>=7.0.0 + if device.type == 'cpu': + device = torch.device('cuda:0') + Binding = namedtuple('Binding', ('name', 'dtype', 'shape', 'data', 'ptr')) + logger = trt.Logger(trt.Logger.INFO) + with open(w, 'rb') as f, trt.Runtime(logger) as runtime: + model = runtime.deserialize_cuda_engine(f.read()) + context = model.create_execution_context() + bindings = OrderedDict() + output_names = [] + fp16 = False # default updated below + dynamic = False + for i in range(model.num_bindings): + name = model.get_binding_name(i) + dtype = trt.nptype(model.get_binding_dtype(i)) + if model.binding_is_input(i): + if -1 in tuple(model.get_binding_shape(i)): # dynamic + dynamic = True + context.set_binding_shape(i, tuple(model.get_profile_shape(0, i)[2])) + if dtype == np.float16: + fp16 = True + else: # output + output_names.append(name) + shape = tuple(context.get_binding_shape(i)) + im = torch.from_numpy(np.empty(shape, dtype=dtype)).to(device) + bindings[name] = Binding(name, dtype, shape, im, int(im.data_ptr())) + binding_addrs = OrderedDict((n, d.ptr) for n, d in bindings.items()) + batch_size = bindings['images'].shape[0] # if dynamic, this is instead max batch size + elif coreml: # CoreML + LOGGER.info(f'Loading {w} for CoreML inference...') + import coremltools as ct + model = ct.models.MLModel(w) + elif saved_model: # TF SavedModel + LOGGER.info(f'Loading {w} for TensorFlow SavedModel inference...') + import tensorflow as tf + keras = False # assume TF1 saved_model + model = tf.keras.models.load_model(w) if keras else tf.saved_model.load(w) + elif pb: # GraphDef https://www.tensorflow.org/guide/migrate#a_graphpb_or_graphpbtxt + LOGGER.info(f'Loading {w} for TensorFlow GraphDef inference...') + import tensorflow as tf + + def wrap_frozen_graph(gd, inputs, outputs): + x = tf.compat.v1.wrap_function(lambda: tf.compat.v1.import_graph_def(gd, name=""), []) # wrapped + ge = x.graph.as_graph_element + return x.prune(tf.nest.map_structure(ge, inputs), tf.nest.map_structure(ge, outputs)) + + def gd_outputs(gd): + name_list, input_list = [], [] + for node in gd.node: # tensorflow.core.framework.node_def_pb2.NodeDef + name_list.append(node.name) + input_list.extend(node.input) + return sorted(f'{x}:0' for x in list(set(name_list) - set(input_list)) if not x.startswith('NoOp')) + + gd = tf.Graph().as_graph_def() # TF GraphDef + with open(w, 'rb') as f: + gd.ParseFromString(f.read()) + frozen_func = wrap_frozen_graph(gd, inputs="x:0", outputs=gd_outputs(gd)) + elif tflite or edgetpu: # https://www.tensorflow.org/lite/guide/python#install_tensorflow_lite_for_python + try: # https://coral.ai/docs/edgetpu/tflite-python/#update-existing-tf-lite-code-for-the-edge-tpu + from tflite_runtime.interpreter import Interpreter, load_delegate + except ImportError: + import tensorflow as tf + Interpreter, load_delegate = tf.lite.Interpreter, tf.lite.experimental.load_delegate, + if edgetpu: # TF Edge TPU https://coral.ai/software/#edgetpu-runtime + LOGGER.info(f'Loading {w} for TensorFlow Lite Edge TPU inference...') + delegate = { + 'Linux': 'libedgetpu.so.1', + 'Darwin': 'libedgetpu.1.dylib', + 'Windows': 'edgetpu.dll'}[platform.system()] + interpreter = Interpreter(model_path=w, experimental_delegates=[load_delegate(delegate)]) + else: # TFLite + LOGGER.info(f'Loading {w} for TensorFlow Lite inference...') + interpreter = Interpreter(model_path=w) # load TFLite model + interpreter.allocate_tensors() # allocate + input_details = interpreter.get_input_details() # inputs + output_details = interpreter.get_output_details() # outputs + # load metadata + with contextlib.suppress(zipfile.BadZipFile): + with zipfile.ZipFile(w, "r") as model: + meta_file = model.namelist()[0] + meta = ast.literal_eval(model.read(meta_file).decode("utf-8")) + stride, names = int(meta['stride']), meta['names'] + elif tfjs: # TF.js + raise NotImplementedError('ERROR: YOLO TF.js inference is not supported') + elif paddle: # PaddlePaddle + LOGGER.info(f'Loading {w} for PaddlePaddle inference...') + check_requirements('paddlepaddle-gpu' if cuda else 'paddlepaddle') + import paddle.inference as pdi + if not Path(w).is_file(): # if not *.pdmodel + w = next(Path(w).rglob('*.pdmodel')) # get *.pdmodel file from *_paddle_model dir + weights = Path(w).with_suffix('.pdiparams') + config = pdi.Config(str(w), str(weights)) + if cuda: + config.enable_use_gpu(memory_pool_init_size_mb=2048, device_id=0) + predictor = pdi.create_predictor(config) + input_handle = predictor.get_input_handle(predictor.get_input_names()[0]) + output_names = predictor.get_output_names() + elif triton: # NVIDIA Triton Inference Server + LOGGER.info(f'Using {w} as Triton Inference Server...') + check_requirements('tritonclient[all]') + from utils.triton import TritonRemoteModel + model = TritonRemoteModel(url=w) + nhwc = model.runtime.startswith("tensorflow") + else: + raise NotImplementedError(f'ERROR: {w} is not a supported format') + + # class names + if 'names' not in locals(): + names = yaml_load(data)['names'] if data else {i: f'class{i}' for i in range(999)} + if names[0] == 'n01440764' and len(names) == 1000: # ImageNet + names = yaml_load(ROOT / 'data/ImageNet.yaml')['names'] # human-readable names + + self.__dict__.update(locals()) # assign all variables to self + + def forward(self, im, augment=False, visualize=False): + # YOLO MultiBackend inference + b, ch, h, w = im.shape # batch, channel, height, width + if self.fp16 and im.dtype != torch.float16: + im = im.half() # to FP16 + if self.nhwc: + im = im.permute(0, 2, 3, 1) # torch BCHW to numpy BHWC shape(1,320,192,3) + + if self.pt: # PyTorch + y = self.model(im, augment=augment, visualize=visualize) if augment or visualize else self.model(im) + elif self.jit: # TorchScript + y = self.model(im) + elif self.dnn: # ONNX OpenCV DNN + im = im.cpu().numpy() # torch to numpy + self.net.setInput(im) + y = self.net.forward() + elif self.onnx: # ONNX Runtime + im = im.cpu().numpy() # torch to numpy + y = self.session.run(self.output_names, {self.session.get_inputs()[0].name: im}) + elif self.xml: # OpenVINO + im = im.cpu().numpy() # FP32 + y = list(self.executable_network([im]).values()) + elif self.engine: # TensorRT + if self.dynamic and im.shape != self.bindings['images'].shape: + i = self.model.get_binding_index('images') + self.context.set_binding_shape(i, im.shape) # reshape if dynamic + self.bindings['images'] = self.bindings['images']._replace(shape=im.shape) + for name in self.output_names: + i = self.model.get_binding_index(name) + self.bindings[name].data.resize_(tuple(self.context.get_binding_shape(i))) + s = self.bindings['images'].shape + assert im.shape == s, f"input size {im.shape} {'>' if self.dynamic else 'not equal to'} max model size {s}" + self.binding_addrs['images'] = int(im.data_ptr()) + self.context.execute_v2(list(self.binding_addrs.values())) + y = [self.bindings[x].data for x in sorted(self.output_names)] + elif self.coreml: # CoreML + im = im.cpu().numpy() + im = Image.fromarray((im[0] * 255).astype('uint8')) + # im = im.resize((192, 320), Image.ANTIALIAS) + y = self.model.predict({'image': im}) # coordinates are xywh normalized + if 'confidence' in y: + box = xywh2xyxy(y['coordinates'] * [[w, h, w, h]]) # xyxy pixels + conf, cls = y['confidence'].max(1), y['confidence'].argmax(1).astype(np.float) + y = np.concatenate((box, conf.reshape(-1, 1), cls.reshape(-1, 1)), 1) + else: + y = list(reversed(y.values())) # reversed for segmentation models (pred, proto) + elif self.paddle: # PaddlePaddle + im = im.cpu().numpy().astype(np.float32) + self.input_handle.copy_from_cpu(im) + self.predictor.run() + y = [self.predictor.get_output_handle(x).copy_to_cpu() for x in self.output_names] + elif self.triton: # NVIDIA Triton Inference Server + y = self.model(im) + else: # TensorFlow (SavedModel, GraphDef, Lite, Edge TPU) + im = im.cpu().numpy() + if self.saved_model: # SavedModel + y = self.model(im, training=False) if self.keras else self.model(im) + elif self.pb: # GraphDef + y = self.frozen_func(x=self.tf.constant(im)) + else: # Lite or Edge TPU + input = self.input_details[0] + int8 = input['dtype'] == np.uint8 # is TFLite quantized uint8 model + if int8: + scale, zero_point = input['quantization'] + im = (im / scale + zero_point).astype(np.uint8) # de-scale + self.interpreter.set_tensor(input['index'], im) + self.interpreter.invoke() + y = [] + for output in self.output_details: + x = self.interpreter.get_tensor(output['index']) + if int8: + scale, zero_point = output['quantization'] + x = (x.astype(np.float32) - zero_point) * scale # re-scale + y.append(x) + y = [x if isinstance(x, np.ndarray) else x.numpy() for x in y] + y[0][..., :4] *= [w, h, w, h] # xywh normalized to pixels + + if isinstance(y, (list, tuple)): + return self.from_numpy(y[0]) if len(y) == 1 else [self.from_numpy(x) for x in y] + else: + return self.from_numpy(y) + + def from_numpy(self, x): + return torch.from_numpy(x).to(self.device) if isinstance(x, np.ndarray) else x + + def warmup(self, imgsz=(1, 3, 640, 640)): + # Warmup model by running inference once + warmup_types = self.pt, self.jit, self.onnx, self.engine, self.saved_model, self.pb, self.triton + if any(warmup_types) and (self.device.type != 'cpu' or self.triton): + im = torch.empty(*imgsz, dtype=torch.half if self.fp16 else torch.float, device=self.device) # input + for _ in range(2 if self.jit else 1): # + self.forward(im) # warmup + + @staticmethod + def _model_type(p='path/to/model.pt'): + # Return model type from model path, i.e. path='path/to/model.onnx' -> type=onnx + # types = [pt, jit, onnx, xml, engine, coreml, saved_model, pb, tflite, edgetpu, tfjs, paddle] + from export import export_formats + from utils.downloads import is_url + sf = list(export_formats().Suffix) # export suffixes + if not is_url(p, check=False): + check_suffix(p, sf) # checks + url = urlparse(p) # if url may be Triton inference server + types = [s in Path(p).name for s in sf] + types[8] &= not types[9] # tflite &= not edgetpu + triton = not any(types) and all([any(s in url.scheme for s in ["http", "grpc"]), url.netloc]) + return types + [triton] + + @staticmethod + def _load_metadata(f=Path('path/to/meta.yaml')): + # Load metadata from meta.yaml if it exists + if f.exists(): + d = yaml_load(f) + return d['stride'], d['names'] # assign stride, names + return None, None + + +class AutoShape(nn.Module): + # YOLO input-robust model wrapper for passing cv2/np/PIL/torch inputs. Includes preprocessing, inference and NMS + conf = 0.25 # NMS confidence threshold + iou = 0.45 # NMS IoU threshold + agnostic = False # NMS class-agnostic + multi_label = False # NMS multiple labels per box + classes = None # (optional list) filter by class, i.e. = [0, 15, 16] for COCO persons, cats and dogs + max_det = 1000 # maximum number of detections per image + amp = False # Automatic Mixed Precision (AMP) inference + + def __init__(self, model, verbose=True): + super().__init__() + if verbose: + LOGGER.info('Adding AutoShape... ') + copy_attr(self, model, include=('yaml', 'nc', 'hyp', 'names', 'stride', 'abc'), exclude=()) # copy attributes + self.dmb = isinstance(model, DetectMultiBackend) # DetectMultiBackend() instance + self.pt = not self.dmb or model.pt # PyTorch model + self.model = model.eval() + if self.pt: + m = self.model.model.model[-1] if self.dmb else self.model.model[-1] # Detect() + m.inplace = False # Detect.inplace=False for safe multithread inference + m.export = True # do not output loss values + + def _apply(self, fn): + # Apply to(), cpu(), cuda(), half() to model tensors that are not parameters or registered buffers + self = super()._apply(fn) + from models.yolo import Detect, Segment + if self.pt: + m = self.model.model.model[-1] if self.dmb else self.model.model[-1] # Detect() + if isinstance(m, (Detect, Segment)): + for k in 'stride', 'anchor_grid', 'stride_grid', 'grid': + x = getattr(m, k) + setattr(m, k, list(map(fn, x))) if isinstance(x, (list, tuple)) else setattr(m, k, fn(x)) + return self + + @smart_inference_mode() + def forward(self, ims, size=640, augment=False, profile=False): + # Inference from various sources. For size(height=640, width=1280), RGB images example inputs are: + # file: ims = 'data/images/zidane.jpg' # str or PosixPath + # URI: = 'https://ultralytics.com/images/zidane.jpg' + # OpenCV: = cv2.imread('image.jpg')[:,:,::-1] # HWC BGR to RGB x(640,1280,3) + # PIL: = Image.open('image.jpg') or ImageGrab.grab() # HWC x(640,1280,3) + # numpy: = np.zeros((640,1280,3)) # HWC + # torch: = torch.zeros(16,3,320,640) # BCHW (scaled to size=640, 0-1 values) + # multiple: = [Image.open('image1.jpg'), Image.open('image2.jpg'), ...] # list of images + + dt = (Profile(), Profile(), Profile()) + with dt[0]: + if isinstance(size, int): # expand + size = (size, size) + p = next(self.model.parameters()) if self.pt else torch.empty(1, device=self.model.device) # param + autocast = self.amp and (p.device.type != 'cpu') # Automatic Mixed Precision (AMP) inference + if isinstance(ims, torch.Tensor): # torch + with amp.autocast(autocast): + return self.model(ims.to(p.device).type_as(p), augment=augment) # inference + + # Pre-process + n, ims = (len(ims), list(ims)) if isinstance(ims, (list, tuple)) else (1, [ims]) # number, list of images + shape0, shape1, files = [], [], [] # image and inference shapes, filenames + for i, im in enumerate(ims): + f = f'image{i}' # filename + if isinstance(im, (str, Path)): # filename or uri + im, f = Image.open(requests.get(im, stream=True).raw if str(im).startswith('http') else im), im + im = np.asarray(exif_transpose(im)) + elif isinstance(im, Image.Image): # PIL Image + im, f = np.asarray(exif_transpose(im)), getattr(im, 'filename', f) or f + files.append(Path(f).with_suffix('.jpg').name) + if im.shape[0] < 5: # image in CHW + im = im.transpose((1, 2, 0)) # reverse dataloader .transpose(2, 0, 1) + im = im[..., :3] if im.ndim == 3 else cv2.cvtColor(im, cv2.COLOR_GRAY2BGR) # enforce 3ch input + s = im.shape[:2] # HWC + shape0.append(s) # image shape + g = max(size) / max(s) # gain + shape1.append([int(y * g) for y in s]) + ims[i] = im if im.data.contiguous else np.ascontiguousarray(im) # update + shape1 = [make_divisible(x, self.stride) for x in np.array(shape1).max(0)] # inf shape + x = [letterbox(im, shape1, auto=False)[0] for im in ims] # pad + x = np.ascontiguousarray(np.array(x).transpose((0, 3, 1, 2))) # stack and BHWC to BCHW + x = torch.from_numpy(x).to(p.device).type_as(p) / 255 # uint8 to fp16/32 + + with amp.autocast(autocast): + # Inference + with dt[1]: + y = self.model(x, augment=augment) # forward + + # Post-process + with dt[2]: + y = non_max_suppression(y if self.dmb else y[0], + self.conf, + self.iou, + self.classes, + self.agnostic, + self.multi_label, + max_det=self.max_det) # NMS + for i in range(n): + scale_boxes(shape1, y[i][:, :4], shape0[i]) + + return Detections(ims, y, files, dt, self.names, x.shape) + + +class Detections: + # YOLO detections class for inference results + def __init__(self, ims, pred, files, times=(0, 0, 0), names=None, shape=None): + super().__init__() + d = pred[0].device # device + gn = [torch.tensor([*(im.shape[i] for i in [1, 0, 1, 0]), 1, 1], device=d) for im in ims] # normalizations + self.ims = ims # list of images as numpy arrays + self.pred = pred # list of tensors pred[0] = (xyxy, conf, cls) + self.names = names # class names + self.files = files # image filenames + self.times = times # profiling times + self.xyxy = pred # xyxy pixels + self.xywh = [xyxy2xywh(x) for x in pred] # xywh pixels + self.xyxyn = [x / g for x, g in zip(self.xyxy, gn)] # xyxy normalized + self.xywhn = [x / g for x, g in zip(self.xywh, gn)] # xywh normalized + self.n = len(self.pred) # number of images (batch size) + self.t = tuple(x.t / self.n * 1E3 for x in times) # timestamps (ms) + self.s = tuple(shape) # inference BCHW shape + + def _run(self, pprint=False, show=False, save=False, crop=False, render=False, labels=True, save_dir=Path('')): + s, crops = '', [] + for i, (im, pred) in enumerate(zip(self.ims, self.pred)): + s += f'\nimage {i + 1}/{len(self.pred)}: {im.shape[0]}x{im.shape[1]} ' # string + if pred.shape[0]: + for c in pred[:, -1].unique(): + n = (pred[:, -1] == c).sum() # detections per class + s += f"{n} {self.names[int(c)]}{'s' * (n > 1)}, " # add to string + s = s.rstrip(', ') + if show or save or render or crop: + annotator = Annotator(im, example=str(self.names)) + for *box, conf, cls in reversed(pred): # xyxy, confidence, class + label = f'{self.names[int(cls)]} {conf:.2f}' + if crop: + file = save_dir / 'crops' / self.names[int(cls)] / self.files[i] if save else None + crops.append({ + 'box': box, + 'conf': conf, + 'cls': cls, + 'label': label, + 'im': save_one_box(box, im, file=file, save=save)}) + else: # all others + annotator.box_label(box, label if labels else '', color=colors(cls)) + im = annotator.im + else: + s += '(no detections)' + + im = Image.fromarray(im.astype(np.uint8)) if isinstance(im, np.ndarray) else im # from np + if show: + display(im) if is_notebook() else im.show(self.files[i]) + if save: + f = self.files[i] + im.save(save_dir / f) # save + if i == self.n - 1: + LOGGER.info(f"Saved {self.n} image{'s' * (self.n > 1)} to {colorstr('bold', save_dir)}") + if render: + self.ims[i] = np.asarray(im) + if pprint: + s = s.lstrip('\n') + return f'{s}\nSpeed: %.1fms pre-process, %.1fms inference, %.1fms NMS per image at shape {self.s}' % self.t + if crop: + if save: + LOGGER.info(f'Saved results to {save_dir}\n') + return crops + + @TryExcept('Showing images is not supported in this environment') + def show(self, labels=True): + self._run(show=True, labels=labels) # show results + + def save(self, labels=True, save_dir='runs/detect/exp', exist_ok=False): + save_dir = increment_path(save_dir, exist_ok, mkdir=True) # increment save_dir + self._run(save=True, labels=labels, save_dir=save_dir) # save results + + def crop(self, save=True, save_dir='runs/detect/exp', exist_ok=False): + save_dir = increment_path(save_dir, exist_ok, mkdir=True) if save else None + return self._run(crop=True, save=save, save_dir=save_dir) # crop results + + def render(self, labels=True): + self._run(render=True, labels=labels) # render results + return self.ims + + def pandas(self): + # return detections as pandas DataFrames, i.e. print(results.pandas().xyxy[0]) + new = copy(self) # return copy + ca = 'xmin', 'ymin', 'xmax', 'ymax', 'confidence', 'class', 'name' # xyxy columns + cb = 'xcenter', 'ycenter', 'width', 'height', 'confidence', 'class', 'name' # xywh columns + for k, c in zip(['xyxy', 'xyxyn', 'xywh', 'xywhn'], [ca, ca, cb, cb]): + a = [[x[:5] + [int(x[5]), self.names[int(x[5])]] for x in x.tolist()] for x in getattr(self, k)] # update + setattr(new, k, [pd.DataFrame(x, columns=c) for x in a]) + return new + + def tolist(self): + # return a list of Detections objects, i.e. 'for result in results.tolist():' + r = range(self.n) # iterable + x = [Detections([self.ims[i]], [self.pred[i]], [self.files[i]], self.times, self.names, self.s) for i in r] + # for d in x: + # for k in ['ims', 'pred', 'xyxy', 'xyxyn', 'xywh', 'xywhn']: + # setattr(d, k, getattr(d, k)[0]) # pop out of list + return x + + def print(self): + LOGGER.info(self.__str__()) + + def __len__(self): # override len(results) + return self.n + + def __str__(self): # override print(results) + return self._run(pprint=True) # print results + + def __repr__(self): + return f'YOLO {self.__class__} instance\n' + self.__str__() + + +class Proto(nn.Module): + # YOLO mask Proto module for segmentation models + def __init__(self, c1, c_=256, c2=32): # ch_in, number of protos, number of masks + super().__init__() + self.cv1 = Conv(c1, c_, k=3) + self.upsample = nn.Upsample(scale_factor=2, mode='nearest') + self.cv2 = Conv(c_, c_, k=3) + self.cv3 = Conv(c_, c2) + + def forward(self, x): + return self.cv3(self.cv2(self.upsample(self.cv1(x)))) + + +class UConv(nn.Module): + def __init__(self, c1, c_=256, c2=256): # ch_in, number of protos, number of masks + super().__init__() + + self.cv1 = Conv(c1, c_, k=3) + self.cv2 = nn.Conv2d(c_, c2, 1, 1) + self.up = nn.Upsample(scale_factor=2, mode='bilinear', align_corners=True) + + def forward(self, x): + return self.up(self.cv2(self.cv1(x))) + + +class Classify(nn.Module): + # YOLO classification head, i.e. x(b,c1,20,20) to x(b,c2) + def __init__(self, c1, c2, k=1, s=1, p=None, g=1): # ch_in, ch_out, kernel, stride, padding, groups + super().__init__() + c_ = 1280 # efficientnet_b0 size + self.conv = Conv(c1, c_, k, s, autopad(k, p), g) + self.pool = nn.AdaptiveAvgPool2d(1) # to x(b,c_,1,1) + self.drop = nn.Dropout(p=0.0, inplace=True) + self.linear = nn.Linear(c_, c2) # to x(b,c2) + + def forward(self, x): + if isinstance(x, list): + x = torch.cat(x, 1) + return self.linear(self.drop(self.pool(self.conv(x)).flatten(1))) diff --git a/cv/3d_detection/yolov9/pytorch/models/detect/gelan-c.yaml b/cv/3d_detection/yolov9/pytorch/models/detect/gelan-c.yaml new file mode 100644 index 000000000..78b41bc39 --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/models/detect/gelan-c.yaml @@ -0,0 +1,80 @@ +# YOLOv9 + +# parameters +nc: 80 # number of classes +depth_multiple: 1.0 # model depth multiple +width_multiple: 1.0 # layer channel multiple +#activation: nn.LeakyReLU(0.1) +#activation: nn.ReLU() + +# anchors +anchors: 3 + +# gelan backbone +backbone: + [ + # conv down + [-1, 1, Conv, [64, 3, 2]], # 0-P1/2 + + # conv down + [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 + + # elan-1 block + [-1, 1, RepNCSPELAN4, [256, 128, 64, 1]], # 2 + + # avg-conv down + [-1, 1, ADown, [256]], # 3-P3/8 + + # elan-2 block + [-1, 1, RepNCSPELAN4, [512, 256, 128, 1]], # 4 + + # avg-conv down + [-1, 1, ADown, [512]], # 5-P4/16 + + # elan-2 block + [-1, 1, RepNCSPELAN4, [512, 512, 256, 1]], # 6 + + # avg-conv down + [-1, 1, ADown, [512]], # 7-P5/32 + + # elan-2 block + [-1, 1, RepNCSPELAN4, [512, 512, 256, 1]], # 8 + ] + +# gelan head +head: + [ + # elan-spp block + [-1, 1, SPPELAN, [512, 256]], # 9 + + # up-concat merge + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 6], 1, Concat, [1]], # cat backbone P4 + + # elan-2 block + [-1, 1, RepNCSPELAN4, [512, 512, 256, 1]], # 12 + + # up-concat merge + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 4], 1, Concat, [1]], # cat backbone P3 + + # elan-2 block + [-1, 1, RepNCSPELAN4, [256, 256, 128, 1]], # 15 (P3/8-small) + + # avg-conv-down merge + [-1, 1, ADown, [256]], + [[-1, 12], 1, Concat, [1]], # cat head P4 + + # elan-2 block + [-1, 1, RepNCSPELAN4, [512, 512, 256, 1]], # 18 (P4/16-medium) + + # avg-conv-down merge + [-1, 1, ADown, [512]], + [[-1, 9], 1, Concat, [1]], # cat head P5 + + # elan-2 block + [-1, 1, RepNCSPELAN4, [512, 512, 256, 1]], # 21 (P5/32-large) + + # detect + [[15, 18, 21], 1, DDetect, [nc]], # DDetect(P3, P4, P5) + ] diff --git a/cv/3d_detection/yolov9/pytorch/models/detect/gelan-e.yaml b/cv/3d_detection/yolov9/pytorch/models/detect/gelan-e.yaml new file mode 100644 index 000000000..a0409bab7 --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/models/detect/gelan-e.yaml @@ -0,0 +1,121 @@ +# YOLOv9 + +# parameters +nc: 80 # number of classes +depth_multiple: 1.0 # model depth multiple +width_multiple: 1.0 # layer channel multiple +#activation: nn.LeakyReLU(0.1) +#activation: nn.ReLU() + +# anchors +anchors: 3 + +# gelan backbone +backbone: + [ + [-1, 1, Silence, []], + + # conv down + [-1, 1, Conv, [64, 3, 2]], # 1-P1/2 + + # conv down + [-1, 1, Conv, [128, 3, 2]], # 2-P2/4 + + # elan-1 block + [-1, 1, RepNCSPELAN4, [256, 128, 64, 2]], # 3 + + # avg-conv down + [-1, 1, ADown, [256]], # 4-P3/8 + + # elan-2 block + [-1, 1, RepNCSPELAN4, [512, 256, 128, 2]], # 5 + + # avg-conv down + [-1, 1, ADown, [512]], # 6-P4/16 + + # elan-2 block + [-1, 1, RepNCSPELAN4, [1024, 512, 256, 2]], # 7 + + # avg-conv down + [-1, 1, ADown, [1024]], # 8-P5/32 + + # elan-2 block + [-1, 1, RepNCSPELAN4, [1024, 512, 256, 2]], # 9 + + # routing + [1, 1, CBLinear, [[64]]], # 10 + [3, 1, CBLinear, [[64, 128]]], # 11 + [5, 1, CBLinear, [[64, 128, 256]]], # 12 + [7, 1, CBLinear, [[64, 128, 256, 512]]], # 13 + [9, 1, CBLinear, [[64, 128, 256, 512, 1024]]], # 14 + + # conv down fuse + [0, 1, Conv, [64, 3, 2]], # 15-P1/2 + [[10, 11, 12, 13, 14, -1], 1, CBFuse, [[0, 0, 0, 0, 0]]], # 16 + + # conv down fuse + [-1, 1, Conv, [128, 3, 2]], # 17-P2/4 + [[11, 12, 13, 14, -1], 1, CBFuse, [[1, 1, 1, 1]]], # 18 + + # elan-1 block + [-1, 1, RepNCSPELAN4, [256, 128, 64, 2]], # 19 + + # avg-conv down fuse + [-1, 1, ADown, [256]], # 20-P3/8 + [[12, 13, 14, -1], 1, CBFuse, [[2, 2, 2]]], # 21 + + # elan-2 block + [-1, 1, RepNCSPELAN4, [512, 256, 128, 2]], # 22 + + # avg-conv down fuse + [-1, 1, ADown, [512]], # 23-P4/16 + [[13, 14, -1], 1, CBFuse, [[3, 3]]], # 24 + + # elan-2 block + [-1, 1, RepNCSPELAN4, [1024, 512, 256, 2]], # 25 + + # avg-conv down fuse + [-1, 1, ADown, [1024]], # 26-P5/32 + [[14, -1], 1, CBFuse, [[4]]], # 27 + + # elan-2 block + [-1, 1, RepNCSPELAN4, [1024, 512, 256, 2]], # 28 + ] + +# gelan head +head: + [ + # elan-spp block + [28, 1, SPPELAN, [512, 256]], # 29 + + # up-concat merge + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 25], 1, Concat, [1]], # cat backbone P4 + + # elan-2 block + [-1, 1, RepNCSPELAN4, [512, 512, 256, 2]], # 32 + + # up-concat merge + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 22], 1, Concat, [1]], # cat backbone P3 + + # elan-2 block + [-1, 1, RepNCSPELAN4, [256, 256, 128, 2]], # 35 (P3/8-small) + + # avg-conv-down merge + [-1, 1, ADown, [256]], + [[-1, 32], 1, Concat, [1]], # cat head P4 + + # elan-2 block + [-1, 1, RepNCSPELAN4, [512, 512, 256, 2]], # 38 (P4/16-medium) + + # avg-conv-down merge + [-1, 1, ADown, [512]], + [[-1, 29], 1, Concat, [1]], # cat head P5 + + # elan-2 block + [-1, 1, RepNCSPELAN4, [512, 1024, 512, 2]], # 41 (P5/32-large) + + # detect + [[35, 38, 41], 1, DDetect, [nc]], # Detect(P3, P4, P5) + ] diff --git a/cv/3d_detection/yolov9/pytorch/models/detect/gelan.yaml b/cv/3d_detection/yolov9/pytorch/models/detect/gelan.yaml new file mode 100644 index 000000000..ecd54d47d --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/models/detect/gelan.yaml @@ -0,0 +1,80 @@ +# YOLOv9 + +# parameters +nc: 80 # number of classes +depth_multiple: 1.0 # model depth multiple +width_multiple: 1.0 # layer channel multiple +#activation: nn.LeakyReLU(0.1) +#activation: nn.ReLU() + +# anchors +anchors: 3 + +# gelan backbone +backbone: + [ + # conv down + [-1, 1, Conv, [64, 3, 2]], # 0-P1/2 + + # conv down + [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 + + # elan-1 block + [-1, 1, RepNCSPELAN4, [256, 128, 64, 1]], # 2 + + # avg-conv down + [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 + + # elan-2 block + [-1, 1, RepNCSPELAN4, [512, 256, 128, 1]], # 4 + + # avg-conv down + [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 + + # elan-2 block + [-1, 1, RepNCSPELAN4, [512, 512, 256, 1]], # 6 + + # avg-conv down + [-1, 1, Conv, [512, 3, 2]], # 7-P5/32 + + # elan-2 block + [-1, 1, RepNCSPELAN4, [512, 512, 256, 1]], # 8 + ] + +# gelan head +head: + [ + # elan-spp block + [-1, 1, SPPELAN, [512, 256]], # 9 + + # up-concat merge + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 6], 1, Concat, [1]], # cat backbone P4 + + # elan-2 block + [-1, 1, RepNCSPELAN4, [512, 512, 256, 1]], # 12 + + # up-concat merge + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 4], 1, Concat, [1]], # cat backbone P3 + + # elan-2 block + [-1, 1, RepNCSPELAN4, [256, 256, 128, 1]], # 15 (P3/8-small) + + # avg-conv-down merge + [-1, 1, Conv, [256, 3, 2]], + [[-1, 12], 1, Concat, [1]], # cat head P4 + + # elan-2 block + [-1, 1, RepNCSPELAN4, [512, 512, 256, 1]], # 18 (P4/16-medium) + + # avg-conv-down merge + [-1, 1, Conv, [512, 3, 2]], + [[-1, 9], 1, Concat, [1]], # cat head P5 + + # elan-2 block + [-1, 1, RepNCSPELAN4, [512, 512, 256, 1]], # 21 (P5/32-large) + + # detect + [[15, 18, 21], 1, DDetect, [nc]], # Detect(P3, P4, P5) + ] diff --git a/cv/3d_detection/yolov9/pytorch/models/detect/yolov7-af.yaml b/cv/3d_detection/yolov9/pytorch/models/detect/yolov7-af.yaml new file mode 100644 index 000000000..f739df15e --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/models/detect/yolov7-af.yaml @@ -0,0 +1,137 @@ +# YOLOv7 + +# Parameters +nc: 80 # number of classes +depth_multiple: 1. # model depth multiple +width_multiple: 1. # layer channel multiple +anchors: 3 + +# YOLOv7 backbone +backbone: + # [from, number, module, args] + [[-1, 1, Conv, [32, 3, 1]], # 0 + + [-1, 1, Conv, [64, 3, 2]], # 1-P1/2 + [-1, 1, Conv, [64, 3, 1]], + + [-1, 1, Conv, [128, 3, 2]], # 3-P2/4 + [-1, 1, Conv, [64, 1, 1]], + [-2, 1, Conv, [64, 1, 1]], + [-1, 1, Conv, [64, 3, 1]], + [-1, 1, Conv, [64, 3, 1]], + [-1, 1, Conv, [64, 3, 1]], + [-1, 1, Conv, [64, 3, 1]], + [[-1, -3, -5, -6], 1, Concat, [1]], + [-1, 1, Conv, [256, 1, 1]], # 11 + + [-1, 1, MP, []], + [-1, 1, Conv, [128, 1, 1]], + [-3, 1, Conv, [128, 1, 1]], + [-1, 1, Conv, [128, 3, 2]], + [[-1, -3], 1, Concat, [1]], # 16-P3/8 + [-1, 1, Conv, [128, 1, 1]], + [-2, 1, Conv, [128, 1, 1]], + [-1, 1, Conv, [128, 3, 1]], + [-1, 1, Conv, [128, 3, 1]], + [-1, 1, Conv, [128, 3, 1]], + [-1, 1, Conv, [128, 3, 1]], + [[-1, -3, -5, -6], 1, Concat, [1]], + [-1, 1, Conv, [512, 1, 1]], # 24 + + [-1, 1, MP, []], + [-1, 1, Conv, [256, 1, 1]], + [-3, 1, Conv, [256, 1, 1]], + [-1, 1, Conv, [256, 3, 2]], + [[-1, -3], 1, Concat, [1]], # 29-P4/16 + [-1, 1, Conv, [256, 1, 1]], + [-2, 1, Conv, [256, 1, 1]], + [-1, 1, Conv, [256, 3, 1]], + [-1, 1, Conv, [256, 3, 1]], + [-1, 1, Conv, [256, 3, 1]], + [-1, 1, Conv, [256, 3, 1]], + [[-1, -3, -5, -6], 1, Concat, [1]], + [-1, 1, Conv, [1024, 1, 1]], # 37 + + [-1, 1, MP, []], + [-1, 1, Conv, [512, 1, 1]], + [-3, 1, Conv, [512, 1, 1]], + [-1, 1, Conv, [512, 3, 2]], + [[-1, -3], 1, Concat, [1]], # 42-P5/32 + [-1, 1, Conv, [256, 1, 1]], + [-2, 1, Conv, [256, 1, 1]], + [-1, 1, Conv, [256, 3, 1]], + [-1, 1, Conv, [256, 3, 1]], + [-1, 1, Conv, [256, 3, 1]], + [-1, 1, Conv, [256, 3, 1]], + [[-1, -3, -5, -6], 1, Concat, [1]], + [-1, 1, Conv, [1024, 1, 1]], # 50 + ] + +# yolov7 head +head: + [[-1, 1, SPPCSPC, [512]], # 51 + + [-1, 1, Conv, [256, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [37, 1, Conv, [256, 1, 1]], # route backbone P4 + [[-1, -2], 1, Concat, [1]], + + [-1, 1, Conv, [256, 1, 1]], + [-2, 1, Conv, [256, 1, 1]], + [-1, 1, Conv, [128, 3, 1]], + [-1, 1, Conv, [128, 3, 1]], + [-1, 1, Conv, [128, 3, 1]], + [-1, 1, Conv, [128, 3, 1]], + [[-1, -2, -3, -4, -5, -6], 1, Concat, [1]], + [-1, 1, Conv, [256, 1, 1]], # 63 + + [-1, 1, Conv, [128, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [24, 1, Conv, [128, 1, 1]], # route backbone P3 + [[-1, -2], 1, Concat, [1]], + + [-1, 1, Conv, [128, 1, 1]], + [-2, 1, Conv, [128, 1, 1]], + [-1, 1, Conv, [64, 3, 1]], + [-1, 1, Conv, [64, 3, 1]], + [-1, 1, Conv, [64, 3, 1]], + [-1, 1, Conv, [64, 3, 1]], + [[-1, -2, -3, -4, -5, -6], 1, Concat, [1]], + [-1, 1, Conv, [128, 1, 1]], # 75 + + [-1, 1, MP, []], + [-1, 1, Conv, [128, 1, 1]], + [-3, 1, Conv, [128, 1, 1]], + [-1, 1, Conv, [128, 3, 2]], + [[-1, -3, 63], 1, Concat, [1]], + + [-1, 1, Conv, [256, 1, 1]], + [-2, 1, Conv, [256, 1, 1]], + [-1, 1, Conv, [128, 3, 1]], + [-1, 1, Conv, [128, 3, 1]], + [-1, 1, Conv, [128, 3, 1]], + [-1, 1, Conv, [128, 3, 1]], + [[-1, -2, -3, -4, -5, -6], 1, Concat, [1]], + [-1, 1, Conv, [256, 1, 1]], # 88 + + [-1, 1, MP, []], + [-1, 1, Conv, [256, 1, 1]], + [-3, 1, Conv, [256, 1, 1]], + [-1, 1, Conv, [256, 3, 2]], + [[-1, -3, 51], 1, Concat, [1]], + + [-1, 1, Conv, [512, 1, 1]], + [-2, 1, Conv, [512, 1, 1]], + [-1, 1, Conv, [256, 3, 1]], + [-1, 1, Conv, [256, 3, 1]], + [-1, 1, Conv, [256, 3, 1]], + [-1, 1, Conv, [256, 3, 1]], + [[-1, -2, -3, -4, -5, -6], 1, Concat, [1]], + [-1, 1, Conv, [512, 1, 1]], # 101 + + [75, 1, Conv, [256, 3, 1]], + [88, 1, Conv, [512, 3, 1]], + [101, 1, Conv, [1024, 3, 1]], + + [[102, 103, 104], 1, Detect, [nc]], # Detect(P3, P4, P5) + ] diff --git a/cv/3d_detection/yolov9/pytorch/models/detect/yolov9-c.yaml b/cv/3d_detection/yolov9/pytorch/models/detect/yolov9-c.yaml new file mode 100644 index 000000000..df8d31d2f --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/models/detect/yolov9-c.yaml @@ -0,0 +1,124 @@ +# YOLOv9 + +# parameters +nc: 80 # number of classes +depth_multiple: 1.0 # model depth multiple +width_multiple: 1.0 # layer channel multiple +#activation: nn.LeakyReLU(0.1) +#activation: nn.ReLU() + +# anchors +anchors: 3 + +# YOLOv9 backbone +backbone: + [ + [-1, 1, Silence, []], + + # conv down + [-1, 1, Conv, [64, 3, 2]], # 1-P1/2 + + # conv down + [-1, 1, Conv, [128, 3, 2]], # 2-P2/4 + + # elan-1 block + [-1, 1, RepNCSPELAN4, [256, 128, 64, 1]], # 3 + + # avg-conv down + [-1, 1, ADown, [256]], # 4-P3/8 + + # elan-2 block + [-1, 1, RepNCSPELAN4, [512, 256, 128, 1]], # 5 + + # avg-conv down + [-1, 1, ADown, [512]], # 6-P4/16 + + # elan-2 block + [-1, 1, RepNCSPELAN4, [512, 512, 256, 1]], # 7 + + # avg-conv down + [-1, 1, ADown, [512]], # 8-P5/32 + + # elan-2 block + [-1, 1, RepNCSPELAN4, [512, 512, 256, 1]], # 9 + ] + +# YOLOv9 head +head: + [ + # elan-spp block + [-1, 1, SPPELAN, [512, 256]], # 10 + + # up-concat merge + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 7], 1, Concat, [1]], # cat backbone P4 + + # elan-2 block + [-1, 1, RepNCSPELAN4, [512, 512, 256, 1]], # 13 + + # up-concat merge + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 5], 1, Concat, [1]], # cat backbone P3 + + # elan-2 block + [-1, 1, RepNCSPELAN4, [256, 256, 128, 1]], # 16 (P3/8-small) + + # avg-conv-down merge + [-1, 1, ADown, [256]], + [[-1, 13], 1, Concat, [1]], # cat head P4 + + # elan-2 block + [-1, 1, RepNCSPELAN4, [512, 512, 256, 1]], # 19 (P4/16-medium) + + # avg-conv-down merge + [-1, 1, ADown, [512]], + [[-1, 10], 1, Concat, [1]], # cat head P5 + + # elan-2 block + [-1, 1, RepNCSPELAN4, [512, 512, 256, 1]], # 22 (P5/32-large) + + + # multi-level reversible auxiliary branch + + # routing + [5, 1, CBLinear, [[256]]], # 23 + [7, 1, CBLinear, [[256, 512]]], # 24 + [9, 1, CBLinear, [[256, 512, 512]]], # 25 + + # conv down + [0, 1, Conv, [64, 3, 2]], # 26-P1/2 + + # conv down + [-1, 1, Conv, [128, 3, 2]], # 27-P2/4 + + # elan-1 block + [-1, 1, RepNCSPELAN4, [256, 128, 64, 1]], # 28 + + # avg-conv down fuse + [-1, 1, ADown, [256]], # 29-P3/8 + [[23, 24, 25, -1], 1, CBFuse, [[0, 0, 0]]], # 30 + + # elan-2 block + [-1, 1, RepNCSPELAN4, [512, 256, 128, 1]], # 31 + + # avg-conv down fuse + [-1, 1, ADown, [512]], # 32-P4/16 + [[24, 25, -1], 1, CBFuse, [[1, 1]]], # 33 + + # elan-2 block + [-1, 1, RepNCSPELAN4, [512, 512, 256, 1]], # 34 + + # avg-conv down fuse + [-1, 1, ADown, [512]], # 35-P5/32 + [[25, -1], 1, CBFuse, [[2]]], # 36 + + # elan-2 block + [-1, 1, RepNCSPELAN4, [512, 512, 256, 1]], # 37 + + + + # detection head + + # detect + [[31, 34, 37, 16, 19, 22], 1, DualDDetect, [nc]], # DualDDetect(A3, A4, A5, P3, P4, P5) + ] diff --git a/cv/3d_detection/yolov9/pytorch/models/detect/yolov9-e.yaml b/cv/3d_detection/yolov9/pytorch/models/detect/yolov9-e.yaml new file mode 100644 index 000000000..dcb122b61 --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/models/detect/yolov9-e.yaml @@ -0,0 +1,144 @@ +# YOLOv9 + +# parameters +nc: 80 # number of classes +depth_multiple: 1.0 # model depth multiple +width_multiple: 1.0 # layer channel multiple +#activation: nn.LeakyReLU(0.1) +#activation: nn.ReLU() + +# anchors +anchors: 3 + +# YOLOv9 backbone +backbone: + [ + [-1, 1, Silence, []], + + # conv down + [-1, 1, Conv, [64, 3, 2]], # 1-P1/2 + + # conv down + [-1, 1, Conv, [128, 3, 2]], # 2-P2/4 + + # csp-elan block + [-1, 1, RepNCSPELAN4, [256, 128, 64, 2]], # 3 + + # avg-conv down + [-1, 1, ADown, [256]], # 4-P3/8 + + # csp-elan block + [-1, 1, RepNCSPELAN4, [512, 256, 128, 2]], # 5 + + # avg-conv down + [-1, 1, ADown, [512]], # 6-P4/16 + + # csp-elan block + [-1, 1, RepNCSPELAN4, [1024, 512, 256, 2]], # 7 + + # avg-conv down + [-1, 1, ADown, [1024]], # 8-P5/32 + + # csp-elan block + [-1, 1, RepNCSPELAN4, [1024, 512, 256, 2]], # 9 + + # routing + [1, 1, CBLinear, [[64]]], # 10 + [3, 1, CBLinear, [[64, 128]]], # 11 + [5, 1, CBLinear, [[64, 128, 256]]], # 12 + [7, 1, CBLinear, [[64, 128, 256, 512]]], # 13 + [9, 1, CBLinear, [[64, 128, 256, 512, 1024]]], # 14 + + # conv down + [0, 1, Conv, [64, 3, 2]], # 15-P1/2 + [[10, 11, 12, 13, 14, -1], 1, CBFuse, [[0, 0, 0, 0, 0]]], # 16 + + # conv down + [-1, 1, Conv, [128, 3, 2]], # 17-P2/4 + [[11, 12, 13, 14, -1], 1, CBFuse, [[1, 1, 1, 1]]], # 18 + + # csp-elan block + [-1, 1, RepNCSPELAN4, [256, 128, 64, 2]], # 19 + + # avg-conv down fuse + [-1, 1, ADown, [256]], # 20-P3/8 + [[12, 13, 14, -1], 1, CBFuse, [[2, 2, 2]]], # 21 + + # csp-elan block + [-1, 1, RepNCSPELAN4, [512, 256, 128, 2]], # 22 + + # avg-conv down fuse + [-1, 1, ADown, [512]], # 23-P4/16 + [[13, 14, -1], 1, CBFuse, [[3, 3]]], # 24 + + # csp-elan block + [-1, 1, RepNCSPELAN4, [1024, 512, 256, 2]], # 25 + + # avg-conv down fuse + [-1, 1, ADown, [1024]], # 26-P5/32 + [[14, -1], 1, CBFuse, [[4]]], # 27 + + # csp-elan block + [-1, 1, RepNCSPELAN4, [1024, 512, 256, 2]], # 28 + ] + +# YOLOv9 head +head: + [ + # multi-level auxiliary branch + + # elan-spp block + [9, 1, SPPELAN, [512, 256]], # 29 + + # up-concat merge + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 7], 1, Concat, [1]], # cat backbone P4 + + # csp-elan block + [-1, 1, RepNCSPELAN4, [512, 512, 256, 2]], # 32 + + # up-concat merge + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 5], 1, Concat, [1]], # cat backbone P3 + + # csp-elan block + [-1, 1, RepNCSPELAN4, [256, 256, 128, 2]], # 35 + + + + # main branch + + # elan-spp block + [28, 1, SPPELAN, [512, 256]], # 36 + + # up-concat merge + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 25], 1, Concat, [1]], # cat backbone P4 + + # csp-elan block + [-1, 1, RepNCSPELAN4, [512, 512, 256, 2]], # 39 + + # up-concat merge + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 22], 1, Concat, [1]], # cat backbone P3 + + # csp-elan block + [-1, 1, RepNCSPELAN4, [256, 256, 128, 2]], # 42 (P3/8-small) + + # avg-conv-down merge + [-1, 1, ADown, [256]], + [[-1, 39], 1, Concat, [1]], # cat head P4 + + # csp-elan block + [-1, 1, RepNCSPELAN4, [512, 512, 256, 2]], # 45 (P4/16-medium) + + # avg-conv-down merge + [-1, 1, ADown, [512]], + [[-1, 36], 1, Concat, [1]], # cat head P5 + + # csp-elan block + [-1, 1, RepNCSPELAN4, [512, 1024, 512, 2]], # 48 (P5/32-large) + + # detect + [[35, 32, 29, 42, 45, 48], 1, DualDDetect, [nc]], # DualDDetect(A3, A4, A5, P3, P4, P5) + ] diff --git a/cv/3d_detection/yolov9/pytorch/models/detect/yolov9.yaml b/cv/3d_detection/yolov9/pytorch/models/detect/yolov9.yaml new file mode 100644 index 000000000..98ecd14f6 --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/models/detect/yolov9.yaml @@ -0,0 +1,117 @@ +# YOLOv9 + +# parameters +nc: 80 # number of classes +depth_multiple: 1.0 # model depth multiple +width_multiple: 1.0 # layer channel multiple +#activation: nn.LeakyReLU(0.1) +activation: nn.ReLU() + +# anchors +anchors: 3 + +# YOLOv9 backbone +backbone: + [ + [-1, 1, Silence, []], + + # conv down + [-1, 1, Conv, [64, 3, 2]], # 1-P1/2 + + # conv down + [-1, 1, Conv, [128, 3, 2]], # 2-P2/4 + + # elan-1 block + [-1, 1, RepNCSPELAN4, [256, 128, 64, 1]], # 3 + + # conv down + [-1, 1, Conv, [256, 3, 2]], # 4-P3/8 + + # elan-2 block + [-1, 1, RepNCSPELAN4, [512, 256, 128, 1]], # 5 + + # conv down + [-1, 1, Conv, [512, 3, 2]], # 6-P4/16 + + # elan-2 block + [-1, 1, RepNCSPELAN4, [512, 512, 256, 1]], # 7 + + # conv down + [-1, 1, Conv, [512, 3, 2]], # 8-P5/32 + + # elan-2 block + [-1, 1, RepNCSPELAN4, [512, 512, 256, 1]], # 9 + ] + +# YOLOv9 head +head: + [ + # elan-spp block + [-1, 1, SPPELAN, [512, 256]], # 10 + + # up-concat merge + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 7], 1, Concat, [1]], # cat backbone P4 + + # elan-2 block + [-1, 1, RepNCSPELAN4, [512, 512, 256, 1]], # 13 + + # up-concat merge + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 5], 1, Concat, [1]], # cat backbone P3 + + # elan-2 block + [-1, 1, RepNCSPELAN4, [256, 256, 128, 1]], # 16 (P3/8-small) + + # conv-down merge + [-1, 1, Conv, [256, 3, 2]], + [[-1, 13], 1, Concat, [1]], # cat head P4 + + # elan-2 block + [-1, 1, RepNCSPELAN4, [512, 512, 256, 1]], # 19 (P4/16-medium) + + # conv-down merge + [-1, 1, Conv, [512, 3, 2]], + [[-1, 10], 1, Concat, [1]], # cat head P5 + + # elan-2 block + [-1, 1, RepNCSPELAN4, [512, 512, 256, 1]], # 22 (P5/32-large) + + # routing + [5, 1, CBLinear, [[256]]], # 23 + [7, 1, CBLinear, [[256, 512]]], # 24 + [9, 1, CBLinear, [[256, 512, 512]]], # 25 + + # conv down + [0, 1, Conv, [64, 3, 2]], # 26-P1/2 + + # conv down + [-1, 1, Conv, [128, 3, 2]], # 27-P2/4 + + # elan-1 block + [-1, 1, RepNCSPELAN4, [256, 128, 64, 1]], # 28 + + # conv down fuse + [-1, 1, Conv, [256, 3, 2]], # 29-P3/8 + [[23, 24, 25, -1], 1, CBFuse, [[0, 0, 0]]], # 30 + + # elan-2 block + [-1, 1, RepNCSPELAN4, [512, 256, 128, 1]], # 31 + + # conv down fuse + [-1, 1, Conv, [512, 3, 2]], # 32-P4/16 + [[24, 25, -1], 1, CBFuse, [[1, 1]]], # 33 + + # elan-2 block + [-1, 1, RepNCSPELAN4, [512, 512, 256, 1]], # 34 + + # conv down fuse + [-1, 1, Conv, [512, 3, 2]], # 35-P5/32 + [[25, -1], 1, CBFuse, [[2]]], # 36 + + # elan-2 block + [-1, 1, RepNCSPELAN4, [512, 512, 256, 1]], # 37 + + # detect + [[31, 34, 37, 16, 19, 22], 1, DualDDetect, [nc]], # DualDDetect(A3, A4, A5, P3, P4, P5) + ] diff --git a/cv/3d_detection/yolov9/pytorch/models/experimental.py b/cv/3d_detection/yolov9/pytorch/models/experimental.py new file mode 100644 index 000000000..b1a466a6c --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/models/experimental.py @@ -0,0 +1,275 @@ +import math + +import numpy as np +import torch +import torch.nn as nn + +from utils.downloads import attempt_download + + +class Sum(nn.Module): + # Weighted sum of 2 or more layers https://arxiv.org/abs/1911.09070 + def __init__(self, n, weight=False): # n: number of inputs + super().__init__() + self.weight = weight # apply weights boolean + self.iter = range(n - 1) # iter object + if weight: + self.w = nn.Parameter(-torch.arange(1.0, n) / 2, requires_grad=True) # layer weights + + def forward(self, x): + y = x[0] # no weight + if self.weight: + w = torch.sigmoid(self.w) * 2 + for i in self.iter: + y = y + x[i + 1] * w[i] + else: + for i in self.iter: + y = y + x[i + 1] + return y + + +class MixConv2d(nn.Module): + # Mixed Depth-wise Conv https://arxiv.org/abs/1907.09595 + def __init__(self, c1, c2, k=(1, 3), s=1, equal_ch=True): # ch_in, ch_out, kernel, stride, ch_strategy + super().__init__() + n = len(k) # number of convolutions + if equal_ch: # equal c_ per group + i = torch.linspace(0, n - 1E-6, c2).floor() # c2 indices + c_ = [(i == g).sum() for g in range(n)] # intermediate channels + else: # equal weight.numel() per group + b = [c2] + [0] * n + a = np.eye(n + 1, n, k=-1) + a -= np.roll(a, 1, axis=1) + a *= np.array(k) ** 2 + a[0] = 1 + c_ = np.linalg.lstsq(a, b, rcond=None)[0].round() # solve for equal weight indices, ax = b + + self.m = nn.ModuleList([ + nn.Conv2d(c1, int(c_), k, s, k // 2, groups=math.gcd(c1, int(c_)), bias=False) for k, c_ in zip(k, c_)]) + self.bn = nn.BatchNorm2d(c2) + self.act = nn.SiLU() + + def forward(self, x): + return self.act(self.bn(torch.cat([m(x) for m in self.m], 1))) + + +class Ensemble(nn.ModuleList): + # Ensemble of models + def __init__(self): + super().__init__() + + def forward(self, x, augment=False, profile=False, visualize=False): + y = [module(x, augment, profile, visualize)[0] for module in self] + # y = torch.stack(y).max(0)[0] # max ensemble + # y = torch.stack(y).mean(0) # mean ensemble + y = torch.cat(y, 1) # nms ensemble + return y, None # inference, train output + + +class ORT_NMS(torch.autograd.Function): + '''ONNX-Runtime NMS operation''' + @staticmethod + def forward(ctx, + boxes, + scores, + max_output_boxes_per_class=torch.tensor([100]), + iou_threshold=torch.tensor([0.45]), + score_threshold=torch.tensor([0.25])): + device = boxes.device + batch = scores.shape[0] + num_det = random.randint(0, 100) + batches = torch.randint(0, batch, (num_det,)).sort()[0].to(device) + idxs = torch.arange(100, 100 + num_det).to(device) + zeros = torch.zeros((num_det,), dtype=torch.int64).to(device) + selected_indices = torch.cat([batches[None], zeros[None], idxs[None]], 0).T.contiguous() + selected_indices = selected_indices.to(torch.int64) + return selected_indices + + @staticmethod + def symbolic(g, boxes, scores, max_output_boxes_per_class, iou_threshold, score_threshold): + return g.op("NonMaxSuppression", boxes, scores, max_output_boxes_per_class, iou_threshold, score_threshold) + + +class TRT_NMS(torch.autograd.Function): + '''TensorRT NMS operation''' + @staticmethod + def forward( + ctx, + boxes, + scores, + background_class=-1, + box_coding=1, + iou_threshold=0.45, + max_output_boxes=100, + plugin_version="1", + score_activation=0, + score_threshold=0.25, + ): + + batch_size, num_boxes, num_classes = scores.shape + num_det = torch.randint(0, max_output_boxes, (batch_size, 1), dtype=torch.int32) + det_boxes = torch.randn(batch_size, max_output_boxes, 4) + det_scores = torch.randn(batch_size, max_output_boxes) + det_classes = torch.randint(0, num_classes, (batch_size, max_output_boxes), dtype=torch.int32) + return num_det, det_boxes, det_scores, det_classes + + @staticmethod + def symbolic(g, + boxes, + scores, + background_class=-1, + box_coding=1, + iou_threshold=0.45, + max_output_boxes=100, + plugin_version="1", + score_activation=0, + score_threshold=0.25): + out = g.op("TRT::EfficientNMS_TRT", + boxes, + scores, + background_class_i=background_class, + box_coding_i=box_coding, + iou_threshold_f=iou_threshold, + max_output_boxes_i=max_output_boxes, + plugin_version_s=plugin_version, + score_activation_i=score_activation, + score_threshold_f=score_threshold, + outputs=4) + nums, boxes, scores, classes = out + return nums, boxes, scores, classes + + +class ONNX_ORT(nn.Module): + '''onnx module with ONNX-Runtime NMS operation.''' + def __init__(self, max_obj=100, iou_thres=0.45, score_thres=0.25, max_wh=640, device=None, n_classes=80): + super().__init__() + self.device = device if device else torch.device("cpu") + self.max_obj = torch.tensor([max_obj]).to(device) + self.iou_threshold = torch.tensor([iou_thres]).to(device) + self.score_threshold = torch.tensor([score_thres]).to(device) + self.max_wh = max_wh # if max_wh != 0 : non-agnostic else : agnostic + self.convert_matrix = torch.tensor([[1, 0, 1, 0], [0, 1, 0, 1], [-0.5, 0, 0.5, 0], [0, -0.5, 0, 0.5]], + dtype=torch.float32, + device=self.device) + self.n_classes=n_classes + + def forward(self, x): + ## https://github.com/thaitc-hust/yolov9-tensorrt/blob/main/torch2onnx.py + ## thanks https://github.com/thaitc-hust + if isinstance(x, list): ## yolov9-c.pt and yolov9-e.pt return list + x = x[1] + x = x.permute(0, 2, 1) + bboxes_x = x[..., 0:1] + bboxes_y = x[..., 1:2] + bboxes_w = x[..., 2:3] + bboxes_h = x[..., 3:4] + bboxes = torch.cat([bboxes_x, bboxes_y, bboxes_w, bboxes_h], dim = -1) + bboxes = bboxes.unsqueeze(2) # [n_batch, n_bboxes, 4] -> [n_batch, n_bboxes, 1, 4] + obj_conf = x[..., 4:] + scores = obj_conf + bboxes @= self.convert_matrix + max_score, category_id = scores.max(2, keepdim=True) + dis = category_id.float() * self.max_wh + nmsbox = bboxes + dis + max_score_tp = max_score.transpose(1, 2).contiguous() + selected_indices = ORT_NMS.apply(nmsbox, max_score_tp, self.max_obj, self.iou_threshold, self.score_threshold) + X, Y = selected_indices[:, 0], selected_indices[:, 2] + selected_boxes = bboxes[X, Y, :] + selected_categories = category_id[X, Y, :].float() + selected_scores = max_score[X, Y, :] + X = X.unsqueeze(1).float() + return torch.cat([X, selected_boxes, selected_categories, selected_scores], 1) + + +class ONNX_TRT(nn.Module): + '''onnx module with TensorRT NMS operation.''' + def __init__(self, max_obj=100, iou_thres=0.45, score_thres=0.25, max_wh=None ,device=None, n_classes=80): + super().__init__() + assert max_wh is None + self.device = device if device else torch.device('cpu') + self.background_class = -1, + self.box_coding = 1, + self.iou_threshold = iou_thres + self.max_obj = max_obj + self.plugin_version = '1' + self.score_activation = 0 + self.score_threshold = score_thres + self.n_classes=n_classes + + def forward(self, x): + ## https://github.com/thaitc-hust/yolov9-tensorrt/blob/main/torch2onnx.py + ## thanks https://github.com/thaitc-hust + if isinstance(x, list): ## yolov9-c.pt and yolov9-e.pt return list + x = x[1] + x = x.permute(0, 2, 1) + bboxes_x = x[..., 0:1] + bboxes_y = x[..., 1:2] + bboxes_w = x[..., 2:3] + bboxes_h = x[..., 3:4] + bboxes = torch.cat([bboxes_x, bboxes_y, bboxes_w, bboxes_h], dim = -1) + bboxes = bboxes.unsqueeze(2) # [n_batch, n_bboxes, 4] -> [n_batch, n_bboxes, 1, 4] + obj_conf = x[..., 4:] + scores = obj_conf + num_det, det_boxes, det_scores, det_classes = TRT_NMS.apply(bboxes, scores, self.background_class, self.box_coding, + self.iou_threshold, self.max_obj, + self.plugin_version, self.score_activation, + self.score_threshold) + return num_det, det_boxes, det_scores, det_classes + +class End2End(nn.Module): + '''export onnx or tensorrt model with NMS operation.''' + def __init__(self, model, max_obj=100, iou_thres=0.45, score_thres=0.25, max_wh=None, device=None, n_classes=80): + super().__init__() + device = device if device else torch.device('cpu') + assert isinstance(max_wh,(int)) or max_wh is None + self.model = model.to(device) + self.model.model[-1].end2end = True + self.patch_model = ONNX_TRT if max_wh is None else ONNX_ORT + self.end2end = self.patch_model(max_obj, iou_thres, score_thres, max_wh, device, n_classes) + self.end2end.eval() + + def forward(self, x): + x = self.model(x) + x = self.end2end(x) + return x + + +def attempt_load(weights, device=None, inplace=True, fuse=True): + # Loads an ensemble of models weights=[a,b,c] or a single model weights=[a] or weights=a + from models.yolo import Detect, Model + + model = Ensemble() + for w in weights if isinstance(weights, list) else [weights]: + ckpt = torch.load(attempt_download(w), map_location='cpu') # load + ckpt = (ckpt.get('ema') or ckpt['model']).to(device).float() # FP32 model + + # Model compatibility updates + if not hasattr(ckpt, 'stride'): + ckpt.stride = torch.tensor([32.]) + if hasattr(ckpt, 'names') and isinstance(ckpt.names, (list, tuple)): + ckpt.names = dict(enumerate(ckpt.names)) # convert to dict + + model.append(ckpt.fuse().eval() if fuse and hasattr(ckpt, 'fuse') else ckpt.eval()) # model in eval mode + + # Module compatibility updates + for m in model.modules(): + t = type(m) + if t in (nn.Hardswish, nn.LeakyReLU, nn.ReLU, nn.ReLU6, nn.SiLU, Detect, Model): + m.inplace = inplace # torch 1.7.0 compatibility + # if t is Detect and not isinstance(m.anchor_grid, list): + # delattr(m, 'anchor_grid') + # setattr(m, 'anchor_grid', [torch.zeros(1)] * m.nl) + elif t is nn.Upsample and not hasattr(m, 'recompute_scale_factor'): + m.recompute_scale_factor = None # torch 1.11.0 compatibility + + # Return model + if len(model) == 1: + return model[-1] + + # Return detection ensemble + print(f'Ensemble created with {weights}\n') + for k in 'names', 'nc', 'yaml': + setattr(model, k, getattr(model[0], k)) + model.stride = model[torch.argmax(torch.tensor([m.stride.max() for m in model])).int()].stride # max stride + assert all(model[0].nc == m.nc for m in model), f'Models have different class counts: {[m.nc for m in model]}' + return model diff --git a/cv/3d_detection/yolov9/pytorch/models/hub/anchors.yaml b/cv/3d_detection/yolov9/pytorch/models/hub/anchors.yaml new file mode 100644 index 000000000..65e85cf47 --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/models/hub/anchors.yaml @@ -0,0 +1,59 @@ +# YOLOv3 & YOLOv5 +# Default anchors for COCO data + + +# P5 ------------------------------------------------------------------------------------------------------------------- +# P5-640: +anchors_p5_640: + - [10,13, 16,30, 33,23] # P3/8 + - [30,61, 62,45, 59,119] # P4/16 + - [116,90, 156,198, 373,326] # P5/32 + + +# P6 ------------------------------------------------------------------------------------------------------------------- +# P6-640: thr=0.25: 0.9964 BPR, 5.54 anchors past thr, n=12, img_size=640, metric_all=0.281/0.716-mean/best, past_thr=0.469-mean: 9,11, 21,19, 17,41, 43,32, 39,70, 86,64, 65,131, 134,130, 120,265, 282,180, 247,354, 512,387 +anchors_p6_640: + - [9,11, 21,19, 17,41] # P3/8 + - [43,32, 39,70, 86,64] # P4/16 + - [65,131, 134,130, 120,265] # P5/32 + - [282,180, 247,354, 512,387] # P6/64 + +# P6-1280: thr=0.25: 0.9950 BPR, 5.55 anchors past thr, n=12, img_size=1280, metric_all=0.281/0.714-mean/best, past_thr=0.468-mean: 19,27, 44,40, 38,94, 96,68, 86,152, 180,137, 140,301, 303,264, 238,542, 436,615, 739,380, 925,792 +anchors_p6_1280: + - [19,27, 44,40, 38,94] # P3/8 + - [96,68, 86,152, 180,137] # P4/16 + - [140,301, 303,264, 238,542] # P5/32 + - [436,615, 739,380, 925,792] # P6/64 + +# P6-1920: thr=0.25: 0.9950 BPR, 5.55 anchors past thr, n=12, img_size=1920, metric_all=0.281/0.714-mean/best, past_thr=0.468-mean: 28,41, 67,59, 57,141, 144,103, 129,227, 270,205, 209,452, 455,396, 358,812, 653,922, 1109,570, 1387,1187 +anchors_p6_1920: + - [28,41, 67,59, 57,141] # P3/8 + - [144,103, 129,227, 270,205] # P4/16 + - [209,452, 455,396, 358,812] # P5/32 + - [653,922, 1109,570, 1387,1187] # P6/64 + + +# P7 ------------------------------------------------------------------------------------------------------------------- +# P7-640: thr=0.25: 0.9962 BPR, 6.76 anchors past thr, n=15, img_size=640, metric_all=0.275/0.733-mean/best, past_thr=0.466-mean: 11,11, 13,30, 29,20, 30,46, 61,38, 39,92, 78,80, 146,66, 79,163, 149,150, 321,143, 157,303, 257,402, 359,290, 524,372 +anchors_p7_640: + - [11,11, 13,30, 29,20] # P3/8 + - [30,46, 61,38, 39,92] # P4/16 + - [78,80, 146,66, 79,163] # P5/32 + - [149,150, 321,143, 157,303] # P6/64 + - [257,402, 359,290, 524,372] # P7/128 + +# P7-1280: thr=0.25: 0.9968 BPR, 6.71 anchors past thr, n=15, img_size=1280, metric_all=0.273/0.732-mean/best, past_thr=0.463-mean: 19,22, 54,36, 32,77, 70,83, 138,71, 75,173, 165,159, 148,334, 375,151, 334,317, 251,626, 499,474, 750,326, 534,814, 1079,818 +anchors_p7_1280: + - [19,22, 54,36, 32,77] # P3/8 + - [70,83, 138,71, 75,173] # P4/16 + - [165,159, 148,334, 375,151] # P5/32 + - [334,317, 251,626, 499,474] # P6/64 + - [750,326, 534,814, 1079,818] # P7/128 + +# P7-1920: thr=0.25: 0.9968 BPR, 6.71 anchors past thr, n=15, img_size=1920, metric_all=0.273/0.732-mean/best, past_thr=0.463-mean: 29,34, 81,55, 47,115, 105,124, 207,107, 113,259, 247,238, 222,500, 563,227, 501,476, 376,939, 749,711, 1126,489, 801,1222, 1618,1227 +anchors_p7_1920: + - [29,34, 81,55, 47,115] # P3/8 + - [105,124, 207,107, 113,259] # P4/16 + - [247,238, 222,500, 563,227] # P5/32 + - [501,476, 376,939, 749,711] # P6/64 + - [1126,489, 801,1222, 1618,1227] # P7/128 diff --git a/cv/3d_detection/yolov9/pytorch/models/hub/yolov3-spp.yaml b/cv/3d_detection/yolov9/pytorch/models/hub/yolov3-spp.yaml new file mode 100644 index 000000000..6fb1c0b72 --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/models/hub/yolov3-spp.yaml @@ -0,0 +1,51 @@ +# YOLOv3 + +# Parameters +nc: 80 # number of classes +depth_multiple: 1.0 # model depth multiple +width_multiple: 1.0 # layer channel multiple +anchors: + - [10,13, 16,30, 33,23] # P3/8 + - [30,61, 62,45, 59,119] # P4/16 + - [116,90, 156,198, 373,326] # P5/32 + +# darknet53 backbone +backbone: + # [from, number, module, args] + [[-1, 1, Conv, [32, 3, 1]], # 0 + [-1, 1, Conv, [64, 3, 2]], # 1-P1/2 + [-1, 1, Bottleneck, [64]], + [-1, 1, Conv, [128, 3, 2]], # 3-P2/4 + [-1, 2, Bottleneck, [128]], + [-1, 1, Conv, [256, 3, 2]], # 5-P3/8 + [-1, 8, Bottleneck, [256]], + [-1, 1, Conv, [512, 3, 2]], # 7-P4/16 + [-1, 8, Bottleneck, [512]], + [-1, 1, Conv, [1024, 3, 2]], # 9-P5/32 + [-1, 4, Bottleneck, [1024]], # 10 + ] + +# YOLOv3-SPP head +head: + [[-1, 1, Bottleneck, [1024, False]], + [-1, 1, SPP, [512, [5, 9, 13]]], + [-1, 1, Conv, [1024, 3, 1]], + [-1, 1, Conv, [512, 1, 1]], + [-1, 1, Conv, [1024, 3, 1]], # 15 (P5/32-large) + + [-2, 1, Conv, [256, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 8], 1, Concat, [1]], # cat backbone P4 + [-1, 1, Bottleneck, [512, False]], + [-1, 1, Bottleneck, [512, False]], + [-1, 1, Conv, [256, 1, 1]], + [-1, 1, Conv, [512, 3, 1]], # 22 (P4/16-medium) + + [-2, 1, Conv, [128, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 6], 1, Concat, [1]], # cat backbone P3 + [-1, 1, Bottleneck, [256, False]], + [-1, 2, Bottleneck, [256, False]], # 27 (P3/8-small) + + [[27, 22, 15], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5) + ] diff --git a/cv/3d_detection/yolov9/pytorch/models/hub/yolov3-tiny.yaml b/cv/3d_detection/yolov9/pytorch/models/hub/yolov3-tiny.yaml new file mode 100644 index 000000000..47372e09a --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/models/hub/yolov3-tiny.yaml @@ -0,0 +1,41 @@ +# YOLOv3 + +# Parameters +nc: 80 # number of classes +depth_multiple: 1.0 # model depth multiple +width_multiple: 1.0 # layer channel multiple +anchors: + - [10,14, 23,27, 37,58] # P4/16 + - [81,82, 135,169, 344,319] # P5/32 + +# YOLOv3-tiny backbone +backbone: + # [from, number, module, args] + [[-1, 1, Conv, [16, 3, 1]], # 0 + [-1, 1, nn.MaxPool2d, [2, 2, 0]], # 1-P1/2 + [-1, 1, Conv, [32, 3, 1]], + [-1, 1, nn.MaxPool2d, [2, 2, 0]], # 3-P2/4 + [-1, 1, Conv, [64, 3, 1]], + [-1, 1, nn.MaxPool2d, [2, 2, 0]], # 5-P3/8 + [-1, 1, Conv, [128, 3, 1]], + [-1, 1, nn.MaxPool2d, [2, 2, 0]], # 7-P4/16 + [-1, 1, Conv, [256, 3, 1]], + [-1, 1, nn.MaxPool2d, [2, 2, 0]], # 9-P5/32 + [-1, 1, Conv, [512, 3, 1]], + [-1, 1, nn.ZeroPad2d, [[0, 1, 0, 1]]], # 11 + [-1, 1, nn.MaxPool2d, [2, 1, 0]], # 12 + ] + +# YOLOv3-tiny head +head: + [[-1, 1, Conv, [1024, 3, 1]], + [-1, 1, Conv, [256, 1, 1]], + [-1, 1, Conv, [512, 3, 1]], # 15 (P5/32-large) + + [-2, 1, Conv, [128, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 8], 1, Concat, [1]], # cat backbone P4 + [-1, 1, Conv, [256, 3, 1]], # 19 (P4/16-medium) + + [[19, 15], 1, Detect, [nc, anchors]], # Detect(P4, P5) + ] diff --git a/cv/3d_detection/yolov9/pytorch/models/hub/yolov3.yaml b/cv/3d_detection/yolov9/pytorch/models/hub/yolov3.yaml new file mode 100644 index 000000000..3ebd78f5e --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/models/hub/yolov3.yaml @@ -0,0 +1,51 @@ +# YOLOv3 + +# Parameters +nc: 80 # number of classes +depth_multiple: 1.0 # model depth multiple +width_multiple: 1.0 # layer channel multiple +anchors: + - [10,13, 16,30, 33,23] # P3/8 + - [30,61, 62,45, 59,119] # P4/16 + - [116,90, 156,198, 373,326] # P5/32 + +# darknet53 backbone +backbone: + # [from, number, module, args] + [[-1, 1, Conv, [32, 3, 1]], # 0 + [-1, 1, Conv, [64, 3, 2]], # 1-P1/2 + [-1, 1, Bottleneck, [64]], + [-1, 1, Conv, [128, 3, 2]], # 3-P2/4 + [-1, 2, Bottleneck, [128]], + [-1, 1, Conv, [256, 3, 2]], # 5-P3/8 + [-1, 8, Bottleneck, [256]], + [-1, 1, Conv, [512, 3, 2]], # 7-P4/16 + [-1, 8, Bottleneck, [512]], + [-1, 1, Conv, [1024, 3, 2]], # 9-P5/32 + [-1, 4, Bottleneck, [1024]], # 10 + ] + +# YOLOv3 head +head: + [[-1, 1, Bottleneck, [1024, False]], + [-1, 1, Conv, [512, 1, 1]], + [-1, 1, Conv, [1024, 3, 1]], + [-1, 1, Conv, [512, 1, 1]], + [-1, 1, Conv, [1024, 3, 1]], # 15 (P5/32-large) + + [-2, 1, Conv, [256, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 8], 1, Concat, [1]], # cat backbone P4 + [-1, 1, Bottleneck, [512, False]], + [-1, 1, Bottleneck, [512, False]], + [-1, 1, Conv, [256, 1, 1]], + [-1, 1, Conv, [512, 3, 1]], # 22 (P4/16-medium) + + [-2, 1, Conv, [128, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 6], 1, Concat, [1]], # cat backbone P3 + [-1, 1, Bottleneck, [256, False]], + [-1, 2, Bottleneck, [256, False]], # 27 (P3/8-small) + + [[27, 22, 15], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5) + ] diff --git a/cv/3d_detection/yolov9/pytorch/models/panoptic/gelan-c-pan.yaml b/cv/3d_detection/yolov9/pytorch/models/panoptic/gelan-c-pan.yaml new file mode 100644 index 000000000..acc41c4e0 --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/models/panoptic/gelan-c-pan.yaml @@ -0,0 +1,80 @@ +# YOLOv9 + +# parameters +nc: 80 # number of classes +depth_multiple: 1.0 # model depth multiple +width_multiple: 1.0 # layer channel multiple +#activation: nn.LeakyReLU(0.1) +#activation: nn.ReLU() + +# anchors +anchors: 3 + +# gelan backbone +backbone: + [ + # conv down + [-1, 1, Conv, [64, 3, 2]], # 0-P1/2 + + # conv down + [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 + + # elan-1 block + [-1, 1, RepNCSPELAN4, [256, 128, 64, 1]], # 2 + + # avg-conv down + [-1, 1, ADown, [256]], # 3-P3/8 + + # elan-2 block + [-1, 1, RepNCSPELAN4, [512, 256, 128, 1]], # 4 + + # avg-conv down + [-1, 1, ADown, [512]], # 5-P4/16 + + # elan-2 block + [-1, 1, RepNCSPELAN4, [512, 512, 256, 1]], # 6 + + # avg-conv down + [-1, 1, ADown, [512]], # 7-P5/32 + + # elan-2 block + [-1, 1, RepNCSPELAN4, [512, 512, 256, 1]], # 8 + ] + +# gelan head +head: + [ + # elan-spp block + [-1, 1, SPPELAN, [512, 256]], # 9 + + # up-concat merge + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 6], 1, Concat, [1]], # cat backbone P4 + + # elan-2 block + [-1, 1, RepNCSPELAN4, [512, 512, 256, 1]], # 12 + + # up-concat merge + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 4], 1, Concat, [1]], # cat backbone P3 + + # elan-2 block + [-1, 1, RepNCSPELAN4, [256, 256, 128, 1]], # 15 (P3/8-small) + + # avg-conv-down merge + [-1, 1, ADown, [256]], + [[-1, 12], 1, Concat, [1]], # cat head P4 + + # elan-2 block + [-1, 1, RepNCSPELAN4, [512, 512, 256, 1]], # 18 (P4/16-medium) + + # avg-conv-down merge + [-1, 1, ADown, [512]], + [[-1, 9], 1, Concat, [1]], # cat head P5 + + # elan-2 block + [-1, 1, RepNCSPELAN4, [512, 512, 256, 1]], # 21 (P5/32-large) + + # panoptic + [[15, 18, 21], 1, Panoptic, [nc, 93, 32, 256]], # Panoptic(P3, P4, P5) + ] diff --git a/cv/3d_detection/yolov9/pytorch/models/panoptic/yolov7-af-pan.yaml b/cv/3d_detection/yolov9/pytorch/models/panoptic/yolov7-af-pan.yaml new file mode 100644 index 000000000..a9bed1d1d --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/models/panoptic/yolov7-af-pan.yaml @@ -0,0 +1,137 @@ +# YOLOv7 + +# Parameters +nc: 80 # number of classes +sem_nc: 93 # number of stuff classes +depth_multiple: 1.0 # model depth multiple +width_multiple: 1.0 # layer channel multiple +anchors: 3 + +# YOLOv7 backbone +backbone: + [[-1, 1, Conv, [32, 3, 1]], # 0 + + [-1, 1, Conv, [64, 3, 2]], # 1-P1/2 + [-1, 1, Conv, [64, 3, 1]], + + [-1, 1, Conv, [128, 3, 2]], # 3-P2/4 + [-1, 1, Conv, [64, 1, 1]], + [-2, 1, Conv, [64, 1, 1]], + [-1, 1, Conv, [64, 3, 1]], + [-1, 1, Conv, [64, 3, 1]], + [-1, 1, Conv, [64, 3, 1]], + [-1, 1, Conv, [64, 3, 1]], + [[-1, -3, -5, -6], 1, Concat, [1]], + [-1, 1, Conv, [256, 1, 1]], # 11 + + [-1, 1, MP, []], + [-1, 1, Conv, [128, 1, 1]], + [-3, 1, Conv, [128, 1, 1]], + [-1, 1, Conv, [128, 3, 2]], + [[-1, -3], 1, Concat, [1]], # 16-P3/8 + [-1, 1, Conv, [128, 1, 1]], + [-2, 1, Conv, [128, 1, 1]], + [-1, 1, Conv, [128, 3, 1]], + [-1, 1, Conv, [128, 3, 1]], + [-1, 1, Conv, [128, 3, 1]], + [-1, 1, Conv, [128, 3, 1]], + [[-1, -3, -5, -6], 1, Concat, [1]], + [-1, 1, Conv, [512, 1, 1]], # 24 + + [-1, 1, MP, []], + [-1, 1, Conv, [256, 1, 1]], + [-3, 1, Conv, [256, 1, 1]], + [-1, 1, Conv, [256, 3, 2]], + [[-1, -3], 1, Concat, [1]], # 29-P4/16 + [-1, 1, Conv, [256, 1, 1]], + [-2, 1, Conv, [256, 1, 1]], + [-1, 1, Conv, [256, 3, 1]], + [-1, 1, Conv, [256, 3, 1]], + [-1, 1, Conv, [256, 3, 1]], + [-1, 1, Conv, [256, 3, 1]], + [[-1, -3, -5, -6], 1, Concat, [1]], + [-1, 1, Conv, [1024, 1, 1]], # 37 + + [-1, 1, MP, []], + [-1, 1, Conv, [512, 1, 1]], + [-3, 1, Conv, [512, 1, 1]], + [-1, 1, Conv, [512, 3, 2]], + [[-1, -3], 1, Concat, [1]], # 42-P5/32 + [-1, 1, Conv, [256, 1, 1]], + [-2, 1, Conv, [256, 1, 1]], + [-1, 1, Conv, [256, 3, 1]], + [-1, 1, Conv, [256, 3, 1]], + [-1, 1, Conv, [256, 3, 1]], + [-1, 1, Conv, [256, 3, 1]], + [[-1, -3, -5, -6], 1, Concat, [1]], + [-1, 1, Conv, [1024, 1, 1]], # 50 + ] + +# yolov7 head +head: + [[-1, 1, SPPCSPC, [512]], # 51 + + [-1, 1, Conv, [256, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [37, 1, Conv, [256, 1, 1]], # route backbone P4 + [[-1, -2], 1, Concat, [1]], + + [-1, 1, Conv, [256, 1, 1]], + [-2, 1, Conv, [256, 1, 1]], + [-1, 1, Conv, [128, 3, 1]], + [-1, 1, Conv, [128, 3, 1]], + [-1, 1, Conv, [128, 3, 1]], + [-1, 1, Conv, [128, 3, 1]], + [[-1, -2, -3, -4, -5, -6], 1, Concat, [1]], + [-1, 1, Conv, [256, 1, 1]], # 63 + + [-1, 1, Conv, [128, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [24, 1, Conv, [128, 1, 1]], # route backbone P3 + [[-1, -2], 1, Concat, [1]], + + [-1, 1, Conv, [128, 1, 1]], + [-2, 1, Conv, [128, 1, 1]], + [-1, 1, Conv, [64, 3, 1]], + [-1, 1, Conv, [64, 3, 1]], + [-1, 1, Conv, [64, 3, 1]], + [-1, 1, Conv, [64, 3, 1]], + [[-1, -2, -3, -4, -5, -6], 1, Concat, [1]], + [-1, 1, Conv, [128, 1, 1]], # 75 + + [-1, 1, MP, []], + [-1, 1, Conv, [128, 1, 1]], + [-3, 1, Conv, [128, 1, 1]], + [-1, 1, Conv, [128, 3, 2]], + [[-1, -3, 63], 1, Concat, [1]], + + [-1, 1, Conv, [256, 1, 1]], + [-2, 1, Conv, [256, 1, 1]], + [-1, 1, Conv, [128, 3, 1]], + [-1, 1, Conv, [128, 3, 1]], + [-1, 1, Conv, [128, 3, 1]], + [-1, 1, Conv, [128, 3, 1]], + [[-1, -2, -3, -4, -5, -6], 1, Concat, [1]], + [-1, 1, Conv, [256, 1, 1]], # 88 + + [-1, 1, MP, []], + [-1, 1, Conv, [256, 1, 1]], + [-3, 1, Conv, [256, 1, 1]], + [-1, 1, Conv, [256, 3, 2]], + [[-1, -3, 51], 1, Concat, [1]], + + [-1, 1, Conv, [512, 1, 1]], + [-2, 1, Conv, [512, 1, 1]], + [-1, 1, Conv, [256, 3, 1]], + [-1, 1, Conv, [256, 3, 1]], + [-1, 1, Conv, [256, 3, 1]], + [-1, 1, Conv, [256, 3, 1]], + [[-1, -2, -3, -4, -5, -6], 1, Concat, [1]], + [-1, 1, Conv, [512, 1, 1]], # 101 + + [75, 1, Conv, [256, 3, 1]], + [88, 1, Conv, [512, 3, 1]], + [101, 1, Conv, [1024, 3, 1]], + + [[102, 103, 104], 1, Panoptic, [nc, 93, 32, 256]], # Panoptic(P3, P4, P5) + ] diff --git a/cv/3d_detection/yolov9/pytorch/models/segment/gelan-c-dseg.yaml b/cv/3d_detection/yolov9/pytorch/models/segment/gelan-c-dseg.yaml new file mode 100644 index 000000000..8e4a8e839 --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/models/segment/gelan-c-dseg.yaml @@ -0,0 +1,84 @@ +# YOLOv9 + +# parameters +nc: 80 # number of classes +depth_multiple: 1.0 # model depth multiple +width_multiple: 1.0 # layer channel multiple +#activation: nn.LeakyReLU(0.1) +#activation: nn.ReLU() + +# anchors +anchors: 3 + +# gelan backbone +backbone: + [ + # conv down + [-1, 1, Conv, [64, 3, 2]], # 0-P1/2 + + # conv down + [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 + + # elan-1 block + [-1, 1, RepNCSPELAN4, [256, 128, 64, 1]], # 2 + + # avg-conv down + [-1, 1, ADown, [256]], # 3-P3/8 + + # elan-2 block + [-1, 1, RepNCSPELAN4, [512, 256, 128, 1]], # 4 + + # avg-conv down + [-1, 1, ADown, [512]], # 5-P4/16 + + # elan-2 block + [-1, 1, RepNCSPELAN4, [512, 512, 256, 1]], # 6 + + # avg-conv down + [-1, 1, ADown, [512]], # 7-P5/32 + + # elan-2 block + [-1, 1, RepNCSPELAN4, [512, 512, 256, 1]], # 8 + ] + +# gelan head +head: + [ + # elan-spp block + [-1, 1, SPPELAN, [512, 256]], # 9 + + # up-concat merge + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 6], 1, Concat, [1]], # cat backbone P4 + + # elan-2 block + [-1, 1, RepNCSPELAN4, [512, 512, 256, 1]], # 12 + + # up-concat merge + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 4], 1, Concat, [1]], # cat backbone P3 + + # elan-2 block + [-1, 1, RepNCSPELAN4, [256, 256, 128, 1]], # 15 (P3/8-small) + + # avg-conv-down merge + [-1, 1, ADown, [256]], + [[-1, 12], 1, Concat, [1]], # cat head P4 + + # elan-2 block + [-1, 1, RepNCSPELAN4, [512, 512, 256, 1]], # 18 (P4/16-medium) + + # avg-conv-down merge + [-1, 1, ADown, [512]], + [[-1, 9], 1, Concat, [1]], # cat head P5 + + # elan-2 block + [-1, 1, RepNCSPELAN4, [512, 512, 256, 1]], # 21 (P5/32-large) + + [15, 1, RepNCSPELAN4, [256, 256, 128, 1]], # 22 + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [-1, 1, Conv, [256, 3, 1]], # 24 + + # segment + [[15, 18, 21, 24], 1, DSegment, [nc, 32, 256]], # Segment(P3, P4, P5) + ] diff --git a/cv/3d_detection/yolov9/pytorch/models/segment/gelan-c-seg.yaml b/cv/3d_detection/yolov9/pytorch/models/segment/gelan-c-seg.yaml new file mode 100644 index 000000000..d7815bb3d --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/models/segment/gelan-c-seg.yaml @@ -0,0 +1,80 @@ +# YOLOv9 + +# parameters +nc: 80 # number of classes +depth_multiple: 1.0 # model depth multiple +width_multiple: 1.0 # layer channel multiple +#activation: nn.LeakyReLU(0.1) +#activation: nn.ReLU() + +# anchors +anchors: 3 + +# gelan backbone +backbone: + [ + # conv down + [-1, 1, Conv, [64, 3, 2]], # 0-P1/2 + + # conv down + [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 + + # elan-1 block + [-1, 1, RepNCSPELAN4, [256, 128, 64, 1]], # 2 + + # avg-conv down + [-1, 1, ADown, [256]], # 3-P3/8 + + # elan-2 block + [-1, 1, RepNCSPELAN4, [512, 256, 128, 1]], # 4 + + # avg-conv down + [-1, 1, ADown, [512]], # 5-P4/16 + + # elan-2 block + [-1, 1, RepNCSPELAN4, [512, 512, 256, 1]], # 6 + + # avg-conv down + [-1, 1, ADown, [512]], # 7-P5/32 + + # elan-2 block + [-1, 1, RepNCSPELAN4, [512, 512, 256, 1]], # 8 + ] + +# gelan head +head: + [ + # elan-spp block + [-1, 1, SPPELAN, [512, 256]], # 9 + + # up-concat merge + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 6], 1, Concat, [1]], # cat backbone P4 + + # elan-2 block + [-1, 1, RepNCSPELAN4, [512, 512, 256, 1]], # 12 + + # up-concat merge + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 4], 1, Concat, [1]], # cat backbone P3 + + # elan-2 block + [-1, 1, RepNCSPELAN4, [256, 256, 128, 1]], # 15 (P3/8-small) + + # avg-conv-down merge + [-1, 1, ADown, [256]], + [[-1, 12], 1, Concat, [1]], # cat head P4 + + # elan-2 block + [-1, 1, RepNCSPELAN4, [512, 512, 256, 1]], # 18 (P4/16-medium) + + # avg-conv-down merge + [-1, 1, ADown, [512]], + [[-1, 9], 1, Concat, [1]], # cat head P5 + + # elan-2 block + [-1, 1, RepNCSPELAN4, [512, 512, 256, 1]], # 21 (P5/32-large) + + # segment + [[15, 18, 21], 1, Segment, [nc, 32, 256]], # Segment(P3, P4, P5) + ] diff --git a/cv/3d_detection/yolov9/pytorch/models/segment/yolov7-af-seg.yaml b/cv/3d_detection/yolov9/pytorch/models/segment/yolov7-af-seg.yaml new file mode 100644 index 000000000..0e4b61f7b --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/models/segment/yolov7-af-seg.yaml @@ -0,0 +1,136 @@ +# YOLOv7 + +# Parameters +nc: 80 # number of classes +depth_multiple: 1.0 # model depth multiple +width_multiple: 1.0 # layer channel multiple +anchors: 3 + +# YOLOv7 backbone +backbone: + [[-1, 1, Conv, [32, 3, 1]], # 0 + + [-1, 1, Conv, [64, 3, 2]], # 1-P1/2 + [-1, 1, Conv, [64, 3, 1]], + + [-1, 1, Conv, [128, 3, 2]], # 3-P2/4 + [-1, 1, Conv, [64, 1, 1]], + [-2, 1, Conv, [64, 1, 1]], + [-1, 1, Conv, [64, 3, 1]], + [-1, 1, Conv, [64, 3, 1]], + [-1, 1, Conv, [64, 3, 1]], + [-1, 1, Conv, [64, 3, 1]], + [[-1, -3, -5, -6], 1, Concat, [1]], + [-1, 1, Conv, [256, 1, 1]], # 11 + + [-1, 1, MP, []], + [-1, 1, Conv, [128, 1, 1]], + [-3, 1, Conv, [128, 1, 1]], + [-1, 1, Conv, [128, 3, 2]], + [[-1, -3], 1, Concat, [1]], # 16-P3/8 + [-1, 1, Conv, [128, 1, 1]], + [-2, 1, Conv, [128, 1, 1]], + [-1, 1, Conv, [128, 3, 1]], + [-1, 1, Conv, [128, 3, 1]], + [-1, 1, Conv, [128, 3, 1]], + [-1, 1, Conv, [128, 3, 1]], + [[-1, -3, -5, -6], 1, Concat, [1]], + [-1, 1, Conv, [512, 1, 1]], # 24 + + [-1, 1, MP, []], + [-1, 1, Conv, [256, 1, 1]], + [-3, 1, Conv, [256, 1, 1]], + [-1, 1, Conv, [256, 3, 2]], + [[-1, -3], 1, Concat, [1]], # 29-P4/16 + [-1, 1, Conv, [256, 1, 1]], + [-2, 1, Conv, [256, 1, 1]], + [-1, 1, Conv, [256, 3, 1]], + [-1, 1, Conv, [256, 3, 1]], + [-1, 1, Conv, [256, 3, 1]], + [-1, 1, Conv, [256, 3, 1]], + [[-1, -3, -5, -6], 1, Concat, [1]], + [-1, 1, Conv, [1024, 1, 1]], # 37 + + [-1, 1, MP, []], + [-1, 1, Conv, [512, 1, 1]], + [-3, 1, Conv, [512, 1, 1]], + [-1, 1, Conv, [512, 3, 2]], + [[-1, -3], 1, Concat, [1]], # 42-P5/32 + [-1, 1, Conv, [256, 1, 1]], + [-2, 1, Conv, [256, 1, 1]], + [-1, 1, Conv, [256, 3, 1]], + [-1, 1, Conv, [256, 3, 1]], + [-1, 1, Conv, [256, 3, 1]], + [-1, 1, Conv, [256, 3, 1]], + [[-1, -3, -5, -6], 1, Concat, [1]], + [-1, 1, Conv, [1024, 1, 1]], # 50 + ] + +# yolov7 head +head: + [[-1, 1, SPPCSPC, [512]], # 51 + + [-1, 1, Conv, [256, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [37, 1, Conv, [256, 1, 1]], # route backbone P4 + [[-1, -2], 1, Concat, [1]], + + [-1, 1, Conv, [256, 1, 1]], + [-2, 1, Conv, [256, 1, 1]], + [-1, 1, Conv, [128, 3, 1]], + [-1, 1, Conv, [128, 3, 1]], + [-1, 1, Conv, [128, 3, 1]], + [-1, 1, Conv, [128, 3, 1]], + [[-1, -2, -3, -4, -5, -6], 1, Concat, [1]], + [-1, 1, Conv, [256, 1, 1]], # 63 + + [-1, 1, Conv, [128, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [24, 1, Conv, [128, 1, 1]], # route backbone P3 + [[-1, -2], 1, Concat, [1]], + + [-1, 1, Conv, [128, 1, 1]], + [-2, 1, Conv, [128, 1, 1]], + [-1, 1, Conv, [64, 3, 1]], + [-1, 1, Conv, [64, 3, 1]], + [-1, 1, Conv, [64, 3, 1]], + [-1, 1, Conv, [64, 3, 1]], + [[-1, -2, -3, -4, -5, -6], 1, Concat, [1]], + [-1, 1, Conv, [128, 1, 1]], # 75 + + [-1, 1, MP, []], + [-1, 1, Conv, [128, 1, 1]], + [-3, 1, Conv, [128, 1, 1]], + [-1, 1, Conv, [128, 3, 2]], + [[-1, -3, 63], 1, Concat, [1]], + + [-1, 1, Conv, [256, 1, 1]], + [-2, 1, Conv, [256, 1, 1]], + [-1, 1, Conv, [128, 3, 1]], + [-1, 1, Conv, [128, 3, 1]], + [-1, 1, Conv, [128, 3, 1]], + [-1, 1, Conv, [128, 3, 1]], + [[-1, -2, -3, -4, -5, -6], 1, Concat, [1]], + [-1, 1, Conv, [256, 1, 1]], # 88 + + [-1, 1, MP, []], + [-1, 1, Conv, [256, 1, 1]], + [-3, 1, Conv, [256, 1, 1]], + [-1, 1, Conv, [256, 3, 2]], + [[-1, -3, 51], 1, Concat, [1]], + + [-1, 1, Conv, [512, 1, 1]], + [-2, 1, Conv, [512, 1, 1]], + [-1, 1, Conv, [256, 3, 1]], + [-1, 1, Conv, [256, 3, 1]], + [-1, 1, Conv, [256, 3, 1]], + [-1, 1, Conv, [256, 3, 1]], + [[-1, -2, -3, -4, -5, -6], 1, Concat, [1]], + [-1, 1, Conv, [512, 1, 1]], # 101 + + [75, 1, Conv, [256, 3, 1]], + [88, 1, Conv, [512, 3, 1]], + [101, 1, Conv, [1024, 3, 1]], + + [[102, 103, 104], 1, Segment, [nc, 32, 256]], # Segment(P3, P4, P5) + ] diff --git a/cv/3d_detection/yolov9/pytorch/models/segment/yolov9-c-dseg.yaml b/cv/3d_detection/yolov9/pytorch/models/segment/yolov9-c-dseg.yaml new file mode 100644 index 000000000..44544511c --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/models/segment/yolov9-c-dseg.yaml @@ -0,0 +1,130 @@ +# YOLOv9 + +# parameters +nc: 80 # number of classes +depth_multiple: 1.0 # model depth multiple +width_multiple: 1.0 # layer channel multiple +#activation: nn.LeakyReLU(0.1) +#activation: nn.ReLU() + +# anchors +anchors: 3 + +# gelan backbone +backbone: + [ + [-1, 1, Silence, []], + + # conv down + [-1, 1, Conv, [64, 3, 2]], # 1-P1/2 + + # conv down + [-1, 1, Conv, [128, 3, 2]], # 2-P2/4 + + # elan-1 block + [-1, 1, RepNCSPELAN4, [256, 128, 64, 1]], # 3 + + # avg-conv down + [-1, 1, ADown, [256]], # 4-P3/8 + + # elan-2 block + [-1, 1, RepNCSPELAN4, [512, 256, 128, 1]], # 5 + + # avg-conv down + [-1, 1, ADown, [512]], # 6-P4/16 + + # elan-2 block + [-1, 1, RepNCSPELAN4, [512, 512, 256, 1]], # 7 + + # avg-conv down + [-1, 1, ADown, [512]], # 8-P5/32 + + # elan-2 block + [-1, 1, RepNCSPELAN4, [512, 512, 256, 1]], # 9 + ] + +# YOLOv9 head +head: + [ + # elan-spp block + [-1, 1, SPPELAN, [512, 256]], # 10 + + # up-concat merge + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 7], 1, Concat, [1]], # cat backbone P4 + + # elan-2 block + [-1, 1, RepNCSPELAN4, [512, 512, 256, 1]], # 13 + + # up-concat merge + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 5], 1, Concat, [1]], # cat backbone P3 + + # elan-2 block + [-1, 1, RepNCSPELAN4, [256, 256, 128, 1]], # 16 (P3/8-small) + + # avg-conv-down merge + [-1, 1, ADown, [256]], + [[-1, 13], 1, Concat, [1]], # cat head P4 + + # elan-2 block + [-1, 1, RepNCSPELAN4, [512, 512, 256, 1]], # 19 (P4/16-medium) + + # avg-conv-down merge + [-1, 1, ADown, [512]], + [[-1, 10], 1, Concat, [1]], # cat head P5 + + # elan-2 block + [-1, 1, RepNCSPELAN4, [512, 512, 256, 1]], # 22 (P5/32-large) + + + # multi-level reversible auxiliary branch + + # routing + [5, 1, CBLinear, [[256]]], # 23 + [7, 1, CBLinear, [[256, 512]]], # 24 + [9, 1, CBLinear, [[256, 512, 512]]], # 25 + + # conv down + [0, 1, Conv, [64, 3, 2]], # 26-P1/2 + + # conv down + [-1, 1, Conv, [128, 3, 2]], # 27-P2/4 + + # elan-1 block + [-1, 1, RepNCSPELAN4, [256, 128, 64, 1]], # 28 + + # avg-conv down fuse + [-1, 1, ADown, [256]], # 29-P3/8 + [[23, 24, 25, -1], 1, CBFuse, [[0, 0, 0]]], # 30 + + # elan-2 block + [-1, 1, RepNCSPELAN4, [512, 256, 128, 1]], # 31 + + # avg-conv down fuse + [-1, 1, ADown, [512]], # 32-P4/16 + [[24, 25, -1], 1, CBFuse, [[1, 1]]], # 33 + + # elan-2 block + [-1, 1, RepNCSPELAN4, [512, 512, 256, 1]], # 34 + + # avg-conv down fuse + [-1, 1, ADown, [512]], # 35-P5/32 + [[25, -1], 1, CBFuse, [[2]]], # 36 + + # elan-2 block + [-1, 1, RepNCSPELAN4, [512, 512, 256, 1]], # 37 + + [31, 1, RepNCSPELAN4, [512, 256, 128, 2]], # 38 + + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [-1, 1, Conv, [256, 3, 1]], # 40 + + [16, 1, RepNCSPELAN4, [256, 256, 128, 2]], # 41 + + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [-1, 1, Conv, [256, 3, 1]], # 43 + + # segment + [[31, 34, 37, 16, 19, 22, 40, 43], 1, DualDSegment, [nc, 32, 256]], # Segment(P3, P4, P5) + ] diff --git a/cv/3d_detection/yolov9/pytorch/models/tf.py b/cv/3d_detection/yolov9/pytorch/models/tf.py new file mode 100644 index 000000000..897efafef --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/models/tf.py @@ -0,0 +1,596 @@ +import argparse +import sys +from copy import deepcopy +from pathlib import Path + +FILE = Path(__file__).resolve() +ROOT = FILE.parents[1] # YOLO root directory +if str(ROOT) not in sys.path: + sys.path.append(str(ROOT)) # add ROOT to PATH +# ROOT = ROOT.relative_to(Path.cwd()) # relative + +import numpy as np +import tensorflow as tf +import torch +import torch.nn as nn +from tensorflow import keras + +from models.common import (C3, SPP, SPPF, Bottleneck, BottleneckCSP, C3x, Concat, Conv, CrossConv, DWConv, + DWConvTranspose2d, Focus, autopad) +from models.experimental import MixConv2d, attempt_load +from models.yolo import Detect, Segment +from utils.activations import SiLU +from utils.general import LOGGER, make_divisible, print_args + + +class TFBN(keras.layers.Layer): + # TensorFlow BatchNormalization wrapper + def __init__(self, w=None): + super().__init__() + self.bn = keras.layers.BatchNormalization( + beta_initializer=keras.initializers.Constant(w.bias.numpy()), + gamma_initializer=keras.initializers.Constant(w.weight.numpy()), + moving_mean_initializer=keras.initializers.Constant(w.running_mean.numpy()), + moving_variance_initializer=keras.initializers.Constant(w.running_var.numpy()), + epsilon=w.eps) + + def call(self, inputs): + return self.bn(inputs) + + +class TFPad(keras.layers.Layer): + # Pad inputs in spatial dimensions 1 and 2 + def __init__(self, pad): + super().__init__() + if isinstance(pad, int): + self.pad = tf.constant([[0, 0], [pad, pad], [pad, pad], [0, 0]]) + else: # tuple/list + self.pad = tf.constant([[0, 0], [pad[0], pad[0]], [pad[1], pad[1]], [0, 0]]) + + def call(self, inputs): + return tf.pad(inputs, self.pad, mode='constant', constant_values=0) + + +class TFConv(keras.layers.Layer): + # Standard convolution + def __init__(self, c1, c2, k=1, s=1, p=None, g=1, act=True, w=None): + # ch_in, ch_out, weights, kernel, stride, padding, groups + super().__init__() + assert g == 1, "TF v2.2 Conv2D does not support 'groups' argument" + # TensorFlow convolution padding is inconsistent with PyTorch (e.g. k=3 s=2 'SAME' padding) + # see https://stackoverflow.com/questions/52975843/comparing-conv2d-with-padding-between-tensorflow-and-pytorch + conv = keras.layers.Conv2D( + filters=c2, + kernel_size=k, + strides=s, + padding='SAME' if s == 1 else 'VALID', + use_bias=not hasattr(w, 'bn'), + kernel_initializer=keras.initializers.Constant(w.conv.weight.permute(2, 3, 1, 0).numpy()), + bias_initializer='zeros' if hasattr(w, 'bn') else keras.initializers.Constant(w.conv.bias.numpy())) + self.conv = conv if s == 1 else keras.Sequential([TFPad(autopad(k, p)), conv]) + self.bn = TFBN(w.bn) if hasattr(w, 'bn') else tf.identity + self.act = activations(w.act) if act else tf.identity + + def call(self, inputs): + return self.act(self.bn(self.conv(inputs))) + + +class TFDWConv(keras.layers.Layer): + # Depthwise convolution + def __init__(self, c1, c2, k=1, s=1, p=None, act=True, w=None): + # ch_in, ch_out, weights, kernel, stride, padding, groups + super().__init__() + assert c2 % c1 == 0, f'TFDWConv() output={c2} must be a multiple of input={c1} channels' + conv = keras.layers.DepthwiseConv2D( + kernel_size=k, + depth_multiplier=c2 // c1, + strides=s, + padding='SAME' if s == 1 else 'VALID', + use_bias=not hasattr(w, 'bn'), + depthwise_initializer=keras.initializers.Constant(w.conv.weight.permute(2, 3, 1, 0).numpy()), + bias_initializer='zeros' if hasattr(w, 'bn') else keras.initializers.Constant(w.conv.bias.numpy())) + self.conv = conv if s == 1 else keras.Sequential([TFPad(autopad(k, p)), conv]) + self.bn = TFBN(w.bn) if hasattr(w, 'bn') else tf.identity + self.act = activations(w.act) if act else tf.identity + + def call(self, inputs): + return self.act(self.bn(self.conv(inputs))) + + +class TFDWConvTranspose2d(keras.layers.Layer): + # Depthwise ConvTranspose2d + def __init__(self, c1, c2, k=1, s=1, p1=0, p2=0, w=None): + # ch_in, ch_out, weights, kernel, stride, padding, groups + super().__init__() + assert c1 == c2, f'TFDWConv() output={c2} must be equal to input={c1} channels' + assert k == 4 and p1 == 1, 'TFDWConv() only valid for k=4 and p1=1' + weight, bias = w.weight.permute(2, 3, 1, 0).numpy(), w.bias.numpy() + self.c1 = c1 + self.conv = [ + keras.layers.Conv2DTranspose(filters=1, + kernel_size=k, + strides=s, + padding='VALID', + output_padding=p2, + use_bias=True, + kernel_initializer=keras.initializers.Constant(weight[..., i:i + 1]), + bias_initializer=keras.initializers.Constant(bias[i])) for i in range(c1)] + + def call(self, inputs): + return tf.concat([m(x) for m, x in zip(self.conv, tf.split(inputs, self.c1, 3))], 3)[:, 1:-1, 1:-1] + + +class TFFocus(keras.layers.Layer): + # Focus wh information into c-space + def __init__(self, c1, c2, k=1, s=1, p=None, g=1, act=True, w=None): + # ch_in, ch_out, kernel, stride, padding, groups + super().__init__() + self.conv = TFConv(c1 * 4, c2, k, s, p, g, act, w.conv) + + def call(self, inputs): # x(b,w,h,c) -> y(b,w/2,h/2,4c) + # inputs = inputs / 255 # normalize 0-255 to 0-1 + inputs = [inputs[:, ::2, ::2, :], inputs[:, 1::2, ::2, :], inputs[:, ::2, 1::2, :], inputs[:, 1::2, 1::2, :]] + return self.conv(tf.concat(inputs, 3)) + + +class TFBottleneck(keras.layers.Layer): + # Standard bottleneck + def __init__(self, c1, c2, shortcut=True, g=1, e=0.5, w=None): # ch_in, ch_out, shortcut, groups, expansion + super().__init__() + c_ = int(c2 * e) # hidden channels + self.cv1 = TFConv(c1, c_, 1, 1, w=w.cv1) + self.cv2 = TFConv(c_, c2, 3, 1, g=g, w=w.cv2) + self.add = shortcut and c1 == c2 + + def call(self, inputs): + return inputs + self.cv2(self.cv1(inputs)) if self.add else self.cv2(self.cv1(inputs)) + + +class TFCrossConv(keras.layers.Layer): + # Cross Convolution + def __init__(self, c1, c2, k=3, s=1, g=1, e=1.0, shortcut=False, w=None): + super().__init__() + c_ = int(c2 * e) # hidden channels + self.cv1 = TFConv(c1, c_, (1, k), (1, s), w=w.cv1) + self.cv2 = TFConv(c_, c2, (k, 1), (s, 1), g=g, w=w.cv2) + self.add = shortcut and c1 == c2 + + def call(self, inputs): + return inputs + self.cv2(self.cv1(inputs)) if self.add else self.cv2(self.cv1(inputs)) + + +class TFConv2d(keras.layers.Layer): + # Substitution for PyTorch nn.Conv2D + def __init__(self, c1, c2, k, s=1, g=1, bias=True, w=None): + super().__init__() + assert g == 1, "TF v2.2 Conv2D does not support 'groups' argument" + self.conv = keras.layers.Conv2D(filters=c2, + kernel_size=k, + strides=s, + padding='VALID', + use_bias=bias, + kernel_initializer=keras.initializers.Constant( + w.weight.permute(2, 3, 1, 0).numpy()), + bias_initializer=keras.initializers.Constant(w.bias.numpy()) if bias else None) + + def call(self, inputs): + return self.conv(inputs) + + +class TFBottleneckCSP(keras.layers.Layer): + # CSP Bottleneck https://github.com/WongKinYiu/CrossStagePartialNetworks + def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5, w=None): + # ch_in, ch_out, number, shortcut, groups, expansion + super().__init__() + c_ = int(c2 * e) # hidden channels + self.cv1 = TFConv(c1, c_, 1, 1, w=w.cv1) + self.cv2 = TFConv2d(c1, c_, 1, 1, bias=False, w=w.cv2) + self.cv3 = TFConv2d(c_, c_, 1, 1, bias=False, w=w.cv3) + self.cv4 = TFConv(2 * c_, c2, 1, 1, w=w.cv4) + self.bn = TFBN(w.bn) + self.act = lambda x: keras.activations.swish(x) + self.m = keras.Sequential([TFBottleneck(c_, c_, shortcut, g, e=1.0, w=w.m[j]) for j in range(n)]) + + def call(self, inputs): + y1 = self.cv3(self.m(self.cv1(inputs))) + y2 = self.cv2(inputs) + return self.cv4(self.act(self.bn(tf.concat((y1, y2), axis=3)))) + + +class TFC3(keras.layers.Layer): + # CSP Bottleneck with 3 convolutions + def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5, w=None): + # ch_in, ch_out, number, shortcut, groups, expansion + super().__init__() + c_ = int(c2 * e) # hidden channels + self.cv1 = TFConv(c1, c_, 1, 1, w=w.cv1) + self.cv2 = TFConv(c1, c_, 1, 1, w=w.cv2) + self.cv3 = TFConv(2 * c_, c2, 1, 1, w=w.cv3) + self.m = keras.Sequential([TFBottleneck(c_, c_, shortcut, g, e=1.0, w=w.m[j]) for j in range(n)]) + + def call(self, inputs): + return self.cv3(tf.concat((self.m(self.cv1(inputs)), self.cv2(inputs)), axis=3)) + + +class TFC3x(keras.layers.Layer): + # 3 module with cross-convolutions + def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5, w=None): + # ch_in, ch_out, number, shortcut, groups, expansion + super().__init__() + c_ = int(c2 * e) # hidden channels + self.cv1 = TFConv(c1, c_, 1, 1, w=w.cv1) + self.cv2 = TFConv(c1, c_, 1, 1, w=w.cv2) + self.cv3 = TFConv(2 * c_, c2, 1, 1, w=w.cv3) + self.m = keras.Sequential([ + TFCrossConv(c_, c_, k=3, s=1, g=g, e=1.0, shortcut=shortcut, w=w.m[j]) for j in range(n)]) + + def call(self, inputs): + return self.cv3(tf.concat((self.m(self.cv1(inputs)), self.cv2(inputs)), axis=3)) + + +class TFSPP(keras.layers.Layer): + # Spatial pyramid pooling layer used in YOLOv3-SPP + def __init__(self, c1, c2, k=(5, 9, 13), w=None): + super().__init__() + c_ = c1 // 2 # hidden channels + self.cv1 = TFConv(c1, c_, 1, 1, w=w.cv1) + self.cv2 = TFConv(c_ * (len(k) + 1), c2, 1, 1, w=w.cv2) + self.m = [keras.layers.MaxPool2D(pool_size=x, strides=1, padding='SAME') for x in k] + + def call(self, inputs): + x = self.cv1(inputs) + return self.cv2(tf.concat([x] + [m(x) for m in self.m], 3)) + + +class TFSPPF(keras.layers.Layer): + # Spatial pyramid pooling-Fast layer + def __init__(self, c1, c2, k=5, w=None): + super().__init__() + c_ = c1 // 2 # hidden channels + self.cv1 = TFConv(c1, c_, 1, 1, w=w.cv1) + self.cv2 = TFConv(c_ * 4, c2, 1, 1, w=w.cv2) + self.m = keras.layers.MaxPool2D(pool_size=k, strides=1, padding='SAME') + + def call(self, inputs): + x = self.cv1(inputs) + y1 = self.m(x) + y2 = self.m(y1) + return self.cv2(tf.concat([x, y1, y2, self.m(y2)], 3)) + + +class TFDetect(keras.layers.Layer): + # TF YOLO Detect layer + def __init__(self, nc=80, anchors=(), ch=(), imgsz=(640, 640), w=None): # detection layer + super().__init__() + self.stride = tf.convert_to_tensor(w.stride.numpy(), dtype=tf.float32) + self.nc = nc # number of classes + self.no = nc + 5 # number of outputs per anchor + self.nl = len(anchors) # number of detection layers + self.na = len(anchors[0]) // 2 # number of anchors + self.grid = [tf.zeros(1)] * self.nl # init grid + self.anchors = tf.convert_to_tensor(w.anchors.numpy(), dtype=tf.float32) + self.anchor_grid = tf.reshape(self.anchors * tf.reshape(self.stride, [self.nl, 1, 1]), [self.nl, 1, -1, 1, 2]) + self.m = [TFConv2d(x, self.no * self.na, 1, w=w.m[i]) for i, x in enumerate(ch)] + self.training = False # set to False after building model + self.imgsz = imgsz + for i in range(self.nl): + ny, nx = self.imgsz[0] // self.stride[i], self.imgsz[1] // self.stride[i] + self.grid[i] = self._make_grid(nx, ny) + + def call(self, inputs): + z = [] # inference output + x = [] + for i in range(self.nl): + x.append(self.m[i](inputs[i])) + # x(bs,20,20,255) to x(bs,3,20,20,85) + ny, nx = self.imgsz[0] // self.stride[i], self.imgsz[1] // self.stride[i] + x[i] = tf.reshape(x[i], [-1, ny * nx, self.na, self.no]) + + if not self.training: # inference + y = x[i] + grid = tf.transpose(self.grid[i], [0, 2, 1, 3]) - 0.5 + anchor_grid = tf.transpose(self.anchor_grid[i], [0, 2, 1, 3]) * 4 + xy = (tf.sigmoid(y[..., 0:2]) * 2 + grid) * self.stride[i] # xy + wh = tf.sigmoid(y[..., 2:4]) ** 2 * anchor_grid + # Normalize xywh to 0-1 to reduce calibration error + xy /= tf.constant([[self.imgsz[1], self.imgsz[0]]], dtype=tf.float32) + wh /= tf.constant([[self.imgsz[1], self.imgsz[0]]], dtype=tf.float32) + y = tf.concat([xy, wh, tf.sigmoid(y[..., 4:5 + self.nc]), y[..., 5 + self.nc:]], -1) + z.append(tf.reshape(y, [-1, self.na * ny * nx, self.no])) + + return tf.transpose(x, [0, 2, 1, 3]) if self.training else (tf.concat(z, 1),) + + @staticmethod + def _make_grid(nx=20, ny=20): + # yv, xv = torch.meshgrid([torch.arange(ny), torch.arange(nx)]) + # return torch.stack((xv, yv), 2).view((1, 1, ny, nx, 2)).float() + xv, yv = tf.meshgrid(tf.range(nx), tf.range(ny)) + return tf.cast(tf.reshape(tf.stack([xv, yv], 2), [1, 1, ny * nx, 2]), dtype=tf.float32) + + +class TFSegment(TFDetect): + # YOLO Segment head for segmentation models + def __init__(self, nc=80, anchors=(), nm=32, npr=256, ch=(), imgsz=(640, 640), w=None): + super().__init__(nc, anchors, ch, imgsz, w) + self.nm = nm # number of masks + self.npr = npr # number of protos + self.no = 5 + nc + self.nm # number of outputs per anchor + self.m = [TFConv2d(x, self.no * self.na, 1, w=w.m[i]) for i, x in enumerate(ch)] # output conv + self.proto = TFProto(ch[0], self.npr, self.nm, w=w.proto) # protos + self.detect = TFDetect.call + + def call(self, x): + p = self.proto(x[0]) + # p = TFUpsample(None, scale_factor=4, mode='nearest')(self.proto(x[0])) # (optional) full-size protos + p = tf.transpose(p, [0, 3, 1, 2]) # from shape(1,160,160,32) to shape(1,32,160,160) + x = self.detect(self, x) + return (x, p) if self.training else (x[0], p) + + +class TFProto(keras.layers.Layer): + + def __init__(self, c1, c_=256, c2=32, w=None): + super().__init__() + self.cv1 = TFConv(c1, c_, k=3, w=w.cv1) + self.upsample = TFUpsample(None, scale_factor=2, mode='nearest') + self.cv2 = TFConv(c_, c_, k=3, w=w.cv2) + self.cv3 = TFConv(c_, c2, w=w.cv3) + + def call(self, inputs): + return self.cv3(self.cv2(self.upsample(self.cv1(inputs)))) + + +class TFUpsample(keras.layers.Layer): + # TF version of torch.nn.Upsample() + def __init__(self, size, scale_factor, mode, w=None): # warning: all arguments needed including 'w' + super().__init__() + assert scale_factor % 2 == 0, "scale_factor must be multiple of 2" + self.upsample = lambda x: tf.image.resize(x, (x.shape[1] * scale_factor, x.shape[2] * scale_factor), mode) + # self.upsample = keras.layers.UpSampling2D(size=scale_factor, interpolation=mode) + # with default arguments: align_corners=False, half_pixel_centers=False + # self.upsample = lambda x: tf.raw_ops.ResizeNearestNeighbor(images=x, + # size=(x.shape[1] * 2, x.shape[2] * 2)) + + def call(self, inputs): + return self.upsample(inputs) + + +class TFConcat(keras.layers.Layer): + # TF version of torch.concat() + def __init__(self, dimension=1, w=None): + super().__init__() + assert dimension == 1, "convert only NCHW to NHWC concat" + self.d = 3 + + def call(self, inputs): + return tf.concat(inputs, self.d) + + +def parse_model(d, ch, model, imgsz): # model_dict, input_channels(3) + LOGGER.info(f"\n{'':>3}{'from':>18}{'n':>3}{'params':>10} {'module':<40}{'arguments':<30}") + anchors, nc, gd, gw = d['anchors'], d['nc'], d['depth_multiple'], d['width_multiple'] + na = (len(anchors[0]) // 2) if isinstance(anchors, list) else anchors # number of anchors + no = na * (nc + 5) # number of outputs = anchors * (classes + 5) + + layers, save, c2 = [], [], ch[-1] # layers, savelist, ch out + for i, (f, n, m, args) in enumerate(d['backbone'] + d['head']): # from, number, module, args + m_str = m + m = eval(m) if isinstance(m, str) else m # eval strings + for j, a in enumerate(args): + try: + args[j] = eval(a) if isinstance(a, str) else a # eval strings + except NameError: + pass + + n = max(round(n * gd), 1) if n > 1 else n # depth gain + if m in [ + nn.Conv2d, Conv, DWConv, DWConvTranspose2d, Bottleneck, SPP, SPPF, MixConv2d, Focus, CrossConv, + BottleneckCSP, C3, C3x]: + c1, c2 = ch[f], args[0] + c2 = make_divisible(c2 * gw, 8) if c2 != no else c2 + + args = [c1, c2, *args[1:]] + if m in [BottleneckCSP, C3, C3x]: + args.insert(2, n) + n = 1 + elif m is nn.BatchNorm2d: + args = [ch[f]] + elif m is Concat: + c2 = sum(ch[-1 if x == -1 else x + 1] for x in f) + elif m in [Detect, Segment]: + args.append([ch[x + 1] for x in f]) + if isinstance(args[1], int): # number of anchors + args[1] = [list(range(args[1] * 2))] * len(f) + if m is Segment: + args[3] = make_divisible(args[3] * gw, 8) + args.append(imgsz) + else: + c2 = ch[f] + + tf_m = eval('TF' + m_str.replace('nn.', '')) + m_ = keras.Sequential([tf_m(*args, w=model.model[i][j]) for j in range(n)]) if n > 1 \ + else tf_m(*args, w=model.model[i]) # module + + torch_m_ = nn.Sequential(*(m(*args) for _ in range(n))) if n > 1 else m(*args) # module + t = str(m)[8:-2].replace('__main__.', '') # module type + np = sum(x.numel() for x in torch_m_.parameters()) # number params + m_.i, m_.f, m_.type, m_.np = i, f, t, np # attach index, 'from' index, type, number params + LOGGER.info(f'{i:>3}{str(f):>18}{str(n):>3}{np:>10} {t:<40}{str(args):<30}') # print + save.extend(x % i for x in ([f] if isinstance(f, int) else f) if x != -1) # append to savelist + layers.append(m_) + ch.append(c2) + return keras.Sequential(layers), sorted(save) + + +class TFModel: + # TF YOLO model + def __init__(self, cfg='yolo.yaml', ch=3, nc=None, model=None, imgsz=(640, 640)): # model, channels, classes + super().__init__() + if isinstance(cfg, dict): + self.yaml = cfg # model dict + else: # is *.yaml + import yaml # for torch hub + self.yaml_file = Path(cfg).name + with open(cfg) as f: + self.yaml = yaml.load(f, Loader=yaml.FullLoader) # model dict + + # Define model + if nc and nc != self.yaml['nc']: + LOGGER.info(f"Overriding {cfg} nc={self.yaml['nc']} with nc={nc}") + self.yaml['nc'] = nc # override yaml value + self.model, self.savelist = parse_model(deepcopy(self.yaml), ch=[ch], model=model, imgsz=imgsz) + + def predict(self, + inputs, + tf_nms=False, + agnostic_nms=False, + topk_per_class=100, + topk_all=100, + iou_thres=0.45, + conf_thres=0.25): + y = [] # outputs + x = inputs + for m in self.model.layers: + if m.f != -1: # if not from previous layer + 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 + + x = m(x) # run + y.append(x if m.i in self.savelist else None) # save output + + # Add TensorFlow NMS + if tf_nms: + boxes = self._xywh2xyxy(x[0][..., :4]) + probs = x[0][:, :, 4:5] + classes = x[0][:, :, 5:] + scores = probs * classes + if agnostic_nms: + nms = AgnosticNMS()((boxes, classes, scores), topk_all, iou_thres, conf_thres) + else: + boxes = tf.expand_dims(boxes, 2) + nms = tf.image.combined_non_max_suppression(boxes, + scores, + topk_per_class, + topk_all, + iou_thres, + conf_thres, + clip_boxes=False) + return (nms,) + return x # output [1,6300,85] = [xywh, conf, class0, class1, ...] + # x = x[0] # [x(1,6300,85), ...] to x(6300,85) + # xywh = x[..., :4] # x(6300,4) boxes + # conf = x[..., 4:5] # x(6300,1) confidences + # cls = tf.reshape(tf.cast(tf.argmax(x[..., 5:], axis=1), tf.float32), (-1, 1)) # x(6300,1) classes + # return tf.concat([conf, cls, xywh], 1) + + @staticmethod + def _xywh2xyxy(xywh): + # Convert nx4 boxes from [x, y, w, h] to [x1, y1, x2, y2] where xy1=top-left, xy2=bottom-right + x, y, w, h = tf.split(xywh, num_or_size_splits=4, axis=-1) + return tf.concat([x - w / 2, y - h / 2, x + w / 2, y + h / 2], axis=-1) + + +class AgnosticNMS(keras.layers.Layer): + # TF Agnostic NMS + def call(self, input, topk_all, iou_thres, conf_thres): + # wrap map_fn to avoid TypeSpec related error https://stackoverflow.com/a/65809989/3036450 + return tf.map_fn(lambda x: self._nms(x, topk_all, iou_thres, conf_thres), + input, + fn_output_signature=(tf.float32, tf.float32, tf.float32, tf.int32), + name='agnostic_nms') + + @staticmethod + def _nms(x, topk_all=100, iou_thres=0.45, conf_thres=0.25): # agnostic NMS + boxes, classes, scores = x + class_inds = tf.cast(tf.argmax(classes, axis=-1), tf.float32) + scores_inp = tf.reduce_max(scores, -1) + selected_inds = tf.image.non_max_suppression(boxes, + scores_inp, + max_output_size=topk_all, + iou_threshold=iou_thres, + score_threshold=conf_thres) + selected_boxes = tf.gather(boxes, selected_inds) + padded_boxes = tf.pad(selected_boxes, + paddings=[[0, topk_all - tf.shape(selected_boxes)[0]], [0, 0]], + mode="CONSTANT", + constant_values=0.0) + selected_scores = tf.gather(scores_inp, selected_inds) + padded_scores = tf.pad(selected_scores, + paddings=[[0, topk_all - tf.shape(selected_boxes)[0]]], + mode="CONSTANT", + constant_values=-1.0) + selected_classes = tf.gather(class_inds, selected_inds) + padded_classes = tf.pad(selected_classes, + paddings=[[0, topk_all - tf.shape(selected_boxes)[0]]], + mode="CONSTANT", + constant_values=-1.0) + valid_detections = tf.shape(selected_inds)[0] + return padded_boxes, padded_scores, padded_classes, valid_detections + + +def activations(act=nn.SiLU): + # Returns TF activation from input PyTorch activation + if isinstance(act, nn.LeakyReLU): + return lambda x: keras.activations.relu(x, alpha=0.1) + elif isinstance(act, nn.Hardswish): + return lambda x: x * tf.nn.relu6(x + 3) * 0.166666667 + elif isinstance(act, (nn.SiLU, SiLU)): + return lambda x: keras.activations.swish(x) + else: + raise Exception(f'no matching TensorFlow activation found for PyTorch activation {act}') + + +def representative_dataset_gen(dataset, ncalib=100): + # Representative dataset generator for use with converter.representative_dataset, returns a generator of np arrays + for n, (path, img, im0s, vid_cap, string) in enumerate(dataset): + im = np.transpose(img, [1, 2, 0]) + im = np.expand_dims(im, axis=0).astype(np.float32) + im /= 255 + yield [im] + if n >= ncalib: + break + + +def run( + weights=ROOT / 'yolo.pt', # weights path + imgsz=(640, 640), # inference size h,w + batch_size=1, # batch size + dynamic=False, # dynamic batch size +): + # PyTorch model + im = torch.zeros((batch_size, 3, *imgsz)) # BCHW image + model = attempt_load(weights, device=torch.device('cpu'), inplace=True, fuse=False) + _ = model(im) # inference + model.info() + + # TensorFlow model + im = tf.zeros((batch_size, *imgsz, 3)) # BHWC image + tf_model = TFModel(cfg=model.yaml, model=model, nc=model.nc, imgsz=imgsz) + _ = tf_model.predict(im) # inference + + # Keras model + im = keras.Input(shape=(*imgsz, 3), batch_size=None if dynamic else batch_size) + keras_model = keras.Model(inputs=im, outputs=tf_model.predict(im)) + keras_model.summary() + + LOGGER.info('PyTorch, TensorFlow and Keras models successfully verified.\nUse export.py for TF model export.') + + +def parse_opt(): + parser = argparse.ArgumentParser() + parser.add_argument('--weights', type=str, default=ROOT / 'yolo.pt', help='weights path') + parser.add_argument('--imgsz', '--img', '--img-size', nargs='+', type=int, default=[640], help='inference size h,w') + parser.add_argument('--batch-size', type=int, default=1, help='batch size') + parser.add_argument('--dynamic', action='store_true', help='dynamic batch size') + opt = parser.parse_args() + opt.imgsz *= 2 if len(opt.imgsz) == 1 else 1 # expand + print_args(vars(opt)) + return opt + + +def main(opt): + run(**vars(opt)) + + +if __name__ == "__main__": + opt = parse_opt() + main(opt) diff --git a/cv/3d_detection/yolov9/pytorch/models/yolo.py b/cv/3d_detection/yolov9/pytorch/models/yolo.py new file mode 100644 index 000000000..332ec11f3 --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/models/yolo.py @@ -0,0 +1,818 @@ +import argparse +import os +import platform +import sys +from copy import deepcopy +from pathlib import Path + +FILE = Path(__file__).resolve() +ROOT = FILE.parents[1] # YOLO root directory +if str(ROOT) not in sys.path: + sys.path.append(str(ROOT)) # add ROOT to PATH +if platform.system() != 'Windows': + ROOT = Path(os.path.relpath(ROOT, Path.cwd())) # relative + +from models.common import * +from models.experimental import * +from utils.general import LOGGER, check_version, check_yaml, make_divisible, print_args +from utils.plots import feature_visualization +from utils.torch_utils import (fuse_conv_and_bn, initialize_weights, model_info, profile, scale_img, select_device, + time_sync) +from utils.tal.anchor_generator import make_anchors, dist2bbox + +try: + import thop # for FLOPs computation +except ImportError: + thop = None + + +class Detect(nn.Module): + # YOLO Detect head for detection models + dynamic = False # force grid reconstruction + export = False # export mode + shape = None + anchors = torch.empty(0) # init + strides = torch.empty(0) # init + + def __init__(self, nc=80, ch=(), inplace=True): # detection layer + super().__init__() + self.nc = nc # number of classes + self.nl = len(ch) # number of detection layers + self.reg_max = 16 + self.no = nc + self.reg_max * 4 # number of outputs per anchor + self.inplace = inplace # use inplace ops (e.g. slice assignment) + self.stride = torch.zeros(self.nl) # strides computed during build + + c2, c3 = max((ch[0] // 4, self.reg_max * 4, 16)), max((ch[0], min((self.nc * 2, 128)))) # channels + self.cv2 = nn.ModuleList( + nn.Sequential(Conv(x, c2, 3), Conv(c2, c2, 3), nn.Conv2d(c2, 4 * self.reg_max, 1)) for x in ch) + self.cv3 = nn.ModuleList( + nn.Sequential(Conv(x, c3, 3), Conv(c3, c3, 3), nn.Conv2d(c3, self.nc, 1)) for x in ch) + self.dfl = DFL(self.reg_max) if self.reg_max > 1 else nn.Identity() + + def forward(self, x): + shape = x[0].shape # BCHW + for i in range(self.nl): + x[i] = torch.cat((self.cv2[i](x[i]), self.cv3[i](x[i])), 1) + if self.training: + return x + elif self.dynamic or self.shape != shape: + self.anchors, self.strides = (x.transpose(0, 1) for x in make_anchors(x, self.stride, 0.5)) + self.shape = shape + + box, cls = torch.cat([xi.view(shape[0], self.no, -1) for xi in x], 2).split((self.reg_max * 4, self.nc), 1) + dbox = dist2bbox(self.dfl(box), self.anchors.unsqueeze(0), xywh=True, dim=1) * self.strides + y = torch.cat((dbox, cls.sigmoid()), 1) + return y if self.export else (y, x) + + def bias_init(self): + # Initialize Detect() biases, WARNING: requires stride availability + m = self # self.model[-1] # Detect() module + # cf = torch.bincount(torch.tensor(np.concatenate(dataset.labels, 0)[:, 0]).long(), minlength=nc) + 1 + # ncf = math.log(0.6 / (m.nc - 0.999999)) if cf is None else torch.log(cf / cf.sum()) # nominal class frequency + for a, b, s in zip(m.cv2, m.cv3, m.stride): # from + a[-1].bias.data[:] = 1.0 # box + b[-1].bias.data[:m.nc] = math.log(5 / m.nc / (640 / s) ** 2) # cls (5 objects and 80 classes per 640 image) + + +class DDetect(nn.Module): + # YOLO Detect head for detection models + dynamic = False # force grid reconstruction + export = False # export mode + shape = None + anchors = torch.empty(0) # init + strides = torch.empty(0) # init + + def __init__(self, nc=80, ch=(), inplace=True): # detection layer + super().__init__() + self.nc = nc # number of classes + self.nl = len(ch) # number of detection layers + self.reg_max = 16 + self.no = nc + self.reg_max * 4 # number of outputs per anchor + self.inplace = inplace # use inplace ops (e.g. slice assignment) + self.stride = torch.zeros(self.nl) # strides computed during build + + c2, c3 = make_divisible(max((ch[0] // 4, self.reg_max * 4, 16)), 4), max((ch[0], min((self.nc * 2, 128)))) # channels + self.cv2 = nn.ModuleList( + nn.Sequential(Conv(x, c2, 3), Conv(c2, c2, 3, g=4), nn.Conv2d(c2, 4 * self.reg_max, 1, groups=4)) for x in ch) + self.cv3 = nn.ModuleList( + nn.Sequential(Conv(x, c3, 3), Conv(c3, c3, 3), nn.Conv2d(c3, self.nc, 1)) for x in ch) + self.dfl = DFL(self.reg_max) if self.reg_max > 1 else nn.Identity() + + def forward(self, x): + shape = x[0].shape # BCHW + for i in range(self.nl): + x[i] = torch.cat((self.cv2[i](x[i]), self.cv3[i](x[i])), 1) + if self.training: + return x + elif self.dynamic or self.shape != shape: + self.anchors, self.strides = (x.transpose(0, 1) for x in make_anchors(x, self.stride, 0.5)) + self.shape = shape + + box, cls = torch.cat([xi.view(shape[0], self.no, -1) for xi in x], 2).split((self.reg_max * 4, self.nc), 1) + dbox = dist2bbox(self.dfl(box), self.anchors.unsqueeze(0), xywh=True, dim=1) * self.strides + y = torch.cat((dbox, cls.sigmoid()), 1) + return y if self.export else (y, x) + + def bias_init(self): + # Initialize Detect() biases, WARNING: requires stride availability + m = self # self.model[-1] # Detect() module + # cf = torch.bincount(torch.tensor(np.concatenate(dataset.labels, 0)[:, 0]).long(), minlength=nc) + 1 + # ncf = math.log(0.6 / (m.nc - 0.999999)) if cf is None else torch.log(cf / cf.sum()) # nominal class frequency + for a, b, s in zip(m.cv2, m.cv3, m.stride): # from + a[-1].bias.data[:] = 1.0 # box + b[-1].bias.data[:m.nc] = math.log(5 / m.nc / (640 / s) ** 2) # cls (5 objects and 80 classes per 640 image) + + +class DualDetect(nn.Module): + # YOLO Detect head for detection models + dynamic = False # force grid reconstruction + export = False # export mode + shape = None + anchors = torch.empty(0) # init + strides = torch.empty(0) # init + + def __init__(self, nc=80, ch=(), inplace=True): # detection layer + super().__init__() + self.nc = nc # number of classes + self.nl = len(ch) // 2 # number of detection layers + self.reg_max = 16 + self.no = nc + self.reg_max * 4 # number of outputs per anchor + self.inplace = inplace # use inplace ops (e.g. slice assignment) + self.stride = torch.zeros(self.nl) # strides computed during build + + c2, c3 = max((ch[0] // 4, self.reg_max * 4, 16)), max((ch[0], min((self.nc * 2, 128)))) # channels + c4, c5 = max((ch[self.nl] // 4, self.reg_max * 4, 16)), max((ch[self.nl], min((self.nc * 2, 128)))) # channels + self.cv2 = nn.ModuleList( + nn.Sequential(Conv(x, c2, 3), Conv(c2, c2, 3), nn.Conv2d(c2, 4 * self.reg_max, 1)) for x in ch[:self.nl]) + self.cv3 = nn.ModuleList( + nn.Sequential(Conv(x, c3, 3), Conv(c3, c3, 3), nn.Conv2d(c3, self.nc, 1)) for x in ch[:self.nl]) + self.cv4 = nn.ModuleList( + nn.Sequential(Conv(x, c4, 3), Conv(c4, c4, 3), nn.Conv2d(c4, 4 * self.reg_max, 1)) for x in ch[self.nl:]) + self.cv5 = nn.ModuleList( + nn.Sequential(Conv(x, c5, 3), Conv(c5, c5, 3), nn.Conv2d(c5, self.nc, 1)) for x in ch[self.nl:]) + self.dfl = DFL(self.reg_max) + self.dfl2 = DFL(self.reg_max) + + def forward(self, x): + shape = x[0].shape # BCHW + d1 = [] + d2 = [] + for i in range(self.nl): + d1.append(torch.cat((self.cv2[i](x[i]), self.cv3[i](x[i])), 1)) + d2.append(torch.cat((self.cv4[i](x[self.nl+i]), self.cv5[i](x[self.nl+i])), 1)) + if self.training: + return [d1, d2] + elif self.dynamic or self.shape != shape: + self.anchors, self.strides = (d1.transpose(0, 1) for d1 in make_anchors(d1, self.stride, 0.5)) + self.shape = shape + + box, cls = torch.cat([di.view(shape[0], self.no, -1) for di in d1], 2).split((self.reg_max * 4, self.nc), 1) + dbox = dist2bbox(self.dfl(box), self.anchors.unsqueeze(0), xywh=True, dim=1) * self.strides + box2, cls2 = torch.cat([di.view(shape[0], self.no, -1) for di in d2], 2).split((self.reg_max * 4, self.nc), 1) + dbox2 = dist2bbox(self.dfl2(box2), self.anchors.unsqueeze(0), xywh=True, dim=1) * self.strides + y = [torch.cat((dbox, cls.sigmoid()), 1), torch.cat((dbox2, cls2.sigmoid()), 1)] + return y if self.export else (y, [d1, d2]) + + def bias_init(self): + # Initialize Detect() biases, WARNING: requires stride availability + m = self # self.model[-1] # Detect() module + # cf = torch.bincount(torch.tensor(np.concatenate(dataset.labels, 0)[:, 0]).long(), minlength=nc) + 1 + # ncf = math.log(0.6 / (m.nc - 0.999999)) if cf is None else torch.log(cf / cf.sum()) # nominal class frequency + for a, b, s in zip(m.cv2, m.cv3, m.stride): # from + a[-1].bias.data[:] = 1.0 # box + b[-1].bias.data[:m.nc] = math.log(5 / m.nc / (640 / s) ** 2) # cls (5 objects and 80 classes per 640 image) + for a, b, s in zip(m.cv4, m.cv5, m.stride): # from + a[-1].bias.data[:] = 1.0 # box + b[-1].bias.data[:m.nc] = math.log(5 / m.nc / (640 / s) ** 2) # cls (5 objects and 80 classes per 640 image) + + +class DualDDetect(nn.Module): + # YOLO Detect head for detection models + dynamic = False # force grid reconstruction + export = False # export mode + shape = None + anchors = torch.empty(0) # init + strides = torch.empty(0) # init + + def __init__(self, nc=80, ch=(), inplace=True): # detection layer + super().__init__() + self.nc = nc # number of classes + self.nl = len(ch) // 2 # number of detection layers + self.reg_max = 16 + self.no = nc + self.reg_max * 4 # number of outputs per anchor + self.inplace = inplace # use inplace ops (e.g. slice assignment) + self.stride = torch.zeros(self.nl) # strides computed during build + + c2, c3 = make_divisible(max((ch[0] // 4, self.reg_max * 4, 16)), 4), max((ch[0], min((self.nc * 2, 128)))) # channels + c4, c5 = make_divisible(max((ch[self.nl] // 4, self.reg_max * 4, 16)), 4), max((ch[self.nl], min((self.nc * 2, 128)))) # channels + self.cv2 = nn.ModuleList( + nn.Sequential(Conv(x, c2, 3), Conv(c2, c2, 3, g=4), nn.Conv2d(c2, 4 * self.reg_max, 1, groups=4)) for x in ch[:self.nl]) + self.cv3 = nn.ModuleList( + nn.Sequential(Conv(x, c3, 3), Conv(c3, c3, 3), nn.Conv2d(c3, self.nc, 1)) for x in ch[:self.nl]) + self.cv4 = nn.ModuleList( + nn.Sequential(Conv(x, c4, 3), Conv(c4, c4, 3, g=4), nn.Conv2d(c4, 4 * self.reg_max, 1, groups=4)) for x in ch[self.nl:]) + self.cv5 = nn.ModuleList( + nn.Sequential(Conv(x, c5, 3), Conv(c5, c5, 3), nn.Conv2d(c5, self.nc, 1)) for x in ch[self.nl:]) + self.dfl = DFL(self.reg_max) + self.dfl2 = DFL(self.reg_max) + + def forward(self, x): + shape = x[0].shape # BCHW + d1 = [] + d2 = [] + for i in range(self.nl): + d1.append(torch.cat((self.cv2[i](x[i]), self.cv3[i](x[i])), 1)) + d2.append(torch.cat((self.cv4[i](x[self.nl+i]), self.cv5[i](x[self.nl+i])), 1)) + if self.training: + return [d1, d2] + elif self.dynamic or self.shape != shape: + self.anchors, self.strides = (d1.transpose(0, 1) for d1 in make_anchors(d1, self.stride, 0.5)) + self.shape = shape + + box, cls = torch.cat([di.view(shape[0], self.no, -1) for di in d1], 2).split((self.reg_max * 4, self.nc), 1) + dbox = dist2bbox(self.dfl(box), self.anchors.unsqueeze(0), xywh=True, dim=1) * self.strides + box2, cls2 = torch.cat([di.view(shape[0], self.no, -1) for di in d2], 2).split((self.reg_max * 4, self.nc), 1) + dbox2 = dist2bbox(self.dfl2(box2), self.anchors.unsqueeze(0), xywh=True, dim=1) * self.strides + y = [torch.cat((dbox, cls.sigmoid()), 1), torch.cat((dbox2, cls2.sigmoid()), 1)] + return y if self.export else (y, [d1, d2]) + #y = torch.cat((dbox2, cls2.sigmoid()), 1) + #return y if self.export else (y, d2) + #y1 = torch.cat((dbox, cls.sigmoid()), 1) + #y2 = torch.cat((dbox2, cls2.sigmoid()), 1) + #return [y1, y2] if self.export else [(y1, d1), (y2, d2)] + #return [y1, y2] if self.export else [(y1, y2), (d1, d2)] + + def bias_init(self): + # Initialize Detect() biases, WARNING: requires stride availability + m = self # self.model[-1] # Detect() module + # cf = torch.bincount(torch.tensor(np.concatenate(dataset.labels, 0)[:, 0]).long(), minlength=nc) + 1 + # ncf = math.log(0.6 / (m.nc - 0.999999)) if cf is None else torch.log(cf / cf.sum()) # nominal class frequency + for a, b, s in zip(m.cv2, m.cv3, m.stride): # from + a[-1].bias.data[:] = 1.0 # box + b[-1].bias.data[:m.nc] = math.log(5 / m.nc / (640 / s) ** 2) # cls (5 objects and 80 classes per 640 image) + for a, b, s in zip(m.cv4, m.cv5, m.stride): # from + a[-1].bias.data[:] = 1.0 # box + b[-1].bias.data[:m.nc] = math.log(5 / m.nc / (640 / s) ** 2) # cls (5 objects and 80 classes per 640 image) + + +class TripleDetect(nn.Module): + # YOLO Detect head for detection models + dynamic = False # force grid reconstruction + export = False # export mode + shape = None + anchors = torch.empty(0) # init + strides = torch.empty(0) # init + + def __init__(self, nc=80, ch=(), inplace=True): # detection layer + super().__init__() + self.nc = nc # number of classes + self.nl = len(ch) // 3 # number of detection layers + self.reg_max = 16 + self.no = nc + self.reg_max * 4 # number of outputs per anchor + self.inplace = inplace # use inplace ops (e.g. slice assignment) + self.stride = torch.zeros(self.nl) # strides computed during build + + c2, c3 = max((ch[0] // 4, self.reg_max * 4, 16)), max((ch[0], min((self.nc * 2, 128)))) # channels + c4, c5 = max((ch[self.nl] // 4, self.reg_max * 4, 16)), max((ch[self.nl], min((self.nc * 2, 128)))) # channels + c6, c7 = max((ch[self.nl * 2] // 4, self.reg_max * 4, 16)), max((ch[self.nl * 2], min((self.nc * 2, 128)))) # channels + self.cv2 = nn.ModuleList( + nn.Sequential(Conv(x, c2, 3), Conv(c2, c2, 3), nn.Conv2d(c2, 4 * self.reg_max, 1)) for x in ch[:self.nl]) + self.cv3 = nn.ModuleList( + nn.Sequential(Conv(x, c3, 3), Conv(c3, c3, 3), nn.Conv2d(c3, self.nc, 1)) for x in ch[:self.nl]) + self.cv4 = nn.ModuleList( + nn.Sequential(Conv(x, c4, 3), Conv(c4, c4, 3), nn.Conv2d(c4, 4 * self.reg_max, 1)) for x in ch[self.nl:self.nl*2]) + self.cv5 = nn.ModuleList( + nn.Sequential(Conv(x, c5, 3), Conv(c5, c5, 3), nn.Conv2d(c5, self.nc, 1)) for x in ch[self.nl:self.nl*2]) + self.cv6 = nn.ModuleList( + nn.Sequential(Conv(x, c6, 3), Conv(c6, c6, 3), nn.Conv2d(c6, 4 * self.reg_max, 1)) for x in ch[self.nl*2:self.nl*3]) + self.cv7 = nn.ModuleList( + nn.Sequential(Conv(x, c7, 3), Conv(c7, c7, 3), nn.Conv2d(c7, self.nc, 1)) for x in ch[self.nl*2:self.nl*3]) + self.dfl = DFL(self.reg_max) + self.dfl2 = DFL(self.reg_max) + self.dfl3 = DFL(self.reg_max) + + def forward(self, x): + shape = x[0].shape # BCHW + d1 = [] + d2 = [] + d3 = [] + for i in range(self.nl): + d1.append(torch.cat((self.cv2[i](x[i]), self.cv3[i](x[i])), 1)) + d2.append(torch.cat((self.cv4[i](x[self.nl+i]), self.cv5[i](x[self.nl+i])), 1)) + d3.append(torch.cat((self.cv6[i](x[self.nl*2+i]), self.cv7[i](x[self.nl*2+i])), 1)) + if self.training: + return [d1, d2, d3] + elif self.dynamic or self.shape != shape: + self.anchors, self.strides = (d1.transpose(0, 1) for d1 in make_anchors(d1, self.stride, 0.5)) + self.shape = shape + + box, cls = torch.cat([di.view(shape[0], self.no, -1) for di in d1], 2).split((self.reg_max * 4, self.nc), 1) + dbox = dist2bbox(self.dfl(box), self.anchors.unsqueeze(0), xywh=True, dim=1) * self.strides + box2, cls2 = torch.cat([di.view(shape[0], self.no, -1) for di in d2], 2).split((self.reg_max * 4, self.nc), 1) + dbox2 = dist2bbox(self.dfl2(box2), self.anchors.unsqueeze(0), xywh=True, dim=1) * self.strides + box3, cls3 = torch.cat([di.view(shape[0], self.no, -1) for di in d3], 2).split((self.reg_max * 4, self.nc), 1) + dbox3 = dist2bbox(self.dfl3(box3), self.anchors.unsqueeze(0), xywh=True, dim=1) * self.strides + y = [torch.cat((dbox, cls.sigmoid()), 1), torch.cat((dbox2, cls2.sigmoid()), 1), torch.cat((dbox3, cls3.sigmoid()), 1)] + return y if self.export else (y, [d1, d2, d3]) + + def bias_init(self): + # Initialize Detect() biases, WARNING: requires stride availability + m = self # self.model[-1] # Detect() module + # cf = torch.bincount(torch.tensor(np.concatenate(dataset.labels, 0)[:, 0]).long(), minlength=nc) + 1 + # ncf = math.log(0.6 / (m.nc - 0.999999)) if cf is None else torch.log(cf / cf.sum()) # nominal class frequency + for a, b, s in zip(m.cv2, m.cv3, m.stride): # from + a[-1].bias.data[:] = 1.0 # box + b[-1].bias.data[:m.nc] = math.log(5 / m.nc / (640 / s) ** 2) # cls (5 objects and 80 classes per 640 image) + for a, b, s in zip(m.cv4, m.cv5, m.stride): # from + a[-1].bias.data[:] = 1.0 # box + b[-1].bias.data[:m.nc] = math.log(5 / m.nc / (640 / s) ** 2) # cls (5 objects and 80 classes per 640 image) + for a, b, s in zip(m.cv6, m.cv7, m.stride): # from + a[-1].bias.data[:] = 1.0 # box + b[-1].bias.data[:m.nc] = math.log(5 / m.nc / (640 / s) ** 2) # cls (5 objects and 80 classes per 640 image) + + +class TripleDDetect(nn.Module): + # YOLO Detect head for detection models + dynamic = False # force grid reconstruction + export = False # export mode + shape = None + anchors = torch.empty(0) # init + strides = torch.empty(0) # init + + def __init__(self, nc=80, ch=(), inplace=True): # detection layer + super().__init__() + self.nc = nc # number of classes + self.nl = len(ch) // 3 # number of detection layers + self.reg_max = 16 + self.no = nc + self.reg_max * 4 # number of outputs per anchor + self.inplace = inplace # use inplace ops (e.g. slice assignment) + self.stride = torch.zeros(self.nl) # strides computed during build + + c2, c3 = make_divisible(max((ch[0] // 4, self.reg_max * 4, 16)), 4), \ + max((ch[0], min((self.nc * 2, 128)))) # channels + c4, c5 = make_divisible(max((ch[self.nl] // 4, self.reg_max * 4, 16)), 4), \ + max((ch[self.nl], min((self.nc * 2, 128)))) # channels + c6, c7 = make_divisible(max((ch[self.nl * 2] // 4, self.reg_max * 4, 16)), 4), \ + max((ch[self.nl * 2], min((self.nc * 2, 128)))) # channels + self.cv2 = nn.ModuleList( + nn.Sequential(Conv(x, c2, 3), Conv(c2, c2, 3, g=4), + nn.Conv2d(c2, 4 * self.reg_max, 1, groups=4)) for x in ch[:self.nl]) + self.cv3 = nn.ModuleList( + nn.Sequential(Conv(x, c3, 3), Conv(c3, c3, 3), nn.Conv2d(c3, self.nc, 1)) for x in ch[:self.nl]) + self.cv4 = nn.ModuleList( + nn.Sequential(Conv(x, c4, 3), Conv(c4, c4, 3, g=4), + nn.Conv2d(c4, 4 * self.reg_max, 1, groups=4)) for x in ch[self.nl:self.nl*2]) + self.cv5 = nn.ModuleList( + nn.Sequential(Conv(x, c5, 3), Conv(c5, c5, 3), nn.Conv2d(c5, self.nc, 1)) for x in ch[self.nl:self.nl*2]) + self.cv6 = nn.ModuleList( + nn.Sequential(Conv(x, c6, 3), Conv(c6, c6, 3, g=4), + nn.Conv2d(c6, 4 * self.reg_max, 1, groups=4)) for x in ch[self.nl*2:self.nl*3]) + self.cv7 = nn.ModuleList( + nn.Sequential(Conv(x, c7, 3), Conv(c7, c7, 3), nn.Conv2d(c7, self.nc, 1)) for x in ch[self.nl*2:self.nl*3]) + self.dfl = DFL(self.reg_max) + self.dfl2 = DFL(self.reg_max) + self.dfl3 = DFL(self.reg_max) + + def forward(self, x): + shape = x[0].shape # BCHW + d1 = [] + d2 = [] + d3 = [] + for i in range(self.nl): + d1.append(torch.cat((self.cv2[i](x[i]), self.cv3[i](x[i])), 1)) + d2.append(torch.cat((self.cv4[i](x[self.nl+i]), self.cv5[i](x[self.nl+i])), 1)) + d3.append(torch.cat((self.cv6[i](x[self.nl*2+i]), self.cv7[i](x[self.nl*2+i])), 1)) + if self.training: + return [d1, d2, d3] + elif self.dynamic or self.shape != shape: + self.anchors, self.strides = (d1.transpose(0, 1) for d1 in make_anchors(d1, self.stride, 0.5)) + self.shape = shape + + box, cls = torch.cat([di.view(shape[0], self.no, -1) for di in d1], 2).split((self.reg_max * 4, self.nc), 1) + dbox = dist2bbox(self.dfl(box), self.anchors.unsqueeze(0), xywh=True, dim=1) * self.strides + box2, cls2 = torch.cat([di.view(shape[0], self.no, -1) for di in d2], 2).split((self.reg_max * 4, self.nc), 1) + dbox2 = dist2bbox(self.dfl2(box2), self.anchors.unsqueeze(0), xywh=True, dim=1) * self.strides + box3, cls3 = torch.cat([di.view(shape[0], self.no, -1) for di in d3], 2).split((self.reg_max * 4, self.nc), 1) + dbox3 = dist2bbox(self.dfl3(box3), self.anchors.unsqueeze(0), xywh=True, dim=1) * self.strides + #y = [torch.cat((dbox, cls.sigmoid()), 1), torch.cat((dbox2, cls2.sigmoid()), 1), torch.cat((dbox3, cls3.sigmoid()), 1)] + #return y if self.export else (y, [d1, d2, d3]) + y = torch.cat((dbox3, cls3.sigmoid()), 1) + return y if self.export else (y, d3) + + def bias_init(self): + # Initialize Detect() biases, WARNING: requires stride availability + m = self # self.model[-1] # Detect() module + # cf = torch.bincount(torch.tensor(np.concatenate(dataset.labels, 0)[:, 0]).long(), minlength=nc) + 1 + # ncf = math.log(0.6 / (m.nc - 0.999999)) if cf is None else torch.log(cf / cf.sum()) # nominal class frequency + for a, b, s in zip(m.cv2, m.cv3, m.stride): # from + a[-1].bias.data[:] = 1.0 # box + b[-1].bias.data[:m.nc] = math.log(5 / m.nc / (640 / s) ** 2) # cls (5 objects and 80 classes per 640 image) + for a, b, s in zip(m.cv4, m.cv5, m.stride): # from + a[-1].bias.data[:] = 1.0 # box + b[-1].bias.data[:m.nc] = math.log(5 / m.nc / (640 / s) ** 2) # cls (5 objects and 80 classes per 640 image) + for a, b, s in zip(m.cv6, m.cv7, m.stride): # from + a[-1].bias.data[:] = 1.0 # box + b[-1].bias.data[:m.nc] = math.log(5 / m.nc / (640 / s) ** 2) # cls (5 objects and 80 classes per 640 image) + + +class Segment(Detect): + # YOLO Segment head for segmentation models + def __init__(self, nc=80, nm=32, npr=256, ch=(), inplace=True): + super().__init__(nc, ch, inplace) + self.nm = nm # number of masks + self.npr = npr # number of protos + self.proto = Proto(ch[0], self.npr, self.nm) # protos + self.detect = Detect.forward + + c4 = max(ch[0] // 4, self.nm) + self.cv4 = nn.ModuleList(nn.Sequential(Conv(x, c4, 3), Conv(c4, c4, 3), nn.Conv2d(c4, self.nm, 1)) for x in ch) + + def forward(self, x): + p = self.proto(x[0]) + bs = p.shape[0] + + mc = torch.cat([self.cv4[i](x[i]).view(bs, self.nm, -1) for i in range(self.nl)], 2) # mask coefficients + x = self.detect(self, x) + if self.training: + return x, mc, p + return (torch.cat([x, mc], 1), p) if self.export else (torch.cat([x[0], mc], 1), (x[1], mc, p)) + + +class DSegment(DDetect): + # YOLO Segment head for segmentation models + def __init__(self, nc=80, nm=32, npr=256, ch=(), inplace=True): + super().__init__(nc, ch[:-1], inplace) + self.nl = len(ch)-1 + self.nm = nm # number of masks + self.npr = npr # number of protos + self.proto = Conv(ch[-1], self.nm, 1) # protos + self.detect = DDetect.forward + + c4 = max(ch[0] // 4, self.nm) + self.cv4 = nn.ModuleList(nn.Sequential(Conv(x, c4, 3), Conv(c4, c4, 3), nn.Conv2d(c4, self.nm, 1)) for x in ch[:-1]) + + def forward(self, x): + p = self.proto(x[-1]) + bs = p.shape[0] + + mc = torch.cat([self.cv4[i](x[i]).view(bs, self.nm, -1) for i in range(self.nl)], 2) # mask coefficients + x = self.detect(self, x[:-1]) + if self.training: + return x, mc, p + return (torch.cat([x, mc], 1), p) if self.export else (torch.cat([x[0], mc], 1), (x[1], mc, p)) + + +class DualDSegment(DualDDetect): + # YOLO Segment head for segmentation models + def __init__(self, nc=80, nm=32, npr=256, ch=(), inplace=True): + super().__init__(nc, ch[:-2], inplace) + self.nl = (len(ch)-2) // 2 + self.nm = nm # number of masks + self.npr = npr # number of protos + self.proto = Conv(ch[-2], self.nm, 1) # protos + self.proto2 = Conv(ch[-1], self.nm, 1) # protos + self.detect = DualDDetect.forward + + c6 = max(ch[0] // 4, self.nm) + c7 = max(ch[self.nl] // 4, self.nm) + self.cv6 = nn.ModuleList(nn.Sequential(Conv(x, c6, 3), Conv(c6, c6, 3), nn.Conv2d(c6, self.nm, 1)) for x in ch[:self.nl]) + self.cv7 = nn.ModuleList(nn.Sequential(Conv(x, c7, 3), Conv(c7, c7, 3), nn.Conv2d(c7, self.nm, 1)) for x in ch[self.nl:self.nl*2]) + + def forward(self, x): + p = [self.proto(x[-2]), self.proto2(x[-1])] + bs = p[0].shape[0] + + mc = [torch.cat([self.cv6[i](x[i]).view(bs, self.nm, -1) for i in range(self.nl)], 2), + torch.cat([self.cv7[i](x[self.nl+i]).view(bs, self.nm, -1) for i in range(self.nl)], 2)] # mask coefficients + d = self.detect(self, x[:-2]) + if self.training: + return d, mc, p + return (torch.cat([d[0][1], mc[1]], 1), (d[1][1], mc[1], p[1])) + + +class Panoptic(Detect): + # YOLO Panoptic head for panoptic segmentation models + def __init__(self, nc=80, sem_nc=93, nm=32, npr=256, ch=(), inplace=True): + super().__init__(nc, ch, inplace) + self.sem_nc = sem_nc + self.nm = nm # number of masks + self.npr = npr # number of protos + self.proto = Proto(ch[0], self.npr, self.nm) # protos + self.uconv = UConv(ch[0], ch[0]//4, self.sem_nc+self.nc) + self.detect = Detect.forward + + c4 = max(ch[0] // 4, self.nm) + self.cv4 = nn.ModuleList(nn.Sequential(Conv(x, c4, 3), Conv(c4, c4, 3), nn.Conv2d(c4, self.nm, 1)) for x in ch) + + + def forward(self, x): + p = self.proto(x[0]) + s = self.uconv(x[0]) + bs = p.shape[0] + + mc = torch.cat([self.cv4[i](x[i]).view(bs, self.nm, -1) for i in range(self.nl)], 2) # mask coefficients + x = self.detect(self, x) + if self.training: + return x, mc, p, s + return (torch.cat([x, mc], 1), p, s) if self.export else (torch.cat([x[0], mc], 1), (x[1], mc, p, s)) + + +class BaseModel(nn.Module): + # YOLO base model + def forward(self, x, profile=False, visualize=False): + return self._forward_once(x, profile, visualize) # single-scale inference, train + + def _forward_once(self, x, profile=False, visualize=False): + y, dt = [], [] # outputs + for m in self.model: + if m.f != -1: # if not from previous layer + 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 + if profile: + self._profile_one_layer(m, x, dt) + x = m(x) # run + y.append(x if m.i in self.save else None) # save output + if visualize: + feature_visualization(x, m.type, m.i, save_dir=visualize) + return x + + def _profile_one_layer(self, m, x, dt): + c = m == self.model[-1] # is final layer, copy input as inplace fix + o = thop.profile(m, inputs=(x.copy() if c else x,), verbose=False)[0] / 1E9 * 2 if thop else 0 # FLOPs + t = time_sync() + for _ in range(10): + m(x.copy() if c else x) + dt.append((time_sync() - t) * 100) + if m == self.model[0]: + LOGGER.info(f"{'time (ms)':>10s} {'GFLOPs':>10s} {'params':>10s} module") + LOGGER.info(f'{dt[-1]:10.2f} {o:10.2f} {m.np:10.0f} {m.type}') + if c: + LOGGER.info(f"{sum(dt):10.2f} {'-':>10s} {'-':>10s} Total") + + def fuse(self): # fuse model Conv2d() + BatchNorm2d() layers + LOGGER.info('Fusing layers... ') + for m in self.model.modules(): + if isinstance(m, (RepConvN)) and hasattr(m, 'fuse_convs'): + m.fuse_convs() + m.forward = m.forward_fuse # update forward + if isinstance(m, (Conv, DWConv)) and hasattr(m, 'bn'): + m.conv = fuse_conv_and_bn(m.conv, m.bn) # update conv + delattr(m, 'bn') # remove batchnorm + m.forward = m.forward_fuse # update forward + self.info() + return self + + def info(self, verbose=False, img_size=640): # print model information + model_info(self, verbose, img_size) + + def _apply(self, fn): + # Apply to(), cpu(), cuda(), half() to model tensors that are not parameters or registered buffers + self = super()._apply(fn) + m = self.model[-1] # Detect() + if isinstance(m, (Detect, DualDetect, TripleDetect, DDetect, DualDDetect, TripleDDetect, Segment, DSegment, DualDSegment, Panoptic)): + m.stride = fn(m.stride) + m.anchors = fn(m.anchors) + m.strides = fn(m.strides) + # m.grid = list(map(fn, m.grid)) + return self + + +class DetectionModel(BaseModel): + # YOLO detection model + def __init__(self, cfg='yolo.yaml', ch=3, nc=None, anchors=None): # model, input channels, number of classes + super().__init__() + if isinstance(cfg, dict): + self.yaml = cfg # model dict + else: # is *.yaml + import yaml # for torch hub + self.yaml_file = Path(cfg).name + with open(cfg, encoding='ascii', errors='ignore') as f: + self.yaml = yaml.safe_load(f) # model dict + + # Define model + ch = self.yaml['ch'] = self.yaml.get('ch', ch) # input channels + if nc and nc != self.yaml['nc']: + LOGGER.info(f"Overriding model.yaml nc={self.yaml['nc']} with nc={nc}") + self.yaml['nc'] = nc # override yaml value + if anchors: + LOGGER.info(f'Overriding model.yaml anchors with anchors={anchors}') + self.yaml['anchors'] = round(anchors) # override yaml value + self.model, self.save = parse_model(deepcopy(self.yaml), ch=[ch]) # model, savelist + self.names = [str(i) for i in range(self.yaml['nc'])] # default names + self.inplace = self.yaml.get('inplace', True) + + # Build strides, anchors + m = self.model[-1] # Detect() + if isinstance(m, (Detect, DDetect, Segment, DSegment, Panoptic)): + s = 256 # 2x min stride + m.inplace = self.inplace + forward = lambda x: self.forward(x)[0] if isinstance(m, (Segment, DSegment, Panoptic)) else self.forward(x) + m.stride = torch.tensor([s / x.shape[-2] for x in forward(torch.zeros(1, ch, s, s))]) # forward + # check_anchor_order(m) + # m.anchors /= m.stride.view(-1, 1, 1) + self.stride = m.stride + m.bias_init() # only run once + if isinstance(m, (DualDetect, TripleDetect, DualDDetect, TripleDDetect, DualDSegment)): + s = 256 # 2x min stride + m.inplace = self.inplace + forward = lambda x: self.forward(x)[0][0] if isinstance(m, (DualDSegment)) else self.forward(x)[0] + m.stride = torch.tensor([s / x.shape[-2] for x in forward(torch.zeros(1, ch, s, s))]) # forward + # check_anchor_order(m) + # m.anchors /= m.stride.view(-1, 1, 1) + self.stride = m.stride + m.bias_init() # only run once + + # Init weights, biases + initialize_weights(self) + self.info() + LOGGER.info('') + + def forward(self, x, augment=False, profile=False, visualize=False): + if augment: + return self._forward_augment(x) # augmented inference, None + return self._forward_once(x, profile, visualize) # single-scale inference, train + + def _forward_augment(self, x): + img_size = x.shape[-2:] # height, width + s = [1, 0.83, 0.67] # scales + f = [None, 3, None] # flips (2-ud, 3-lr) + y = [] # outputs + for si, fi in zip(s, f): + xi = scale_img(x.flip(fi) if fi else x, si, gs=int(self.stride.max())) + yi = self._forward_once(xi)[0] # forward + # cv2.imwrite(f'img_{si}.jpg', 255 * xi[0].cpu().numpy().transpose((1, 2, 0))[:, :, ::-1]) # save + yi = self._descale_pred(yi, fi, si, img_size) + y.append(yi) + y = self._clip_augmented(y) # clip augmented tails + return torch.cat(y, 1), None # augmented inference, train + + def _descale_pred(self, p, flips, scale, img_size): + # de-scale predictions following augmented inference (inverse operation) + if self.inplace: + p[..., :4] /= scale # de-scale + if flips == 2: + p[..., 1] = img_size[0] - p[..., 1] # de-flip ud + elif flips == 3: + p[..., 0] = img_size[1] - p[..., 0] # de-flip lr + else: + x, y, wh = p[..., 0:1] / scale, p[..., 1:2] / scale, p[..., 2:4] / scale # de-scale + if flips == 2: + y = img_size[0] - y # de-flip ud + elif flips == 3: + x = img_size[1] - x # de-flip lr + p = torch.cat((x, y, wh, p[..., 4:]), -1) + return p + + def _clip_augmented(self, y): + # Clip YOLO augmented inference tails + nl = self.model[-1].nl # number of detection layers (P3-P5) + g = sum(4 ** x for x in range(nl)) # grid points + e = 1 # exclude layer count + i = (y[0].shape[1] // g) * sum(4 ** x for x in range(e)) # indices + y[0] = y[0][:, :-i] # large + i = (y[-1].shape[1] // g) * sum(4 ** (nl - 1 - x) for x in range(e)) # indices + y[-1] = y[-1][:, i:] # small + return y + + +Model = DetectionModel # retain YOLO 'Model' class for backwards compatibility + + +class SegmentationModel(DetectionModel): + # YOLO segmentation model + def __init__(self, cfg='yolo-seg.yaml', ch=3, nc=None, anchors=None): + super().__init__(cfg, ch, nc, anchors) + + +class ClassificationModel(BaseModel): + # YOLO classification model + def __init__(self, cfg=None, model=None, nc=1000, cutoff=10): # yaml, model, number of classes, cutoff index + super().__init__() + self._from_detection_model(model, nc, cutoff) if model is not None else self._from_yaml(cfg) + + def _from_detection_model(self, model, nc=1000, cutoff=10): + # Create a YOLO classification model from a YOLO detection model + if isinstance(model, DetectMultiBackend): + model = model.model # unwrap DetectMultiBackend + model.model = model.model[:cutoff] # backbone + m = model.model[-1] # last layer + ch = m.conv.in_channels if hasattr(m, 'conv') else m.cv1.conv.in_channels # ch into module + c = Classify(ch, nc) # Classify() + c.i, c.f, c.type = m.i, m.f, 'models.common.Classify' # index, from, type + model.model[-1] = c # replace + self.model = model.model + self.stride = model.stride + self.save = [] + self.nc = nc + + def _from_yaml(self, cfg): + # Create a YOLO classification model from a *.yaml file + self.model = None + + +def parse_model(d, ch): # model_dict, input_channels(3) + # Parse a YOLO model.yaml dictionary + LOGGER.info(f"\n{'':>3}{'from':>18}{'n':>3}{'params':>10} {'module':<40}{'arguments':<30}") + anchors, nc, gd, gw, act = d['anchors'], d['nc'], d['depth_multiple'], d['width_multiple'], d.get('activation') + if act: + Conv.default_act = eval(act) # redefine default activation, i.e. Conv.default_act = nn.SiLU() + RepConvN.default_act = eval(act) # redefine default activation, i.e. Conv.default_act = nn.SiLU() + LOGGER.info(f"{colorstr('activation:')} {act}") # print + na = (len(anchors[0]) // 2) if isinstance(anchors, list) else anchors # number of anchors + no = na * (nc + 5) # number of outputs = anchors * (classes + 5) + + layers, save, c2 = [], [], ch[-1] # layers, savelist, ch out + for i, (f, n, m, args) in enumerate(d['backbone'] + d['head']): # from, number, module, args + m = eval(m) if isinstance(m, str) else m # eval strings + for j, a in enumerate(args): + with contextlib.suppress(NameError): + args[j] = eval(a) if isinstance(a, str) else a # eval strings + + n = n_ = max(round(n * gd), 1) if n > 1 else n # depth gain + if m in { + Conv, AConv, ConvTranspose, + Bottleneck, SPP, SPPF, DWConv, BottleneckCSP, nn.ConvTranspose2d, DWConvTranspose2d, SPPCSPC, ADown, + RepNCSPELAN4, SPPELAN}: + c1, c2 = ch[f], args[0] + if c2 != no: # if not output + c2 = make_divisible(c2 * gw, 8) + + args = [c1, c2, *args[1:]] + if m in {BottleneckCSP, SPPCSPC}: + args.insert(2, n) # number of repeats + n = 1 + elif m is nn.BatchNorm2d: + args = [ch[f]] + elif m is Concat: + c2 = sum(ch[x] for x in f) + elif m is Shortcut: + c2 = ch[f[0]] + elif m is ReOrg: + c2 = ch[f] * 4 + elif m is CBLinear: + c2 = args[0] + c1 = ch[f] + args = [c1, c2, *args[1:]] + elif m is CBFuse: + c2 = ch[f[-1]] + # TODO: channel, gw, gd + elif m in {Detect, DualDetect, TripleDetect, DDetect, DualDDetect, TripleDDetect, Segment, DSegment, DualDSegment, Panoptic}: + args.append([ch[x] for x in f]) + # if isinstance(args[1], int): # number of anchors + # args[1] = [list(range(args[1] * 2))] * len(f) + if m in {Segment, DSegment, DualDSegment, Panoptic}: + args[2] = make_divisible(args[2] * gw, 8) + elif m is Contract: + c2 = ch[f] * args[0] ** 2 + elif m is Expand: + c2 = ch[f] // args[0] ** 2 + else: + c2 = ch[f] + + m_ = nn.Sequential(*(m(*args) for _ in range(n))) if n > 1 else m(*args) # module + t = str(m)[8:-2].replace('__main__.', '') # module type + np = sum(x.numel() for x in m_.parameters()) # number params + m_.i, m_.f, m_.type, m_.np = i, f, t, np # attach index, 'from' index, type, number params + LOGGER.info(f'{i:>3}{str(f):>18}{n_:>3}{np:10.0f} {t:<40}{str(args):<30}') # print + save.extend(x % i for x in ([f] if isinstance(f, int) else f) if x != -1) # append to savelist + layers.append(m_) + if i == 0: + ch = [] + ch.append(c2) + return nn.Sequential(*layers), sorted(save) + + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument('--cfg', type=str, default='yolo.yaml', help='model.yaml') + parser.add_argument('--batch-size', type=int, default=1, help='total batch size for all GPUs') + parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu') + parser.add_argument('--profile', action='store_true', help='profile model speed') + parser.add_argument('--line-profile', action='store_true', help='profile model speed layer by layer') + parser.add_argument('--test', action='store_true', help='test all yolo*.yaml') + opt = parser.parse_args() + opt.cfg = check_yaml(opt.cfg) # check YAML + print_args(vars(opt)) + device = select_device(opt.device) + + # Create model + im = torch.rand(opt.batch_size, 3, 640, 640).to(device) + model = Model(opt.cfg).to(device) + model.eval() + + # Options + if opt.line_profile: # profile layer by layer + model(im, profile=True) + + elif opt.profile: # profile forward-backward + results = profile(input=im, ops=[model], n=3) + + elif opt.test: # test all models + for cfg in Path(ROOT / 'models').rglob('yolo*.yaml'): + try: + _ = Model(cfg) + except Exception as e: + print(f'Error in {cfg}: {e}') + + else: # report fused model summary + model.fuse() diff --git a/cv/3d_detection/yolov9/pytorch/panoptic/predict.py b/cv/3d_detection/yolov9/pytorch/panoptic/predict.py new file mode 100644 index 000000000..9d7d2d800 --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/panoptic/predict.py @@ -0,0 +1,246 @@ +import argparse +import os +import platform +import sys +from pathlib import Path + +import torch + +FILE = Path(__file__).resolve() +ROOT = FILE.parents[1] # YOLO root directory +if str(ROOT) not in sys.path: + sys.path.append(str(ROOT)) # add ROOT to PATH +ROOT = Path(os.path.relpath(ROOT, Path.cwd())) # relative + +from models.common import DetectMultiBackend +from utils.dataloaders import IMG_FORMATS, VID_FORMATS, LoadImages, LoadScreenshots, LoadStreams +from utils.general import (LOGGER, Profile, check_file, check_img_size, check_imshow, check_requirements, colorstr, cv2, + increment_path, non_max_suppression, print_args, scale_boxes, scale_segments, + strip_optimizer, xyxy2xywh) +from utils.plots import Annotator, colors, save_one_box +from utils.segment.general import masks2segments, process_mask +from utils.torch_utils import select_device, smart_inference_mode + + +@smart_inference_mode() +def run( + weights=ROOT / 'yolo-pan.pt', # model.pt path(s) + source=ROOT / 'data/images', # file/dir/URL/glob/screen/0(webcam) + data=ROOT / 'data/coco128.yaml', # dataset.yaml path + imgsz=(640, 640), # inference size (height, width) + conf_thres=0.25, # confidence threshold + iou_thres=0.45, # NMS IOU threshold + max_det=1000, # maximum detections per image + device='', # cuda device, i.e. 0 or 0,1,2,3 or cpu + view_img=False, # show results + save_txt=False, # save results to *.txt + save_conf=False, # save confidences in --save-txt labels + save_crop=False, # save cropped prediction boxes + nosave=False, # do not save images/videos + classes=None, # filter by class: --class 0, or --class 0 2 3 + agnostic_nms=False, # class-agnostic NMS + augment=False, # augmented inference + visualize=False, # visualize features + update=False, # update all models + project=ROOT / 'runs/predict-seg', # save results to project/name + name='exp', # save results to project/name + exist_ok=False, # existing project/name ok, do not increment + line_thickness=3, # bounding box thickness (pixels) + hide_labels=False, # hide labels + hide_conf=False, # hide confidences + half=False, # use FP16 half-precision inference + dnn=False, # use OpenCV DNN for ONNX inference + vid_stride=1, # video frame-rate stride + retina_masks=False, +): + source = str(source) + save_img = not nosave and not source.endswith('.txt') # save inference images + is_file = Path(source).suffix[1:] in (IMG_FORMATS + VID_FORMATS) + is_url = source.lower().startswith(('rtsp://', 'rtmp://', 'http://', 'https://')) + webcam = source.isnumeric() or source.endswith('.txt') or (is_url and not is_file) + screenshot = source.lower().startswith('screen') + if is_url and is_file: + source = check_file(source) # download + + # Directories + save_dir = increment_path(Path(project) / name, exist_ok=exist_ok) # increment run + (save_dir / 'labels' if save_txt else save_dir).mkdir(parents=True, exist_ok=True) # make dir + + # Load model + device = select_device(device) + model = DetectMultiBackend(weights, device=device, dnn=dnn, data=data, fp16=half) + stride, names, pt = model.stride, model.names, model.pt + imgsz = check_img_size(imgsz, s=stride) # check image size + + # Dataloader + bs = 1 # batch_size + if webcam: + view_img = check_imshow(warn=True) + dataset = LoadStreams(source, img_size=imgsz, stride=stride, auto=pt, vid_stride=vid_stride) + bs = len(dataset) + elif screenshot: + dataset = LoadScreenshots(source, img_size=imgsz, stride=stride, auto=pt) + else: + dataset = LoadImages(source, img_size=imgsz, stride=stride, auto=pt, vid_stride=vid_stride) + vid_path, vid_writer = [None] * bs, [None] * bs + + # Run inference + model.warmup(imgsz=(1 if pt else bs, 3, *imgsz)) # warmup + seen, windows, dt = 0, [], (Profile(), Profile(), Profile()) + for path, im, im0s, vid_cap, s in dataset: + with dt[0]: + im = torch.from_numpy(im).to(model.device) + im = im.half() if model.fp16 else im.float() # uint8 to fp16/32 + im /= 255 # 0 - 255 to 0.0 - 1.0 + if len(im.shape) == 3: + im = im[None] # expand for batch dim + + # Inference + with dt[1]: + visualize = increment_path(save_dir / Path(path).stem, mkdir=True) if visualize else False + pred, proto = model(im, augment=augment, visualize=visualize)[:2] + + # NMS + with dt[2]: + pred = non_max_suppression(pred, conf_thres, iou_thres, classes, agnostic_nms, max_det=max_det, nm=32) + + # Second-stage classifier (optional) + # pred = utils.general.apply_classifier(pred, classifier_model, im, im0s) + + # Process predictions + for i, det in enumerate(pred): # per image + seen += 1 + if webcam: # batch_size >= 1 + p, im0, frame = path[i], im0s[i].copy(), dataset.count + s += f'{i}: ' + else: + p, im0, frame = path, im0s.copy(), getattr(dataset, 'frame', 0) + + p = Path(p) # to Path + save_path = str(save_dir / p.name) # im.jpg + txt_path = str(save_dir / 'labels' / p.stem) + ('' if dataset.mode == 'image' else f'_{frame}') # im.txt + s += '%gx%g ' % im.shape[2:] # print string + imc = im0.copy() if save_crop else im0 # for save_crop + annotator = Annotator(im0, line_width=line_thickness, example=str(names)) + if len(det): + masks = process_mask(proto[i], det[:, 6:], det[:, :4], im.shape[2:], upsample=True) # HWC + det[:, :4] = scale_boxes(im.shape[2:], det[:, :4], im0.shape).round() # rescale boxes to im0 size + + # Segments + if save_txt: + segments = reversed(masks2segments(masks)) + segments = [scale_segments(im.shape[2:], x, im0.shape, normalize=True) for x in segments] + + # Print results + for c in det[:, 5].unique(): + n = (det[:, 5] == c).sum() # detections per class + s += f"{n} {names[int(c)]}{'s' * (n > 1)}, " # add to string + + # Mask plotting + annotator.masks(masks, + colors=[colors(x, True) for x in det[:, 5]], + im_gpu=None if retina_masks else im[i]) + + # Write results + for j, (*xyxy, conf, cls) in enumerate(reversed(det[:, :6])): + if save_txt: # Write to file + segj = segments[j].reshape(-1) # (n,2) to (n*2) + line = (cls, *segj, conf) if save_conf else (cls, *segj) # label format + with open(f'{txt_path}.txt', 'a') as f: + f.write(('%g ' * len(line)).rstrip() % line + '\n') + + if save_img or save_crop or view_img: # Add bbox to image + c = int(cls) # integer class + label = None if hide_labels else (names[c] if hide_conf else f'{names[c]} {conf:.2f}') + annotator.box_label(xyxy, label, color=colors(c, True)) + # annotator.draw.polygon(segments[j], outline=colors(c, True), width=3) + if save_crop: + save_one_box(xyxy, imc, file=save_dir / 'crops' / names[c] / f'{p.stem}.jpg', BGR=True) + + # Stream results + im0 = annotator.result() + if view_img: + if platform.system() == 'Linux' and p not in windows: + windows.append(p) + cv2.namedWindow(str(p), cv2.WINDOW_NORMAL | cv2.WINDOW_KEEPRATIO) # allow window resize (Linux) + cv2.resizeWindow(str(p), im0.shape[1], im0.shape[0]) + cv2.imshow(str(p), im0) + if cv2.waitKey(1) == ord('q'): # 1 millisecond + exit() + + # Save results (image with detections) + if save_img: + if dataset.mode == 'image': + cv2.imwrite(save_path, im0) + else: # 'video' or 'stream' + if vid_path[i] != save_path: # new video + vid_path[i] = save_path + if isinstance(vid_writer[i], cv2.VideoWriter): + vid_writer[i].release() # release previous video writer + if vid_cap: # video + fps = vid_cap.get(cv2.CAP_PROP_FPS) + w = int(vid_cap.get(cv2.CAP_PROP_FRAME_WIDTH)) + h = int(vid_cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) + else: # stream + fps, w, h = 30, im0.shape[1], im0.shape[0] + save_path = str(Path(save_path).with_suffix('.mp4')) # force *.mp4 suffix on results videos + vid_writer[i] = cv2.VideoWriter(save_path, cv2.VideoWriter_fourcc(*'mp4v'), fps, (w, h)) + vid_writer[i].write(im0) + + # Print time (inference-only) + LOGGER.info(f"{s}{'' if len(det) else '(no detections), '}{dt[1].dt * 1E3:.1f}ms") + + # Print results + t = tuple(x.t / seen * 1E3 for x in dt) # speeds per image + LOGGER.info(f'Speed: %.1fms pre-process, %.1fms inference, %.1fms NMS per image at shape {(1, 3, *imgsz)}' % t) + if save_txt or save_img: + s = f"\n{len(list(save_dir.glob('labels/*.txt')))} labels saved to {save_dir / 'labels'}" if save_txt else '' + LOGGER.info(f"Results saved to {colorstr('bold', save_dir)}{s}") + if update: + strip_optimizer(weights[0]) # update model (to fix SourceChangeWarning) + + +def parse_opt(): + parser = argparse.ArgumentParser() + parser.add_argument('--weights', nargs='+', type=str, default=ROOT / 'yolo-pan.pt', help='model path(s)') + parser.add_argument('--source', type=str, default=ROOT / 'data/images', help='file/dir/URL/glob/screen/0(webcam)') + parser.add_argument('--data', type=str, default=ROOT / 'data/coco128.yaml', help='(optional) dataset.yaml path') + parser.add_argument('--imgsz', '--img', '--img-size', nargs='+', type=int, default=[640], help='inference size h,w') + parser.add_argument('--conf-thres', type=float, default=0.25, help='confidence threshold') + parser.add_argument('--iou-thres', type=float, default=0.45, help='NMS IoU threshold') + parser.add_argument('--max-det', type=int, default=1000, help='maximum detections per image') + parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu') + parser.add_argument('--view-img', action='store_true', help='show results') + parser.add_argument('--save-txt', action='store_true', help='save results to *.txt') + parser.add_argument('--save-conf', action='store_true', help='save confidences in --save-txt labels') + parser.add_argument('--save-crop', action='store_true', help='save cropped prediction boxes') + parser.add_argument('--nosave', action='store_true', help='do not save images/videos') + parser.add_argument('--classes', nargs='+', type=int, help='filter by class: --classes 0, or --classes 0 2 3') + parser.add_argument('--agnostic-nms', action='store_true', help='class-agnostic NMS') + parser.add_argument('--augment', action='store_true', help='augmented inference') + parser.add_argument('--visualize', action='store_true', help='visualize features') + parser.add_argument('--update', action='store_true', help='update all models') + parser.add_argument('--project', default=ROOT / 'runs/predict-seg', help='save results to project/name') + parser.add_argument('--name', default='exp', help='save results to project/name') + parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment') + parser.add_argument('--line-thickness', default=3, type=int, help='bounding box thickness (pixels)') + parser.add_argument('--hide-labels', default=False, action='store_true', help='hide labels') + parser.add_argument('--hide-conf', default=False, action='store_true', help='hide confidences') + parser.add_argument('--half', action='store_true', help='use FP16 half-precision inference') + parser.add_argument('--dnn', action='store_true', help='use OpenCV DNN for ONNX inference') + parser.add_argument('--vid-stride', type=int, default=1, help='video frame-rate stride') + parser.add_argument('--retina-masks', action='store_true', help='whether to plot masks in native resolution') + opt = parser.parse_args() + opt.imgsz *= 2 if len(opt.imgsz) == 1 else 1 # expand + print_args(vars(opt)) + return opt + + +def main(opt): + check_requirements(exclude=('tensorboard', 'thop')) + run(**vars(opt)) + + +if __name__ == "__main__": + opt = parse_opt() + main(opt) diff --git a/cv/3d_detection/yolov9/pytorch/panoptic/train.py b/cv/3d_detection/yolov9/pytorch/panoptic/train.py new file mode 100644 index 000000000..e20244c99 --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/panoptic/train.py @@ -0,0 +1,662 @@ +import argparse +import math +import os +import random +import sys +import time +from copy import deepcopy +from datetime import datetime +from pathlib import Path + +import numpy as np +import torch +import torch.distributed as dist +import torch.nn as nn +import yaml +from torch.optim import lr_scheduler +from tqdm import tqdm + +FILE = Path(__file__).resolve() +ROOT = FILE.parents[1] # YOLO root directory +if str(ROOT) not in sys.path: + sys.path.append(str(ROOT)) # add ROOT to PATH +ROOT = Path(os.path.relpath(ROOT, Path.cwd())) # relative + +import panoptic.val as validate # for end-of-epoch mAP +from models.experimental import attempt_load +from models.yolo import SegmentationModel +from utils.autoanchor import check_anchors +from utils.autobatch import check_train_batch_size +from utils.callbacks import Callbacks +from utils.downloads import attempt_download, is_url +from utils.general import (LOGGER, TQDM_BAR_FORMAT, check_amp, check_dataset, check_file, check_git_info, + check_git_status, check_img_size, check_requirements, check_suffix, check_yaml, colorstr, + get_latest_run, increment_path, init_seeds, intersect_dicts, labels_to_class_weights, + labels_to_image_weights, one_cycle, one_flat_cycle, print_args, print_mutation, strip_optimizer, yaml_save) +from utils.loggers import GenericLogger +from utils.plots import plot_evolve, plot_labels +from utils.panoptic.dataloaders import create_dataloader +from utils.panoptic.loss_tal import ComputeLoss +from utils.panoptic.metrics import KEYS, fitness +from utils.panoptic.plots import plot_images_and_masks, plot_results_with_masks +from utils.torch_utils import (EarlyStopping, ModelEMA, de_parallel, select_device, smart_DDP, smart_optimizer, + smart_resume, torch_distributed_zero_first) + +LOCAL_RANK = int(os.getenv('LOCAL_RANK', -1)) # https://pytorch.org/docs/stable/elastic/run.html +RANK = int(os.getenv('RANK', -1)) +WORLD_SIZE = int(os.getenv('WORLD_SIZE', 1)) +GIT_INFO = None#check_git_info() + + +def train(hyp, opt, device, callbacks): # hyp is path/to/hyp.yaml or hyp dictionary + save_dir, epochs, batch_size, weights, single_cls, evolve, data, cfg, resume, noval, nosave, workers, freeze, mask_ratio = \ + Path(opt.save_dir), opt.epochs, opt.batch_size, opt.weights, opt.single_cls, opt.evolve, opt.data, opt.cfg, \ + opt.resume, opt.noval, opt.nosave, opt.workers, opt.freeze, opt.mask_ratio + # callbacks.run('on_pretrain_routine_start') + + # Directories + w = save_dir / 'weights' # weights dir + (w.parent if evolve else w).mkdir(parents=True, exist_ok=True) # make dir + last, best = w / 'last.pt', w / 'best.pt' + + # Hyperparameters + if isinstance(hyp, str): + with open(hyp, errors='ignore') as f: + hyp = yaml.safe_load(f) # load hyps dict + LOGGER.info(colorstr('hyperparameters: ') + ', '.join(f'{k}={v}' for k, v in hyp.items())) + opt.hyp = hyp.copy() # for saving hyps to checkpoints + + # Save run settings + if not evolve: + yaml_save(save_dir / 'hyp.yaml', hyp) + yaml_save(save_dir / 'opt.yaml', vars(opt)) + + # Loggers + data_dict = None + if RANK in {-1, 0}: + logger = GenericLogger(opt=opt, console_logger=LOGGER) + + # Config + plots = not evolve and not opt.noplots # create plots + overlap = not opt.no_overlap + cuda = device.type != 'cpu' + init_seeds(opt.seed + 1 + RANK, deterministic=True) + with torch_distributed_zero_first(LOCAL_RANK): + data_dict = data_dict or check_dataset(data) # check if None + train_path, val_path = data_dict['train'], data_dict['val'] + nc = 1 if single_cls else int(data_dict['nc']) # number of classes + names = {0: 'item'} if single_cls and len(data_dict['names']) != 1 else data_dict['names'] # class names + #is_coco = isinstance(val_path, str) and val_path.endswith('coco/val2017.txt') # COCO dataset + is_coco = isinstance(val_path, str) and val_path.endswith('val2017.txt') # COCO dataset + + # Model + check_suffix(weights, '.pt') # check weights + pretrained = weights.endswith('.pt') + if pretrained: + with torch_distributed_zero_first(LOCAL_RANK): + weights = attempt_download(weights) # download if not found locally + ckpt = torch.load(weights, map_location='cpu') # load checkpoint to CPU to avoid CUDA memory leak + model = SegmentationModel(cfg or ckpt['model'].yaml, ch=3, nc=nc).to(device) + exclude = ['anchor'] if (cfg or hyp.get('anchors')) and not resume else [] # exclude keys + csd = ckpt['model'].float().state_dict() # checkpoint state_dict as FP32 + csd = intersect_dicts(csd, model.state_dict(), exclude=exclude) # intersect + model.load_state_dict(csd, strict=False) # load + LOGGER.info(f'Transferred {len(csd)}/{len(model.state_dict())} items from {weights}') # report + else: + model = SegmentationModel(cfg, ch=3, nc=nc).to(device) # create + amp = check_amp(model) # check AMP + + # Freeze + freeze = [f'model.{x}.' for x in (freeze if len(freeze) > 1 else range(freeze[0]))] # layers to freeze + for k, v in model.named_parameters(): + #v.requires_grad = True # train all layers + # v.register_hook(lambda x: torch.nan_to_num(x)) # NaN to 0 (commented for erratic training results) + if any(x in k for x in freeze): + LOGGER.info(f'freezing {k}') + v.requires_grad = False + + # Image size + gs = max(int(model.stride.max()), 32) # grid size (max stride) + imgsz = check_img_size(opt.imgsz, gs, floor=gs * 2) # verify imgsz is gs-multiple + + # Batch size + if RANK == -1 and batch_size == -1: # single-GPU only, estimate best batch size + batch_size = check_train_batch_size(model, imgsz, amp) + logger.update_params({"batch_size": batch_size}) + # loggers.on_params_update({"batch_size": batch_size}) + + # Optimizer + nbs = 64 # nominal batch size + accumulate = max(round(nbs / batch_size), 1) # accumulate loss before optimizing + hyp['weight_decay'] *= batch_size * accumulate / nbs # scale weight_decay + optimizer = smart_optimizer(model, opt.optimizer, hyp['lr0'], hyp['momentum'], hyp['weight_decay']) + + # Scheduler + if opt.cos_lr: + lf = one_cycle(1, hyp['lrf'], epochs) # cosine 1->hyp['lrf'] + elif opt.flat_cos_lr: + lf = one_flat_cycle(1, hyp['lrf'], epochs) # cosine 1->hyp['lrf'] + elif opt.fixed_lr: + lf = lambda x: 1.0 + elif opt.poly_lr: + power = 0.9 + lf = lambda x: ((1 - (x / epochs)) ** power) * (1.0 - hyp['lrf']) + hyp['lrf'] + else: + lf = lambda x: (1 - x / epochs) * (1.0 - hyp['lrf']) + hyp['lrf'] # linear + scheduler = lr_scheduler.LambdaLR(optimizer, lr_lambda=lf) # plot_lr_scheduler(optimizer, scheduler, epochs) + + # EMA + ema = ModelEMA(model) if RANK in {-1, 0} else None + + # Resume + best_fitness, start_epoch = 0.0, 0 + if pretrained: + if resume: + best_fitness, start_epoch, epochs = smart_resume(ckpt, optimizer, ema, weights, epochs, resume) + del ckpt, csd + + # DP mode + if cuda and RANK == -1 and torch.cuda.device_count() > 1: + LOGGER.warning('WARNING ⚠️ DP not recommended, use torch.distributed.run for best DDP Multi-GPU results.') + model = torch.nn.DataParallel(model) + + # SyncBatchNorm + if opt.sync_bn and cuda and RANK != -1: + model = torch.nn.SyncBatchNorm.convert_sync_batchnorm(model).to(device) + LOGGER.info('Using SyncBatchNorm()') + + # Trainloader + train_loader, dataset = create_dataloader( + train_path, + imgsz, + batch_size // WORLD_SIZE, + gs, + single_cls, + hyp=hyp, + augment=True, + cache=None if opt.cache == 'val' else opt.cache, + rect=opt.rect, + rank=LOCAL_RANK, + workers=workers, + image_weights=opt.image_weights, + close_mosaic=opt.close_mosaic != 0, + quad=opt.quad, + prefix=colorstr('train: '), + shuffle=True, + mask_downsample_ratio=mask_ratio, + overlap_mask=overlap, + ) + labels = np.concatenate(dataset.labels, 0) + mlc = int(labels[:, 0].max()) # max label class + assert mlc < nc, f'Label class {mlc} exceeds nc={nc} in {data}. Possible class labels are 0-{nc - 1}' + + # Process 0 + if RANK in {-1, 0}: + val_loader = create_dataloader(val_path, + imgsz, + batch_size // WORLD_SIZE * 2, + gs, + single_cls, + hyp=hyp, + cache=None if noval else opt.cache, + rect=True, + rank=-1, + workers=workers * 2, + pad=0.5, + mask_downsample_ratio=mask_ratio, + overlap_mask=overlap, + prefix=colorstr('val: '))[0] + + if not resume: + #if not opt.noautoanchor: + # check_anchors(dataset, model=model, thr=hyp['anchor_t'], imgsz=imgsz) # run AutoAnchor + model.half().float() # pre-reduce anchor precision + + if plots: + plot_labels(labels, names, save_dir) + # callbacks.run('on_pretrain_routine_end', labels, names) + + # DDP mode + if cuda and RANK != -1: + model = smart_DDP(model) + + # Model attributes + nl = de_parallel(model).model[-1].nl # number of detection layers (to scale hyps) + #hyp['box'] *= 3 / nl # scale to layers + #hyp['cls'] *= nc / 80 * 3 / nl # scale to classes and layers + #hyp['obj'] *= (imgsz / 640) ** 2 * 3 / nl # scale to image size and layers + hyp['label_smoothing'] = opt.label_smoothing + model.nc = nc # attach number of classes to model + model.hyp = hyp # attach hyperparameters to model + model.class_weights = labels_to_class_weights(dataset.labels, nc).to(device) * nc # attach class weights + model.names = names + + # Start training + t0 = time.time() + nb = len(train_loader) # number of batches + nw = max(round(hyp['warmup_epochs'] * nb), 100) # number of warmup iterations, max(3 epochs, 100 iterations) + # nw = min(nw, (epochs - start_epoch) / 2 * nb) # limit warmup to < 1/2 of training + last_opt_step = -1 + maps = np.zeros(nc) # mAP per class + results = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) # P, R, mAP@.5, mAP@.5-.95, val_loss(box, obj, cls) + scheduler.last_epoch = start_epoch - 1 # do not move + scaler = torch.cuda.amp.GradScaler(enabled=amp) + stopper, stop = EarlyStopping(patience=opt.patience), False + compute_loss = ComputeLoss(model, overlap=overlap) # init loss class + # callbacks.run('on_train_start') + LOGGER.info(f'Image sizes {imgsz} train, {imgsz} val\n' + f'Using {train_loader.num_workers * WORLD_SIZE} dataloader workers\n' + f"Logging results to {colorstr('bold', save_dir)}\n" + f'Starting training for {epochs} epochs...') + for epoch in range(start_epoch, epochs): # epoch ------------------------------------------------------------------ + # callbacks.run('on_train_epoch_start') + model.train() + + # Update image weights (optional, single-GPU only) + if opt.image_weights: + cw = model.class_weights.cpu().numpy() * (1 - maps) ** 2 / nc # class weights + iw = labels_to_image_weights(dataset.labels, nc=nc, class_weights=cw) # image weights + dataset.indices = random.choices(range(dataset.n), weights=iw, k=dataset.n) # rand weighted idx + if epoch == (epochs - opt.close_mosaic): + LOGGER.info("Closing dataloader mosaic") + dataset.mosaic = False + + # Update mosaic border (optional) + # b = int(random.uniform(0.25 * imgsz, 0.75 * imgsz + gs) // gs * gs) + # dataset.mosaic_border = [b - imgsz, -b] # height, width borders + + mloss = torch.zeros(6, device=device) # mean losses + if RANK != -1: + train_loader.sampler.set_epoch(epoch) + pbar = enumerate(train_loader) + LOGGER.info(('\n' + '%11s' * 10) % + ('Epoch', 'GPU_mem', 'box_loss', 'seg_loss', 'cls_loss', 'dfl_loss', 'fcl_loss', 'dic_loss', 'Instances', 'Size')) + if RANK in {-1, 0}: + pbar = tqdm(pbar, total=nb, bar_format=TQDM_BAR_FORMAT) # progress bar + optimizer.zero_grad() + for i, (imgs, targets, paths, _, masks, semasks) in pbar: # batch ------------------------------------------------------ + # callbacks.run('on_train_batch_start') + #print(imgs.shape) + #print(semasks.shape) + #print(masks.shape) + ni = i + nb * epoch # number integrated batches (since train start) + imgs = imgs.to(device, non_blocking=True).float() / 255 # uint8 to float32, 0-255 to 0.0-1.0 + + # Warmup + if ni <= nw: + xi = [0, nw] # x interp + # compute_loss.gr = np.interp(ni, xi, [0.0, 1.0]) # iou loss ratio (obj_loss = 1.0 or iou) + accumulate = max(1, np.interp(ni, xi, [1, nbs / batch_size]).round()) + for j, x in enumerate(optimizer.param_groups): + # bias lr falls from 0.1 to lr0, all other lrs rise from 0.0 to lr0 + x['lr'] = np.interp(ni, xi, [hyp['warmup_bias_lr'] if j == 0 else 0.0, x['initial_lr'] * lf(epoch)]) + if 'momentum' in x: + x['momentum'] = np.interp(ni, xi, [hyp['warmup_momentum'], hyp['momentum']]) + + # Multi-scale + if opt.multi_scale: + sz = random.randrange(imgsz * 0.5, imgsz * 1.5 + gs) // gs * gs # size + sf = sz / max(imgs.shape[2:]) # scale factor + if sf != 1: + ns = [math.ceil(x * sf / gs) * gs for x in imgs.shape[2:]] # new shape (stretched to gs-multiple) + imgs = nn.functional.interpolate(imgs, size=ns, mode='bilinear', align_corners=False) + + # Forward + with torch.cuda.amp.autocast(amp): + pred = model(imgs) # forward + loss, loss_items = compute_loss(pred, targets.to(device), masks=masks.to(device).float(), + semasks=semasks.to(device).float()) + if RANK != -1: + loss *= WORLD_SIZE # gradient averaged between devices in DDP mode + if opt.quad: + loss *= 4. + + # Backward + torch.use_deterministic_algorithms(False) + scaler.scale(loss).backward() + + # Optimize - https://pytorch.org/docs/master/notes/amp_examples.html + if ni - last_opt_step >= accumulate: + scaler.unscale_(optimizer) # unscale gradients + torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=10.0) # clip gradients + scaler.step(optimizer) # optimizer.step + scaler.update() + optimizer.zero_grad() + if ema: + ema.update(model) + last_opt_step = ni + + # Log + if RANK in {-1, 0}: + mloss = (mloss * i + loss_items) / (i + 1) # update mean losses + mem = f'{torch.cuda.memory_reserved() / 1E9 if torch.cuda.is_available() else 0:.3g}G' # (GB) + pbar.set_description(('%11s' * 2 + '%11.4g' * 8) % + (f'{epoch}/{epochs - 1}', mem, *mloss, targets.shape[0], imgs.shape[-1])) + # callbacks.run('on_train_batch_end', model, ni, imgs, targets, paths) + # if callbacks.stop_training: + # return + + # Mosaic plots + if plots: + if ni < 10: + plot_images_and_masks(imgs, targets, masks, semasks, paths, save_dir / f"train_batch{ni}.jpg") + if ni == 10: + files = sorted(save_dir.glob('train*.jpg')) + logger.log_images(files, "Mosaics", epoch) + # end batch ------------------------------------------------------------------------------------------------ + + # Scheduler + lr = [x['lr'] for x in optimizer.param_groups] # for loggers + scheduler.step() + + if RANK in {-1, 0}: + # mAP + # callbacks.run('on_train_epoch_end', epoch=epoch) + ema.update_attr(model, include=['yaml', 'nc', 'hyp', 'names', 'stride', 'class_weights']) + final_epoch = (epoch + 1 == epochs) or stopper.possible_stop + if not noval or final_epoch: # Calculate mAP + if (opt.save_period > 0 and epoch % opt.save_period == 0) or (epoch > (epochs - 2 * opt.close_mosaic)): + results, maps, _ = validate.run(data_dict, + batch_size=batch_size // WORLD_SIZE * 2, + imgsz=imgsz, + half=amp, + model=ema.ema, + single_cls=single_cls, + dataloader=val_loader, + save_dir=save_dir, + plots=False, + callbacks=callbacks, + compute_loss=compute_loss, + mask_downsample_ratio=mask_ratio, + overlap=overlap) + + # Update best mAP + fi = fitness(np.array(results).reshape(1, -1)) # weighted combination of [P, R, mAP@.5, mAP@.5-.95] + stop = stopper(epoch=epoch, fitness=fi) # early stop check + if fi > best_fitness: + best_fitness = fi + log_vals = list(mloss) + list(results) + lr + # callbacks.run('on_fit_epoch_end', log_vals, epoch, best_fitness, fi) + # Log val metrics and media + metrics_dict = dict(zip(KEYS, log_vals)) + logger.log_metrics(metrics_dict, epoch) + + # Save model + if (not nosave) or (final_epoch and not evolve): # if save + ckpt = { + 'epoch': epoch, + 'best_fitness': best_fitness, + 'model': deepcopy(de_parallel(model)).half(), + 'ema': deepcopy(ema.ema).half(), + 'updates': ema.updates, + 'optimizer': optimizer.state_dict(), + 'opt': vars(opt), + 'git': GIT_INFO, # {remote, branch, commit} if a git repo + 'date': datetime.now().isoformat()} + + # Save last, best and delete + torch.save(ckpt, last) + if best_fitness == fi: + torch.save(ckpt, best) + if opt.save_period > 0 and epoch % opt.save_period == 0: + torch.save(ckpt, w / f'epoch{epoch}.pt') + logger.log_model(w / f'epoch{epoch}.pt') + del ckpt + # callbacks.run('on_model_save', last, epoch, final_epoch, best_fitness, fi) + + # EarlyStopping + if RANK != -1: # if DDP training + broadcast_list = [stop if RANK == 0 else None] + dist.broadcast_object_list(broadcast_list, 0) # broadcast 'stop' to all ranks + if RANK != 0: + stop = broadcast_list[0] + if stop: + break # must break all DDP ranks + + # end epoch ---------------------------------------------------------------------------------------------------- + # end training ----------------------------------------------------------------------------------------------------- + if RANK in {-1, 0}: + LOGGER.info(f'\n{epoch - start_epoch + 1} epochs completed in {(time.time() - t0) / 3600:.3f} hours.') + for f in last, best: + if f.exists(): + strip_optimizer(f) # strip optimizers + if f is best: + LOGGER.info(f'\nValidating {f}...') + results, _, _ = validate.run( + data_dict, + batch_size=batch_size // WORLD_SIZE * 2, + imgsz=imgsz, + model=attempt_load(f, device).half(), + iou_thres=0.65 if is_coco else 0.60, # best pycocotools at iou 0.65 + single_cls=single_cls, + dataloader=val_loader, + save_dir=save_dir, + save_json=is_coco, + verbose=True, + plots=plots, + callbacks=callbacks, + compute_loss=compute_loss, + mask_downsample_ratio=mask_ratio, + overlap=overlap) # val best model with plots + if is_coco: + # callbacks.run('on_fit_epoch_end', list(mloss) + list(results) + lr, epoch, best_fitness, fi) + metrics_dict = dict(zip(KEYS, list(mloss) + list(results) + lr)) + logger.log_metrics(metrics_dict, epoch) + + # callbacks.run('on_train_end', last, best, epoch, results) + # on train end callback using genericLogger + logger.log_metrics(dict(zip(KEYS[6:22], results)), epochs) + if not opt.evolve: + logger.log_model(best, epoch) + if plots: + plot_results_with_masks(file=save_dir / 'results.csv') # save results.png + files = ['results.png', 'confusion_matrix.png', *(f'{x}_curve.png' for x in ('F1', 'PR', 'P', 'R'))] + files = [(save_dir / f) for f in files if (save_dir / f).exists()] # filter + LOGGER.info(f"Results saved to {colorstr('bold', save_dir)}") + logger.log_images(files, "Results", epoch + 1) + logger.log_images(sorted(save_dir.glob('val*.jpg')), "Validation", epoch + 1) + torch.cuda.empty_cache() + return results + + +def parse_opt(known=False): + parser = argparse.ArgumentParser() + parser.add_argument('--weights', type=str, default=ROOT / 'yolo-pan.pt', help='initial weights path') + parser.add_argument('--cfg', type=str, default='', help='model.yaml path') + parser.add_argument('--data', type=str, default=ROOT / 'data/coco128-seg.yaml', help='dataset.yaml path') + parser.add_argument('--hyp', type=str, default=ROOT / 'data/hyps/hyp.scratch-low.yaml', help='hyperparameters path') + parser.add_argument('--epochs', type=int, default=100, help='total training epochs') + parser.add_argument('--batch-size', type=int, default=16, help='total batch size for all GPUs, -1 for autobatch') + parser.add_argument('--imgsz', '--img', '--img-size', type=int, default=640, help='train, val image size (pixels)') + parser.add_argument('--rect', action='store_true', help='rectangular training') + parser.add_argument('--resume', nargs='?', const=True, default=False, help='resume most recent training') + parser.add_argument('--nosave', action='store_true', help='only save final checkpoint') + parser.add_argument('--noval', action='store_true', help='only validate final epoch') + parser.add_argument('--noautoanchor', action='store_true', help='disable AutoAnchor') + parser.add_argument('--noplots', action='store_true', help='save no plot files') + parser.add_argument('--evolve', type=int, nargs='?', const=300, help='evolve hyperparameters for x generations') + parser.add_argument('--bucket', type=str, default='', help='gsutil bucket') + parser.add_argument('--cache', type=str, nargs='?', const='ram', help='image --cache ram/disk') + parser.add_argument('--image-weights', action='store_true', help='use weighted image selection for training') + parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu') + parser.add_argument('--multi-scale', action='store_true', help='vary img-size +/- 50%%') + parser.add_argument('--single-cls', action='store_true', help='train multi-class data as single-class') + parser.add_argument('--optimizer', type=str, choices=['SGD', 'Adam', 'AdamW', 'LION'], default='SGD', help='optimizer') + parser.add_argument('--sync-bn', action='store_true', help='use SyncBatchNorm, only available in DDP mode') + parser.add_argument('--workers', type=int, default=8, help='max dataloader workers (per RANK in DDP mode)') + parser.add_argument('--project', default=ROOT / 'runs/train-pan', help='save to project/name') + parser.add_argument('--name', default='exp', help='save to project/name') + parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment') + parser.add_argument('--quad', action='store_true', help='quad dataloader') + parser.add_argument('--cos-lr', action='store_true', help='cosine LR scheduler') + parser.add_argument('--flat-cos-lr', action='store_true', help='cosine LR scheduler') + parser.add_argument('--fixed-lr', action='store_true', help='fixed LR scheduler') + parser.add_argument('--poly-lr', action='store_true', help='fixed LR scheduler') + parser.add_argument('--label-smoothing', type=float, default=0.0, help='Label smoothing epsilon') + parser.add_argument('--patience', type=int, default=100, help='EarlyStopping patience (epochs without improvement)') + parser.add_argument('--freeze', nargs='+', type=int, default=[0], help='Freeze layers: backbone=10, first3=0 1 2') + parser.add_argument('--save-period', type=int, default=-1, help='Save checkpoint every x epochs (disabled if < 1)') + parser.add_argument('--seed', type=int, default=0, help='Global training seed') + parser.add_argument('--local_rank', type=int, default=-1, help='Automatic DDP Multi-GPU argument, do not modify') + parser.add_argument('--close-mosaic', type=int, default=0, help='Experimental') + + # Instance Segmentation Args + parser.add_argument('--mask-ratio', type=int, default=4, help='Downsample the truth masks to saving memory') + parser.add_argument('--no-overlap', action='store_true', help='Overlap masks train faster at slightly less mAP') + + return parser.parse_known_args()[0] if known else parser.parse_args() + + +def main(opt, callbacks=Callbacks()): + # Checks + if RANK in {-1, 0}: + print_args(vars(opt)) + #check_git_status() + #check_requirements() + + # Resume + if opt.resume and not opt.evolve: # resume from specified or most recent last.pt + last = Path(check_file(opt.resume) if isinstance(opt.resume, str) else get_latest_run()) + opt_yaml = last.parent.parent / 'opt.yaml' # train options yaml + opt_data = opt.data # original dataset + if opt_yaml.is_file(): + with open(opt_yaml, errors='ignore') as f: + d = yaml.safe_load(f) + else: + d = torch.load(last, map_location='cpu')['opt'] + opt = argparse.Namespace(**d) # replace + opt.cfg, opt.weights, opt.resume = '', str(last), True # reinstate + if is_url(opt_data): + opt.data = check_file(opt_data) # avoid HUB resume auth timeout + else: + opt.data, opt.cfg, opt.hyp, opt.weights, opt.project = \ + check_file(opt.data), check_yaml(opt.cfg), check_yaml(opt.hyp), str(opt.weights), str(opt.project) # checks + assert len(opt.cfg) or len(opt.weights), 'either --cfg or --weights must be specified' + if opt.evolve: + if opt.project == str(ROOT / 'runs/train'): # if default project name, rename to runs/evolve + opt.project = str(ROOT / 'runs/evolve') + opt.exist_ok, opt.resume = opt.resume, False # pass resume to exist_ok and disable resume + if opt.name == 'cfg': + opt.name = Path(opt.cfg).stem # use model.yaml as name + opt.save_dir = str(increment_path(Path(opt.project) / opt.name, exist_ok=opt.exist_ok)) + + # DDP mode + device = select_device(opt.device, batch_size=opt.batch_size) + if LOCAL_RANK != -1: + msg = 'is not compatible with YOLO Multi-GPU DDP training' + assert not opt.image_weights, f'--image-weights {msg}' + assert not opt.evolve, f'--evolve {msg}' + assert opt.batch_size != -1, f'AutoBatch with --batch-size -1 {msg}, please pass a valid --batch-size' + assert opt.batch_size % WORLD_SIZE == 0, f'--batch-size {opt.batch_size} must be multiple of WORLD_SIZE' + assert torch.cuda.device_count() > LOCAL_RANK, 'insufficient CUDA devices for DDP command' + torch.cuda.set_device(LOCAL_RANK) + device = torch.device('cuda', LOCAL_RANK) + dist.init_process_group(backend="nccl" if dist.is_nccl_available() else "gloo") + + # Train + if not opt.evolve: + train(opt.hyp, opt, device, callbacks) + + # Evolve hyperparameters (optional) + else: + # Hyperparameter evolution metadata (mutation scale 0-1, lower_limit, upper_limit) + meta = { + 'lr0': (1, 1e-5, 1e-1), # initial learning rate (SGD=1E-2, Adam=1E-3) + 'lrf': (1, 0.01, 1.0), # final OneCycleLR learning rate (lr0 * lrf) + 'momentum': (0.3, 0.6, 0.98), # SGD momentum/Adam beta1 + 'weight_decay': (1, 0.0, 0.001), # optimizer weight decay + 'warmup_epochs': (1, 0.0, 5.0), # warmup epochs (fractions ok) + 'warmup_momentum': (1, 0.0, 0.95), # warmup initial momentum + 'warmup_bias_lr': (1, 0.0, 0.2), # warmup initial bias lr + 'box': (1, 0.02, 0.2), # box loss gain + 'cls': (1, 0.2, 4.0), # cls loss gain + 'cls_pw': (1, 0.5, 2.0), # cls BCELoss positive_weight + 'obj': (1, 0.2, 4.0), # obj loss gain (scale with pixels) + 'obj_pw': (1, 0.5, 2.0), # obj BCELoss positive_weight + 'iou_t': (0, 0.1, 0.7), # IoU training threshold + 'anchor_t': (1, 2.0, 8.0), # anchor-multiple threshold + 'anchors': (2, 2.0, 10.0), # anchors per output grid (0 to ignore) + 'fl_gamma': (0, 0.0, 2.0), # focal loss gamma (efficientDet default gamma=1.5) + 'hsv_h': (1, 0.0, 0.1), # image HSV-Hue augmentation (fraction) + 'hsv_s': (1, 0.0, 0.9), # image HSV-Saturation augmentation (fraction) + 'hsv_v': (1, 0.0, 0.9), # image HSV-Value augmentation (fraction) + 'degrees': (1, 0.0, 45.0), # image rotation (+/- deg) + 'translate': (1, 0.0, 0.9), # image translation (+/- fraction) + 'scale': (1, 0.0, 0.9), # image scale (+/- gain) + 'shear': (1, 0.0, 10.0), # image shear (+/- deg) + 'perspective': (0, 0.0, 0.001), # image perspective (+/- fraction), range 0-0.001 + 'flipud': (1, 0.0, 1.0), # image flip up-down (probability) + 'fliplr': (0, 0.0, 1.0), # image flip left-right (probability) + 'mosaic': (1, 0.0, 1.0), # image mixup (probability) + 'mixup': (1, 0.0, 1.0), # image mixup (probability) + 'copy_paste': (1, 0.0, 1.0)} # segment copy-paste (probability) + + with open(opt.hyp, errors='ignore') as f: + hyp = yaml.safe_load(f) # load hyps dict + if 'anchors' not in hyp: # anchors commented in hyp.yaml + hyp['anchors'] = 3 + if opt.noautoanchor: + del hyp['anchors'], meta['anchors'] + opt.noval, opt.nosave, save_dir = True, True, Path(opt.save_dir) # only val/save final epoch + # ei = [isinstance(x, (int, float)) for x in hyp.values()] # evolvable indices + evolve_yaml, evolve_csv = save_dir / 'hyp_evolve.yaml', save_dir / 'evolve.csv' + if opt.bucket: + os.system(f'gsutil cp gs://{opt.bucket}/evolve.csv {evolve_csv}') # download evolve.csv if exists + + for _ in range(opt.evolve): # generations to evolve + if evolve_csv.exists(): # if evolve.csv exists: select best hyps and mutate + # Select parent(s) + parent = 'single' # parent selection method: 'single' or 'weighted' + x = np.loadtxt(evolve_csv, ndmin=2, delimiter=',', skiprows=1) + n = min(5, len(x)) # number of previous results to consider + x = x[np.argsort(-fitness(x))][:n] # top n mutations + w = fitness(x) - fitness(x).min() + 1E-6 # weights (sum > 0) + if parent == 'single' or len(x) == 1: + # x = x[random.randint(0, n - 1)] # random selection + x = x[random.choices(range(n), weights=w)[0]] # weighted selection + elif parent == 'weighted': + x = (x * w.reshape(n, 1)).sum(0) / w.sum() # weighted combination + + # Mutate + mp, s = 0.8, 0.2 # mutation probability, sigma + npr = np.random + npr.seed(int(time.time())) + g = np.array([meta[k][0] for k in hyp.keys()]) # gains 0-1 + ng = len(meta) + v = np.ones(ng) + while all(v == 1): # mutate until a change occurs (prevent duplicates) + v = (g * (npr.random(ng) < mp) * npr.randn(ng) * npr.random() * s + 1).clip(0.3, 3.0) + for i, k in enumerate(hyp.keys()): # plt.hist(v.ravel(), 300) + hyp[k] = float(x[i + 7] * v[i]) # mutate + + # Constrain to limits + for k, v in meta.items(): + hyp[k] = max(hyp[k], v[1]) # lower limit + hyp[k] = min(hyp[k], v[2]) # upper limit + hyp[k] = round(hyp[k], 5) # significant digits + + # Train mutation + results = train(hyp.copy(), opt, device, callbacks) + callbacks = Callbacks() + # Write mutation results + print_mutation(KEYS, results, hyp.copy(), save_dir, opt.bucket) + + # Plot results + plot_evolve(evolve_csv) + LOGGER.info(f'Hyperparameter evolution finished {opt.evolve} generations\n' + f"Results saved to {colorstr('bold', save_dir)}\n" + f'Usage example: $ python train.py --hyp {evolve_yaml}') + + +def run(**kwargs): + # Usage: import train; train.run(data='coco128.yaml', imgsz=320, weights='yolo.pt') + opt = parse_opt(True) + for k, v in kwargs.items(): + setattr(opt, k, v) + main(opt) + return opt + + +if __name__ == "__main__": + opt = parse_opt() + main(opt) diff --git a/cv/3d_detection/yolov9/pytorch/panoptic/val.py b/cv/3d_detection/yolov9/pytorch/panoptic/val.py new file mode 100644 index 000000000..569b7efe0 --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/panoptic/val.py @@ -0,0 +1,597 @@ +import argparse +import json +import os +import sys +from multiprocessing.pool import ThreadPool +from pathlib import Path + +import numpy as np +import torch +from tqdm import tqdm + +FILE = Path(__file__).resolve() +ROOT = FILE.parents[1] # YOLO root directory +if str(ROOT) not in sys.path: + sys.path.append(str(ROOT)) # add ROOT to PATH +ROOT = Path(os.path.relpath(ROOT, Path.cwd())) # relative + +import torch.nn.functional as F +import torchvision.transforms as transforms +from pycocotools import mask as maskUtils +from models.common import DetectMultiBackend +from models.yolo import SegmentationModel +from utils.callbacks import Callbacks +from utils.coco_utils import getCocoIds, getMappingId, getMappingIndex +from utils.general import (LOGGER, NUM_THREADS, TQDM_BAR_FORMAT, Profile, check_dataset, check_img_size, + check_requirements, check_yaml, coco80_to_coco91_class, colorstr, increment_path, + non_max_suppression, print_args, scale_boxes, xywh2xyxy, xyxy2xywh) +from utils.metrics import ConfusionMatrix, box_iou +from utils.plots import output_to_target, plot_val_study +from utils.panoptic.dataloaders import create_dataloader +from utils.panoptic.general import mask_iou, process_mask, process_mask_upsample, scale_image +from utils.panoptic.metrics import Metrics, ap_per_class_box_and_mask, Semantic_Metrics +from utils.panoptic.plots import plot_images_and_masks +from utils.torch_utils import de_parallel, select_device, smart_inference_mode + + +def save_one_txt(predn, save_conf, shape, file): + # Save one txt result + gn = torch.tensor(shape)[[1, 0, 1, 0]] # normalization gain whwh + for *xyxy, conf, cls in predn.tolist(): + xywh = (xyxy2xywh(torch.tensor(xyxy).view(1, 4)) / gn).view(-1).tolist() # normalized xywh + line = (cls, *xywh, conf) if save_conf else (cls, *xywh) # label format + with open(file, 'a') as f: + f.write(('%g ' * len(line)).rstrip() % line + '\n') + + +def save_one_json(predn, jdict, path, class_map, pred_masks): + # Save one JSON result {"image_id": 42, "category_id": 18, "bbox": [258.15, 41.29, 348.26, 243.78], "score": 0.236} + from pycocotools.mask import encode + + def single_encode(x): + rle = encode(np.asarray(x[:, :, None], order="F", dtype="uint8"))[0] + rle["counts"] = rle["counts"].decode("utf-8") + return rle + + image_id = int(path.stem) if path.stem.isnumeric() else path.stem + box = xyxy2xywh(predn[:, :4]) # xywh + box[:, :2] -= box[:, 2:] / 2 # xy center to top-left corner + pred_masks = np.transpose(pred_masks, (2, 0, 1)) + with ThreadPool(NUM_THREADS) as pool: + rles = pool.map(single_encode, pred_masks) + for i, (p, b) in enumerate(zip(predn.tolist(), box.tolist())): + jdict.append({ + 'image_id': image_id, + 'category_id': class_map[int(p[5])], + 'bbox': [round(x, 3) for x in b], + 'score': round(p[4], 5), + 'segmentation': rles[i]}) + + +def process_batch(detections, labels, iouv, pred_masks=None, gt_masks=None, overlap=False, masks=False): + """ + Return correct prediction matrix + Arguments: + detections (array[N, 6]), x1, y1, x2, y2, conf, class + labels (array[M, 5]), class, x1, y1, x2, y2 + Returns: + correct (array[N, 10]), for 10 IoU levels + """ + if masks: + if overlap: + nl = len(labels) + index = torch.arange(nl, device=gt_masks.device).view(nl, 1, 1) + 1 + gt_masks = gt_masks.repeat(nl, 1, 1) # shape(1,640,640) -> (n,640,640) + gt_masks = torch.where(gt_masks == index, 1.0, 0.0) + if gt_masks.shape[1:] != pred_masks.shape[1:]: + gt_masks = F.interpolate(gt_masks[None], pred_masks.shape[1:], mode="bilinear", align_corners=False)[0] + gt_masks = gt_masks.gt_(0.5) + iou = mask_iou(gt_masks.view(gt_masks.shape[0], -1), pred_masks.view(pred_masks.shape[0], -1)) + else: # boxes + iou = box_iou(labels[:, 1:], detections[:, :4]) + + correct = np.zeros((detections.shape[0], iouv.shape[0])).astype(bool) + correct_class = labels[:, 0:1] == detections[:, 5] + for i in range(len(iouv)): + x = torch.where((iou >= iouv[i]) & correct_class) # IoU > threshold and classes match + if x[0].shape[0]: + matches = torch.cat((torch.stack(x, 1), iou[x[0], x[1]][:, None]), 1).cpu().numpy() # [label, detect, iou] + if x[0].shape[0] > 1: + matches = matches[matches[:, 2].argsort()[::-1]] + matches = matches[np.unique(matches[:, 1], return_index=True)[1]] + # matches = matches[matches[:, 2].argsort()[::-1]] + matches = matches[np.unique(matches[:, 0], return_index=True)[1]] + correct[matches[:, 1].astype(int), i] = True + return torch.tensor(correct, dtype=torch.bool, device=iouv.device) + + +@smart_inference_mode() +def run( + data, + weights=None, # model.pt path(s) + batch_size=32, # batch size + imgsz=640, # inference size (pixels) + conf_thres=0.001, # confidence threshold + iou_thres=0.6, # NMS IoU threshold + max_det=300, # maximum detections per image + task='val', # train, val, test, speed or study + device='', # cuda device, i.e. 0 or 0,1,2,3 or cpu + workers=8, # max dataloader workers (per RANK in DDP mode) + single_cls=False, # treat as single-class dataset + augment=False, # augmented inference + verbose=False, # verbose output + save_txt=False, # save results to *.txt + save_hybrid=False, # save label+prediction hybrid results to *.txt + save_conf=False, # save confidences in --save-txt labels + save_json=False, # save a COCO-JSON results file + project=ROOT / 'runs/val-pan', # save to project/name + name='exp', # save to project/name + exist_ok=False, # existing project/name ok, do not increment + half=True, # use FP16 half-precision inference + dnn=False, # use OpenCV DNN for ONNX inference + model=None, + dataloader=None, + save_dir=Path(''), + plots=True, + overlap=False, + mask_downsample_ratio=1, + compute_loss=None, + callbacks=Callbacks(), +): + if save_json: + check_requirements(['pycocotools']) + process = process_mask_upsample # more accurate + else: + process = process_mask # faster + + # Initialize/load model and set device + training = model is not None + if training: # called by train.py + device, pt, jit, engine = next(model.parameters()).device, True, False, False # get model device, PyTorch model + half &= device.type != 'cpu' # half precision only supported on CUDA + model.half() if half else model.float() + nm = de_parallel(model).model[-1].nm # number of masks + else: # called directly + device = select_device(device, batch_size=batch_size) + + # Directories + save_dir = increment_path(Path(project) / name, exist_ok=exist_ok) # increment run + (save_dir / 'labels' if save_txt else save_dir).mkdir(parents=True, exist_ok=True) # make dir + + # Load model + model = DetectMultiBackend(weights, device=device, dnn=dnn, data=data, fp16=half) + stride, pt, jit, engine = model.stride, model.pt, model.jit, model.engine + imgsz = check_img_size(imgsz, s=stride) # check image size + half = model.fp16 # FP16 supported on limited backends with CUDA + nm = de_parallel(model).model.model[-1].nm if isinstance(model, SegmentationModel) else 32 # number of masks + if engine: + batch_size = model.batch_size + else: + device = model.device + if not (pt or jit): + batch_size = 1 # export.py models default to batch-size 1 + LOGGER.info(f'Forcing --batch-size 1 square inference (1,3,{imgsz},{imgsz}) for non-PyTorch models') + + # Data + data = check_dataset(data) # check + + # Configure + model.eval() + cuda = device.type != 'cpu' + #is_coco = isinstance(data.get('val'), str) and data['val'].endswith(f'coco{os.sep}val2017.txt') # COCO dataset + is_coco = isinstance(data.get('val'), str) and data['val'].endswith(f'val2017.txt') # COCO dataset + nc = 1 if single_cls else int(data['nc']) # number of classes + stuff_names = data.get('stuff_names', []) # names of stuff classes + stuff_nc = len(stuff_names) # number of stuff classes + iouv = torch.linspace(0.5, 0.95, 10, device=device) # iou vector for mAP@0.5:0.95 + niou = iouv.numel() + + # Semantic Segmentation + img_id_list = [] + + # Dataloader + if not training: + if pt and not single_cls: # check --weights are trained on --data + ncm = model.model.nc + assert ncm == nc, f'{weights} ({ncm} classes) trained on different --data than what you passed ({nc} ' \ + f'classes). Pass correct combination of --weights and --data that are trained together.' + model.warmup(imgsz=(1 if pt else batch_size, 3, imgsz, imgsz)) # warmup + pad, rect = (0.0, False) if task == 'speed' else (0.5, pt) # square inference for benchmarks + task = task if task in ('train', 'val', 'test') else 'val' # path to train/val/test images + dataloader = create_dataloader(data[task], + imgsz, + batch_size, + stride, + single_cls, + pad=pad, + rect=rect, + workers=workers, + prefix=colorstr(f'{task}: '), + overlap_mask=overlap, + mask_downsample_ratio=mask_downsample_ratio)[0] + + seen = 0 + confusion_matrix = ConfusionMatrix(nc=nc) + names = model.names if hasattr(model, 'names') else model.module.names # get class names + if isinstance(names, (list, tuple)): # old format + names = dict(enumerate(names)) + class_map = coco80_to_coco91_class() if is_coco else list(range(1000)) + s = ('%22s' + '%11s' * 12) % ('Class', 'Images', 'Instances', 'Box(P', "R", "mAP50", "mAP50-95)", "Mask(P", "R", + "mAP50", "mAP50-95)", 'S(MIoU', 'FWIoU)') + dt = Profile(), Profile(), Profile() + metrics = Metrics() + semantic_metrics = Semantic_Metrics(nc = (nc + stuff_nc), device = device) + loss = torch.zeros(6, device=device) + jdict, stats = [], [] + semantic_jdict = [] + # callbacks.run('on_val_start') + pbar = tqdm(dataloader, desc=s, bar_format=TQDM_BAR_FORMAT) # progress bar + for batch_i, (im, targets, paths, shapes, masks, semasks) in enumerate(pbar): + # callbacks.run('on_val_batch_start') + with dt[0]: + if cuda: + im = im.to(device, non_blocking=True) + targets = targets.to(device) + masks = masks.to(device) + semasks = semasks.to(device) + masks = masks.float() + semasks = semasks.float() + im = im.half() if half else im.float() # uint8 to fp16/32 + im /= 255 # 0 - 255 to 0.0 - 1.0 + nb, _, height, width = im.shape # batch size, channels, height, width + + # Inference + with dt[1]: + preds, train_out = model(im)# if compute_loss else (*model(im, augment=augment)[:2], None) + #train_out, preds, protos = p if len(p) == 3 else p[1] + #preds = p + #train_out = p[1][0] if len(p[1]) == 3 else p[0] + # protos = train_out[-1] + #print(preds.shape) + #print(train_out[0].shape) + #print(train_out[1].shape) + #print(train_out[2].shape) + _, pred_masks, protos, psemasks = train_out + + # Loss + if compute_loss: + loss += compute_loss(train_out, targets, masks, semasks = semasks)[1] # box, obj, cls + + # NMS + targets[:, 2:] *= torch.tensor((width, height, width, height), device=device) # to pixels + lb = [targets[targets[:, 0] == i, 1:] for i in range(nb)] if save_hybrid else [] # for autolabelling + with dt[2]: + preds = non_max_suppression(preds, + conf_thres, + iou_thres, + labels=lb, + multi_label=True, + agnostic=single_cls, + max_det=max_det, + nm=nm) + + # Metrics + plot_masks = [] # masks for plotting + plot_semasks = [] # masks for plotting + + if training: + semantic_metrics.update(psemasks, semasks) + else: + _, _, smh, smw = semasks.shape + semantic_metrics.update(torch.nn.functional.interpolate(psemasks, size = (smh, smw), mode = 'bilinear', align_corners = False), semasks) + + if plots and batch_i < 3: + plot_semasks.append(psemasks.clone().detach().cpu()) + + for si, (pred, proto, psemask) in enumerate(zip(preds, protos, psemasks)): + labels = targets[targets[:, 0] == si, 1:] + nl, npr = labels.shape[0], pred.shape[0] # number of labels, predictions + path, shape = Path(paths[si]), shapes[si][0] + image_id = path.stem + img_id_list.append(image_id) + correct_masks = torch.zeros(npr, niou, dtype=torch.bool, device=device) # init + correct_bboxes = torch.zeros(npr, niou, dtype=torch.bool, device=device) # init + seen += 1 + + if npr == 0: + if nl: + stats.append((correct_masks, correct_bboxes, *torch.zeros((2, 0), device=device), labels[:, 0])) + if plots: + confusion_matrix.process_batch(detections=None, labels=labels[:, 0]) + else: + # Masks + midx = [si] if overlap else targets[:, 0] == si + gt_masks = masks[midx] + pred_masks = process(proto, pred[:, 6:], pred[:, :4], shape=im[si].shape[1:]) + + # Predictions + if single_cls: + pred[:, 5] = 0 + predn = pred.clone() + scale_boxes(im[si].shape[1:], predn[:, :4], shape, shapes[si][1]) # native-space pred + + # Evaluate + if nl: + tbox = xywh2xyxy(labels[:, 1:5]) # target boxes + scale_boxes(im[si].shape[1:], tbox, shape, shapes[si][1]) # native-space labels + labelsn = torch.cat((labels[:, 0:1], tbox), 1) # native-space labels + correct_bboxes = process_batch(predn, labelsn, iouv) + correct_masks = process_batch(predn, labelsn, iouv, pred_masks, gt_masks, overlap=overlap, masks=True) + if plots: + confusion_matrix.process_batch(predn, labelsn) + stats.append((correct_masks, correct_bboxes, pred[:, 4], pred[:, 5], labels[:, 0])) # (conf, pcls, tcls) + + pred_masks = torch.as_tensor(pred_masks, dtype=torch.uint8) + if plots and batch_i < 3: + plot_masks.append(pred_masks[:15].cpu()) # filter top 15 to plot + + # Save/log + if save_txt: + save_one_txt(predn, save_conf, shape, file=save_dir / 'labels' / f'{path.stem}.txt') + if save_json: + pred_masks = scale_image(im[si].shape[1:], + pred_masks.permute(1, 2, 0).contiguous().cpu().numpy(), shape, shapes[si][1]) + save_one_json(predn, jdict, path, class_map, pred_masks) # append to COCO-JSON dictionary + # callbacks.run('on_val_image_end', pred, predn, path, names, im[si]) + + # Semantic Segmentation + h0, w0 = shape + + # resize + _, mask_h, mask_w = psemask.shape + h_ratio = mask_h / h0 + w_ratio = mask_w / w0 + + if h_ratio == w_ratio: + psemask = torch.nn.functional.interpolate(psemask[None, :], size = (h0, w0), mode = 'bilinear', align_corners = False) + else: + transform = transforms.CenterCrop((h0, w0)) + + if (1 != h_ratio) and (1 != w_ratio): + h_new = h0 if (h_ratio < w_ratio) else int(mask_h / w_ratio) + w_new = w0 if (h_ratio > w_ratio) else int(mask_w / h_ratio) + psemask = torch.nn.functional.interpolate(psemask[None, :], size = (h_new, w_new), mode = 'bilinear', align_corners = False) + + psemask = transform(psemask) + + psemask = torch.squeeze(psemask) + + nc, h, w = psemask.shape + + semantic_mask = torch.flatten(psemask, start_dim = 1).permute(1, 0) # class x h x w -> (h x w) x class + + max_idx = semantic_mask.argmax(1) + output_masks = torch.zeros(semantic_mask.shape).scatter(1, max_idx.cpu().unsqueeze(1), 1.0) # one hot: (h x w) x class + output_masks = torch.reshape(output_masks.permute(1, 0), (nc, h, w)) # (h x w) x class -> class x h x w + psemask = output_masks.to(device = device) + + # TODO: check is_coco + instances_ids = getCocoIds(name = 'instances') + stuff_mask = torch.zeros((h, w), device = device) + check_semantic_mask = False + for idx, pred_semantic_mask in enumerate(psemask): + category_id = int(getMappingId(idx)) + if 183 == category_id: + # set all non-stuff pixels to other + pred_semantic_mask = (torch.logical_xor(stuff_mask, torch.ones((h, w), device = device))).int() + + # ignore the classes which all zeros / unlabeled class + if (0 >= torch.max(pred_semantic_mask)) or (0 >= category_id): + continue + + if category_id not in instances_ids: + # record all stuff mask + stuff_mask = torch.logical_or(stuff_mask, pred_semantic_mask) + + if (category_id not in instances_ids): + rle = maskUtils.encode(np.asfortranarray(pred_semantic_mask.cpu(), dtype = np.uint8)) + rle['counts'] = rle['counts'].decode('utf-8') + + temp_d = { + 'image_id': int(image_id) if image_id.isnumeric() else image_id, + 'category_id': category_id, + 'segmentation': rle, + 'score': 1 + } + + semantic_jdict.append(temp_d) + check_semantic_mask = True + + if not check_semantic_mask: + # append a other mask for evaluation if the image without any mask + other_mask = (torch.ones((h, w), device = device)).int() + + rle = maskUtils.encode(np.asfortranarray(other_mask.cpu(), dtype = np.uint8)) + rle['counts'] = rle['counts'].decode('utf-8') + + temp_d = { + 'image_id': int(image_id) if image_id.isnumeric() else image_id, + 'category_id': 183, + 'segmentation': rle, + 'score': 1 + } + + semantic_jdict.append(temp_d) + + # Plot images + if plots and batch_i < 3: + if len(plot_masks): + plot_masks = torch.cat(plot_masks, dim=0) + if len(plot_semasks): + plot_semasks = torch.cat(plot_semasks, dim = 0) + plot_images_and_masks(im, targets, masks, semasks, paths, save_dir / f'val_batch{batch_i}_labels.jpg', names) + plot_images_and_masks(im, output_to_target(preds, max_det=15), plot_masks, plot_semasks, paths, + save_dir / f'val_batch{batch_i}_pred.jpg', names) # pred + + # callbacks.run('on_val_batch_end') + + # Compute metrics + stats = [torch.cat(x, 0).cpu().numpy() for x in zip(*stats)] # to numpy + if len(stats) and stats[0].any(): + results = ap_per_class_box_and_mask(*stats, plot=plots, save_dir=save_dir, names=names) + metrics.update(results) + nt = np.bincount(stats[4].astype(int), minlength=nc) # number of targets per class + + # Print results + pf = '%22s' + '%11i' * 2 + '%11.3g' * 10 # print format + LOGGER.info(pf % ("all", seen, nt.sum(), *metrics.mean_results(), *semantic_metrics.results())) + if nt.sum() == 0: + LOGGER.warning(f'WARNING ⚠️ no labels found in {task} set, can not compute metrics without labels') + + # Print results per class + if (verbose or (nc < 50 and not training)) and nc > 1 and len(stats): + for i, c in enumerate(metrics.ap_class_index): + LOGGER.info(pf % (names[c], seen, nt[c], *metrics.class_result(i), *semantic_metrics.results())) + + # Print speeds + t = tuple(x.t / seen * 1E3 for x in dt) # speeds per image + if not training: + shape = (batch_size, 3, imgsz, imgsz) + LOGGER.info(f'Speed: %.1fms pre-process, %.1fms inference, %.1fms NMS per image at shape {shape}' % t) + + # Plots + if plots: + confusion_matrix.plot(save_dir=save_dir, names=list(names.values())) + # callbacks.run('on_val_end') + + mp_bbox, mr_bbox, map50_bbox, map_bbox, mp_mask, mr_mask, map50_mask, map_mask = metrics.mean_results() + miou_sem, fwiou_sem = semantic_metrics.results() + semantic_metrics.reset() + + # Save JSON + if save_json and len(jdict): + w = Path(weights[0] if isinstance(weights, list) else weights).stem if weights is not None else '' # weights + anno_path = Path(data.get('path', '../coco')) + anno_json = str(anno_path / 'annotations/instances_val2017.json') # annotations json + pred_json = str(save_dir / f"{w}_predictions.json") # predictions json + LOGGER.info(f'\nEvaluating pycocotools mAP... saving {pred_json}...') + with open(pred_json, 'w') as f: + json.dump(jdict, f) + + semantic_anno_json = str(anno_path / 'annotations/stuff_val2017.json') # annotations json + semantic_pred_json = str(save_dir / f"{w}_predictions_stuff.json") # predictions json + LOGGER.info(f'\nsaving {semantic_pred_json}...') + with open(semantic_pred_json, 'w') as f: + json.dump(semantic_jdict, f) + + try: # https://github.com/cocodataset/cocoapi/blob/master/PythonAPI/pycocoEvalDemo.ipynb + from pycocotools.coco import COCO + from pycocotools.cocoeval import COCOeval + + anno = COCO(anno_json) # init annotations api + pred = anno.loadRes(pred_json) # init predictions api + results = [] + for eval in COCOeval(anno, pred, 'bbox'), COCOeval(anno, pred, 'segm'): + if is_coco: + eval.params.imgIds = [int(Path(x).stem) for x in dataloader.dataset.im_files] # img ID to evaluate + eval.evaluate() + eval.accumulate() + eval.summarize() + results.extend(eval.stats[:2]) # update results (mAP@0.5:0.95, mAP@0.5) + map_bbox, map50_bbox, map_mask, map50_mask = results + + # Semantic Segmentation + from utils.stuff_seg.cocostuffeval import COCOStuffeval + + LOGGER.info(f'\nEvaluating pycocotools stuff... ') + imgIds = [int(x) for x in img_id_list] + + stuffGt = COCO(semantic_anno_json) # initialize COCO ground truth api + stuffDt = stuffGt.loadRes(semantic_pred_json) # initialize COCO pred api + + cocoStuffEval = COCOStuffeval(stuffGt, stuffDt) + cocoStuffEval.params.imgIds = imgIds # image IDs to evaluate + cocoStuffEval.evaluate() + stats, statsClass = cocoStuffEval.summarize() + stuffIds = getCocoIds(name = 'stuff') + title = ' {:<5} | {:^6} | {:^6} '.format('class', 'iou', 'macc') if (0 >= len(stuff_names)) else \ + ' {:<5} | {:<20} | {:^6} | {:^6} '.format('class', 'class name', 'iou', 'macc') + print(title) + for idx, (iou, macc) in enumerate(zip(statsClass['ious'], statsClass['maccs'])): + id = (idx + 1) + if id not in stuffIds: + continue + content = ' {:<5} | {:0.4f} | {:0.4f} '.format(str(id), iou, macc) if (0 >= len(stuff_names)) else \ + ' {:<5} | {:<20} | {:0.4f} | {:0.4f} '.format(str(id), str(stuff_names[getMappingIndex(id, name = 'stuff')]), iou, macc) + print(content) + + except Exception as e: + LOGGER.info(f'pycocotools unable to run: {e}') + + # Return results + model.float() # for training + if not training: + s = f"\n{len(list(save_dir.glob('labels/*.txt')))} labels saved to {save_dir / 'labels'}" if save_txt else '' + LOGGER.info(f"Results saved to {colorstr('bold', save_dir)}{s}") + final_metric = mp_bbox, mr_bbox, map50_bbox, map_bbox, mp_mask, mr_mask, map50_mask, map_mask, miou_sem, fwiou_sem + return (*final_metric, *(loss.cpu() / len(dataloader)).tolist()), metrics.get_maps(nc), t + + +def parse_opt(): + parser = argparse.ArgumentParser() + parser.add_argument('--data', type=str, default=ROOT / 'data/coco128-pan.yaml', help='dataset.yaml path') + parser.add_argument('--weights', nargs='+', type=str, default=ROOT / 'yolo-pan.pt', help='model path(s)') + parser.add_argument('--batch-size', type=int, default=32, help='batch size') + parser.add_argument('--imgsz', '--img', '--img-size', type=int, default=640, help='inference size (pixels)') + parser.add_argument('--conf-thres', type=float, default=0.001, help='confidence threshold') + parser.add_argument('--iou-thres', type=float, default=0.6, help='NMS IoU threshold') + parser.add_argument('--max-det', type=int, default=300, help='maximum detections per image') + parser.add_argument('--task', default='val', help='train, val, test, speed or study') + parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu') + parser.add_argument('--workers', type=int, default=8, help='max dataloader workers (per RANK in DDP mode)') + parser.add_argument('--single-cls', action='store_true', help='treat as single-class dataset') + parser.add_argument('--augment', action='store_true', help='augmented inference') + parser.add_argument('--verbose', action='store_true', help='report mAP by class') + parser.add_argument('--save-txt', action='store_true', help='save results to *.txt') + parser.add_argument('--save-hybrid', action='store_true', help='save label+prediction hybrid results to *.txt') + parser.add_argument('--save-conf', action='store_true', help='save confidences in --save-txt labels') + parser.add_argument('--save-json', action='store_true', help='save a COCO-JSON results file') + parser.add_argument('--project', default=ROOT / 'runs/val-pan', help='save results to project/name') + parser.add_argument('--name', default='exp', help='save to project/name') + parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment') + parser.add_argument('--half', action='store_true', help='use FP16 half-precision inference') + parser.add_argument('--dnn', action='store_true', help='use OpenCV DNN for ONNX inference') + opt = parser.parse_args() + opt.data = check_yaml(opt.data) # check YAML + # opt.save_json |= opt.data.endswith('coco.yaml') + opt.save_txt |= opt.save_hybrid + print_args(vars(opt)) + return opt + + +def main(opt): + #check_requirements(requirements=ROOT / 'requirements.txt', exclude=('tensorboard', 'thop')) + + if opt.task in ('train', 'val', 'test'): # run normally + if opt.conf_thres > 0.001: # https://github.com/ + LOGGER.warning(f'WARNING ⚠️ confidence threshold {opt.conf_thres} > 0.001 produces invalid results') + if opt.save_hybrid: + LOGGER.warning('WARNING ⚠️ --save-hybrid returns high mAP from hybrid labels, not from predictions alone') + run(**vars(opt)) + + else: + weights = opt.weights if isinstance(opt.weights, list) else [opt.weights] + opt.half = torch.cuda.is_available() and opt.device != 'cpu' # FP16 for fastest results + if opt.task == 'speed': # speed benchmarks + # python val.py --task speed --data coco.yaml --batch 1 --weights yolo.pt... + opt.conf_thres, opt.iou_thres, opt.save_json = 0.25, 0.45, False + for opt.weights in weights: + run(**vars(opt), plots=False) + + elif opt.task == 'study': # speed vs mAP benchmarks + # python val.py --task study --data coco.yaml --iou 0.7 --weights yolo.pt... + for opt.weights in weights: + f = f'study_{Path(opt.data).stem}_{Path(opt.weights).stem}.txt' # filename to save to + x, y = list(range(256, 1536 + 128, 128)), [] # x axis (image sizes), y axis + for opt.imgsz in x: # img-size + LOGGER.info(f'\nRunning {f} --imgsz {opt.imgsz}...') + r, _, t = run(**vars(opt), plots=False) + y.append(r + t) # results and times + np.savetxt(f, y, fmt='%10.4g') # save + os.system('zip -r study.zip study_*.txt') + plot_val_study(x=x) # plot + + +if __name__ == "__main__": + opt = parse_opt() + main(opt) diff --git a/cv/3d_detection/yolov9/pytorch/requirements.txt b/cv/3d_detection/yolov9/pytorch/requirements.txt new file mode 100644 index 000000000..bbdd44953 --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/requirements.txt @@ -0,0 +1,47 @@ +# requirements +# Usage: pip install -r requirements.txt + +# Base ------------------------------------------------------------------------ +gitpython +ipython +matplotlib>=3.2.2 +numpy>=1.18.5 +opencv-python>=4.1.1 +Pillow==9.5.0 +psutil +PyYAML>=5.3.1 +requests>=2.23.0 +scipy>=1.4.1 +thop>=0.1.1 +torch>=1.7.0 +torchvision>=0.8.1 +tqdm>=4.64.0 +# protobuf<=3.20.1 + +# Logging --------------------------------------------------------------------- +tensorboard>=2.4.1 +# clearml>=1.2.0 +# comet + +# Plotting -------------------------------------------------------------------- +pandas>=1.1.4 +seaborn>=0.11.0 + +# Export ---------------------------------------------------------------------- +# coremltools>=6.0 +# onnx>=1.9.0 +# onnx-simplifier>=0.4.1 +# nvidia-pyindex +# nvidia-tensorrt +# scikit-learn<=1.1.2 +# tensorflow>=2.4.1 +# tensorflowjs>=3.9.0 +# openvino-dev + +# Deploy ---------------------------------------------------------------------- +# tritonclient[all]~=2.24.0 + +# Extras ---------------------------------------------------------------------- +# mss +albumentations>=1.0.3 +pycocotools>=2.0 diff --git a/cv/3d_detection/yolov9/pytorch/scripts/get_coco.sh b/cv/3d_detection/yolov9/pytorch/scripts/get_coco.sh new file mode 100644 index 000000000..524f8dd9e --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/scripts/get_coco.sh @@ -0,0 +1,22 @@ +#!/bin/bash +# COCO 2017 dataset http://cocodataset.org +# Download command: bash ./scripts/get_coco.sh + +# Download/unzip labels +d='./' # unzip directory +url=https://github.com/ultralytics/yolov5/releases/download/v1.0/ +f='coco2017labels-segments.zip' # or 'coco2017labels.zip', 68 MB +echo 'Downloading' $url$f ' ...' +curl -L $url$f -o $f && unzip -q $f -d $d && rm $f & # download, unzip, remove in background + +# Download/unzip images +d='./coco/images' # unzip directory +url=http://images.cocodataset.org/zips/ +f1='train2017.zip' # 19G, 118k images +f2='val2017.zip' # 1G, 5k images +f3='test2017.zip' # 7G, 41k images (optional) +for f in $f1 $f2 $f3; do + echo 'Downloading' $url$f '...' + curl -L $url$f -o $f && unzip -q $f -d $d && rm $f & # download, unzip, remove in background +done +wait # finish background tasks diff --git a/cv/3d_detection/yolov9/pytorch/segment/predict.py b/cv/3d_detection/yolov9/pytorch/segment/predict.py new file mode 100644 index 000000000..aeab78781 --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/segment/predict.py @@ -0,0 +1,246 @@ +import argparse +import os +import platform +import sys +from pathlib import Path + +import torch + +FILE = Path(__file__).resolve() +ROOT = FILE.parents[1] # YOLO root directory +if str(ROOT) not in sys.path: + sys.path.append(str(ROOT)) # add ROOT to PATH +ROOT = Path(os.path.relpath(ROOT, Path.cwd())) # relative + +from models.common import DetectMultiBackend +from utils.dataloaders import IMG_FORMATS, VID_FORMATS, LoadImages, LoadScreenshots, LoadStreams +from utils.general import (LOGGER, Profile, check_file, check_img_size, check_imshow, check_requirements, colorstr, cv2, + increment_path, non_max_suppression, print_args, scale_boxes, scale_segments, + strip_optimizer, xyxy2xywh) +from utils.plots import Annotator, colors, save_one_box +from utils.segment.general import masks2segments, process_mask +from utils.torch_utils import select_device, smart_inference_mode + + +@smart_inference_mode() +def run( + weights=ROOT / 'yolo-seg.pt', # model.pt path(s) + source=ROOT / 'data/images', # file/dir/URL/glob/screen/0(webcam) + data=ROOT / 'data/coco.yaml', # dataset.yaml path + imgsz=(640, 640), # inference size (height, width) + conf_thres=0.25, # confidence threshold + iou_thres=0.45, # NMS IOU threshold + max_det=1000, # maximum detections per image + device='', # cuda device, i.e. 0 or 0,1,2,3 or cpu + view_img=False, # show results + save_txt=False, # save results to *.txt + save_conf=False, # save confidences in --save-txt labels + save_crop=False, # save cropped prediction boxes + nosave=False, # do not save images/videos + classes=None, # filter by class: --class 0, or --class 0 2 3 + agnostic_nms=False, # class-agnostic NMS + augment=False, # augmented inference + visualize=False, # visualize features + update=False, # update all models + project=ROOT / 'runs/predict-seg', # save results to project/name + name='exp', # save results to project/name + exist_ok=False, # existing project/name ok, do not increment + line_thickness=3, # bounding box thickness (pixels) + hide_labels=False, # hide labels + hide_conf=False, # hide confidences + half=False, # use FP16 half-precision inference + dnn=False, # use OpenCV DNN for ONNX inference + vid_stride=1, # video frame-rate stride + retina_masks=False, +): + source = str(source) + save_img = not nosave and not source.endswith('.txt') # save inference images + is_file = Path(source).suffix[1:] in (IMG_FORMATS + VID_FORMATS) + is_url = source.lower().startswith(('rtsp://', 'rtmp://', 'http://', 'https://')) + webcam = source.isnumeric() or source.endswith('.txt') or (is_url and not is_file) + screenshot = source.lower().startswith('screen') + if is_url and is_file: + source = check_file(source) # download + + # Directories + save_dir = increment_path(Path(project) / name, exist_ok=exist_ok) # increment run + (save_dir / 'labels' if save_txt else save_dir).mkdir(parents=True, exist_ok=True) # make dir + + # Load model + device = select_device(device) + model = DetectMultiBackend(weights, device=device, dnn=dnn, data=data, fp16=half) + stride, names, pt = model.stride, model.names, model.pt + imgsz = check_img_size(imgsz, s=stride) # check image size + + # Dataloader + bs = 1 # batch_size + if webcam: + view_img = check_imshow(warn=True) + dataset = LoadStreams(source, img_size=imgsz, stride=stride, auto=pt, vid_stride=vid_stride) + bs = len(dataset) + elif screenshot: + dataset = LoadScreenshots(source, img_size=imgsz, stride=stride, auto=pt) + else: + dataset = LoadImages(source, img_size=imgsz, stride=stride, auto=pt, vid_stride=vid_stride) + vid_path, vid_writer = [None] * bs, [None] * bs + + # Run inference + model.warmup(imgsz=(1 if pt else bs, 3, *imgsz)) # warmup + seen, windows, dt = 0, [], (Profile(), Profile(), Profile()) + for path, im, im0s, vid_cap, s in dataset: + with dt[0]: + im = torch.from_numpy(im).to(model.device) + im = im.half() if model.fp16 else im.float() # uint8 to fp16/32 + im /= 255 # 0 - 255 to 0.0 - 1.0 + if len(im.shape) == 3: + im = im[None] # expand for batch dim + + # Inference + with dt[1]: + visualize = increment_path(save_dir / Path(path).stem, mkdir=True) if visualize else False + pred, proto = model(im, augment=augment, visualize=visualize)[:2] + + # NMS + with dt[2]: + pred = non_max_suppression(pred, conf_thres, iou_thres, classes, agnostic_nms, max_det=max_det, nm=32) + + # Second-stage classifier (optional) + # pred = utils.general.apply_classifier(pred, classifier_model, im, im0s) + + # Process predictions + for i, det in enumerate(pred): # per image + seen += 1 + if webcam: # batch_size >= 1 + p, im0, frame = path[i], im0s[i].copy(), dataset.count + s += f'{i}: ' + else: + p, im0, frame = path, im0s.copy(), getattr(dataset, 'frame', 0) + + p = Path(p) # to Path + save_path = str(save_dir / p.name) # im.jpg + txt_path = str(save_dir / 'labels' / p.stem) + ('' if dataset.mode == 'image' else f'_{frame}') # im.txt + s += '%gx%g ' % im.shape[2:] # print string + imc = im0.copy() if save_crop else im0 # for save_crop + annotator = Annotator(im0, line_width=line_thickness, example=str(names)) + if len(det): + masks = process_mask(proto[i], det[:, 6:], det[:, :4], im.shape[2:], upsample=True) # HWC + det[:, :4] = scale_boxes(im.shape[2:], det[:, :4], im0.shape).round() # rescale boxes to im0 size + + # Segments + if save_txt: + segments = reversed(masks2segments(masks)) + segments = [scale_segments(im.shape[2:], x, im0.shape, normalize=True) for x in segments] + + # Print results + for c in det[:, 5].unique(): + n = (det[:, 5] == c).sum() # detections per class + s += f"{n} {names[int(c)]}{'s' * (n > 1)}, " # add to string + + # Mask plotting + annotator.masks(masks, + colors=[colors(x, True) for x in det[:, 5]], + im_gpu=None if retina_masks else im[i]) + + # Write results + for j, (*xyxy, conf, cls) in enumerate(reversed(det[:, :6])): + if save_txt: # Write to file + segj = segments[j].reshape(-1) # (n,2) to (n*2) + line = (cls, *segj, conf) if save_conf else (cls, *segj) # label format + with open(f'{txt_path}.txt', 'a') as f: + f.write(('%g ' * len(line)).rstrip() % line + '\n') + + if save_img or save_crop or view_img: # Add bbox to image + c = int(cls) # integer class + label = None if hide_labels else (names[c] if hide_conf else f'{names[c]} {conf:.2f}') + annotator.box_label(xyxy, label, color=colors(c, True)) + # annotator.draw.polygon(segments[j], outline=colors(c, True), width=3) + if save_crop: + save_one_box(xyxy, imc, file=save_dir / 'crops' / names[c] / f'{p.stem}.jpg', BGR=True) + + # Stream results + im0 = annotator.result() + if view_img: + if platform.system() == 'Linux' and p not in windows: + windows.append(p) + cv2.namedWindow(str(p), cv2.WINDOW_NORMAL | cv2.WINDOW_KEEPRATIO) # allow window resize (Linux) + cv2.resizeWindow(str(p), im0.shape[1], im0.shape[0]) + cv2.imshow(str(p), im0) + if cv2.waitKey(1) == ord('q'): # 1 millisecond + exit() + + # Save results (image with detections) + if save_img: + if dataset.mode == 'image': + cv2.imwrite(save_path, im0) + else: # 'video' or 'stream' + if vid_path[i] != save_path: # new video + vid_path[i] = save_path + if isinstance(vid_writer[i], cv2.VideoWriter): + vid_writer[i].release() # release previous video writer + if vid_cap: # video + fps = vid_cap.get(cv2.CAP_PROP_FPS) + w = int(vid_cap.get(cv2.CAP_PROP_FRAME_WIDTH)) + h = int(vid_cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) + else: # stream + fps, w, h = 30, im0.shape[1], im0.shape[0] + save_path = str(Path(save_path).with_suffix('.mp4')) # force *.mp4 suffix on results videos + vid_writer[i] = cv2.VideoWriter(save_path, cv2.VideoWriter_fourcc(*'mp4v'), fps, (w, h)) + vid_writer[i].write(im0) + + # Print time (inference-only) + LOGGER.info(f"{s}{'' if len(det) else '(no detections), '}{dt[1].dt * 1E3:.1f}ms") + + # Print results + t = tuple(x.t / seen * 1E3 for x in dt) # speeds per image + LOGGER.info(f'Speed: %.1fms pre-process, %.1fms inference, %.1fms NMS per image at shape {(1, 3, *imgsz)}' % t) + if save_txt or save_img: + s = f"\n{len(list(save_dir.glob('labels/*.txt')))} labels saved to {save_dir / 'labels'}" if save_txt else '' + LOGGER.info(f"Results saved to {colorstr('bold', save_dir)}{s}") + if update: + strip_optimizer(weights[0]) # update model (to fix SourceChangeWarning) + + +def parse_opt(): + parser = argparse.ArgumentParser() + parser.add_argument('--weights', nargs='+', type=str, default=ROOT / 'yolo-seg.pt', help='model path(s)') + parser.add_argument('--source', type=str, default=ROOT / 'data/images', help='file/dir/URL/glob/screen/0(webcam)') + parser.add_argument('--data', type=str, default=ROOT / 'data/coco128.yaml', help='(optional) dataset.yaml path') + parser.add_argument('--imgsz', '--img', '--img-size', nargs='+', type=int, default=[640], help='inference size h,w') + parser.add_argument('--conf-thres', type=float, default=0.25, help='confidence threshold') + parser.add_argument('--iou-thres', type=float, default=0.45, help='NMS IoU threshold') + parser.add_argument('--max-det', type=int, default=1000, help='maximum detections per image') + parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu') + parser.add_argument('--view-img', action='store_true', help='show results') + parser.add_argument('--save-txt', action='store_true', help='save results to *.txt') + parser.add_argument('--save-conf', action='store_true', help='save confidences in --save-txt labels') + parser.add_argument('--save-crop', action='store_true', help='save cropped prediction boxes') + parser.add_argument('--nosave', action='store_true', help='do not save images/videos') + parser.add_argument('--classes', nargs='+', type=int, help='filter by class: --classes 0, or --classes 0 2 3') + parser.add_argument('--agnostic-nms', action='store_true', help='class-agnostic NMS') + parser.add_argument('--augment', action='store_true', help='augmented inference') + parser.add_argument('--visualize', action='store_true', help='visualize features') + parser.add_argument('--update', action='store_true', help='update all models') + parser.add_argument('--project', default=ROOT / 'runs/predict-seg', help='save results to project/name') + parser.add_argument('--name', default='exp', help='save results to project/name') + parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment') + parser.add_argument('--line-thickness', default=3, type=int, help='bounding box thickness (pixels)') + parser.add_argument('--hide-labels', default=False, action='store_true', help='hide labels') + parser.add_argument('--hide-conf', default=False, action='store_true', help='hide confidences') + parser.add_argument('--half', action='store_true', help='use FP16 half-precision inference') + parser.add_argument('--dnn', action='store_true', help='use OpenCV DNN for ONNX inference') + parser.add_argument('--vid-stride', type=int, default=1, help='video frame-rate stride') + parser.add_argument('--retina-masks', action='store_true', help='whether to plot masks in native resolution') + opt = parser.parse_args() + opt.imgsz *= 2 if len(opt.imgsz) == 1 else 1 # expand + print_args(vars(opt)) + return opt + + +def main(opt): + check_requirements(exclude=('tensorboard', 'thop')) + run(**vars(opt)) + + +if __name__ == "__main__": + opt = parse_opt() + main(opt) diff --git a/cv/3d_detection/yolov9/pytorch/segment/train.py b/cv/3d_detection/yolov9/pytorch/segment/train.py new file mode 100644 index 000000000..311f21d9d --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/segment/train.py @@ -0,0 +1,646 @@ +import argparse +import math +import os +import random +import sys +import time +from copy import deepcopy +from datetime import datetime +from pathlib import Path + +import numpy as np +import torch +import torch.distributed as dist +import torch.nn as nn +import yaml +from torch.optim import lr_scheduler +from tqdm import tqdm + +FILE = Path(__file__).resolve() +ROOT = FILE.parents[1] # YOLO root directory +if str(ROOT) not in sys.path: + sys.path.append(str(ROOT)) # add ROOT to PATH +ROOT = Path(os.path.relpath(ROOT, Path.cwd())) # relative + +import segment.val as validate # for end-of-epoch mAP +from models.experimental import attempt_load +from models.yolo import SegmentationModel +from utils.autoanchor import check_anchors +from utils.autobatch import check_train_batch_size +from utils.callbacks import Callbacks +from utils.downloads import attempt_download, is_url +from utils.general import (LOGGER, TQDM_BAR_FORMAT, check_amp, check_dataset, check_file, check_git_info, + check_git_status, check_img_size, check_requirements, check_suffix, check_yaml, colorstr, + get_latest_run, increment_path, init_seeds, intersect_dicts, labels_to_class_weights, + labels_to_image_weights, one_cycle, print_args, print_mutation, strip_optimizer, yaml_save) +from utils.loggers import GenericLogger +from utils.plots import plot_evolve, plot_labels +from utils.segment.dataloaders import create_dataloader +from utils.segment.loss_tal import ComputeLoss +from utils.segment.metrics import KEYS, fitness +from utils.segment.plots import plot_images_and_masks, plot_results_with_masks +from utils.torch_utils import (EarlyStopping, ModelEMA, de_parallel, select_device, smart_DDP, smart_optimizer, + smart_resume, torch_distributed_zero_first) + +LOCAL_RANK = int(os.getenv('LOCAL_RANK', -1)) # https://pytorch.org/docs/stable/elastic/run.html +RANK = int(os.getenv('RANK', -1)) +WORLD_SIZE = int(os.getenv('WORLD_SIZE', 1)) +GIT_INFO = None#check_git_info() + + +def train(hyp, opt, device, callbacks): # hyp is path/to/hyp.yaml or hyp dictionary + save_dir, epochs, batch_size, weights, single_cls, evolve, data, cfg, resume, noval, nosave, workers, freeze, mask_ratio = \ + Path(opt.save_dir), opt.epochs, opt.batch_size, opt.weights, opt.single_cls, opt.evolve, opt.data, opt.cfg, \ + opt.resume, opt.noval, opt.nosave, opt.workers, opt.freeze, opt.mask_ratio + # callbacks.run('on_pretrain_routine_start') + + # Directories + w = save_dir / 'weights' # weights dir + (w.parent if evolve else w).mkdir(parents=True, exist_ok=True) # make dir + last, best = w / 'last.pt', w / 'best.pt' + + # Hyperparameters + if isinstance(hyp, str): + with open(hyp, errors='ignore') as f: + hyp = yaml.safe_load(f) # load hyps dict + LOGGER.info(colorstr('hyperparameters: ') + ', '.join(f'{k}={v}' for k, v in hyp.items())) + opt.hyp = hyp.copy() # for saving hyps to checkpoints + + # Save run settings + if not evolve: + yaml_save(save_dir / 'hyp.yaml', hyp) + yaml_save(save_dir / 'opt.yaml', vars(opt)) + + # Loggers + data_dict = None + if RANK in {-1, 0}: + logger = GenericLogger(opt=opt, console_logger=LOGGER) + + # Config + plots = not evolve and not opt.noplots # create plots + overlap = not opt.no_overlap + cuda = device.type != 'cpu' + init_seeds(opt.seed + 1 + RANK, deterministic=True) + with torch_distributed_zero_first(LOCAL_RANK): + data_dict = data_dict or check_dataset(data) # check if None + train_path, val_path = data_dict['train'], data_dict['val'] + nc = 1 if single_cls else int(data_dict['nc']) # number of classes + names = {0: 'item'} if single_cls and len(data_dict['names']) != 1 else data_dict['names'] # class names + #is_coco = isinstance(val_path, str) and val_path.endswith('coco/val2017.txt') # COCO dataset + is_coco = isinstance(val_path, str) and val_path.endswith('val2017.txt') # COCO dataset + + # Model + check_suffix(weights, '.pt') # check weights + pretrained = weights.endswith('.pt') + if pretrained: + with torch_distributed_zero_first(LOCAL_RANK): + weights = attempt_download(weights) # download if not found locally + ckpt = torch.load(weights, map_location='cpu') # load checkpoint to CPU to avoid CUDA memory leak + model = SegmentationModel(cfg or ckpt['model'].yaml, ch=3, nc=nc).to(device) + exclude = ['anchor'] if (cfg or hyp.get('anchors')) and not resume else [] # exclude keys + csd = ckpt['model'].float().state_dict() # checkpoint state_dict as FP32 + csd = intersect_dicts(csd, model.state_dict(), exclude=exclude) # intersect + model.load_state_dict(csd, strict=False) # load + LOGGER.info(f'Transferred {len(csd)}/{len(model.state_dict())} items from {weights}') # report + else: + model = SegmentationModel(cfg, ch=3, nc=nc).to(device) # create + amp = check_amp(model) # check AMP + + # Freeze + freeze = [f'model.{x}.' for x in (freeze if len(freeze) > 1 else range(freeze[0]))] # layers to freeze + for k, v in model.named_parameters(): + #v.requires_grad = True # train all layers + # v.register_hook(lambda x: torch.nan_to_num(x)) # NaN to 0 (commented for erratic training results) + if any(x in k for x in freeze): + LOGGER.info(f'freezing {k}') + v.requires_grad = False + + # Image size + gs = max(int(model.stride.max()), 32) # grid size (max stride) + imgsz = check_img_size(opt.imgsz, gs, floor=gs * 2) # verify imgsz is gs-multiple + + # Batch size + if RANK == -1 and batch_size == -1: # single-GPU only, estimate best batch size + batch_size = check_train_batch_size(model, imgsz, amp) + logger.update_params({"batch_size": batch_size}) + # loggers.on_params_update({"batch_size": batch_size}) + + # Optimizer + nbs = 64 # nominal batch size + accumulate = max(round(nbs / batch_size), 1) # accumulate loss before optimizing + hyp['weight_decay'] *= batch_size * accumulate / nbs # scale weight_decay + optimizer = smart_optimizer(model, opt.optimizer, hyp['lr0'], hyp['momentum'], hyp['weight_decay']) + + # Scheduler + if opt.cos_lr: + lf = one_cycle(1, hyp['lrf'], epochs) # cosine 1->hyp['lrf'] + else: + lf = lambda x: (1 - x / epochs) * (1.0 - hyp['lrf']) + hyp['lrf'] # linear + scheduler = lr_scheduler.LambdaLR(optimizer, lr_lambda=lf) # plot_lr_scheduler(optimizer, scheduler, epochs) + + # EMA + ema = ModelEMA(model) if RANK in {-1, 0} else None + + # Resume + best_fitness, start_epoch = 0.0, 0 + if pretrained: + if resume: + best_fitness, start_epoch, epochs = smart_resume(ckpt, optimizer, ema, weights, epochs, resume) + del ckpt, csd + + # DP mode + if cuda and RANK == -1 and torch.cuda.device_count() > 1: + LOGGER.warning('WARNING ⚠️ DP not recommended, use torch.distributed.run for best DDP Multi-GPU results.') + model = torch.nn.DataParallel(model) + + # SyncBatchNorm + if opt.sync_bn and cuda and RANK != -1: + model = torch.nn.SyncBatchNorm.convert_sync_batchnorm(model).to(device) + LOGGER.info('Using SyncBatchNorm()') + + # Trainloader + train_loader, dataset = create_dataloader( + train_path, + imgsz, + batch_size // WORLD_SIZE, + gs, + single_cls, + hyp=hyp, + augment=True, + cache=None if opt.cache == 'val' else opt.cache, + rect=opt.rect, + rank=LOCAL_RANK, + workers=workers, + image_weights=opt.image_weights, + close_mosaic=opt.close_mosaic != 0, + quad=opt.quad, + prefix=colorstr('train: '), + shuffle=True, + mask_downsample_ratio=mask_ratio, + overlap_mask=overlap, + ) + labels = np.concatenate(dataset.labels, 0) + mlc = int(labels[:, 0].max()) # max label class + assert mlc < nc, f'Label class {mlc} exceeds nc={nc} in {data}. Possible class labels are 0-{nc - 1}' + + # Process 0 + if RANK in {-1, 0}: + val_loader = create_dataloader(val_path, + imgsz, + batch_size // WORLD_SIZE * 2, + gs, + single_cls, + hyp=hyp, + cache=None if noval else opt.cache, + rect=True, + rank=-1, + workers=workers * 2, + pad=0.5, + mask_downsample_ratio=mask_ratio, + overlap_mask=overlap, + prefix=colorstr('val: '))[0] + + if not resume: + #if not opt.noautoanchor: + # check_anchors(dataset, model=model, thr=hyp['anchor_t'], imgsz=imgsz) # run AutoAnchor + model.half().float() # pre-reduce anchor precision + + if plots: + plot_labels(labels, names, save_dir) + # callbacks.run('on_pretrain_routine_end', labels, names) + + # DDP mode + if cuda and RANK != -1: + model = smart_DDP(model) + + # Model attributes + nl = de_parallel(model).model[-1].nl # number of detection layers (to scale hyps) + #hyp['box'] *= 3 / nl # scale to layers + #hyp['cls'] *= nc / 80 * 3 / nl # scale to classes and layers + #hyp['obj'] *= (imgsz / 640) ** 2 * 3 / nl # scale to image size and layers + hyp['label_smoothing'] = opt.label_smoothing + model.nc = nc # attach number of classes to model + model.hyp = hyp # attach hyperparameters to model + model.class_weights = labels_to_class_weights(dataset.labels, nc).to(device) * nc # attach class weights + model.names = names + + # Start training + t0 = time.time() + nb = len(train_loader) # number of batches + nw = max(round(hyp['warmup_epochs'] * nb), 100) # number of warmup iterations, max(3 epochs, 100 iterations) + # nw = min(nw, (epochs - start_epoch) / 2 * nb) # limit warmup to < 1/2 of training + last_opt_step = -1 + maps = np.zeros(nc) # mAP per class + results = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) # P, R, mAP@.5, mAP@.5-.95, val_loss(box, obj, cls) + scheduler.last_epoch = start_epoch - 1 # do not move + scaler = torch.cuda.amp.GradScaler(enabled=amp) + stopper, stop = EarlyStopping(patience=opt.patience), False + compute_loss = ComputeLoss(model, overlap=overlap) # init loss class + # callbacks.run('on_train_start') + LOGGER.info(f'Image sizes {imgsz} train, {imgsz} val\n' + f'Using {train_loader.num_workers * WORLD_SIZE} dataloader workers\n' + f"Logging results to {colorstr('bold', save_dir)}\n" + f'Starting training for {epochs} epochs...') + for epoch in range(start_epoch, epochs): # epoch ------------------------------------------------------------------ + # callbacks.run('on_train_epoch_start') + model.train() + + # Update image weights (optional, single-GPU only) + if opt.image_weights: + cw = model.class_weights.cpu().numpy() * (1 - maps) ** 2 / nc # class weights + iw = labels_to_image_weights(dataset.labels, nc=nc, class_weights=cw) # image weights + dataset.indices = random.choices(range(dataset.n), weights=iw, k=dataset.n) # rand weighted idx + if epoch == (epochs - opt.close_mosaic): + LOGGER.info("Closing dataloader mosaic") + dataset.mosaic = False + + # Update mosaic border (optional) + # b = int(random.uniform(0.25 * imgsz, 0.75 * imgsz + gs) // gs * gs) + # dataset.mosaic_border = [b - imgsz, -b] # height, width borders + + mloss = torch.zeros(4, device=device) # mean losses + if RANK != -1: + train_loader.sampler.set_epoch(epoch) + pbar = enumerate(train_loader) + LOGGER.info(('\n' + '%11s' * 8) % + ('Epoch', 'GPU_mem', 'box_loss', 'seg_loss', 'cls_loss', 'dfl_loss', 'Instances', 'Size')) + if RANK in {-1, 0}: + pbar = tqdm(pbar, total=nb, bar_format=TQDM_BAR_FORMAT) # progress bar + optimizer.zero_grad() + for i, (imgs, targets, paths, _, masks) in pbar: # batch ------------------------------------------------------ + # callbacks.run('on_train_batch_start') + ni = i + nb * epoch # number integrated batches (since train start) + imgs = imgs.to(device, non_blocking=True).float() / 255 # uint8 to float32, 0-255 to 0.0-1.0 + + # Warmup + if ni <= nw: + xi = [0, nw] # x interp + # compute_loss.gr = np.interp(ni, xi, [0.0, 1.0]) # iou loss ratio (obj_loss = 1.0 or iou) + accumulate = max(1, np.interp(ni, xi, [1, nbs / batch_size]).round()) + for j, x in enumerate(optimizer.param_groups): + # bias lr falls from 0.1 to lr0, all other lrs rise from 0.0 to lr0 + x['lr'] = np.interp(ni, xi, [hyp['warmup_bias_lr'] if j == 0 else 0.0, x['initial_lr'] * lf(epoch)]) + if 'momentum' in x: + x['momentum'] = np.interp(ni, xi, [hyp['warmup_momentum'], hyp['momentum']]) + + # Multi-scale + if opt.multi_scale: + sz = random.randrange(imgsz * 0.5, imgsz * 1.5 + gs) // gs * gs # size + sf = sz / max(imgs.shape[2:]) # scale factor + if sf != 1: + ns = [math.ceil(x * sf / gs) * gs for x in imgs.shape[2:]] # new shape (stretched to gs-multiple) + imgs = nn.functional.interpolate(imgs, size=ns, mode='bilinear', align_corners=False) + + # Forward + with torch.cuda.amp.autocast(amp): + pred = model(imgs) # forward + loss, loss_items = compute_loss(pred, targets.to(device), masks=masks.to(device).float()) + if RANK != -1: + loss *= WORLD_SIZE # gradient averaged between devices in DDP mode + if opt.quad: + loss *= 4. + + # Backward + scaler.scale(loss).backward() + + # Optimize - https://pytorch.org/docs/master/notes/amp_examples.html + if ni - last_opt_step >= accumulate: + scaler.unscale_(optimizer) # unscale gradients + torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=10.0) # clip gradients + scaler.step(optimizer) # optimizer.step + scaler.update() + optimizer.zero_grad() + if ema: + ema.update(model) + last_opt_step = ni + + # Log + if RANK in {-1, 0}: + mloss = (mloss * i + loss_items) / (i + 1) # update mean losses + mem = f'{torch.cuda.memory_reserved() / 1E9 if torch.cuda.is_available() else 0:.3g}G' # (GB) + pbar.set_description(('%11s' * 2 + '%11.4g' * 6) % + (f'{epoch}/{epochs - 1}', mem, *mloss, targets.shape[0], imgs.shape[-1])) + # callbacks.run('on_train_batch_end', model, ni, imgs, targets, paths) + # if callbacks.stop_training: + # return + + # Mosaic plots + if plots: + if ni < 3: + plot_images_and_masks(imgs, targets, masks, paths, save_dir / f"train_batch{ni}.jpg") + if ni == 10: + files = sorted(save_dir.glob('train*.jpg')) + logger.log_images(files, "Mosaics", epoch) + # end batch ------------------------------------------------------------------------------------------------ + + # Scheduler + lr = [x['lr'] for x in optimizer.param_groups] # for loggers + scheduler.step() + + if RANK in {-1, 0}: + # mAP + # callbacks.run('on_train_epoch_end', epoch=epoch) + ema.update_attr(model, include=['yaml', 'nc', 'hyp', 'names', 'stride', 'class_weights']) + final_epoch = (epoch + 1 == epochs) or stopper.possible_stop + if not noval or final_epoch: # Calculate mAP + results, maps, _ = validate.run(data_dict, + batch_size=batch_size // WORLD_SIZE * 2, + imgsz=imgsz, + half=amp, + model=ema.ema, + single_cls=single_cls, + dataloader=val_loader, + save_dir=save_dir, + plots=False, + callbacks=callbacks, + compute_loss=compute_loss, + mask_downsample_ratio=mask_ratio, + overlap=overlap) + + # Update best mAP + fi = fitness(np.array(results).reshape(1, -1)) # weighted combination of [P, R, mAP@.5, mAP@.5-.95] + stop = stopper(epoch=epoch, fitness=fi) # early stop check + if fi > best_fitness: + best_fitness = fi + log_vals = list(mloss) + list(results) + lr + # callbacks.run('on_fit_epoch_end', log_vals, epoch, best_fitness, fi) + # Log val metrics and media + metrics_dict = dict(zip(KEYS, log_vals)) + logger.log_metrics(metrics_dict, epoch) + + # Save model + if (not nosave) or (final_epoch and not evolve): # if save + ckpt = { + 'epoch': epoch, + 'best_fitness': best_fitness, + 'model': deepcopy(de_parallel(model)).half(), + 'ema': deepcopy(ema.ema).half(), + 'updates': ema.updates, + 'optimizer': optimizer.state_dict(), + 'opt': vars(opt), + 'git': GIT_INFO, # {remote, branch, commit} if a git repo + 'date': datetime.now().isoformat()} + + # Save last, best and delete + torch.save(ckpt, last) + if best_fitness == fi: + torch.save(ckpt, best) + if opt.save_period > 0 and epoch % opt.save_period == 0: + torch.save(ckpt, w / f'epoch{epoch}.pt') + logger.log_model(w / f'epoch{epoch}.pt') + del ckpt + # callbacks.run('on_model_save', last, epoch, final_epoch, best_fitness, fi) + + # EarlyStopping + if RANK != -1: # if DDP training + broadcast_list = [stop if RANK == 0 else None] + dist.broadcast_object_list(broadcast_list, 0) # broadcast 'stop' to all ranks + if RANK != 0: + stop = broadcast_list[0] + if stop: + break # must break all DDP ranks + + # end epoch ---------------------------------------------------------------------------------------------------- + # end training ----------------------------------------------------------------------------------------------------- + if RANK in {-1, 0}: + LOGGER.info(f'\n{epoch - start_epoch + 1} epochs completed in {(time.time() - t0) / 3600:.3f} hours.') + for f in last, best: + if f.exists(): + strip_optimizer(f) # strip optimizers + if f is best: + LOGGER.info(f'\nValidating {f}...') + results, _, _ = validate.run( + data_dict, + batch_size=batch_size // WORLD_SIZE * 2, + imgsz=imgsz, + model=attempt_load(f, device).half(), + iou_thres=0.65 if is_coco else 0.60, # best pycocotools at iou 0.65 + single_cls=single_cls, + dataloader=val_loader, + save_dir=save_dir, + save_json=is_coco, + verbose=True, + plots=plots, + callbacks=callbacks, + compute_loss=compute_loss, + mask_downsample_ratio=mask_ratio, + overlap=overlap) # val best model with plots + if is_coco: + # callbacks.run('on_fit_epoch_end', list(mloss) + list(results) + lr, epoch, best_fitness, fi) + metrics_dict = dict(zip(KEYS, list(mloss) + list(results) + lr)) + logger.log_metrics(metrics_dict, epoch) + + # callbacks.run('on_train_end', last, best, epoch, results) + # on train end callback using genericLogger + logger.log_metrics(dict(zip(KEYS[4:16], results)), epochs) + if not opt.evolve: + logger.log_model(best, epoch) + if plots: + plot_results_with_masks(file=save_dir / 'results.csv') # save results.png + files = ['results.png', 'confusion_matrix.png', *(f'{x}_curve.png' for x in ('F1', 'PR', 'P', 'R'))] + files = [(save_dir / f) for f in files if (save_dir / f).exists()] # filter + LOGGER.info(f"Results saved to {colorstr('bold', save_dir)}") + logger.log_images(files, "Results", epoch + 1) + logger.log_images(sorted(save_dir.glob('val*.jpg')), "Validation", epoch + 1) + torch.cuda.empty_cache() + return results + + +def parse_opt(known=False): + parser = argparse.ArgumentParser() + parser.add_argument('--weights', type=str, default=ROOT / 'yolo-seg.pt', help='initial weights path') + parser.add_argument('--cfg', type=str, default='', help='model.yaml path') + parser.add_argument('--data', type=str, default=ROOT / 'data/coco128-seg.yaml', help='dataset.yaml path') + parser.add_argument('--hyp', type=str, default=ROOT / 'data/hyps/hyp.scratch-low.yaml', help='hyperparameters path') + parser.add_argument('--epochs', type=int, default=100, help='total training epochs') + parser.add_argument('--batch-size', type=int, default=16, help='total batch size for all GPUs, -1 for autobatch') + parser.add_argument('--imgsz', '--img', '--img-size', type=int, default=640, help='train, val image size (pixels)') + parser.add_argument('--rect', action='store_true', help='rectangular training') + parser.add_argument('--resume', nargs='?', const=True, default=False, help='resume most recent training') + parser.add_argument('--nosave', action='store_true', help='only save final checkpoint') + parser.add_argument('--noval', action='store_true', help='only validate final epoch') + parser.add_argument('--noautoanchor', action='store_true', help='disable AutoAnchor') + parser.add_argument('--noplots', action='store_true', help='save no plot files') + parser.add_argument('--evolve', type=int, nargs='?', const=300, help='evolve hyperparameters for x generations') + parser.add_argument('--bucket', type=str, default='', help='gsutil bucket') + parser.add_argument('--cache', type=str, nargs='?', const='ram', help='image --cache ram/disk') + parser.add_argument('--image-weights', action='store_true', help='use weighted image selection for training') + parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu') + parser.add_argument('--multi-scale', action='store_true', help='vary img-size +/- 50%%') + parser.add_argument('--single-cls', action='store_true', help='train multi-class data as single-class') + parser.add_argument('--optimizer', type=str, choices=['SGD', 'Adam', 'AdamW', 'LION'], default='SGD', help='optimizer') + parser.add_argument('--sync-bn', action='store_true', help='use SyncBatchNorm, only available in DDP mode') + parser.add_argument('--workers', type=int, default=8, help='max dataloader workers (per RANK in DDP mode)') + parser.add_argument('--project', default=ROOT / 'runs/train-seg', help='save to project/name') + parser.add_argument('--name', default='exp', help='save to project/name') + parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment') + parser.add_argument('--quad', action='store_true', help='quad dataloader') + parser.add_argument('--cos-lr', action='store_true', help='cosine LR scheduler') + parser.add_argument('--label-smoothing', type=float, default=0.0, help='Label smoothing epsilon') + parser.add_argument('--patience', type=int, default=100, help='EarlyStopping patience (epochs without improvement)') + parser.add_argument('--freeze', nargs='+', type=int, default=[0], help='Freeze layers: backbone=10, first3=0 1 2') + parser.add_argument('--save-period', type=int, default=-1, help='Save checkpoint every x epochs (disabled if < 1)') + parser.add_argument('--seed', type=int, default=0, help='Global training seed') + parser.add_argument('--local_rank', type=int, default=-1, help='Automatic DDP Multi-GPU argument, do not modify') + parser.add_argument('--close-mosaic', type=int, default=0, help='Experimental') + + # Instance Segmentation Args + parser.add_argument('--mask-ratio', type=int, default=4, help='Downsample the truth masks to saving memory') + parser.add_argument('--no-overlap', action='store_true', help='Overlap masks train faster at slightly less mAP') + + return parser.parse_known_args()[0] if known else parser.parse_args() + + +def main(opt, callbacks=Callbacks()): + # Checks + if RANK in {-1, 0}: + print_args(vars(opt)) + #check_git_status() + #check_requirements() + + # Resume + if opt.resume and not opt.evolve: # resume from specified or most recent last.pt + last = Path(check_file(opt.resume) if isinstance(opt.resume, str) else get_latest_run()) + opt_yaml = last.parent.parent / 'opt.yaml' # train options yaml + opt_data = opt.data # original dataset + if opt_yaml.is_file(): + with open(opt_yaml, errors='ignore') as f: + d = yaml.safe_load(f) + else: + d = torch.load(last, map_location='cpu')['opt'] + opt = argparse.Namespace(**d) # replace + opt.cfg, opt.weights, opt.resume = '', str(last), True # reinstate + if is_url(opt_data): + opt.data = check_file(opt_data) # avoid HUB resume auth timeout + else: + opt.data, opt.cfg, opt.hyp, opt.weights, opt.project = \ + check_file(opt.data), check_yaml(opt.cfg), check_yaml(opt.hyp), str(opt.weights), str(opt.project) # checks + assert len(opt.cfg) or len(opt.weights), 'either --cfg or --weights must be specified' + if opt.evolve: + if opt.project == str(ROOT / 'runs/train'): # if default project name, rename to runs/evolve + opt.project = str(ROOT / 'runs/evolve') + opt.exist_ok, opt.resume = opt.resume, False # pass resume to exist_ok and disable resume + if opt.name == 'cfg': + opt.name = Path(opt.cfg).stem # use model.yaml as name + opt.save_dir = str(increment_path(Path(opt.project) / opt.name, exist_ok=opt.exist_ok)) + + # DDP mode + device = select_device(opt.device, batch_size=opt.batch_size) + if LOCAL_RANK != -1: + msg = 'is not compatible with YOLO Multi-GPU DDP training' + assert not opt.image_weights, f'--image-weights {msg}' + assert not opt.evolve, f'--evolve {msg}' + assert opt.batch_size != -1, f'AutoBatch with --batch-size -1 {msg}, please pass a valid --batch-size' + assert opt.batch_size % WORLD_SIZE == 0, f'--batch-size {opt.batch_size} must be multiple of WORLD_SIZE' + assert torch.cuda.device_count() > LOCAL_RANK, 'insufficient CUDA devices for DDP command' + torch.cuda.set_device(LOCAL_RANK) + device = torch.device('cuda', LOCAL_RANK) + dist.init_process_group(backend="nccl" if dist.is_nccl_available() else "gloo") + + # Train + if not opt.evolve: + train(opt.hyp, opt, device, callbacks) + + # Evolve hyperparameters (optional) + else: + # Hyperparameter evolution metadata (mutation scale 0-1, lower_limit, upper_limit) + meta = { + 'lr0': (1, 1e-5, 1e-1), # initial learning rate (SGD=1E-2, Adam=1E-3) + 'lrf': (1, 0.01, 1.0), # final OneCycleLR learning rate (lr0 * lrf) + 'momentum': (0.3, 0.6, 0.98), # SGD momentum/Adam beta1 + 'weight_decay': (1, 0.0, 0.001), # optimizer weight decay + 'warmup_epochs': (1, 0.0, 5.0), # warmup epochs (fractions ok) + 'warmup_momentum': (1, 0.0, 0.95), # warmup initial momentum + 'warmup_bias_lr': (1, 0.0, 0.2), # warmup initial bias lr + 'box': (1, 0.02, 0.2), # box loss gain + 'cls': (1, 0.2, 4.0), # cls loss gain + 'cls_pw': (1, 0.5, 2.0), # cls BCELoss positive_weight + 'obj': (1, 0.2, 4.0), # obj loss gain (scale with pixels) + 'obj_pw': (1, 0.5, 2.0), # obj BCELoss positive_weight + 'iou_t': (0, 0.1, 0.7), # IoU training threshold + 'anchor_t': (1, 2.0, 8.0), # anchor-multiple threshold + 'anchors': (2, 2.0, 10.0), # anchors per output grid (0 to ignore) + 'fl_gamma': (0, 0.0, 2.0), # focal loss gamma (efficientDet default gamma=1.5) + 'hsv_h': (1, 0.0, 0.1), # image HSV-Hue augmentation (fraction) + 'hsv_s': (1, 0.0, 0.9), # image HSV-Saturation augmentation (fraction) + 'hsv_v': (1, 0.0, 0.9), # image HSV-Value augmentation (fraction) + 'degrees': (1, 0.0, 45.0), # image rotation (+/- deg) + 'translate': (1, 0.0, 0.9), # image translation (+/- fraction) + 'scale': (1, 0.0, 0.9), # image scale (+/- gain) + 'shear': (1, 0.0, 10.0), # image shear (+/- deg) + 'perspective': (0, 0.0, 0.001), # image perspective (+/- fraction), range 0-0.001 + 'flipud': (1, 0.0, 1.0), # image flip up-down (probability) + 'fliplr': (0, 0.0, 1.0), # image flip left-right (probability) + 'mosaic': (1, 0.0, 1.0), # image mixup (probability) + 'mixup': (1, 0.0, 1.0), # image mixup (probability) + 'copy_paste': (1, 0.0, 1.0)} # segment copy-paste (probability) + + with open(opt.hyp, errors='ignore') as f: + hyp = yaml.safe_load(f) # load hyps dict + if 'anchors' not in hyp: # anchors commented in hyp.yaml + hyp['anchors'] = 3 + if opt.noautoanchor: + del hyp['anchors'], meta['anchors'] + opt.noval, opt.nosave, save_dir = True, True, Path(opt.save_dir) # only val/save final epoch + # ei = [isinstance(x, (int, float)) for x in hyp.values()] # evolvable indices + evolve_yaml, evolve_csv = save_dir / 'hyp_evolve.yaml', save_dir / 'evolve.csv' + if opt.bucket: + os.system(f'gsutil cp gs://{opt.bucket}/evolve.csv {evolve_csv}') # download evolve.csv if exists + + for _ in range(opt.evolve): # generations to evolve + if evolve_csv.exists(): # if evolve.csv exists: select best hyps and mutate + # Select parent(s) + parent = 'single' # parent selection method: 'single' or 'weighted' + x = np.loadtxt(evolve_csv, ndmin=2, delimiter=',', skiprows=1) + n = min(5, len(x)) # number of previous results to consider + x = x[np.argsort(-fitness(x))][:n] # top n mutations + w = fitness(x) - fitness(x).min() + 1E-6 # weights (sum > 0) + if parent == 'single' or len(x) == 1: + # x = x[random.randint(0, n - 1)] # random selection + x = x[random.choices(range(n), weights=w)[0]] # weighted selection + elif parent == 'weighted': + x = (x * w.reshape(n, 1)).sum(0) / w.sum() # weighted combination + + # Mutate + mp, s = 0.8, 0.2 # mutation probability, sigma + npr = np.random + npr.seed(int(time.time())) + g = np.array([meta[k][0] for k in hyp.keys()]) # gains 0-1 + ng = len(meta) + v = np.ones(ng) + while all(v == 1): # mutate until a change occurs (prevent duplicates) + v = (g * (npr.random(ng) < mp) * npr.randn(ng) * npr.random() * s + 1).clip(0.3, 3.0) + for i, k in enumerate(hyp.keys()): # plt.hist(v.ravel(), 300) + hyp[k] = float(x[i + 7] * v[i]) # mutate + + # Constrain to limits + for k, v in meta.items(): + hyp[k] = max(hyp[k], v[1]) # lower limit + hyp[k] = min(hyp[k], v[2]) # upper limit + hyp[k] = round(hyp[k], 5) # significant digits + + # Train mutation + results = train(hyp.copy(), opt, device, callbacks) + callbacks = Callbacks() + # Write mutation results + print_mutation(KEYS, results, hyp.copy(), save_dir, opt.bucket) + + # Plot results + plot_evolve(evolve_csv) + LOGGER.info(f'Hyperparameter evolution finished {opt.evolve} generations\n' + f"Results saved to {colorstr('bold', save_dir)}\n" + f'Usage example: $ python train.py --hyp {evolve_yaml}') + + +def run(**kwargs): + # Usage: import train; train.run(data='coco128.yaml', imgsz=320, weights='yolo.pt') + opt = parse_opt(True) + for k, v in kwargs.items(): + setattr(opt, k, v) + main(opt) + return opt + + +if __name__ == "__main__": + opt = parse_opt() + main(opt) diff --git a/cv/3d_detection/yolov9/pytorch/segment/train_dual.py b/cv/3d_detection/yolov9/pytorch/segment/train_dual.py new file mode 100644 index 000000000..1411f245b --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/segment/train_dual.py @@ -0,0 +1,647 @@ +import argparse +import math +import os +import random +import sys +import time +from copy import deepcopy +from datetime import datetime +from pathlib import Path + +import numpy as np +import torch +import torch.distributed as dist +import torch.nn as nn +import yaml +from torch.optim import lr_scheduler +from tqdm import tqdm + +FILE = Path(__file__).resolve() +ROOT = FILE.parents[1] # YOLO root directory +if str(ROOT) not in sys.path: + sys.path.append(str(ROOT)) # add ROOT to PATH +ROOT = Path(os.path.relpath(ROOT, Path.cwd())) # relative + +import segment.val_dual as validate # for end-of-epoch mAP +from models.experimental import attempt_load +from models.yolo import SegmentationModel +from utils.autoanchor import check_anchors +from utils.autobatch import check_train_batch_size +from utils.callbacks import Callbacks +from utils.downloads import attempt_download, is_url +from utils.general import (LOGGER, TQDM_BAR_FORMAT, check_amp, check_dataset, check_file, check_git_info, + check_git_status, check_img_size, check_requirements, check_suffix, check_yaml, colorstr, + get_latest_run, increment_path, init_seeds, intersect_dicts, labels_to_class_weights, + labels_to_image_weights, one_cycle, print_args, print_mutation, strip_optimizer, yaml_save) +from utils.loggers import GenericLogger +from utils.plots import plot_evolve, plot_labels +from utils.segment.dataloaders import create_dataloader +from utils.segment.loss_tal_dual import ComputeLoss +#from utils.segment.loss_tal_dual import ComputeLossLH as ComputeLoss +from utils.segment.metrics import KEYS, fitness +from utils.segment.plots import plot_images_and_masks, plot_results_with_masks +from utils.torch_utils import (EarlyStopping, ModelEMA, de_parallel, select_device, smart_DDP, smart_optimizer, + smart_resume, torch_distributed_zero_first) + +LOCAL_RANK = int(os.getenv('LOCAL_RANK', -1)) # https://pytorch.org/docs/stable/elastic/run.html +RANK = int(os.getenv('RANK', -1)) +WORLD_SIZE = int(os.getenv('WORLD_SIZE', 1)) +GIT_INFO = None#check_git_info() + + +def train(hyp, opt, device, callbacks): # hyp is path/to/hyp.yaml or hyp dictionary + save_dir, epochs, batch_size, weights, single_cls, evolve, data, cfg, resume, noval, nosave, workers, freeze, mask_ratio = \ + Path(opt.save_dir), opt.epochs, opt.batch_size, opt.weights, opt.single_cls, opt.evolve, opt.data, opt.cfg, \ + opt.resume, opt.noval, opt.nosave, opt.workers, opt.freeze, opt.mask_ratio + # callbacks.run('on_pretrain_routine_start') + + # Directories + w = save_dir / 'weights' # weights dir + (w.parent if evolve else w).mkdir(parents=True, exist_ok=True) # make dir + last, best = w / 'last.pt', w / 'best.pt' + + # Hyperparameters + if isinstance(hyp, str): + with open(hyp, errors='ignore') as f: + hyp = yaml.safe_load(f) # load hyps dict + LOGGER.info(colorstr('hyperparameters: ') + ', '.join(f'{k}={v}' for k, v in hyp.items())) + opt.hyp = hyp.copy() # for saving hyps to checkpoints + + # Save run settings + if not evolve: + yaml_save(save_dir / 'hyp.yaml', hyp) + yaml_save(save_dir / 'opt.yaml', vars(opt)) + + # Loggers + data_dict = None + if RANK in {-1, 0}: + logger = GenericLogger(opt=opt, console_logger=LOGGER) + + # Config + plots = not evolve and not opt.noplots # create plots + overlap = not opt.no_overlap + cuda = device.type != 'cpu' + init_seeds(opt.seed + 1 + RANK, deterministic=True) + with torch_distributed_zero_first(LOCAL_RANK): + data_dict = data_dict or check_dataset(data) # check if None + train_path, val_path = data_dict['train'], data_dict['val'] + nc = 1 if single_cls else int(data_dict['nc']) # number of classes + names = {0: 'item'} if single_cls and len(data_dict['names']) != 1 else data_dict['names'] # class names + #is_coco = isinstance(val_path, str) and val_path.endswith('coco/val2017.txt') # COCO dataset + is_coco = isinstance(val_path, str) and val_path.endswith('val2017.txt') # COCO dataset + + # Model + check_suffix(weights, '.pt') # check weights + pretrained = weights.endswith('.pt') + if pretrained: + with torch_distributed_zero_first(LOCAL_RANK): + weights = attempt_download(weights) # download if not found locally + ckpt = torch.load(weights, map_location='cpu') # load checkpoint to CPU to avoid CUDA memory leak + model = SegmentationModel(cfg or ckpt['model'].yaml, ch=3, nc=nc).to(device) + exclude = ['anchor'] if (cfg or hyp.get('anchors')) and not resume else [] # exclude keys + csd = ckpt['model'].float().state_dict() # checkpoint state_dict as FP32 + csd = intersect_dicts(csd, model.state_dict(), exclude=exclude) # intersect + model.load_state_dict(csd, strict=False) # load + LOGGER.info(f'Transferred {len(csd)}/{len(model.state_dict())} items from {weights}') # report + else: + model = SegmentationModel(cfg, ch=3, nc=nc).to(device) # create + amp = check_amp(model) # check AMP + + # Freeze + freeze = [f'model.{x}.' for x in (freeze if len(freeze) > 1 else range(freeze[0]))] # layers to freeze + for k, v in model.named_parameters(): + #v.requires_grad = True # train all layers + # v.register_hook(lambda x: torch.nan_to_num(x)) # NaN to 0 (commented for erratic training results) + if any(x in k for x in freeze): + LOGGER.info(f'freezing {k}') + v.requires_grad = False + + # Image size + gs = max(int(model.stride.max()), 32) # grid size (max stride) + imgsz = check_img_size(opt.imgsz, gs, floor=gs * 2) # verify imgsz is gs-multiple + + # Batch size + if RANK == -1 and batch_size == -1: # single-GPU only, estimate best batch size + batch_size = check_train_batch_size(model, imgsz, amp) + logger.update_params({"batch_size": batch_size}) + # loggers.on_params_update({"batch_size": batch_size}) + + # Optimizer + nbs = 64 # nominal batch size + accumulate = max(round(nbs / batch_size), 1) # accumulate loss before optimizing + hyp['weight_decay'] *= batch_size * accumulate / nbs # scale weight_decay + optimizer = smart_optimizer(model, opt.optimizer, hyp['lr0'], hyp['momentum'], hyp['weight_decay']) + + # Scheduler + if opt.cos_lr: + lf = one_cycle(1, hyp['lrf'], epochs) # cosine 1->hyp['lrf'] + else: + lf = lambda x: (1 - x / epochs) * (1.0 - hyp['lrf']) + hyp['lrf'] # linear + scheduler = lr_scheduler.LambdaLR(optimizer, lr_lambda=lf) # plot_lr_scheduler(optimizer, scheduler, epochs) + + # EMA + ema = ModelEMA(model) if RANK in {-1, 0} else None + + # Resume + best_fitness, start_epoch = 0.0, 0 + if pretrained: + if resume: + best_fitness, start_epoch, epochs = smart_resume(ckpt, optimizer, ema, weights, epochs, resume) + del ckpt, csd + + # DP mode + if cuda and RANK == -1 and torch.cuda.device_count() > 1: + LOGGER.warning('WARNING ⚠️ DP not recommended, use torch.distributed.run for best DDP Multi-GPU results.') + model = torch.nn.DataParallel(model) + + # SyncBatchNorm + if opt.sync_bn and cuda and RANK != -1: + model = torch.nn.SyncBatchNorm.convert_sync_batchnorm(model).to(device) + LOGGER.info('Using SyncBatchNorm()') + + # Trainloader + train_loader, dataset = create_dataloader( + train_path, + imgsz, + batch_size // WORLD_SIZE, + gs, + single_cls, + hyp=hyp, + augment=True, + cache=None if opt.cache == 'val' else opt.cache, + rect=opt.rect, + rank=LOCAL_RANK, + workers=workers, + image_weights=opt.image_weights, + close_mosaic=opt.close_mosaic != 0, + quad=opt.quad, + prefix=colorstr('train: '), + shuffle=True, + mask_downsample_ratio=mask_ratio, + overlap_mask=overlap, + ) + labels = np.concatenate(dataset.labels, 0) + mlc = int(labels[:, 0].max()) # max label class + assert mlc < nc, f'Label class {mlc} exceeds nc={nc} in {data}. Possible class labels are 0-{nc - 1}' + + # Process 0 + if RANK in {-1, 0}: + val_loader = create_dataloader(val_path, + imgsz, + batch_size // WORLD_SIZE * 2, + gs, + single_cls, + hyp=hyp, + cache=None if noval else opt.cache, + rect=True, + rank=-1, + workers=workers * 2, + pad=0.5, + mask_downsample_ratio=mask_ratio, + overlap_mask=overlap, + prefix=colorstr('val: '))[0] + + if not resume: + #if not opt.noautoanchor: + # check_anchors(dataset, model=model, thr=hyp['anchor_t'], imgsz=imgsz) # run AutoAnchor + model.half().float() # pre-reduce anchor precision + + if plots: + plot_labels(labels, names, save_dir) + # callbacks.run('on_pretrain_routine_end', labels, names) + + # DDP mode + if cuda and RANK != -1: + model = smart_DDP(model) + + # Model attributes + nl = de_parallel(model).model[-1].nl # number of detection layers (to scale hyps) + #hyp['box'] *= 3 / nl # scale to layers + #hyp['cls'] *= nc / 80 * 3 / nl # scale to classes and layers + #hyp['obj'] *= (imgsz / 640) ** 2 * 3 / nl # scale to image size and layers + hyp['label_smoothing'] = opt.label_smoothing + model.nc = nc # attach number of classes to model + model.hyp = hyp # attach hyperparameters to model + model.class_weights = labels_to_class_weights(dataset.labels, nc).to(device) * nc # attach class weights + model.names = names + + # Start training + t0 = time.time() + nb = len(train_loader) # number of batches + nw = max(round(hyp['warmup_epochs'] * nb), 100) # number of warmup iterations, max(3 epochs, 100 iterations) + # nw = min(nw, (epochs - start_epoch) / 2 * nb) # limit warmup to < 1/2 of training + last_opt_step = -1 + maps = np.zeros(nc) # mAP per class + results = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) # P, R, mAP@.5, mAP@.5-.95, val_loss(box, obj, cls) + scheduler.last_epoch = start_epoch - 1 # do not move + scaler = torch.cuda.amp.GradScaler(enabled=amp) + stopper, stop = EarlyStopping(patience=opt.patience), False + compute_loss = ComputeLoss(model, overlap=overlap) # init loss class + # callbacks.run('on_train_start') + LOGGER.info(f'Image sizes {imgsz} train, {imgsz} val\n' + f'Using {train_loader.num_workers * WORLD_SIZE} dataloader workers\n' + f"Logging results to {colorstr('bold', save_dir)}\n" + f'Starting training for {epochs} epochs...') + for epoch in range(start_epoch, epochs): # epoch ------------------------------------------------------------------ + # callbacks.run('on_train_epoch_start') + model.train() + + # Update image weights (optional, single-GPU only) + if opt.image_weights: + cw = model.class_weights.cpu().numpy() * (1 - maps) ** 2 / nc # class weights + iw = labels_to_image_weights(dataset.labels, nc=nc, class_weights=cw) # image weights + dataset.indices = random.choices(range(dataset.n), weights=iw, k=dataset.n) # rand weighted idx + if epoch == (epochs - opt.close_mosaic): + LOGGER.info("Closing dataloader mosaic") + dataset.mosaic = False + + # Update mosaic border (optional) + # b = int(random.uniform(0.25 * imgsz, 0.75 * imgsz + gs) // gs * gs) + # dataset.mosaic_border = [b - imgsz, -b] # height, width borders + + mloss = torch.zeros(4, device=device) # mean losses + if RANK != -1: + train_loader.sampler.set_epoch(epoch) + pbar = enumerate(train_loader) + LOGGER.info(('\n' + '%11s' * 8) % + ('Epoch', 'GPU_mem', 'box_loss', 'seg_loss', 'cls_loss', 'dfl_loss', 'Instances', 'Size')) + if RANK in {-1, 0}: + pbar = tqdm(pbar, total=nb, bar_format=TQDM_BAR_FORMAT) # progress bar + optimizer.zero_grad() + for i, (imgs, targets, paths, _, masks) in pbar: # batch ------------------------------------------------------ + # callbacks.run('on_train_batch_start') + ni = i + nb * epoch # number integrated batches (since train start) + imgs = imgs.to(device, non_blocking=True).float() / 255 # uint8 to float32, 0-255 to 0.0-1.0 + + # Warmup + if ni <= nw: + xi = [0, nw] # x interp + # compute_loss.gr = np.interp(ni, xi, [0.0, 1.0]) # iou loss ratio (obj_loss = 1.0 or iou) + accumulate = max(1, np.interp(ni, xi, [1, nbs / batch_size]).round()) + for j, x in enumerate(optimizer.param_groups): + # bias lr falls from 0.1 to lr0, all other lrs rise from 0.0 to lr0 + x['lr'] = np.interp(ni, xi, [hyp['warmup_bias_lr'] if j == 0 else 0.0, x['initial_lr'] * lf(epoch)]) + if 'momentum' in x: + x['momentum'] = np.interp(ni, xi, [hyp['warmup_momentum'], hyp['momentum']]) + + # Multi-scale + if opt.multi_scale: + sz = random.randrange(imgsz * 0.5, imgsz * 1.5 + gs) // gs * gs # size + sf = sz / max(imgs.shape[2:]) # scale factor + if sf != 1: + ns = [math.ceil(x * sf / gs) * gs for x in imgs.shape[2:]] # new shape (stretched to gs-multiple) + imgs = nn.functional.interpolate(imgs, size=ns, mode='bilinear', align_corners=False) + + # Forward + with torch.cuda.amp.autocast(amp): + pred = model(imgs) # forward + loss, loss_items = compute_loss(pred, targets.to(device), masks=masks.to(device).float()) + if RANK != -1: + loss *= WORLD_SIZE # gradient averaged between devices in DDP mode + if opt.quad: + loss *= 4. + + # Backward + scaler.scale(loss).backward() + + # Optimize - https://pytorch.org/docs/master/notes/amp_examples.html + if ni - last_opt_step >= accumulate: + scaler.unscale_(optimizer) # unscale gradients + torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=10.0) # clip gradients + scaler.step(optimizer) # optimizer.step + scaler.update() + optimizer.zero_grad() + if ema: + ema.update(model) + last_opt_step = ni + + # Log + if RANK in {-1, 0}: + mloss = (mloss * i + loss_items) / (i + 1) # update mean losses + mem = f'{torch.cuda.memory_reserved() / 1E9 if torch.cuda.is_available() else 0:.3g}G' # (GB) + pbar.set_description(('%11s' * 2 + '%11.4g' * 6) % + (f'{epoch}/{epochs - 1}', mem, *mloss, targets.shape[0], imgs.shape[-1])) + # callbacks.run('on_train_batch_end', model, ni, imgs, targets, paths) + # if callbacks.stop_training: + # return + + # Mosaic plots + if plots: + if ni < 3: + plot_images_and_masks(imgs, targets, masks, paths, save_dir / f"train_batch{ni}.jpg") + if ni == 10: + files = sorted(save_dir.glob('train*.jpg')) + logger.log_images(files, "Mosaics", epoch) + # end batch ------------------------------------------------------------------------------------------------ + + # Scheduler + lr = [x['lr'] for x in optimizer.param_groups] # for loggers + scheduler.step() + + if RANK in {-1, 0}: + # mAP + # callbacks.run('on_train_epoch_end', epoch=epoch) + ema.update_attr(model, include=['yaml', 'nc', 'hyp', 'names', 'stride', 'class_weights']) + final_epoch = (epoch + 1 == epochs) or stopper.possible_stop + if not noval or final_epoch: # Calculate mAP + results, maps, _ = validate.run(data_dict, + batch_size=batch_size // WORLD_SIZE * 2, + imgsz=imgsz, + half=amp, + model=ema.ema, + single_cls=single_cls, + dataloader=val_loader, + save_dir=save_dir, + plots=False, + callbacks=callbacks, + compute_loss=compute_loss, + mask_downsample_ratio=mask_ratio, + overlap=overlap) + + # Update best mAP + fi = fitness(np.array(results).reshape(1, -1)) # weighted combination of [P, R, mAP@.5, mAP@.5-.95] + stop = stopper(epoch=epoch, fitness=fi) # early stop check + if fi > best_fitness: + best_fitness = fi + log_vals = list(mloss) + list(results) + lr + # callbacks.run('on_fit_epoch_end', log_vals, epoch, best_fitness, fi) + # Log val metrics and media + metrics_dict = dict(zip(KEYS, log_vals)) + logger.log_metrics(metrics_dict, epoch) + + # Save model + if (not nosave) or (final_epoch and not evolve): # if save + ckpt = { + 'epoch': epoch, + 'best_fitness': best_fitness, + 'model': deepcopy(de_parallel(model)).half(), + 'ema': deepcopy(ema.ema).half(), + 'updates': ema.updates, + 'optimizer': optimizer.state_dict(), + 'opt': vars(opt), + 'git': GIT_INFO, # {remote, branch, commit} if a git repo + 'date': datetime.now().isoformat()} + + # Save last, best and delete + torch.save(ckpt, last) + if best_fitness == fi: + torch.save(ckpt, best) + if opt.save_period > 0 and epoch % opt.save_period == 0: + torch.save(ckpt, w / f'epoch{epoch}.pt') + logger.log_model(w / f'epoch{epoch}.pt') + del ckpt + # callbacks.run('on_model_save', last, epoch, final_epoch, best_fitness, fi) + + # EarlyStopping + if RANK != -1: # if DDP training + broadcast_list = [stop if RANK == 0 else None] + dist.broadcast_object_list(broadcast_list, 0) # broadcast 'stop' to all ranks + if RANK != 0: + stop = broadcast_list[0] + if stop: + break # must break all DDP ranks + + # end epoch ---------------------------------------------------------------------------------------------------- + # end training ----------------------------------------------------------------------------------------------------- + if RANK in {-1, 0}: + LOGGER.info(f'\n{epoch - start_epoch + 1} epochs completed in {(time.time() - t0) / 3600:.3f} hours.') + for f in last, best: + if f.exists(): + strip_optimizer(f) # strip optimizers + if f is best: + LOGGER.info(f'\nValidating {f}...') + results, _, _ = validate.run( + data_dict, + batch_size=batch_size // WORLD_SIZE * 2, + imgsz=imgsz, + model=attempt_load(f, device).half(), + iou_thres=0.65 if is_coco else 0.60, # best pycocotools at iou 0.65 + single_cls=single_cls, + dataloader=val_loader, + save_dir=save_dir, + save_json=is_coco, + verbose=True, + plots=plots, + callbacks=callbacks, + compute_loss=compute_loss, + mask_downsample_ratio=mask_ratio, + overlap=overlap) # val best model with plots + if is_coco: + # callbacks.run('on_fit_epoch_end', list(mloss) + list(results) + lr, epoch, best_fitness, fi) + metrics_dict = dict(zip(KEYS, list(mloss) + list(results) + lr)) + logger.log_metrics(metrics_dict, epoch) + + # callbacks.run('on_train_end', last, best, epoch, results) + # on train end callback using genericLogger + logger.log_metrics(dict(zip(KEYS[4:16], results)), epochs) + if not opt.evolve: + logger.log_model(best, epoch) + if plots: + plot_results_with_masks(file=save_dir / 'results.csv') # save results.png + files = ['results.png', 'confusion_matrix.png', *(f'{x}_curve.png' for x in ('F1', 'PR', 'P', 'R'))] + files = [(save_dir / f) for f in files if (save_dir / f).exists()] # filter + LOGGER.info(f"Results saved to {colorstr('bold', save_dir)}") + logger.log_images(files, "Results", epoch + 1) + logger.log_images(sorted(save_dir.glob('val*.jpg')), "Validation", epoch + 1) + torch.cuda.empty_cache() + return results + + +def parse_opt(known=False): + parser = argparse.ArgumentParser() + parser.add_argument('--weights', type=str, default=ROOT / 'yolo-seg.pt', help='initial weights path') + parser.add_argument('--cfg', type=str, default='', help='model.yaml path') + parser.add_argument('--data', type=str, default=ROOT / 'data/coco128-seg.yaml', help='dataset.yaml path') + parser.add_argument('--hyp', type=str, default=ROOT / 'data/hyps/hyp.scratch-low.yaml', help='hyperparameters path') + parser.add_argument('--epochs', type=int, default=100, help='total training epochs') + parser.add_argument('--batch-size', type=int, default=16, help='total batch size for all GPUs, -1 for autobatch') + parser.add_argument('--imgsz', '--img', '--img-size', type=int, default=640, help='train, val image size (pixels)') + parser.add_argument('--rect', action='store_true', help='rectangular training') + parser.add_argument('--resume', nargs='?', const=True, default=False, help='resume most recent training') + parser.add_argument('--nosave', action='store_true', help='only save final checkpoint') + parser.add_argument('--noval', action='store_true', help='only validate final epoch') + parser.add_argument('--noautoanchor', action='store_true', help='disable AutoAnchor') + parser.add_argument('--noplots', action='store_true', help='save no plot files') + parser.add_argument('--evolve', type=int, nargs='?', const=300, help='evolve hyperparameters for x generations') + parser.add_argument('--bucket', type=str, default='', help='gsutil bucket') + parser.add_argument('--cache', type=str, nargs='?', const='ram', help='image --cache ram/disk') + parser.add_argument('--image-weights', action='store_true', help='use weighted image selection for training') + parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu') + parser.add_argument('--multi-scale', action='store_true', help='vary img-size +/- 50%%') + parser.add_argument('--single-cls', action='store_true', help='train multi-class data as single-class') + parser.add_argument('--optimizer', type=str, choices=['SGD', 'Adam', 'AdamW', 'LION'], default='SGD', help='optimizer') + parser.add_argument('--sync-bn', action='store_true', help='use SyncBatchNorm, only available in DDP mode') + parser.add_argument('--workers', type=int, default=8, help='max dataloader workers (per RANK in DDP mode)') + parser.add_argument('--project', default=ROOT / 'runs/train-seg', help='save to project/name') + parser.add_argument('--name', default='exp', help='save to project/name') + parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment') + parser.add_argument('--quad', action='store_true', help='quad dataloader') + parser.add_argument('--cos-lr', action='store_true', help='cosine LR scheduler') + parser.add_argument('--label-smoothing', type=float, default=0.0, help='Label smoothing epsilon') + parser.add_argument('--patience', type=int, default=100, help='EarlyStopping patience (epochs without improvement)') + parser.add_argument('--freeze', nargs='+', type=int, default=[0], help='Freeze layers: backbone=10, first3=0 1 2') + parser.add_argument('--save-period', type=int, default=-1, help='Save checkpoint every x epochs (disabled if < 1)') + parser.add_argument('--seed', type=int, default=0, help='Global training seed') + parser.add_argument('--local_rank', type=int, default=-1, help='Automatic DDP Multi-GPU argument, do not modify') + parser.add_argument('--close-mosaic', type=int, default=0, help='Experimental') + + # Instance Segmentation Args + parser.add_argument('--mask-ratio', type=int, default=4, help='Downsample the truth masks to saving memory') + parser.add_argument('--no-overlap', action='store_true', help='Overlap masks train faster at slightly less mAP') + + return parser.parse_known_args()[0] if known else parser.parse_args() + + +def main(opt, callbacks=Callbacks()): + # Checks + if RANK in {-1, 0}: + print_args(vars(opt)) + #check_git_status() + #check_requirements() + + # Resume + if opt.resume and not opt.evolve: # resume from specified or most recent last.pt + last = Path(check_file(opt.resume) if isinstance(opt.resume, str) else get_latest_run()) + opt_yaml = last.parent.parent / 'opt.yaml' # train options yaml + opt_data = opt.data # original dataset + if opt_yaml.is_file(): + with open(opt_yaml, errors='ignore') as f: + d = yaml.safe_load(f) + else: + d = torch.load(last, map_location='cpu')['opt'] + opt = argparse.Namespace(**d) # replace + opt.cfg, opt.weights, opt.resume = '', str(last), True # reinstate + if is_url(opt_data): + opt.data = check_file(opt_data) # avoid HUB resume auth timeout + else: + opt.data, opt.cfg, opt.hyp, opt.weights, opt.project = \ + check_file(opt.data), check_yaml(opt.cfg), check_yaml(opt.hyp), str(opt.weights), str(opt.project) # checks + assert len(opt.cfg) or len(opt.weights), 'either --cfg or --weights must be specified' + if opt.evolve: + if opt.project == str(ROOT / 'runs/train'): # if default project name, rename to runs/evolve + opt.project = str(ROOT / 'runs/evolve') + opt.exist_ok, opt.resume = opt.resume, False # pass resume to exist_ok and disable resume + if opt.name == 'cfg': + opt.name = Path(opt.cfg).stem # use model.yaml as name + opt.save_dir = str(increment_path(Path(opt.project) / opt.name, exist_ok=opt.exist_ok)) + + # DDP mode + device = select_device(opt.device, batch_size=opt.batch_size) + if LOCAL_RANK != -1: + msg = 'is not compatible with YOLO Multi-GPU DDP training' + assert not opt.image_weights, f'--image-weights {msg}' + assert not opt.evolve, f'--evolve {msg}' + assert opt.batch_size != -1, f'AutoBatch with --batch-size -1 {msg}, please pass a valid --batch-size' + assert opt.batch_size % WORLD_SIZE == 0, f'--batch-size {opt.batch_size} must be multiple of WORLD_SIZE' + assert torch.cuda.device_count() > LOCAL_RANK, 'insufficient CUDA devices for DDP command' + torch.cuda.set_device(LOCAL_RANK) + device = torch.device('cuda', LOCAL_RANK) + dist.init_process_group(backend="nccl" if dist.is_nccl_available() else "gloo") + + # Train + if not opt.evolve: + train(opt.hyp, opt, device, callbacks) + + # Evolve hyperparameters (optional) + else: + # Hyperparameter evolution metadata (mutation scale 0-1, lower_limit, upper_limit) + meta = { + 'lr0': (1, 1e-5, 1e-1), # initial learning rate (SGD=1E-2, Adam=1E-3) + 'lrf': (1, 0.01, 1.0), # final OneCycleLR learning rate (lr0 * lrf) + 'momentum': (0.3, 0.6, 0.98), # SGD momentum/Adam beta1 + 'weight_decay': (1, 0.0, 0.001), # optimizer weight decay + 'warmup_epochs': (1, 0.0, 5.0), # warmup epochs (fractions ok) + 'warmup_momentum': (1, 0.0, 0.95), # warmup initial momentum + 'warmup_bias_lr': (1, 0.0, 0.2), # warmup initial bias lr + 'box': (1, 0.02, 0.2), # box loss gain + 'cls': (1, 0.2, 4.0), # cls loss gain + 'cls_pw': (1, 0.5, 2.0), # cls BCELoss positive_weight + 'obj': (1, 0.2, 4.0), # obj loss gain (scale with pixels) + 'obj_pw': (1, 0.5, 2.0), # obj BCELoss positive_weight + 'iou_t': (0, 0.1, 0.7), # IoU training threshold + 'anchor_t': (1, 2.0, 8.0), # anchor-multiple threshold + 'anchors': (2, 2.0, 10.0), # anchors per output grid (0 to ignore) + 'fl_gamma': (0, 0.0, 2.0), # focal loss gamma (efficientDet default gamma=1.5) + 'hsv_h': (1, 0.0, 0.1), # image HSV-Hue augmentation (fraction) + 'hsv_s': (1, 0.0, 0.9), # image HSV-Saturation augmentation (fraction) + 'hsv_v': (1, 0.0, 0.9), # image HSV-Value augmentation (fraction) + 'degrees': (1, 0.0, 45.0), # image rotation (+/- deg) + 'translate': (1, 0.0, 0.9), # image translation (+/- fraction) + 'scale': (1, 0.0, 0.9), # image scale (+/- gain) + 'shear': (1, 0.0, 10.0), # image shear (+/- deg) + 'perspective': (0, 0.0, 0.001), # image perspective (+/- fraction), range 0-0.001 + 'flipud': (1, 0.0, 1.0), # image flip up-down (probability) + 'fliplr': (0, 0.0, 1.0), # image flip left-right (probability) + 'mosaic': (1, 0.0, 1.0), # image mixup (probability) + 'mixup': (1, 0.0, 1.0), # image mixup (probability) + 'copy_paste': (1, 0.0, 1.0)} # segment copy-paste (probability) + + with open(opt.hyp, errors='ignore') as f: + hyp = yaml.safe_load(f) # load hyps dict + if 'anchors' not in hyp: # anchors commented in hyp.yaml + hyp['anchors'] = 3 + if opt.noautoanchor: + del hyp['anchors'], meta['anchors'] + opt.noval, opt.nosave, save_dir = True, True, Path(opt.save_dir) # only val/save final epoch + # ei = [isinstance(x, (int, float)) for x in hyp.values()] # evolvable indices + evolve_yaml, evolve_csv = save_dir / 'hyp_evolve.yaml', save_dir / 'evolve.csv' + if opt.bucket: + os.system(f'gsutil cp gs://{opt.bucket}/evolve.csv {evolve_csv}') # download evolve.csv if exists + + for _ in range(opt.evolve): # generations to evolve + if evolve_csv.exists(): # if evolve.csv exists: select best hyps and mutate + # Select parent(s) + parent = 'single' # parent selection method: 'single' or 'weighted' + x = np.loadtxt(evolve_csv, ndmin=2, delimiter=',', skiprows=1) + n = min(5, len(x)) # number of previous results to consider + x = x[np.argsort(-fitness(x))][:n] # top n mutations + w = fitness(x) - fitness(x).min() + 1E-6 # weights (sum > 0) + if parent == 'single' or len(x) == 1: + # x = x[random.randint(0, n - 1)] # random selection + x = x[random.choices(range(n), weights=w)[0]] # weighted selection + elif parent == 'weighted': + x = (x * w.reshape(n, 1)).sum(0) / w.sum() # weighted combination + + # Mutate + mp, s = 0.8, 0.2 # mutation probability, sigma + npr = np.random + npr.seed(int(time.time())) + g = np.array([meta[k][0] for k in hyp.keys()]) # gains 0-1 + ng = len(meta) + v = np.ones(ng) + while all(v == 1): # mutate until a change occurs (prevent duplicates) + v = (g * (npr.random(ng) < mp) * npr.randn(ng) * npr.random() * s + 1).clip(0.3, 3.0) + for i, k in enumerate(hyp.keys()): # plt.hist(v.ravel(), 300) + hyp[k] = float(x[i + 7] * v[i]) # mutate + + # Constrain to limits + for k, v in meta.items(): + hyp[k] = max(hyp[k], v[1]) # lower limit + hyp[k] = min(hyp[k], v[2]) # upper limit + hyp[k] = round(hyp[k], 5) # significant digits + + # Train mutation + results = train(hyp.copy(), opt, device, callbacks) + callbacks = Callbacks() + # Write mutation results + print_mutation(KEYS, results, hyp.copy(), save_dir, opt.bucket) + + # Plot results + plot_evolve(evolve_csv) + LOGGER.info(f'Hyperparameter evolution finished {opt.evolve} generations\n' + f"Results saved to {colorstr('bold', save_dir)}\n" + f'Usage example: $ python train.py --hyp {evolve_yaml}') + + +def run(**kwargs): + # Usage: import train; train.run(data='coco128.yaml', imgsz=320, weights='yolo.pt') + opt = parse_opt(True) + for k, v in kwargs.items(): + setattr(opt, k, v) + main(opt) + return opt + + +if __name__ == "__main__": + opt = parse_opt() + main(opt) diff --git a/cv/3d_detection/yolov9/pytorch/segment/val.py b/cv/3d_detection/yolov9/pytorch/segment/val.py new file mode 100644 index 000000000..479a09a08 --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/segment/val.py @@ -0,0 +1,457 @@ +import argparse +import json +import os +import sys +from multiprocessing.pool import ThreadPool +from pathlib import Path + +import numpy as np +import torch +from tqdm import tqdm + +FILE = Path(__file__).resolve() +ROOT = FILE.parents[1] # YOLO root directory +if str(ROOT) not in sys.path: + sys.path.append(str(ROOT)) # add ROOT to PATH +ROOT = Path(os.path.relpath(ROOT, Path.cwd())) # relative + +import torch.nn.functional as F + +from models.common import DetectMultiBackend +from models.yolo import SegmentationModel +from utils.callbacks import Callbacks +from utils.general import (LOGGER, NUM_THREADS, TQDM_BAR_FORMAT, Profile, check_dataset, check_img_size, + check_requirements, check_yaml, coco80_to_coco91_class, colorstr, increment_path, + non_max_suppression, print_args, scale_boxes, xywh2xyxy, xyxy2xywh) +from utils.metrics import ConfusionMatrix, box_iou +from utils.plots import output_to_target, plot_val_study +from utils.segment.dataloaders import create_dataloader +from utils.segment.general import mask_iou, process_mask, process_mask_upsample, scale_image +from utils.segment.metrics import Metrics, ap_per_class_box_and_mask +from utils.segment.plots import plot_images_and_masks +from utils.torch_utils import de_parallel, select_device, smart_inference_mode + + +def save_one_txt(predn, save_conf, shape, file): + # Save one txt result + gn = torch.tensor(shape)[[1, 0, 1, 0]] # normalization gain whwh + for *xyxy, conf, cls in predn.tolist(): + xywh = (xyxy2xywh(torch.tensor(xyxy).view(1, 4)) / gn).view(-1).tolist() # normalized xywh + line = (cls, *xywh, conf) if save_conf else (cls, *xywh) # label format + with open(file, 'a') as f: + f.write(('%g ' * len(line)).rstrip() % line + '\n') + + +def save_one_json(predn, jdict, path, class_map, pred_masks): + # Save one JSON result {"image_id": 42, "category_id": 18, "bbox": [258.15, 41.29, 348.26, 243.78], "score": 0.236} + from pycocotools.mask import encode + + def single_encode(x): + rle = encode(np.asarray(x[:, :, None], order="F", dtype="uint8"))[0] + rle["counts"] = rle["counts"].decode("utf-8") + return rle + + image_id = int(path.stem) if path.stem.isnumeric() else path.stem + box = xyxy2xywh(predn[:, :4]) # xywh + box[:, :2] -= box[:, 2:] / 2 # xy center to top-left corner + pred_masks = np.transpose(pred_masks, (2, 0, 1)) + with ThreadPool(NUM_THREADS) as pool: + rles = pool.map(single_encode, pred_masks) + for i, (p, b) in enumerate(zip(predn.tolist(), box.tolist())): + jdict.append({ + 'image_id': image_id, + 'category_id': class_map[int(p[5])], + 'bbox': [round(x, 3) for x in b], + 'score': round(p[4], 5), + 'segmentation': rles[i]}) + + +def process_batch(detections, labels, iouv, pred_masks=None, gt_masks=None, overlap=False, masks=False): + """ + Return correct prediction matrix + Arguments: + detections (array[N, 6]), x1, y1, x2, y2, conf, class + labels (array[M, 5]), class, x1, y1, x2, y2 + Returns: + correct (array[N, 10]), for 10 IoU levels + """ + if masks: + if overlap: + nl = len(labels) + index = torch.arange(nl, device=gt_masks.device).view(nl, 1, 1) + 1 + gt_masks = gt_masks.repeat(nl, 1, 1) # shape(1,640,640) -> (n,640,640) + gt_masks = torch.where(gt_masks == index, 1.0, 0.0) + if gt_masks.shape[1:] != pred_masks.shape[1:]: + gt_masks = F.interpolate(gt_masks[None], pred_masks.shape[1:], mode="bilinear", align_corners=False)[0] + gt_masks = gt_masks.gt_(0.5) + iou = mask_iou(gt_masks.view(gt_masks.shape[0], -1), pred_masks.view(pred_masks.shape[0], -1)) + else: # boxes + iou = box_iou(labels[:, 1:], detections[:, :4]) + + correct = np.zeros((detections.shape[0], iouv.shape[0])).astype(bool) + correct_class = labels[:, 0:1] == detections[:, 5] + for i in range(len(iouv)): + x = torch.where((iou >= iouv[i]) & correct_class) # IoU > threshold and classes match + if x[0].shape[0]: + matches = torch.cat((torch.stack(x, 1), iou[x[0], x[1]][:, None]), 1).cpu().numpy() # [label, detect, iou] + if x[0].shape[0] > 1: + matches = matches[matches[:, 2].argsort()[::-1]] + matches = matches[np.unique(matches[:, 1], return_index=True)[1]] + # matches = matches[matches[:, 2].argsort()[::-1]] + matches = matches[np.unique(matches[:, 0], return_index=True)[1]] + correct[matches[:, 1].astype(int), i] = True + return torch.tensor(correct, dtype=torch.bool, device=iouv.device) + + +@smart_inference_mode() +def run( + data, + weights=None, # model.pt path(s) + batch_size=32, # batch size + imgsz=640, # inference size (pixels) + conf_thres=0.001, # confidence threshold + iou_thres=0.6, # NMS IoU threshold + max_det=300, # maximum detections per image + task='val', # train, val, test, speed or study + device='', # cuda device, i.e. 0 or 0,1,2,3 or cpu + workers=8, # max dataloader workers (per RANK in DDP mode) + single_cls=False, # treat as single-class dataset + augment=False, # augmented inference + verbose=False, # verbose output + save_txt=False, # save results to *.txt + save_hybrid=False, # save label+prediction hybrid results to *.txt + save_conf=False, # save confidences in --save-txt labels + save_json=False, # save a COCO-JSON results file + project=ROOT / 'runs/val-seg', # save to project/name + name='exp', # save to project/name + exist_ok=False, # existing project/name ok, do not increment + half=True, # use FP16 half-precision inference + dnn=False, # use OpenCV DNN for ONNX inference + model=None, + dataloader=None, + save_dir=Path(''), + plots=True, + overlap=False, + mask_downsample_ratio=1, + compute_loss=None, + callbacks=Callbacks(), +): + if save_json: + check_requirements(['pycocotools']) + process = process_mask_upsample # more accurate + else: + process = process_mask # faster + + # Initialize/load model and set device + training = model is not None + if training: # called by train.py + device, pt, jit, engine = next(model.parameters()).device, True, False, False # get model device, PyTorch model + half &= device.type != 'cpu' # half precision only supported on CUDA + model.half() if half else model.float() + nm = de_parallel(model).model[-1].nm # number of masks + else: # called directly + device = select_device(device, batch_size=batch_size) + + # Directories + save_dir = increment_path(Path(project) / name, exist_ok=exist_ok) # increment run + (save_dir / 'labels' if save_txt else save_dir).mkdir(parents=True, exist_ok=True) # make dir + + # Load model + model = DetectMultiBackend(weights, device=device, dnn=dnn, data=data, fp16=half) + stride, pt, jit, engine = model.stride, model.pt, model.jit, model.engine + imgsz = check_img_size(imgsz, s=stride) # check image size + half = model.fp16 # FP16 supported on limited backends with CUDA + nm = de_parallel(model).model.model[-1].nm if isinstance(model, SegmentationModel) else 32 # number of masks + if engine: + batch_size = model.batch_size + else: + device = model.device + if not (pt or jit): + batch_size = 1 # export.py models default to batch-size 1 + LOGGER.info(f'Forcing --batch-size 1 square inference (1,3,{imgsz},{imgsz}) for non-PyTorch models') + + # Data + data = check_dataset(data) # check + + # Configure + model.eval() + cuda = device.type != 'cpu' + #is_coco = isinstance(data.get('val'), str) and data['val'].endswith(f'coco{os.sep}val2017.txt') # COCO dataset + is_coco = isinstance(data.get('val'), str) and data['val'].endswith(f'val2017.txt') # COCO dataset + nc = 1 if single_cls else int(data['nc']) # number of classes + iouv = torch.linspace(0.5, 0.95, 10, device=device) # iou vector for mAP@0.5:0.95 + niou = iouv.numel() + + # Dataloader + if not training: + if pt and not single_cls: # check --weights are trained on --data + ncm = model.model.nc + assert ncm == nc, f'{weights} ({ncm} classes) trained on different --data than what you passed ({nc} ' \ + f'classes). Pass correct combination of --weights and --data that are trained together.' + model.warmup(imgsz=(1 if pt else batch_size, 3, imgsz, imgsz)) # warmup + pad, rect = (0.0, False) if task == 'speed' else (0.5, pt) # square inference for benchmarks + task = task if task in ('train', 'val', 'test') else 'val' # path to train/val/test images + dataloader = create_dataloader(data[task], + imgsz, + batch_size, + stride, + single_cls, + pad=pad, + rect=rect, + workers=workers, + prefix=colorstr(f'{task}: '), + overlap_mask=overlap, + mask_downsample_ratio=mask_downsample_ratio)[0] + + seen = 0 + confusion_matrix = ConfusionMatrix(nc=nc) + names = model.names if hasattr(model, 'names') else model.module.names # get class names + if isinstance(names, (list, tuple)): # old format + names = dict(enumerate(names)) + class_map = coco80_to_coco91_class() if is_coco else list(range(1000)) + s = ('%22s' + '%11s' * 10) % ('Class', 'Images', 'Instances', 'Box(P', "R", "mAP50", "mAP50-95)", "Mask(P", "R", + "mAP50", "mAP50-95)") + dt = Profile(), Profile(), Profile() + metrics = Metrics() + loss = torch.zeros(4, device=device) + jdict, stats = [], [] + # callbacks.run('on_val_start') + pbar = tqdm(dataloader, desc=s, bar_format=TQDM_BAR_FORMAT) # progress bar + for batch_i, (im, targets, paths, shapes, masks) in enumerate(pbar): + # callbacks.run('on_val_batch_start') + with dt[0]: + if cuda: + im = im.to(device, non_blocking=True) + targets = targets.to(device) + masks = masks.to(device) + masks = masks.float() + im = im.half() if half else im.float() # uint8 to fp16/32 + im /= 255 # 0 - 255 to 0.0 - 1.0 + nb, _, height, width = im.shape # batch size, channels, height, width + + # Inference + with dt[1]: + preds, train_out = model(im)# if compute_loss else (*model(im, augment=augment)[:2], None) + #train_out, preds, protos = p if len(p) == 3 else p[1] + #preds = p + #train_out = p[1][0] if len(p[1]) == 3 else p[0] + protos = train_out[-1] + #print(preds.shape) + #print(train_out[0].shape) + #print(train_out[1].shape) + #print(train_out[2].shape) + + # Loss + if compute_loss: + loss += compute_loss(train_out, targets, masks)[1] # box, obj, cls + + # NMS + targets[:, 2:] *= torch.tensor((width, height, width, height), device=device) # to pixels + lb = [targets[targets[:, 0] == i, 1:] for i in range(nb)] if save_hybrid else [] # for autolabelling + with dt[2]: + preds = non_max_suppression(preds, + conf_thres, + iou_thres, + labels=lb, + multi_label=True, + agnostic=single_cls, + max_det=max_det, + nm=nm) + + # Metrics + plot_masks = [] # masks for plotting + for si, (pred, proto) in enumerate(zip(preds, protos)): + labels = targets[targets[:, 0] == si, 1:] + nl, npr = labels.shape[0], pred.shape[0] # number of labels, predictions + path, shape = Path(paths[si]), shapes[si][0] + correct_masks = torch.zeros(npr, niou, dtype=torch.bool, device=device) # init + correct_bboxes = torch.zeros(npr, niou, dtype=torch.bool, device=device) # init + seen += 1 + + if npr == 0: + if nl: + stats.append((correct_masks, correct_bboxes, *torch.zeros((2, 0), device=device), labels[:, 0])) + if plots: + confusion_matrix.process_batch(detections=None, labels=labels[:, 0]) + continue + + # Masks + midx = [si] if overlap else targets[:, 0] == si + gt_masks = masks[midx] + pred_masks = process(proto, pred[:, 6:], pred[:, :4], shape=im[si].shape[1:]) + + # Predictions + if single_cls: + pred[:, 5] = 0 + predn = pred.clone() + scale_boxes(im[si].shape[1:], predn[:, :4], shape, shapes[si][1]) # native-space pred + + # Evaluate + if nl: + tbox = xywh2xyxy(labels[:, 1:5]) # target boxes + scale_boxes(im[si].shape[1:], tbox, shape, shapes[si][1]) # native-space labels + labelsn = torch.cat((labels[:, 0:1], tbox), 1) # native-space labels + correct_bboxes = process_batch(predn, labelsn, iouv) + correct_masks = process_batch(predn, labelsn, iouv, pred_masks, gt_masks, overlap=overlap, masks=True) + if plots: + confusion_matrix.process_batch(predn, labelsn) + stats.append((correct_masks, correct_bboxes, pred[:, 4], pred[:, 5], labels[:, 0])) # (conf, pcls, tcls) + + pred_masks = torch.as_tensor(pred_masks, dtype=torch.uint8) + if plots and batch_i < 3: + plot_masks.append(pred_masks[:15].cpu()) # filter top 15 to plot + + # Save/log + if save_txt: + save_one_txt(predn, save_conf, shape, file=save_dir / 'labels' / f'{path.stem}.txt') + if save_json: + pred_masks = scale_image(im[si].shape[1:], + pred_masks.permute(1, 2, 0).contiguous().cpu().numpy(), shape, shapes[si][1]) + save_one_json(predn, jdict, path, class_map, pred_masks) # append to COCO-JSON dictionary + # callbacks.run('on_val_image_end', pred, predn, path, names, im[si]) + + # Plot images + if plots and batch_i < 3: + if len(plot_masks): + plot_masks = torch.cat(plot_masks, dim=0) + plot_images_and_masks(im, targets, masks, paths, save_dir / f'val_batch{batch_i}_labels.jpg', names) + plot_images_and_masks(im, output_to_target(preds, max_det=15), plot_masks, paths, + save_dir / f'val_batch{batch_i}_pred.jpg', names) # pred + + # callbacks.run('on_val_batch_end') + + # Compute metrics + stats = [torch.cat(x, 0).cpu().numpy() for x in zip(*stats)] # to numpy + if len(stats) and stats[0].any(): + results = ap_per_class_box_and_mask(*stats, plot=plots, save_dir=save_dir, names=names) + metrics.update(results) + nt = np.bincount(stats[4].astype(int), minlength=nc) # number of targets per class + + # Print results + pf = '%22s' + '%11i' * 2 + '%11.3g' * 8 # print format + LOGGER.info(pf % ("all", seen, nt.sum(), *metrics.mean_results())) + if nt.sum() == 0: + LOGGER.warning(f'WARNING ⚠️ no labels found in {task} set, can not compute metrics without labels') + + # Print results per class + if (verbose or (nc < 50 and not training)) and nc > 1 and len(stats): + for i, c in enumerate(metrics.ap_class_index): + LOGGER.info(pf % (names[c], seen, nt[c], *metrics.class_result(i))) + + # Print speeds + t = tuple(x.t / seen * 1E3 for x in dt) # speeds per image + if not training: + shape = (batch_size, 3, imgsz, imgsz) + LOGGER.info(f'Speed: %.1fms pre-process, %.1fms inference, %.1fms NMS per image at shape {shape}' % t) + + # Plots + if plots: + confusion_matrix.plot(save_dir=save_dir, names=list(names.values())) + # callbacks.run('on_val_end') + + mp_bbox, mr_bbox, map50_bbox, map_bbox, mp_mask, mr_mask, map50_mask, map_mask = metrics.mean_results() + + # Save JSON + if save_json and len(jdict): + w = Path(weights[0] if isinstance(weights, list) else weights).stem if weights is not None else '' # weights + anno_json = str(Path(data.get('path', '../coco')) / 'annotations/instances_val2017.json') # annotations json + pred_json = str(save_dir / f"{w}_predictions.json") # predictions json + LOGGER.info(f'\nEvaluating pycocotools mAP... saving {pred_json}...') + with open(pred_json, 'w') as f: + json.dump(jdict, f) + + try: # https://github.com/cocodataset/cocoapi/blob/master/PythonAPI/pycocoEvalDemo.ipynb + from pycocotools.coco import COCO + from pycocotools.cocoeval import COCOeval + + anno = COCO(anno_json) # init annotations api + pred = anno.loadRes(pred_json) # init predictions api + results = [] + for eval in COCOeval(anno, pred, 'bbox'), COCOeval(anno, pred, 'segm'): + if is_coco: + eval.params.imgIds = [int(Path(x).stem) for x in dataloader.dataset.im_files] # img ID to evaluate + eval.evaluate() + eval.accumulate() + eval.summarize() + results.extend(eval.stats[:2]) # update results (mAP@0.5:0.95, mAP@0.5) + map_bbox, map50_bbox, map_mask, map50_mask = results + except Exception as e: + LOGGER.info(f'pycocotools unable to run: {e}') + + # Return results + model.float() # for training + if not training: + s = f"\n{len(list(save_dir.glob('labels/*.txt')))} labels saved to {save_dir / 'labels'}" if save_txt else '' + LOGGER.info(f"Results saved to {colorstr('bold', save_dir)}{s}") + final_metric = mp_bbox, mr_bbox, map50_bbox, map_bbox, mp_mask, mr_mask, map50_mask, map_mask + return (*final_metric, *(loss.cpu() / len(dataloader)).tolist()), metrics.get_maps(nc), t + + +def parse_opt(): + parser = argparse.ArgumentParser() + parser.add_argument('--data', type=str, default=ROOT / 'data/coco128-seg.yaml', help='dataset.yaml path') + parser.add_argument('--weights', nargs='+', type=str, default=ROOT / 'yolo-seg.pt', help='model path(s)') + parser.add_argument('--batch-size', type=int, default=32, help='batch size') + parser.add_argument('--imgsz', '--img', '--img-size', type=int, default=640, help='inference size (pixels)') + parser.add_argument('--conf-thres', type=float, default=0.001, help='confidence threshold') + parser.add_argument('--iou-thres', type=float, default=0.6, help='NMS IoU threshold') + parser.add_argument('--max-det', type=int, default=300, help='maximum detections per image') + parser.add_argument('--task', default='val', help='train, val, test, speed or study') + parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu') + parser.add_argument('--workers', type=int, default=8, help='max dataloader workers (per RANK in DDP mode)') + parser.add_argument('--single-cls', action='store_true', help='treat as single-class dataset') + parser.add_argument('--augment', action='store_true', help='augmented inference') + parser.add_argument('--verbose', action='store_true', help='report mAP by class') + parser.add_argument('--save-txt', action='store_true', help='save results to *.txt') + parser.add_argument('--save-hybrid', action='store_true', help='save label+prediction hybrid results to *.txt') + parser.add_argument('--save-conf', action='store_true', help='save confidences in --save-txt labels') + parser.add_argument('--save-json', action='store_true', help='save a COCO-JSON results file') + parser.add_argument('--project', default=ROOT / 'runs/val-seg', help='save results to project/name') + parser.add_argument('--name', default='exp', help='save to project/name') + parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment') + parser.add_argument('--half', action='store_true', help='use FP16 half-precision inference') + parser.add_argument('--dnn', action='store_true', help='use OpenCV DNN for ONNX inference') + opt = parser.parse_args() + opt.data = check_yaml(opt.data) # check YAML + # opt.save_json |= opt.data.endswith('coco.yaml') + opt.save_txt |= opt.save_hybrid + print_args(vars(opt)) + return opt + + +def main(opt): + #check_requirements(requirements=ROOT / 'requirements.txt', exclude=('tensorboard', 'thop')) + + if opt.task in ('train', 'val', 'test'): # run normally + if opt.conf_thres > 0.001: # https://github.com/ultralytics/yolov5/issues/1466 + LOGGER.warning(f'WARNING ⚠️ confidence threshold {opt.conf_thres} > 0.001 produces invalid results') + if opt.save_hybrid: + LOGGER.warning('WARNING ⚠️ --save-hybrid returns high mAP from hybrid labels, not from predictions alone') + run(**vars(opt)) + + else: + weights = opt.weights if isinstance(opt.weights, list) else [opt.weights] + opt.half = torch.cuda.is_available() and opt.device != 'cpu' # FP16 for fastest results + if opt.task == 'speed': # speed benchmarks + # python val.py --task speed --data coco.yaml --batch 1 --weights yolo.pt... + opt.conf_thres, opt.iou_thres, opt.save_json = 0.25, 0.45, False + for opt.weights in weights: + run(**vars(opt), plots=False) + + elif opt.task == 'study': # speed vs mAP benchmarks + # python val.py --task study --data coco.yaml --iou 0.7 --weights yolo.pt... + for opt.weights in weights: + f = f'study_{Path(opt.data).stem}_{Path(opt.weights).stem}.txt' # filename to save to + x, y = list(range(256, 1536 + 128, 128)), [] # x axis (image sizes), y axis + for opt.imgsz in x: # img-size + LOGGER.info(f'\nRunning {f} --imgsz {opt.imgsz}...') + r, _, t = run(**vars(opt), plots=False) + y.append(r + t) # results and times + np.savetxt(f, y, fmt='%10.4g') # save + os.system('zip -r study.zip study_*.txt') + plot_val_study(x=x) # plot + + +if __name__ == "__main__": + opt = parse_opt() + main(opt) diff --git a/cv/3d_detection/yolov9/pytorch/segment/val_dual.py b/cv/3d_detection/yolov9/pytorch/segment/val_dual.py new file mode 100644 index 000000000..c30f12fa2 --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/segment/val_dual.py @@ -0,0 +1,458 @@ +import argparse +import json +import os +import sys +from multiprocessing.pool import ThreadPool +from pathlib import Path + +import numpy as np +import torch +from tqdm import tqdm + +FILE = Path(__file__).resolve() +ROOT = FILE.parents[1] # YOLO root directory +if str(ROOT) not in sys.path: + sys.path.append(str(ROOT)) # add ROOT to PATH +ROOT = Path(os.path.relpath(ROOT, Path.cwd())) # relative + +import torch.nn.functional as F + +from models.common import DetectMultiBackend +from models.yolo import SegmentationModel +from utils.callbacks import Callbacks +from utils.general import (LOGGER, NUM_THREADS, TQDM_BAR_FORMAT, Profile, check_dataset, check_img_size, + check_requirements, check_yaml, coco80_to_coco91_class, colorstr, increment_path, + non_max_suppression, print_args, scale_boxes, xywh2xyxy, xyxy2xywh) +from utils.metrics import ConfusionMatrix, box_iou +from utils.plots import output_to_target, plot_val_study +from utils.segment.dataloaders import create_dataloader +from utils.segment.general import mask_iou, process_mask, process_mask_upsample, scale_image +from utils.segment.metrics import Metrics, ap_per_class_box_and_mask +from utils.segment.plots import plot_images_and_masks +from utils.torch_utils import de_parallel, select_device, smart_inference_mode + + +def save_one_txt(predn, save_conf, shape, file): + # Save one txt result + gn = torch.tensor(shape)[[1, 0, 1, 0]] # normalization gain whwh + for *xyxy, conf, cls in predn.tolist(): + xywh = (xyxy2xywh(torch.tensor(xyxy).view(1, 4)) / gn).view(-1).tolist() # normalized xywh + line = (cls, *xywh, conf) if save_conf else (cls, *xywh) # label format + with open(file, 'a') as f: + f.write(('%g ' * len(line)).rstrip() % line + '\n') + + +def save_one_json(predn, jdict, path, class_map, pred_masks): + # Save one JSON result {"image_id": 42, "category_id": 18, "bbox": [258.15, 41.29, 348.26, 243.78], "score": 0.236} + from pycocotools.mask import encode + + def single_encode(x): + rle = encode(np.asarray(x[:, :, None], order="F", dtype="uint8"))[0] + rle["counts"] = rle["counts"].decode("utf-8") + return rle + + image_id = int(path.stem) if path.stem.isnumeric() else path.stem + box = xyxy2xywh(predn[:, :4]) # xywh + box[:, :2] -= box[:, 2:] / 2 # xy center to top-left corner + pred_masks = np.transpose(pred_masks, (2, 0, 1)) + with ThreadPool(NUM_THREADS) as pool: + rles = pool.map(single_encode, pred_masks) + for i, (p, b) in enumerate(zip(predn.tolist(), box.tolist())): + jdict.append({ + 'image_id': image_id, + 'category_id': class_map[int(p[5])], + 'bbox': [round(x, 3) for x in b], + 'score': round(p[4], 5), + 'segmentation': rles[i]}) + + +def process_batch(detections, labels, iouv, pred_masks=None, gt_masks=None, overlap=False, masks=False): + """ + Return correct prediction matrix + Arguments: + detections (array[N, 6]), x1, y1, x2, y2, conf, class + labels (array[M, 5]), class, x1, y1, x2, y2 + Returns: + correct (array[N, 10]), for 10 IoU levels + """ + if masks: + if overlap: + nl = len(labels) + index = torch.arange(nl, device=gt_masks.device).view(nl, 1, 1) + 1 + gt_masks = gt_masks.repeat(nl, 1, 1) # shape(1,640,640) -> (n,640,640) + gt_masks = torch.where(gt_masks == index, 1.0, 0.0) + if gt_masks.shape[1:] != pred_masks.shape[1:]: + gt_masks = F.interpolate(gt_masks[None], pred_masks.shape[1:], mode="bilinear", align_corners=False)[0] + gt_masks = gt_masks.gt_(0.5) + iou = mask_iou(gt_masks.view(gt_masks.shape[0], -1), pred_masks.view(pred_masks.shape[0], -1)) + else: # boxes + iou = box_iou(labels[:, 1:], detections[:, :4]) + + correct = np.zeros((detections.shape[0], iouv.shape[0])).astype(bool) + correct_class = labels[:, 0:1] == detections[:, 5] + for i in range(len(iouv)): + x = torch.where((iou >= iouv[i]) & correct_class) # IoU > threshold and classes match + if x[0].shape[0]: + matches = torch.cat((torch.stack(x, 1), iou[x[0], x[1]][:, None]), 1).cpu().numpy() # [label, detect, iou] + if x[0].shape[0] > 1: + matches = matches[matches[:, 2].argsort()[::-1]] + matches = matches[np.unique(matches[:, 1], return_index=True)[1]] + # matches = matches[matches[:, 2].argsort()[::-1]] + matches = matches[np.unique(matches[:, 0], return_index=True)[1]] + correct[matches[:, 1].astype(int), i] = True + return torch.tensor(correct, dtype=torch.bool, device=iouv.device) + + +@smart_inference_mode() +def run( + data, + weights=None, # model.pt path(s) + batch_size=32, # batch size + imgsz=640, # inference size (pixels) + conf_thres=0.001, # confidence threshold + iou_thres=0.6, # NMS IoU threshold + max_det=300, # maximum detections per image + task='val', # train, val, test, speed or study + device='', # cuda device, i.e. 0 or 0,1,2,3 or cpu + workers=8, # max dataloader workers (per RANK in DDP mode) + single_cls=False, # treat as single-class dataset + augment=False, # augmented inference + verbose=False, # verbose output + save_txt=False, # save results to *.txt + save_hybrid=False, # save label+prediction hybrid results to *.txt + save_conf=False, # save confidences in --save-txt labels + save_json=False, # save a COCO-JSON results file + project=ROOT / 'runs/val-seg', # save to project/name + name='exp', # save to project/name + exist_ok=False, # existing project/name ok, do not increment + half=True, # use FP16 half-precision inference + dnn=False, # use OpenCV DNN for ONNX inference + model=None, + dataloader=None, + save_dir=Path(''), + plots=True, + overlap=False, + mask_downsample_ratio=1, + compute_loss=None, + callbacks=Callbacks(), +): + if save_json: + check_requirements(['pycocotools']) + process = process_mask_upsample # more accurate + else: + process = process_mask # faster + + # Initialize/load model and set device + training = model is not None + if training: # called by train.py + device, pt, jit, engine = next(model.parameters()).device, True, False, False # get model device, PyTorch model + half &= device.type != 'cpu' # half precision only supported on CUDA + model.half() if half else model.float() + nm = de_parallel(model).model[-1].nm # number of masks + else: # called directly + device = select_device(device, batch_size=batch_size) + + # Directories + save_dir = increment_path(Path(project) / name, exist_ok=exist_ok) # increment run + (save_dir / 'labels' if save_txt else save_dir).mkdir(parents=True, exist_ok=True) # make dir + + # Load model + model = DetectMultiBackend(weights, device=device, dnn=dnn, data=data, fp16=half) + stride, pt, jit, engine = model.stride, model.pt, model.jit, model.engine + imgsz = check_img_size(imgsz, s=stride) # check image size + half = model.fp16 # FP16 supported on limited backends with CUDA + nm = de_parallel(model).model.model[-1].nm if isinstance(model, SegmentationModel) else 32 # number of masks + if engine: + batch_size = model.batch_size + else: + device = model.device + if not (pt or jit): + batch_size = 1 # export.py models default to batch-size 1 + LOGGER.info(f'Forcing --batch-size 1 square inference (1,3,{imgsz},{imgsz}) for non-PyTorch models') + + # Data + data = check_dataset(data) # check + + # Configure + model.eval() + cuda = device.type != 'cpu' + #is_coco = isinstance(data.get('val'), str) and data['val'].endswith(f'coco{os.sep}val2017.txt') # COCO dataset + is_coco = isinstance(data.get('val'), str) and data['val'].endswith(f'val2017.txt') # COCO dataset + nc = 1 if single_cls else int(data['nc']) # number of classes + iouv = torch.linspace(0.5, 0.95, 10, device=device) # iou vector for mAP@0.5:0.95 + niou = iouv.numel() + + # Dataloader + if not training: + if pt and not single_cls: # check --weights are trained on --data + ncm = model.model.nc + assert ncm == nc, f'{weights} ({ncm} classes) trained on different --data than what you passed ({nc} ' \ + f'classes). Pass correct combination of --weights and --data that are trained together.' + model.warmup(imgsz=(1 if pt else batch_size, 3, imgsz, imgsz)) # warmup + pad, rect = (0.0, False) if task == 'speed' else (0.5, pt) # square inference for benchmarks + task = task if task in ('train', 'val', 'test') else 'val' # path to train/val/test images + dataloader = create_dataloader(data[task], + imgsz, + batch_size, + stride, + single_cls, + pad=pad, + rect=rect, + workers=workers, + prefix=colorstr(f'{task}: '), + overlap_mask=overlap, + mask_downsample_ratio=mask_downsample_ratio)[0] + + seen = 0 + confusion_matrix = ConfusionMatrix(nc=nc) + names = model.names if hasattr(model, 'names') else model.module.names # get class names + if isinstance(names, (list, tuple)): # old format + names = dict(enumerate(names)) + class_map = coco80_to_coco91_class() if is_coco else list(range(1000)) + s = ('%22s' + '%11s' * 10) % ('Class', 'Images', 'Instances', 'Box(P', "R", "mAP50", "mAP50-95)", "Mask(P", "R", + "mAP50", "mAP50-95)") + dt = Profile(), Profile(), Profile() + metrics = Metrics() + loss = torch.zeros(4, device=device) + jdict, stats = [], [] + # callbacks.run('on_val_start') + pbar = tqdm(dataloader, desc=s, bar_format=TQDM_BAR_FORMAT) # progress bar + for batch_i, (im, targets, paths, shapes, masks) in enumerate(pbar): + # callbacks.run('on_val_batch_start') + with dt[0]: + if cuda: + im = im.to(device, non_blocking=True) + targets = targets.to(device) + masks = masks.to(device) + masks = masks.float() + im = im.half() if half else im.float() # uint8 to fp16/32 + im /= 255 # 0 - 255 to 0.0 - 1.0 + nb, _, height, width = im.shape # batch size, channels, height, width + + # Inference + with dt[1]: + preds, train_out = model(im)# if compute_loss else (*model(im, augment=augment)[:2], None) + #preds = preds[1] + #train_out, preds, protos = p if len(p) == 3 else p[1] + #preds = p + #train_out = p[1][0] if len(p[1]) == 3 else p[0] + protos = train_out[-1] + #print(preds.shape) + #print(train_out[0].shape) + #print(train_out[1].shape) + #print(train_out[2].shape) + + # Loss + #if compute_loss: + # loss += compute_loss(train_out, targets, masks)[1] # box, obj, cls + + # NMS + targets[:, 2:] *= torch.tensor((width, height, width, height), device=device) # to pixels + lb = [targets[targets[:, 0] == i, 1:] for i in range(nb)] if save_hybrid else [] # for autolabelling + with dt[2]: + preds = non_max_suppression(preds, + conf_thres, + iou_thres, + labels=lb, + multi_label=True, + agnostic=single_cls, + max_det=max_det, + nm=nm) + + # Metrics + plot_masks = [] # masks for plotting + for si, (pred, proto) in enumerate(zip(preds, protos)): + labels = targets[targets[:, 0] == si, 1:] + nl, npr = labels.shape[0], pred.shape[0] # number of labels, predictions + path, shape = Path(paths[si]), shapes[si][0] + correct_masks = torch.zeros(npr, niou, dtype=torch.bool, device=device) # init + correct_bboxes = torch.zeros(npr, niou, dtype=torch.bool, device=device) # init + seen += 1 + + if npr == 0: + if nl: + stats.append((correct_masks, correct_bboxes, *torch.zeros((2, 0), device=device), labels[:, 0])) + if plots: + confusion_matrix.process_batch(detections=None, labels=labels[:, 0]) + continue + + # Masks + midx = [si] if overlap else targets[:, 0] == si + gt_masks = masks[midx] + pred_masks = process(proto, pred[:, 6:], pred[:, :4], shape=im[si].shape[1:]) + + # Predictions + if single_cls: + pred[:, 5] = 0 + predn = pred.clone() + scale_boxes(im[si].shape[1:], predn[:, :4], shape, shapes[si][1]) # native-space pred + + # Evaluate + if nl: + tbox = xywh2xyxy(labels[:, 1:5]) # target boxes + scale_boxes(im[si].shape[1:], tbox, shape, shapes[si][1]) # native-space labels + labelsn = torch.cat((labels[:, 0:1], tbox), 1) # native-space labels + correct_bboxes = process_batch(predn, labelsn, iouv) + correct_masks = process_batch(predn, labelsn, iouv, pred_masks, gt_masks, overlap=overlap, masks=True) + if plots: + confusion_matrix.process_batch(predn, labelsn) + stats.append((correct_masks, correct_bboxes, pred[:, 4], pred[:, 5], labels[:, 0])) # (conf, pcls, tcls) + + pred_masks = torch.as_tensor(pred_masks, dtype=torch.uint8) + if plots and batch_i < 3: + plot_masks.append(pred_masks[:15].cpu()) # filter top 15 to plot + + # Save/log + if save_txt: + save_one_txt(predn, save_conf, shape, file=save_dir / 'labels' / f'{path.stem}.txt') + if save_json: + pred_masks = scale_image(im[si].shape[1:], + pred_masks.permute(1, 2, 0).contiguous().cpu().numpy(), shape, shapes[si][1]) + save_one_json(predn, jdict, path, class_map, pred_masks) # append to COCO-JSON dictionary + # callbacks.run('on_val_image_end', pred, predn, path, names, im[si]) + + # Plot images + if plots and batch_i < 3: + if len(plot_masks): + plot_masks = torch.cat(plot_masks, dim=0) + plot_images_and_masks(im, targets, masks, paths, save_dir / f'val_batch{batch_i}_labels.jpg', names) + plot_images_and_masks(im, output_to_target(preds, max_det=15), plot_masks, paths, + save_dir / f'val_batch{batch_i}_pred.jpg', names) # pred + + # callbacks.run('on_val_batch_end') + + # Compute metrics + stats = [torch.cat(x, 0).cpu().numpy() for x in zip(*stats)] # to numpy + if len(stats) and stats[0].any(): + results = ap_per_class_box_and_mask(*stats, plot=plots, save_dir=save_dir, names=names) + metrics.update(results) + nt = np.bincount(stats[4].astype(int), minlength=nc) # number of targets per class + + # Print results + pf = '%22s' + '%11i' * 2 + '%11.3g' * 8 # print format + LOGGER.info(pf % ("all", seen, nt.sum(), *metrics.mean_results())) + if nt.sum() == 0: + LOGGER.warning(f'WARNING ⚠️ no labels found in {task} set, can not compute metrics without labels') + + # Print results per class + if (verbose or (nc < 50 and not training)) and nc > 1 and len(stats): + for i, c in enumerate(metrics.ap_class_index): + LOGGER.info(pf % (names[c], seen, nt[c], *metrics.class_result(i))) + + # Print speeds + t = tuple(x.t / seen * 1E3 for x in dt) # speeds per image + if not training: + shape = (batch_size, 3, imgsz, imgsz) + LOGGER.info(f'Speed: %.1fms pre-process, %.1fms inference, %.1fms NMS per image at shape {shape}' % t) + + # Plots + if plots: + confusion_matrix.plot(save_dir=save_dir, names=list(names.values())) + # callbacks.run('on_val_end') + + mp_bbox, mr_bbox, map50_bbox, map_bbox, mp_mask, mr_mask, map50_mask, map_mask = metrics.mean_results() + + # Save JSON + if save_json and len(jdict): + w = Path(weights[0] if isinstance(weights, list) else weights).stem if weights is not None else '' # weights + anno_json = str(Path(data.get('path', '../coco')) / 'annotations/instances_val2017.json') # annotations json + pred_json = str(save_dir / f"{w}_predictions.json") # predictions json + LOGGER.info(f'\nEvaluating pycocotools mAP... saving {pred_json}...') + with open(pred_json, 'w') as f: + json.dump(jdict, f) + + try: # https://github.com/cocodataset/cocoapi/blob/master/PythonAPI/pycocoEvalDemo.ipynb + from pycocotools.coco import COCO + from pycocotools.cocoeval import COCOeval + + anno = COCO(anno_json) # init annotations api + pred = anno.loadRes(pred_json) # init predictions api + results = [] + for eval in COCOeval(anno, pred, 'bbox'), COCOeval(anno, pred, 'segm'): + if is_coco: + eval.params.imgIds = [int(Path(x).stem) for x in dataloader.dataset.im_files] # img ID to evaluate + eval.evaluate() + eval.accumulate() + eval.summarize() + results.extend(eval.stats[:2]) # update results (mAP@0.5:0.95, mAP@0.5) + map_bbox, map50_bbox, map_mask, map50_mask = results + except Exception as e: + LOGGER.info(f'pycocotools unable to run: {e}') + + # Return results + model.float() # for training + if not training: + s = f"\n{len(list(save_dir.glob('labels/*.txt')))} labels saved to {save_dir / 'labels'}" if save_txt else '' + LOGGER.info(f"Results saved to {colorstr('bold', save_dir)}{s}") + final_metric = mp_bbox, mr_bbox, map50_bbox, map_bbox, mp_mask, mr_mask, map50_mask, map_mask + return (*final_metric, *(loss.cpu() / len(dataloader)).tolist()), metrics.get_maps(nc), t + + +def parse_opt(): + parser = argparse.ArgumentParser() + parser.add_argument('--data', type=str, default=ROOT / 'data/coco128-seg.yaml', help='dataset.yaml path') + parser.add_argument('--weights', nargs='+', type=str, default=ROOT / 'yolo-seg.pt', help='model path(s)') + parser.add_argument('--batch-size', type=int, default=32, help='batch size') + parser.add_argument('--imgsz', '--img', '--img-size', type=int, default=640, help='inference size (pixels)') + parser.add_argument('--conf-thres', type=float, default=0.001, help='confidence threshold') + parser.add_argument('--iou-thres', type=float, default=0.6, help='NMS IoU threshold') + parser.add_argument('--max-det', type=int, default=300, help='maximum detections per image') + parser.add_argument('--task', default='val', help='train, val, test, speed or study') + parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu') + parser.add_argument('--workers', type=int, default=8, help='max dataloader workers (per RANK in DDP mode)') + parser.add_argument('--single-cls', action='store_true', help='treat as single-class dataset') + parser.add_argument('--augment', action='store_true', help='augmented inference') + parser.add_argument('--verbose', action='store_true', help='report mAP by class') + parser.add_argument('--save-txt', action='store_true', help='save results to *.txt') + parser.add_argument('--save-hybrid', action='store_true', help='save label+prediction hybrid results to *.txt') + parser.add_argument('--save-conf', action='store_true', help='save confidences in --save-txt labels') + parser.add_argument('--save-json', action='store_true', help='save a COCO-JSON results file') + parser.add_argument('--project', default=ROOT / 'runs/val-seg', help='save results to project/name') + parser.add_argument('--name', default='exp', help='save to project/name') + parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment') + parser.add_argument('--half', action='store_true', help='use FP16 half-precision inference') + parser.add_argument('--dnn', action='store_true', help='use OpenCV DNN for ONNX inference') + opt = parser.parse_args() + opt.data = check_yaml(opt.data) # check YAML + # opt.save_json |= opt.data.endswith('coco.yaml') + opt.save_txt |= opt.save_hybrid + print_args(vars(opt)) + return opt + + +def main(opt): + #check_requirements(requirements=ROOT / 'requirements.txt', exclude=('tensorboard', 'thop')) + + if opt.task in ('train', 'val', 'test'): # run normally + if opt.conf_thres > 0.001: # https://github.com/ultralytics/yolov5/issues/1466 + LOGGER.warning(f'WARNING ⚠️ confidence threshold {opt.conf_thres} > 0.001 produces invalid results') + if opt.save_hybrid: + LOGGER.warning('WARNING ⚠️ --save-hybrid returns high mAP from hybrid labels, not from predictions alone') + run(**vars(opt)) + + else: + weights = opt.weights if isinstance(opt.weights, list) else [opt.weights] + opt.half = torch.cuda.is_available() and opt.device != 'cpu' # FP16 for fastest results + if opt.task == 'speed': # speed benchmarks + # python val.py --task speed --data coco.yaml --batch 1 --weights yolo.pt... + opt.conf_thres, opt.iou_thres, opt.save_json = 0.25, 0.45, False + for opt.weights in weights: + run(**vars(opt), plots=False) + + elif opt.task == 'study': # speed vs mAP benchmarks + # python val.py --task study --data coco.yaml --iou 0.7 --weights yolo.pt... + for opt.weights in weights: + f = f'study_{Path(opt.data).stem}_{Path(opt.weights).stem}.txt' # filename to save to + x, y = list(range(256, 1536 + 128, 128)), [] # x axis (image sizes), y axis + for opt.imgsz in x: # img-size + LOGGER.info(f'\nRunning {f} --imgsz {opt.imgsz}...') + r, _, t = run(**vars(opt), plots=False) + y.append(r + t) # results and times + np.savetxt(f, y, fmt='%10.4g') # save + os.system('zip -r study.zip study_*.txt') + plot_val_study(x=x) # plot + + +if __name__ == "__main__": + opt = parse_opt() + main(opt) diff --git a/cv/3d_detection/yolov9/pytorch/tools/reparameterization.ipynb b/cv/3d_detection/yolov9/pytorch/tools/reparameterization.ipynb new file mode 100644 index 000000000..43b786d88 --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/tools/reparameterization.ipynb @@ -0,0 +1,244 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "4beac401", + "metadata": {}, + "outputs": [], + "source": [ + "import torch\n", + "from models.yolo import Model" + ] + }, + { + "cell_type": "markdown", + "id": "8680f822", + "metadata": {}, + "source": [ + "## Convert YOLOv9-C" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "59f0198d", + "metadata": {}, + "outputs": [], + "source": [ + "device = torch.device(\"cpu\")\n", + "cfg = \"./models/detect/gelan-c.yaml\"\n", + "model = Model(cfg, ch=3, nc=80, anchors=3)\n", + "#model = model.half()\n", + "model = model.to(device)\n", + "_ = model.eval()\n", + "ckpt = torch.load('./yolov9-c.pt', map_location='cpu')\n", + "model.names = ckpt['model'].names\n", + "model.nc = ckpt['model'].nc" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2de7e1be", + "metadata": {}, + "outputs": [], + "source": [ + "idx = 0\n", + "for k, v in model.state_dict().items():\n", + " if \"model.{}.\".format(idx) in k:\n", + " if idx < 22:\n", + " kr = k.replace(\"model.{}.\".format(idx), \"model.{}.\".format(idx+1))\n", + " model.state_dict()[k] -= model.state_dict()[k]\n", + " model.state_dict()[k] += ckpt['model'].state_dict()[kr]\n", + " elif \"model.{}.cv2.\".format(idx) in k:\n", + " kr = k.replace(\"model.{}.cv2.\".format(idx), \"model.{}.cv4.\".format(idx+16))\n", + " model.state_dict()[k] -= model.state_dict()[k]\n", + " model.state_dict()[k] += ckpt['model'].state_dict()[kr]\n", + " elif \"model.{}.cv3.\".format(idx) in k:\n", + " kr = k.replace(\"model.{}.cv3.\".format(idx), \"model.{}.cv5.\".format(idx+16))\n", + " model.state_dict()[k] -= model.state_dict()[k]\n", + " model.state_dict()[k] += ckpt['model'].state_dict()[kr]\n", + " elif \"model.{}.dfl.\".format(idx) in k:\n", + " kr = k.replace(\"model.{}.dfl.\".format(idx), \"model.{}.dfl2.\".format(idx+16))\n", + " model.state_dict()[k] -= model.state_dict()[k]\n", + " model.state_dict()[k] += ckpt['model'].state_dict()[kr]\n", + " else:\n", + " while True:\n", + " idx += 1\n", + " if \"model.{}.\".format(idx) in k:\n", + " break\n", + " if idx < 22:\n", + " kr = k.replace(\"model.{}.\".format(idx), \"model.{}.\".format(idx+1))\n", + " model.state_dict()[k] -= model.state_dict()[k]\n", + " model.state_dict()[k] += ckpt['model'].state_dict()[kr]\n", + " elif \"model.{}.cv2.\".format(idx) in k:\n", + " kr = k.replace(\"model.{}.cv2.\".format(idx), \"model.{}.cv4.\".format(idx+16))\n", + " model.state_dict()[k] -= model.state_dict()[k]\n", + " model.state_dict()[k] += ckpt['model'].state_dict()[kr]\n", + " elif \"model.{}.cv3.\".format(idx) in k:\n", + " kr = k.replace(\"model.{}.cv3.\".format(idx), \"model.{}.cv5.\".format(idx+16))\n", + " model.state_dict()[k] -= model.state_dict()[k]\n", + " model.state_dict()[k] += ckpt['model'].state_dict()[kr]\n", + " elif \"model.{}.dfl.\".format(idx) in k:\n", + " kr = k.replace(\"model.{}.dfl.\".format(idx), \"model.{}.dfl2.\".format(idx+16))\n", + " model.state_dict()[k] -= model.state_dict()[k]\n", + " model.state_dict()[k] += ckpt['model'].state_dict()[kr]\n", + "_ = model.eval()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "960796e3", + "metadata": {}, + "outputs": [], + "source": [ + "m_ckpt = {'model': model.half(),\n", + " 'optimizer': None,\n", + " 'best_fitness': None,\n", + " 'ema': None,\n", + " 'updates': None,\n", + " 'opt': None,\n", + " 'git': None,\n", + " 'date': None,\n", + " 'epoch': -1}\n", + "torch.save(m_ckpt, \"./yolov9-c-converted.pt\")" + ] + }, + { + "cell_type": "markdown", + "id": "47c6e6ae", + "metadata": {}, + "source": [ + "## Convert YOLOv9-E" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "801a1b7c", + "metadata": {}, + "outputs": [], + "source": [ + "device = torch.device(\"cpu\")\n", + "cfg = \"./models/detect/gelan-e.yaml\"\n", + "model = Model(cfg, ch=3, nc=80, anchors=3)\n", + "#model = model.half()\n", + "model = model.to(device)\n", + "_ = model.eval()\n", + "ckpt = torch.load('./yolov9-e.pt', map_location='cpu')\n", + "model.names = ckpt['model'].names\n", + "model.nc = ckpt['model'].nc" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a2ef4fe6", + "metadata": {}, + "outputs": [], + "source": [ + "idx = 0\n", + "for k, v in model.state_dict().items():\n", + " if \"model.{}.\".format(idx) in k:\n", + " if idx < 29:\n", + " kr = k.replace(\"model.{}.\".format(idx), \"model.{}.\".format(idx))\n", + " model.state_dict()[k] -= model.state_dict()[k]\n", + " model.state_dict()[k] += ckpt['model'].state_dict()[kr]\n", + " print(k, \"perfectly matched!!\")\n", + " elif idx < 42:\n", + " kr = k.replace(\"model.{}.\".format(idx), \"model.{}.\".format(idx+7))\n", + " model.state_dict()[k] -= model.state_dict()[k]\n", + " model.state_dict()[k] += ckpt['model'].state_dict()[kr]\n", + " print(k, \"perfectly matched!!\")\n", + " elif \"model.{}.cv2.\".format(idx) in k:\n", + " kr = k.replace(\"model.{}.cv2.\".format(idx), \"model.{}.cv4.\".format(idx+7))\n", + " model.state_dict()[k] -= model.state_dict()[k]\n", + " model.state_dict()[k] += ckpt['model'].state_dict()[kr]\n", + " print(k, \"perfectly matched!!\")\n", + " elif \"model.{}.cv3.\".format(idx) in k:\n", + " kr = k.replace(\"model.{}.cv3.\".format(idx), \"model.{}.cv5.\".format(idx+7))\n", + " model.state_dict()[k] -= model.state_dict()[k]\n", + " model.state_dict()[k] += ckpt['model'].state_dict()[kr]\n", + " print(k, \"perfectly matched!!\")\n", + " elif \"model.{}.dfl.\".format(idx) in k:\n", + " kr = k.replace(\"model.{}.dfl.\".format(idx), \"model.{}.dfl2.\".format(idx+7))\n", + " model.state_dict()[k] -= model.state_dict()[k]\n", + " model.state_dict()[k] += ckpt['model'].state_dict()[kr]\n", + " print(k, \"perfectly matched!!\")\n", + " else:\n", + " while True:\n", + " idx += 1\n", + " if \"model.{}.\".format(idx) in k:\n", + " break\n", + " if idx < 29:\n", + " kr = k.replace(\"model.{}.\".format(idx), \"model.{}.\".format(idx))\n", + " model.state_dict()[k] -= model.state_dict()[k]\n", + " model.state_dict()[k] += ckpt['model'].state_dict()[kr]\n", + " print(k, \"perfectly matched!!\")\n", + " elif idx < 42:\n", + " kr = k.replace(\"model.{}.\".format(idx), \"model.{}.\".format(idx+7))\n", + " model.state_dict()[k] -= model.state_dict()[k]\n", + " model.state_dict()[k] += ckpt['model'].state_dict()[kr]\n", + " print(k, \"perfectly matched!!\")\n", + " elif \"model.{}.cv2.\".format(idx) in k:\n", + " kr = k.replace(\"model.{}.cv2.\".format(idx), \"model.{}.cv4.\".format(idx+7))\n", + " model.state_dict()[k] -= model.state_dict()[k]\n", + " model.state_dict()[k] += ckpt['model'].state_dict()[kr]\n", + " print(k, \"perfectly matched!!\")\n", + " elif \"model.{}.cv3.\".format(idx) in k:\n", + " kr = k.replace(\"model.{}.cv3.\".format(idx), \"model.{}.cv5.\".format(idx+7))\n", + " model.state_dict()[k] -= model.state_dict()[k]\n", + " model.state_dict()[k] += ckpt['model'].state_dict()[kr]\n", + " print(k, \"perfectly matched!!\")\n", + " elif \"model.{}.dfl.\".format(idx) in k:\n", + " kr = k.replace(\"model.{}.dfl.\".format(idx), \"model.{}.dfl2.\".format(idx+7))\n", + " model.state_dict()[k] -= model.state_dict()[k]\n", + " model.state_dict()[k] += ckpt['model'].state_dict()[kr]\n", + " print(k, \"perfectly matched!!\")\n", + "_ = model.eval()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "27bc1869", + "metadata": {}, + "outputs": [], + "source": [ + "m_ckpt = {'model': model.half(),\n", + " 'optimizer': None,\n", + " 'best_fitness': None,\n", + " 'ema': None,\n", + " 'updates': None,\n", + " 'opt': None,\n", + " 'git': None,\n", + " 'date': None,\n", + " 'epoch': -1}\n", + "torch.save(m_ckpt, \"./yolov9-e-converted.pt\")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.12" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/cv/3d_detection/yolov9/pytorch/train.py b/cv/3d_detection/yolov9/pytorch/train.py new file mode 100644 index 000000000..59c372afe --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/train.py @@ -0,0 +1,634 @@ +import argparse +import math +import os +import random +import sys +import time +from copy import deepcopy +from datetime import datetime +from pathlib import Path + +import numpy as np +import torch +import torch.distributed as dist +import torch.nn as nn +import yaml +from torch.optim import lr_scheduler +from tqdm import tqdm + +FILE = Path(__file__).resolve() +ROOT = FILE.parents[0] # root directory +if str(ROOT) not in sys.path: + sys.path.append(str(ROOT)) # add ROOT to PATH +ROOT = Path(os.path.relpath(ROOT, Path.cwd())) # relative + +import val as validate # for end-of-epoch mAP +from models.experimental import attempt_load +from models.yolo import Model +from utils.autoanchor import check_anchors +from utils.autobatch import check_train_batch_size +from utils.callbacks import Callbacks +from utils.dataloaders import create_dataloader +from utils.downloads import attempt_download, is_url +from utils.general import (LOGGER, TQDM_BAR_FORMAT, check_amp, check_dataset, check_file, check_img_size, + check_suffix, check_yaml, colorstr, get_latest_run, increment_path, init_seeds, + intersect_dicts, labels_to_class_weights, labels_to_image_weights, methods, + one_cycle, one_flat_cycle, print_args, print_mutation, strip_optimizer, yaml_save) +from utils.loggers import Loggers +from utils.loggers.comet.comet_utils import check_comet_resume +from utils.loss_tal import ComputeLoss +from utils.metrics import fitness +from utils.plots import plot_evolve +from utils.torch_utils import (EarlyStopping, ModelEMA, de_parallel, select_device, smart_DDP, + smart_optimizer, smart_resume, torch_distributed_zero_first) + +LOCAL_RANK = int(os.getenv('LOCAL_RANK', -1)) # https://pytorch.org/docs/stable/elastic/run.html +RANK = int(os.getenv('RANK', -1)) +WORLD_SIZE = int(os.getenv('WORLD_SIZE', 1)) +GIT_INFO = None + + +def train(hyp, opt, device, callbacks): # hyp is path/to/hyp.yaml or hyp dictionary + save_dir, epochs, batch_size, weights, single_cls, evolve, data, cfg, resume, noval, nosave, workers, freeze = \ + Path(opt.save_dir), opt.epochs, opt.batch_size, opt.weights, opt.single_cls, opt.evolve, opt.data, opt.cfg, \ + opt.resume, opt.noval, opt.nosave, opt.workers, opt.freeze + callbacks.run('on_pretrain_routine_start') + + # Directories + w = save_dir / 'weights' # weights dir + (w.parent if evolve else w).mkdir(parents=True, exist_ok=True) # make dir + last, best = w / 'last.pt', w / 'best.pt' + last_striped, best_striped = w / 'last_striped.pt', w / 'best_striped.pt' + + # Hyperparameters + if isinstance(hyp, str): + with open(hyp, errors='ignore') as f: + hyp = yaml.safe_load(f) # load hyps dict + LOGGER.info(colorstr('hyperparameters: ') + ', '.join(f'{k}={v}' for k, v in hyp.items())) + hyp['anchor_t'] = 5.0 + opt.hyp = hyp.copy() # for saving hyps to checkpoints + + # Save run settings + if not evolve: + yaml_save(save_dir / 'hyp.yaml', hyp) + yaml_save(save_dir / 'opt.yaml', vars(opt)) + + # Loggers + data_dict = None + if RANK in {-1, 0}: + loggers = Loggers(save_dir, weights, opt, hyp, LOGGER) # loggers instance + + # Register actions + for k in methods(loggers): + callbacks.register_action(k, callback=getattr(loggers, k)) + + # Process custom dataset artifact link + data_dict = loggers.remote_dataset + if resume: # If resuming runs from remote artifact + weights, epochs, hyp, batch_size = opt.weights, opt.epochs, opt.hyp, opt.batch_size + + # Config + plots = not evolve and not opt.noplots # create plots + cuda = device.type != 'cpu' + init_seeds(opt.seed + 1 + RANK, deterministic=True) + with torch_distributed_zero_first(LOCAL_RANK): + data_dict = data_dict or check_dataset(data) # check if None + train_path, val_path = data_dict['train'], data_dict['val'] + nc = 1 if single_cls else int(data_dict['nc']) # number of classes + names = {0: 'item'} if single_cls and len(data_dict['names']) != 1 else data_dict['names'] # class names + #is_coco = isinstance(val_path, str) and val_path.endswith('coco/val2017.txt') # COCO dataset + is_coco = isinstance(val_path, str) and val_path.endswith('val2017.txt') # COCO dataset + + # Model + check_suffix(weights, '.pt') # check weights + pretrained = weights.endswith('.pt') + if pretrained: + with torch_distributed_zero_first(LOCAL_RANK): + weights = attempt_download(weights) # download if not found locally + ckpt = torch.load(weights, map_location='cpu') # load checkpoint to CPU to avoid CUDA memory leak + model = Model(cfg or ckpt['model'].yaml, ch=3, nc=nc, anchors=hyp.get('anchors')).to(device) # create + exclude = ['anchor'] if (cfg or hyp.get('anchors')) and not resume else [] # exclude keys + csd = ckpt['model'].float().state_dict() # checkpoint state_dict as FP32 + csd = intersect_dicts(csd, model.state_dict(), exclude=exclude) # intersect + model.load_state_dict(csd, strict=False) # load + LOGGER.info(f'Transferred {len(csd)}/{len(model.state_dict())} items from {weights}') # report + else: + model = Model(cfg, ch=3, nc=nc, anchors=hyp.get('anchors')).to(device) # create + amp = check_amp(model) # check AMP + + # Freeze + freeze = [f'model.{x}.' for x in (freeze if len(freeze) > 1 else range(freeze[0]))] # layers to freeze + for k, v in model.named_parameters(): + # v.requires_grad = True # train all layers TODO: uncomment this line as in master + # v.register_hook(lambda x: torch.nan_to_num(x)) # NaN to 0 (commented for erratic training results) + if any(x in k for x in freeze): + LOGGER.info(f'freezing {k}') + v.requires_grad = False + + # Image size + gs = max(int(model.stride.max()), 32) # grid size (max stride) + imgsz = check_img_size(opt.imgsz, gs, floor=gs * 2) # verify imgsz is gs-multiple + + # Batch size + if RANK == -1 and batch_size == -1: # single-GPU only, estimate best batch size + batch_size = check_train_batch_size(model, imgsz, amp) + loggers.on_params_update({"batch_size": batch_size}) + + # Optimizer + nbs = 64 # nominal batch size + accumulate = max(round(nbs / batch_size), 1) # accumulate loss before optimizing + hyp['weight_decay'] *= batch_size * accumulate / nbs # scale weight_decay + optimizer = smart_optimizer(model, opt.optimizer, hyp['lr0'], hyp['momentum'], hyp['weight_decay']) + + # Scheduler + if opt.cos_lr: + lf = one_cycle(1, hyp['lrf'], epochs) # cosine 1->hyp['lrf'] + elif opt.flat_cos_lr: + lf = one_flat_cycle(1, hyp['lrf'], epochs) # flat cosine 1->hyp['lrf'] + elif opt.fixed_lr: + lf = lambda x: 1.0 + else: + lf = lambda x: (1 - x / epochs) * (1.0 - hyp['lrf']) + hyp['lrf'] # linear + + scheduler = lr_scheduler.LambdaLR(optimizer, lr_lambda=lf) + # from utils.plots import plot_lr_scheduler; plot_lr_scheduler(optimizer, scheduler, epochs) + + # EMA + ema = ModelEMA(model) if RANK in {-1, 0} else None + + # Resume + best_fitness, start_epoch = 0.0, 0 + if pretrained: + if resume: + best_fitness, start_epoch, epochs = smart_resume(ckpt, optimizer, ema, weights, epochs, resume) + del ckpt, csd + + # DP mode + if cuda and RANK == -1 and torch.cuda.device_count() > 1: + LOGGER.warning('WARNING ⚠️ DP not recommended, use torch.distributed.run for best DDP Multi-GPU results.') + model = torch.nn.DataParallel(model) + + # SyncBatchNorm + if opt.sync_bn and cuda and RANK != -1: + model = torch.nn.SyncBatchNorm.convert_sync_batchnorm(model).to(device) + LOGGER.info('Using SyncBatchNorm()') + + # Trainloader + train_loader, dataset = create_dataloader(train_path, + imgsz, + batch_size // WORLD_SIZE, + gs, + single_cls, + hyp=hyp, + augment=True, + cache=None if opt.cache == 'val' else opt.cache, + rect=opt.rect, + rank=LOCAL_RANK, + workers=workers, + image_weights=opt.image_weights, + close_mosaic=opt.close_mosaic != 0, + quad=opt.quad, + prefix=colorstr('train: '), + shuffle=True, + min_items=opt.min_items) + labels = np.concatenate(dataset.labels, 0) + mlc = int(labels[:, 0].max()) # max label class + assert mlc < nc, f'Label class {mlc} exceeds nc={nc} in {data}. Possible class labels are 0-{nc - 1}' + + # Process 0 + if RANK in {-1, 0}: + val_loader = create_dataloader(val_path, + imgsz, + batch_size // WORLD_SIZE * 2, + gs, + single_cls, + hyp=hyp, + cache=None if noval else opt.cache, + rect=True, + rank=-1, + workers=workers * 2, + pad=0.5, + prefix=colorstr('val: '))[0] + + if not resume: + # if not opt.noautoanchor: + # check_anchors(dataset, model=model, thr=hyp['anchor_t'], imgsz=imgsz) # run AutoAnchor + model.half().float() # pre-reduce anchor precision + + callbacks.run('on_pretrain_routine_end', labels, names) + + # DDP mode + if cuda and RANK != -1: + model = smart_DDP(model) + + # Model attributes + nl = de_parallel(model).model[-1].nl # number of detection layers (to scale hyps) + #hyp['box'] *= 3 / nl # scale to layers + #hyp['cls'] *= nc / 80 * 3 / nl # scale to classes and layers + #hyp['obj'] *= (imgsz / 640) ** 2 * 3 / nl # scale to image size and layers + hyp['label_smoothing'] = opt.label_smoothing + model.nc = nc # attach number of classes to model + model.hyp = hyp # attach hyperparameters to model + model.class_weights = labels_to_class_weights(dataset.labels, nc).to(device) * nc # attach class weights + model.names = names + + # Start training + t0 = time.time() + nb = len(train_loader) # number of batches + nw = max(round(hyp['warmup_epochs'] * nb), 100) # number of warmup iterations, max(3 epochs, 100 iterations) + # nw = min(nw, (epochs - start_epoch) / 2 * nb) # limit warmup to < 1/2 of training + last_opt_step = -1 + maps = np.zeros(nc) # mAP per class + results = (0, 0, 0, 0, 0, 0, 0) # P, R, mAP@.5, mAP@.5-.95, val_loss(box, obj, cls) + scheduler.last_epoch = start_epoch - 1 # do not move + scaler = torch.cuda.amp.GradScaler(enabled=amp) + stopper, stop = EarlyStopping(patience=opt.patience), False + compute_loss = ComputeLoss(model) # init loss class + callbacks.run('on_train_start') + LOGGER.info(f'Image sizes {imgsz} train, {imgsz} val\n' + f'Using {train_loader.num_workers * WORLD_SIZE} dataloader workers\n' + f"Logging results to {colorstr('bold', save_dir)}\n" + f'Starting training for {epochs} epochs...') + for epoch in range(start_epoch, epochs): # epoch ------------------------------------------------------------------ + callbacks.run('on_train_epoch_start') + model.train() + + # Update image weights (optional, single-GPU only) + if opt.image_weights: + cw = model.class_weights.cpu().numpy() * (1 - maps) ** 2 / nc # class weights + iw = labels_to_image_weights(dataset.labels, nc=nc, class_weights=cw) # image weights + dataset.indices = random.choices(range(dataset.n), weights=iw, k=dataset.n) # rand weighted idx + if epoch == (epochs - opt.close_mosaic): + LOGGER.info("Closing dataloader mosaic") + dataset.mosaic = False + + # Update mosaic border (optional) + # b = int(random.uniform(0.25 * imgsz, 0.75 * imgsz + gs) // gs * gs) + # dataset.mosaic_border = [b - imgsz, -b] # height, width borders + + mloss = torch.zeros(3, device=device) # mean losses + if RANK != -1: + train_loader.sampler.set_epoch(epoch) + pbar = enumerate(train_loader) + LOGGER.info(('\n' + '%11s' * 7) % ('Epoch', 'GPU_mem', 'box_loss', 'cls_loss', 'dfl_loss', 'Instances', 'Size')) + if RANK in {-1, 0}: + pbar = tqdm(pbar, total=nb, bar_format=TQDM_BAR_FORMAT) # progress bar + optimizer.zero_grad() + for i, (imgs, targets, paths, _) in pbar: # batch ------------------------------------------------------------- + callbacks.run('on_train_batch_start') + ni = i + nb * epoch # number integrated batches (since train start) + imgs = imgs.to(device, non_blocking=True).float() / 255 # uint8 to float32, 0-255 to 0.0-1.0 + + # Warmup + if ni <= nw: + xi = [0, nw] # x interp + # compute_loss.gr = np.interp(ni, xi, [0.0, 1.0]) # iou loss ratio (obj_loss = 1.0 or iou) + accumulate = max(1, np.interp(ni, xi, [1, nbs / batch_size]).round()) + for j, x in enumerate(optimizer.param_groups): + # bias lr falls from 0.1 to lr0, all other lrs rise from 0.0 to lr0 + x['lr'] = np.interp(ni, xi, [hyp['warmup_bias_lr'] if j == 0 else 0.0, x['initial_lr'] * lf(epoch)]) + if 'momentum' in x: + x['momentum'] = np.interp(ni, xi, [hyp['warmup_momentum'], hyp['momentum']]) + + # Multi-scale + if opt.multi_scale: + sz = random.randrange(imgsz * 0.5, imgsz * 1.5 + gs) // gs * gs # size + sf = sz / max(imgs.shape[2:]) # scale factor + if sf != 1: + ns = [math.ceil(x * sf / gs) * gs for x in imgs.shape[2:]] # new shape (stretched to gs-multiple) + imgs = nn.functional.interpolate(imgs, size=ns, mode='bilinear', align_corners=False) + + # Forward + with torch.cuda.amp.autocast(amp): + pred = model(imgs) # forward + loss, loss_items = compute_loss(pred, targets.to(device)) # loss scaled by batch_size + if RANK != -1: + loss *= WORLD_SIZE # gradient averaged between devices in DDP mode + if opt.quad: + loss *= 4. + + # Backward + scaler.scale(loss).backward() + + # Optimize - https://pytorch.org/docs/master/notes/amp_examples.html + if ni - last_opt_step >= accumulate: + scaler.unscale_(optimizer) # unscale gradients + torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=10.0) # clip gradients + scaler.step(optimizer) # optimizer.step + scaler.update() + optimizer.zero_grad() + if ema: + ema.update(model) + last_opt_step = ni + + # Log + if RANK in {-1, 0}: + mloss = (mloss * i + loss_items) / (i + 1) # update mean losses + mem = f'{torch.cuda.memory_reserved() / 1E9 if torch.cuda.is_available() else 0:.3g}G' # (GB) + pbar.set_description(('%11s' * 2 + '%11.4g' * 5) % + (f'{epoch}/{epochs - 1}', mem, *mloss, targets.shape[0], imgs.shape[-1])) + callbacks.run('on_train_batch_end', model, ni, imgs, targets, paths, list(mloss)) + if callbacks.stop_training: + return + # end batch ------------------------------------------------------------------------------------------------ + + # Scheduler + lr = [x['lr'] for x in optimizer.param_groups] # for loggers + scheduler.step() + + if RANK in {-1, 0}: + # mAP + callbacks.run('on_train_epoch_end', epoch=epoch) + ema.update_attr(model, include=['yaml', 'nc', 'hyp', 'names', 'stride', 'class_weights']) + final_epoch = (epoch + 1 == epochs) or stopper.possible_stop + if not noval or final_epoch: # Calculate mAP + results, maps, _ = validate.run(data_dict, + batch_size=batch_size // WORLD_SIZE * 2, + imgsz=imgsz, + half=amp, + model=ema.ema, + single_cls=single_cls, + dataloader=val_loader, + save_dir=save_dir, + plots=False, + callbacks=callbacks, + compute_loss=compute_loss) + + # Update best mAP + fi = fitness(np.array(results).reshape(1, -1)) # weighted combination of [P, R, mAP@.5, mAP@.5-.95] + stop = stopper(epoch=epoch, fitness=fi) # early stop check + if fi > best_fitness: + best_fitness = fi + log_vals = list(mloss) + list(results) + lr + callbacks.run('on_fit_epoch_end', log_vals, epoch, best_fitness, fi) + + # Save model + if (not nosave) or (final_epoch and not evolve): # if save + ckpt = { + 'epoch': epoch, + 'best_fitness': best_fitness, + 'model': deepcopy(de_parallel(model)).half(), + 'ema': deepcopy(ema.ema).half(), + 'updates': ema.updates, + 'optimizer': optimizer.state_dict(), + 'opt': vars(opt), + 'git': GIT_INFO, # {remote, branch, commit} if a git repo + 'date': datetime.now().isoformat()} + + # Save last, best and delete + torch.save(ckpt, last) + if best_fitness == fi: + torch.save(ckpt, best) + if opt.save_period > 0 and epoch % opt.save_period == 0: + torch.save(ckpt, w / f'epoch{epoch}.pt') + del ckpt + callbacks.run('on_model_save', last, epoch, final_epoch, best_fitness, fi) + + # EarlyStopping + if RANK != -1: # if DDP training + broadcast_list = [stop if RANK == 0 else None] + dist.broadcast_object_list(broadcast_list, 0) # broadcast 'stop' to all ranks + if RANK != 0: + stop = broadcast_list[0] + if stop: + break # must break all DDP ranks + + # end epoch ---------------------------------------------------------------------------------------------------- + # end training ----------------------------------------------------------------------------------------------------- + if RANK in {-1, 0}: + LOGGER.info(f'\n{epoch - start_epoch + 1} epochs completed in {(time.time() - t0) / 3600:.3f} hours.') + for f in last, best: + if f.exists(): + if f is last: + strip_optimizer(f, last_striped) # strip optimizers + else: + strip_optimizer(f, best_striped) # strip optimizers + if f is best: + LOGGER.info(f'\nValidating {f}...') + results, _, _ = validate.run( + data_dict, + batch_size=batch_size // WORLD_SIZE * 2, + imgsz=imgsz, + model=attempt_load(f, device).half(), + single_cls=single_cls, + dataloader=val_loader, + save_dir=save_dir, + save_json=is_coco, + verbose=True, + plots=plots, + callbacks=callbacks, + compute_loss=compute_loss) # val best model with plots + if is_coco: + callbacks.run('on_fit_epoch_end', list(mloss) + list(results) + lr, epoch, best_fitness, fi) + + callbacks.run('on_train_end', last, best, epoch, results) + + torch.cuda.empty_cache() + return results + + +def parse_opt(known=False): + parser = argparse.ArgumentParser() + # parser.add_argument('--weights', type=str, default=ROOT / 'yolo.pt', help='initial weights path') + # parser.add_argument('--cfg', type=str, default='', help='model.yaml path') + parser.add_argument('--weights', type=str, default='', help='initial weights path') + parser.add_argument('--cfg', type=str, default='yolo.yaml', help='model.yaml path') + parser.add_argument('--data', type=str, default=ROOT / 'data/coco128.yaml', help='dataset.yaml path') + parser.add_argument('--hyp', type=str, default=ROOT / 'data/hyps/hyp.scratch-low.yaml', help='hyperparameters path') + parser.add_argument('--epochs', type=int, default=100, help='total training epochs') + parser.add_argument('--batch-size', type=int, default=16, help='total batch size for all GPUs, -1 for autobatch') + parser.add_argument('--imgsz', '--img', '--img-size', type=int, default=640, help='train, val image size (pixels)') + parser.add_argument('--rect', action='store_true', help='rectangular training') + parser.add_argument('--resume', nargs='?', const=True, default=False, help='resume most recent training') + parser.add_argument('--nosave', action='store_true', help='only save final checkpoint') + parser.add_argument('--noval', action='store_true', help='only validate final epoch') + parser.add_argument('--noautoanchor', action='store_true', help='disable AutoAnchor') + parser.add_argument('--noplots', action='store_true', help='save no plot files') + parser.add_argument('--evolve', type=int, nargs='?', const=300, help='evolve hyperparameters for x generations') + parser.add_argument('--bucket', type=str, default='', help='gsutil bucket') + parser.add_argument('--cache', type=str, nargs='?', const='ram', help='image --cache ram/disk') + parser.add_argument('--image-weights', action='store_true', help='use weighted image selection for training') + parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu') + parser.add_argument('--multi-scale', action='store_true', help='vary img-size +/- 50%%') + parser.add_argument('--single-cls', action='store_true', help='train multi-class data as single-class') + parser.add_argument('--optimizer', type=str, choices=['SGD', 'Adam', 'AdamW', 'LION'], default='SGD', help='optimizer') + parser.add_argument('--sync-bn', action='store_true', help='use SyncBatchNorm, only available in DDP mode') + parser.add_argument('--workers', type=int, default=8, help='max dataloader workers (per RANK in DDP mode)') + parser.add_argument('--project', default=ROOT / 'runs/train', help='save to project/name') + parser.add_argument('--name', default='exp', help='save to project/name') + parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment') + parser.add_argument('--quad', action='store_true', help='quad dataloader') + parser.add_argument('--cos-lr', action='store_true', help='cosine LR scheduler') + parser.add_argument('--flat-cos-lr', action='store_true', help='flat cosine LR scheduler') + parser.add_argument('--fixed-lr', action='store_true', help='fixed LR scheduler') + parser.add_argument('--label-smoothing', type=float, default=0.0, help='Label smoothing epsilon') + parser.add_argument('--patience', type=int, default=100, help='EarlyStopping patience (epochs without improvement)') + parser.add_argument('--freeze', nargs='+', type=int, default=[0], help='Freeze layers: backbone=10, first3=0 1 2') + parser.add_argument('--save-period', type=int, default=-1, help='Save checkpoint every x epochs (disabled if < 1)') + parser.add_argument('--seed', type=int, default=0, help='Global training seed') + parser.add_argument('--local_rank', type=int, default=-1, help='Automatic DDP Multi-GPU argument, do not modify') + parser.add_argument('--min-items', type=int, default=0, help='Experimental') + parser.add_argument('--close-mosaic', type=int, default=0, help='Experimental') + + # Logger arguments + parser.add_argument('--entity', default=None, help='Entity') + parser.add_argument('--upload_dataset', nargs='?', const=True, default=False, help='Upload data, "val" option') + parser.add_argument('--bbox_interval', type=int, default=-1, help='Set bounding-box image logging interval') + parser.add_argument('--artifact_alias', type=str, default='latest', help='Version of dataset artifact to use') + + return parser.parse_known_args()[0] if known else parser.parse_args() + + +def main(opt, callbacks=Callbacks()): + # Checks + if RANK in {-1, 0}: + print_args(vars(opt)) + + # Resume (from specified or most recent last.pt) + if opt.resume and not check_comet_resume(opt) and not opt.evolve: + last = Path(check_file(opt.resume) if isinstance(opt.resume, str) else get_latest_run()) + opt_yaml = last.parent.parent / 'opt.yaml' # train options yaml + opt_data = opt.data # original dataset + if opt_yaml.is_file(): + with open(opt_yaml, errors='ignore') as f: + d = yaml.safe_load(f) + else: + d = torch.load(last, map_location='cpu')['opt'] + opt = argparse.Namespace(**d) # replace + opt.cfg, opt.weights, opt.resume = '', str(last), True # reinstate + if is_url(opt_data): + opt.data = check_file(opt_data) # avoid HUB resume auth timeout + else: + opt.data, opt.cfg, opt.hyp, opt.weights, opt.project = \ + check_file(opt.data), check_yaml(opt.cfg), check_yaml(opt.hyp), str(opt.weights), str(opt.project) # checks + assert len(opt.cfg) or len(opt.weights), 'either --cfg or --weights must be specified' + if opt.evolve: + if opt.project == str(ROOT / 'runs/train'): # if default project name, rename to runs/evolve + opt.project = str(ROOT / 'runs/evolve') + opt.exist_ok, opt.resume = opt.resume, False # pass resume to exist_ok and disable resume + if opt.name == 'cfg': + opt.name = Path(opt.cfg).stem # use model.yaml as name + opt.save_dir = str(increment_path(Path(opt.project) / opt.name, exist_ok=opt.exist_ok)) + + # DDP mode + device = select_device(opt.device, batch_size=opt.batch_size) + if LOCAL_RANK != -1: + msg = 'is not compatible with YOLO Multi-GPU DDP training' + assert not opt.image_weights, f'--image-weights {msg}' + assert not opt.evolve, f'--evolve {msg}' + assert opt.batch_size != -1, f'AutoBatch with --batch-size -1 {msg}, please pass a valid --batch-size' + assert opt.batch_size % WORLD_SIZE == 0, f'--batch-size {opt.batch_size} must be multiple of WORLD_SIZE' + assert torch.cuda.device_count() > LOCAL_RANK, 'insufficient CUDA devices for DDP command' + torch.cuda.set_device(LOCAL_RANK) + device = torch.device('cuda', LOCAL_RANK) + dist.init_process_group(backend="nccl" if dist.is_nccl_available() else "gloo") + + # Train + if not opt.evolve: + train(opt.hyp, opt, device, callbacks) + + # Evolve hyperparameters (optional) + else: + # Hyperparameter evolution metadata (mutation scale 0-1, lower_limit, upper_limit) + meta = { + 'lr0': (1, 1e-5, 1e-1), # initial learning rate (SGD=1E-2, Adam=1E-3) + 'lrf': (1, 0.01, 1.0), # final OneCycleLR learning rate (lr0 * lrf) + 'momentum': (0.3, 0.6, 0.98), # SGD momentum/Adam beta1 + 'weight_decay': (1, 0.0, 0.001), # optimizer weight decay + 'warmup_epochs': (1, 0.0, 5.0), # warmup epochs (fractions ok) + 'warmup_momentum': (1, 0.0, 0.95), # warmup initial momentum + 'warmup_bias_lr': (1, 0.0, 0.2), # warmup initial bias lr + 'box': (1, 0.02, 0.2), # box loss gain + 'cls': (1, 0.2, 4.0), # cls loss gain + 'cls_pw': (1, 0.5, 2.0), # cls BCELoss positive_weight + 'obj': (1, 0.2, 4.0), # obj loss gain (scale with pixels) + 'obj_pw': (1, 0.5, 2.0), # obj BCELoss positive_weight + 'iou_t': (0, 0.1, 0.7), # IoU training threshold + 'anchor_t': (1, 2.0, 8.0), # anchor-multiple threshold + 'anchors': (2, 2.0, 10.0), # anchors per output grid (0 to ignore) + 'fl_gamma': (0, 0.0, 2.0), # focal loss gamma (efficientDet default gamma=1.5) + 'hsv_h': (1, 0.0, 0.1), # image HSV-Hue augmentation (fraction) + 'hsv_s': (1, 0.0, 0.9), # image HSV-Saturation augmentation (fraction) + 'hsv_v': (1, 0.0, 0.9), # image HSV-Value augmentation (fraction) + 'degrees': (1, 0.0, 45.0), # image rotation (+/- deg) + 'translate': (1, 0.0, 0.9), # image translation (+/- fraction) + 'scale': (1, 0.0, 0.9), # image scale (+/- gain) + 'shear': (1, 0.0, 10.0), # image shear (+/- deg) + 'perspective': (0, 0.0, 0.001), # image perspective (+/- fraction), range 0-0.001 + 'flipud': (1, 0.0, 1.0), # image flip up-down (probability) + 'fliplr': (0, 0.0, 1.0), # image flip left-right (probability) + 'mosaic': (1, 0.0, 1.0), # image mixup (probability) + 'mixup': (1, 0.0, 1.0), # image mixup (probability) + 'copy_paste': (1, 0.0, 1.0)} # segment copy-paste (probability) + + with open(opt.hyp, errors='ignore') as f: + hyp = yaml.safe_load(f) # load hyps dict + if 'anchors' not in hyp: # anchors commented in hyp.yaml + hyp['anchors'] = 3 + if opt.noautoanchor: + del hyp['anchors'], meta['anchors'] + opt.noval, opt.nosave, save_dir = True, True, Path(opt.save_dir) # only val/save final epoch + # ei = [isinstance(x, (int, float)) for x in hyp.values()] # evolvable indices + evolve_yaml, evolve_csv = save_dir / 'hyp_evolve.yaml', save_dir / 'evolve.csv' + if opt.bucket: + os.system(f'gsutil cp gs://{opt.bucket}/evolve.csv {evolve_csv}') # download evolve.csv if exists + + for _ in range(opt.evolve): # generations to evolve + if evolve_csv.exists(): # if evolve.csv exists: select best hyps and mutate + # Select parent(s) + parent = 'single' # parent selection method: 'single' or 'weighted' + x = np.loadtxt(evolve_csv, ndmin=2, delimiter=',', skiprows=1) + n = min(5, len(x)) # number of previous results to consider + x = x[np.argsort(-fitness(x))][:n] # top n mutations + w = fitness(x) - fitness(x).min() + 1E-6 # weights (sum > 0) + if parent == 'single' or len(x) == 1: + # x = x[random.randint(0, n - 1)] # random selection + x = x[random.choices(range(n), weights=w)[0]] # weighted selection + elif parent == 'weighted': + x = (x * w.reshape(n, 1)).sum(0) / w.sum() # weighted combination + + # Mutate + mp, s = 0.8, 0.2 # mutation probability, sigma + npr = np.random + npr.seed(int(time.time())) + g = np.array([meta[k][0] for k in hyp.keys()]) # gains 0-1 + ng = len(meta) + v = np.ones(ng) + while all(v == 1): # mutate until a change occurs (prevent duplicates) + v = (g * (npr.random(ng) < mp) * npr.randn(ng) * npr.random() * s + 1).clip(0.3, 3.0) + for i, k in enumerate(hyp.keys()): # plt.hist(v.ravel(), 300) + hyp[k] = float(x[i + 7] * v[i]) # mutate + + # Constrain to limits + for k, v in meta.items(): + hyp[k] = max(hyp[k], v[1]) # lower limit + hyp[k] = min(hyp[k], v[2]) # upper limit + hyp[k] = round(hyp[k], 5) # significant digits + + # Train mutation + results = train(hyp.copy(), opt, device, callbacks) + callbacks = Callbacks() + # Write mutation results + keys = ('metrics/precision', 'metrics/recall', 'metrics/mAP_0.5', 'metrics/mAP_0.5:0.95', 'val/box_loss', + 'val/obj_loss', 'val/cls_loss') + print_mutation(keys, results, hyp.copy(), save_dir, opt.bucket) + + # Plot results + plot_evolve(evolve_csv) + LOGGER.info(f'Hyperparameter evolution finished {opt.evolve} generations\n' + f"Results saved to {colorstr('bold', save_dir)}\n" + f'Usage example: $ python train.py --hyp {evolve_yaml}') + + +def run(**kwargs): + # Usage: import train; train.run(data='coco128.yaml', imgsz=320, weights='yolo.pt') + opt = parse_opt(True) + for k, v in kwargs.items(): + setattr(opt, k, v) + main(opt) + return opt + + +if __name__ == "__main__": + opt = parse_opt() + main(opt) diff --git a/cv/3d_detection/yolov9/pytorch/train_dual.py b/cv/3d_detection/yolov9/pytorch/train_dual.py new file mode 100644 index 000000000..672e32426 --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/train_dual.py @@ -0,0 +1,644 @@ +import argparse +import math +import os +import random +import sys +import time +from copy import deepcopy +from datetime import datetime +from pathlib import Path + +import numpy as np +import torch +import torch.distributed as dist +import torch.nn as nn +import yaml +from torch.optim import lr_scheduler +from tqdm import tqdm + +FILE = Path(__file__).resolve() +ROOT = FILE.parents[0] # YOLO root directory +if str(ROOT) not in sys.path: + sys.path.append(str(ROOT)) # add ROOT to PATH +ROOT = Path(os.path.relpath(ROOT, Path.cwd())) # relative + +import val_dual as validate # for end-of-epoch mAP +from models.experimental import attempt_load +from models.yolo import Model +from utils.autoanchor import check_anchors +from utils.autobatch import check_train_batch_size +from utils.callbacks import Callbacks +from utils.dataloaders import create_dataloader +from utils.downloads import attempt_download, is_url +from utils.general import (LOGGER, TQDM_BAR_FORMAT, check_amp, check_dataset, check_file, check_git_info, + check_git_status, check_img_size, check_requirements, check_suffix, check_yaml, colorstr, + get_latest_run, increment_path, init_seeds, intersect_dicts, labels_to_class_weights, + labels_to_image_weights, methods, one_cycle, print_args, print_mutation, strip_optimizer, + yaml_save, one_flat_cycle) +from utils.loggers import Loggers +from utils.loggers.comet.comet_utils import check_comet_resume +from utils.loss_tal_dual import ComputeLoss +#from utils.loss_tal_dual import ComputeLossLH as ComputeLoss +#from utils.loss_tal_dual import ComputeLossLHCF as ComputeLoss +from utils.metrics import fitness +from utils.plots import plot_evolve +from utils.torch_utils import (EarlyStopping, ModelEMA, de_parallel, select_device, smart_DDP, smart_optimizer, + smart_resume, torch_distributed_zero_first) + +LOCAL_RANK = int(os.getenv('LOCAL_RANK', -1)) # https://pytorch.org/docs/stable/elastic/run.html +RANK = int(os.getenv('RANK', -1)) +WORLD_SIZE = int(os.getenv('WORLD_SIZE', 1)) +GIT_INFO = None#check_git_info() + + +def train(hyp, opt, device, callbacks): # hyp is path/to/hyp.yaml or hyp dictionary + save_dir, epochs, batch_size, weights, single_cls, evolve, data, cfg, resume, noval, nosave, workers, freeze = \ + Path(opt.save_dir), opt.epochs, opt.batch_size, opt.weights, opt.single_cls, opt.evolve, opt.data, opt.cfg, \ + opt.resume, opt.noval, opt.nosave, opt.workers, opt.freeze + callbacks.run('on_pretrain_routine_start') + + # Directories + w = save_dir / 'weights' # weights dir + (w.parent if evolve else w).mkdir(parents=True, exist_ok=True) # make dir + last, best = w / 'last.pt', w / 'best.pt' + + # Hyperparameters + if isinstance(hyp, str): + with open(hyp, errors='ignore') as f: + hyp = yaml.safe_load(f) # load hyps dict + LOGGER.info(colorstr('hyperparameters: ') + ', '.join(f'{k}={v}' for k, v in hyp.items())) + hyp['anchor_t'] = 5.0 + opt.hyp = hyp.copy() # for saving hyps to checkpoints + + # Save run settings + if not evolve: + yaml_save(save_dir / 'hyp.yaml', hyp) + yaml_save(save_dir / 'opt.yaml', vars(opt)) + + # Loggers + data_dict = None + if RANK in {-1, 0}: + loggers = Loggers(save_dir, weights, opt, hyp, LOGGER) # loggers instance + + # Register actions + for k in methods(loggers): + callbacks.register_action(k, callback=getattr(loggers, k)) + + # Process custom dataset artifact link + data_dict = loggers.remote_dataset + if resume: # If resuming runs from remote artifact + weights, epochs, hyp, batch_size = opt.weights, opt.epochs, opt.hyp, opt.batch_size + + # Config + plots = not evolve and not opt.noplots # create plots + cuda = device.type != 'cpu' + init_seeds(opt.seed + 1 + RANK, deterministic=True) + with torch_distributed_zero_first(LOCAL_RANK): + data_dict = data_dict or check_dataset(data) # check if None + train_path, val_path = data_dict['train'], data_dict['val'] + nc = 1 if single_cls else int(data_dict['nc']) # number of classes + names = {0: 'item'} if single_cls and len(data_dict['names']) != 1 else data_dict['names'] # class names + #is_coco = isinstance(val_path, str) and val_path.endswith('coco/val2017.txt') # COCO dataset + is_coco = isinstance(val_path, str) and val_path.endswith('val2017.txt') # COCO dataset + + # Model + check_suffix(weights, '.pt') # check weights + pretrained = weights.endswith('.pt') + if pretrained: + with torch_distributed_zero_first(LOCAL_RANK): + weights = attempt_download(weights) # download if not found locally + ckpt = torch.load(weights, map_location='cpu') # load checkpoint to CPU to avoid CUDA memory leak + model = Model(cfg or ckpt['model'].yaml, ch=3, nc=nc, anchors=hyp.get('anchors')).to(device) # create + exclude = ['anchor'] if (cfg or hyp.get('anchors')) and not resume else [] # exclude keys + csd = ckpt['model'].float().state_dict() # checkpoint state_dict as FP32 + csd = intersect_dicts(csd, model.state_dict(), exclude=exclude) # intersect + model.load_state_dict(csd, strict=False) # load + LOGGER.info(f'Transferred {len(csd)}/{len(model.state_dict())} items from {weights}') # report + else: + model = Model(cfg, ch=3, nc=nc, anchors=hyp.get('anchors')).to(device) # create + amp = check_amp(model) # check AMP + + # Freeze + freeze = [f'model.{x}.' for x in (freeze if len(freeze) > 1 else range(freeze[0]))] # layers to freeze + for k, v in model.named_parameters(): + # v.requires_grad = True # train all layers TODO: uncomment this line as in master + # v.register_hook(lambda x: torch.nan_to_num(x)) # NaN to 0 (commented for erratic training results) + if any(x in k for x in freeze): + LOGGER.info(f'freezing {k}') + v.requires_grad = False + + # Image size + gs = max(int(model.stride.max()), 32) # grid size (max stride) + imgsz = check_img_size(opt.imgsz, gs, floor=gs * 2) # verify imgsz is gs-multiple + + # Batch size + if RANK == -1 and batch_size == -1: # single-GPU only, estimate best batch size + batch_size = check_train_batch_size(model, imgsz, amp) + loggers.on_params_update({"batch_size": batch_size}) + + # Optimizer + nbs = 64 # nominal batch size + accumulate = max(round(nbs / batch_size), 1) # accumulate loss before optimizing + hyp['weight_decay'] *= batch_size * accumulate / nbs # scale weight_decay + optimizer = smart_optimizer(model, opt.optimizer, hyp['lr0'], hyp['momentum'], hyp['weight_decay']) + + # Scheduler + if opt.cos_lr: + lf = one_cycle(1, hyp['lrf'], epochs) # cosine 1->hyp['lrf'] + elif opt.flat_cos_lr: + lf = one_flat_cycle(1, hyp['lrf'], epochs) # flat cosine 1->hyp['lrf'] + elif opt.fixed_lr: + lf = lambda x: 1.0 + else: + lf = lambda x: (1 - x / epochs) * (1.0 - hyp['lrf']) + hyp['lrf'] # linear + + # def lf(x): # saw + # return (1 - (x % 30) / 30) * (1 - x / epochs) * (1.0 - hyp['lrf']) + hyp['lrf'] + # + # def lf(x): # triangle start at min + # return 2 * abs(x / 30 - math.floor(x / 30 + 1 / 2)) * (1 - x / epochs) * (1.0 - hyp['lrf']) + hyp['lrf'] + # + # def lf(x): # triangle start at max + # return 2 * abs(x / 32 + .5 - math.floor(x / 32 + 1)) * (1 - x / epochs) * (1.0 - hyp['lrf']) + hyp['lrf'] + + scheduler = lr_scheduler.LambdaLR(optimizer, lr_lambda=lf) + # from utils.plots import plot_lr_scheduler; plot_lr_scheduler(optimizer, scheduler, epochs) + + # EMA + ema = ModelEMA(model) if RANK in {-1, 0} else None + + # Resume + best_fitness, start_epoch = 0.0, 0 + if pretrained: + if resume: + best_fitness, start_epoch, epochs = smart_resume(ckpt, optimizer, ema, weights, epochs, resume) + del ckpt, csd + + # DP mode + if cuda and RANK == -1 and torch.cuda.device_count() > 1: + LOGGER.warning('WARNING ⚠️ DP not recommended, use torch.distributed.run for best DDP Multi-GPU results.') + model = torch.nn.DataParallel(model) + + # SyncBatchNorm + if opt.sync_bn and cuda and RANK != -1: + model = torch.nn.SyncBatchNorm.convert_sync_batchnorm(model).to(device) + LOGGER.info('Using SyncBatchNorm()') + + # Trainloader + train_loader, dataset = create_dataloader(train_path, + imgsz, + batch_size // WORLD_SIZE, + gs, + single_cls, + hyp=hyp, + augment=True, + cache=None if opt.cache == 'val' else opt.cache, + rect=opt.rect, + rank=LOCAL_RANK, + workers=workers, + image_weights=opt.image_weights, + close_mosaic=opt.close_mosaic != 0, + quad=opt.quad, + prefix=colorstr('train: '), + shuffle=True, + min_items=opt.min_items) + labels = np.concatenate(dataset.labels, 0) + mlc = int(labels[:, 0].max()) # max label class + assert mlc < nc, f'Label class {mlc} exceeds nc={nc} in {data}. Possible class labels are 0-{nc - 1}' + + # Process 0 + if RANK in {-1, 0}: + val_loader = create_dataloader(val_path, + imgsz, + batch_size // WORLD_SIZE * 2, + gs, + single_cls, + hyp=hyp, + cache=None if noval else opt.cache, + rect=True, + rank=-1, + workers=workers * 2, + pad=0.5, + prefix=colorstr('val: '))[0] + + if not resume: + # if not opt.noautoanchor: + # check_anchors(dataset, model=model, thr=hyp['anchor_t'], imgsz=imgsz) # run AutoAnchor + model.half().float() # pre-reduce anchor precision + + callbacks.run('on_pretrain_routine_end', labels, names) + + # DDP mode + if cuda and RANK != -1: + model = smart_DDP(model) + + # Model attributes + nl = de_parallel(model).model[-1].nl # number of detection layers (to scale hyps) + #hyp['box'] *= 3 / nl # scale to layers + #hyp['cls'] *= nc / 80 * 3 / nl # scale to classes and layers + #hyp['obj'] *= (imgsz / 640) ** 2 * 3 / nl # scale to image size and layers + hyp['label_smoothing'] = opt.label_smoothing + model.nc = nc # attach number of classes to model + model.hyp = hyp # attach hyperparameters to model + model.class_weights = labels_to_class_weights(dataset.labels, nc).to(device) * nc # attach class weights + model.names = names + + # Start training + t0 = time.time() + nb = len(train_loader) # number of batches + nw = max(round(hyp['warmup_epochs'] * nb), 100) # number of warmup iterations, max(3 epochs, 100 iterations) + # nw = min(nw, (epochs - start_epoch) / 2 * nb) # limit warmup to < 1/2 of training + last_opt_step = -1 + maps = np.zeros(nc) # mAP per class + results = (0, 0, 0, 0, 0, 0, 0) # P, R, mAP@.5, mAP@.5-.95, val_loss(box, obj, cls) + scheduler.last_epoch = start_epoch - 1 # do not move + scaler = torch.cuda.amp.GradScaler(enabled=amp) + stopper, stop = EarlyStopping(patience=opt.patience), False + compute_loss = ComputeLoss(model) # init loss class + callbacks.run('on_train_start') + LOGGER.info(f'Image sizes {imgsz} train, {imgsz} val\n' + f'Using {train_loader.num_workers * WORLD_SIZE} dataloader workers\n' + f"Logging results to {colorstr('bold', save_dir)}\n" + f'Starting training for {epochs} epochs...') + for epoch in range(start_epoch, epochs): # epoch ------------------------------------------------------------------ + callbacks.run('on_train_epoch_start') + model.train() + + # Update image weights (optional, single-GPU only) + if opt.image_weights: + cw = model.class_weights.cpu().numpy() * (1 - maps) ** 2 / nc # class weights + iw = labels_to_image_weights(dataset.labels, nc=nc, class_weights=cw) # image weights + dataset.indices = random.choices(range(dataset.n), weights=iw, k=dataset.n) # rand weighted idx + if epoch == (epochs - opt.close_mosaic): + LOGGER.info("Closing dataloader mosaic") + dataset.mosaic = False + + # Update mosaic border (optional) + # b = int(random.uniform(0.25 * imgsz, 0.75 * imgsz + gs) // gs * gs) + # dataset.mosaic_border = [b - imgsz, -b] # height, width borders + + mloss = torch.zeros(3, device=device) # mean losses + if RANK != -1: + train_loader.sampler.set_epoch(epoch) + pbar = enumerate(train_loader) + LOGGER.info(('\n' + '%11s' * 7) % ('Epoch', 'GPU_mem', 'box_loss', 'cls_loss', 'dfl_loss', 'Instances', 'Size')) + if RANK in {-1, 0}: + pbar = tqdm(pbar, total=nb, bar_format=TQDM_BAR_FORMAT) # progress bar + optimizer.zero_grad() + for i, (imgs, targets, paths, _) in pbar: # batch ------------------------------------------------------------- + callbacks.run('on_train_batch_start') + ni = i + nb * epoch # number integrated batches (since train start) + imgs = imgs.to(device, non_blocking=True).float() / 255 # uint8 to float32, 0-255 to 0.0-1.0 + + # Warmup + if ni <= nw: + xi = [0, nw] # x interp + # compute_loss.gr = np.interp(ni, xi, [0.0, 1.0]) # iou loss ratio (obj_loss = 1.0 or iou) + accumulate = max(1, np.interp(ni, xi, [1, nbs / batch_size]).round()) + for j, x in enumerate(optimizer.param_groups): + # bias lr falls from 0.1 to lr0, all other lrs rise from 0.0 to lr0 + x['lr'] = np.interp(ni, xi, [hyp['warmup_bias_lr'] if j == 0 else 0.0, x['initial_lr'] * lf(epoch)]) + if 'momentum' in x: + x['momentum'] = np.interp(ni, xi, [hyp['warmup_momentum'], hyp['momentum']]) + + # Multi-scale + if opt.multi_scale: + sz = random.randrange(imgsz * 0.5, imgsz * 1.5 + gs) // gs * gs # size + sf = sz / max(imgs.shape[2:]) # scale factor + if sf != 1: + ns = [math.ceil(x * sf / gs) * gs for x in imgs.shape[2:]] # new shape (stretched to gs-multiple) + imgs = nn.functional.interpolate(imgs, size=ns, mode='bilinear', align_corners=False) + + # Forward + with torch.cuda.amp.autocast(amp): + pred = model(imgs) # forward + loss, loss_items = compute_loss(pred, targets.to(device)) # loss scaled by batch_size + if RANK != -1: + loss *= WORLD_SIZE # gradient averaged between devices in DDP mode + if opt.quad: + loss *= 4. + + # Backward + scaler.scale(loss).backward() + + # Optimize - https://pytorch.org/docs/master/notes/amp_examples.html + if ni - last_opt_step >= accumulate: + scaler.unscale_(optimizer) # unscale gradients + torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=10.0) # clip gradients + scaler.step(optimizer) # optimizer.step + scaler.update() + optimizer.zero_grad() + if ema: + ema.update(model) + last_opt_step = ni + + # Log + if RANK in {-1, 0}: + mloss = (mloss * i + loss_items) / (i + 1) # update mean losses + mem = f'{torch.cuda.memory_reserved() / 1E9 if torch.cuda.is_available() else 0:.3g}G' # (GB) + pbar.set_description(('%11s' * 2 + '%11.4g' * 5) % + (f'{epoch}/{epochs - 1}', mem, *mloss, targets.shape[0], imgs.shape[-1])) + callbacks.run('on_train_batch_end', model, ni, imgs, targets, paths, list(mloss)) + if callbacks.stop_training: + return + # end batch ------------------------------------------------------------------------------------------------ + + # Scheduler + lr = [x['lr'] for x in optimizer.param_groups] # for loggers + scheduler.step() + + if RANK in {-1, 0}: + # mAP + callbacks.run('on_train_epoch_end', epoch=epoch) + ema.update_attr(model, include=['yaml', 'nc', 'hyp', 'names', 'stride', 'class_weights']) + final_epoch = (epoch + 1 == epochs) or stopper.possible_stop + if not noval or final_epoch: # Calculate mAP + results, maps, _ = validate.run(data_dict, + batch_size=batch_size // WORLD_SIZE * 2, + imgsz=imgsz, + half=amp, + model=ema.ema, + single_cls=single_cls, + dataloader=val_loader, + save_dir=save_dir, + plots=False, + callbacks=callbacks, + compute_loss=compute_loss) + + # Update best mAP + fi = fitness(np.array(results).reshape(1, -1)) # weighted combination of [P, R, mAP@.5, mAP@.5-.95] + stop = stopper(epoch=epoch, fitness=fi) # early stop check + if fi > best_fitness: + best_fitness = fi + log_vals = list(mloss) + list(results) + lr + callbacks.run('on_fit_epoch_end', log_vals, epoch, best_fitness, fi) + + # Save model + if (not nosave) or (final_epoch and not evolve): # if save + ckpt = { + 'epoch': epoch, + 'best_fitness': best_fitness, + 'model': deepcopy(de_parallel(model)).half(), + 'ema': deepcopy(ema.ema).half(), + 'updates': ema.updates, + 'optimizer': optimizer.state_dict(), + 'opt': vars(opt), + 'git': GIT_INFO, # {remote, branch, commit} if a git repo + 'date': datetime.now().isoformat()} + + # Save last, best and delete + torch.save(ckpt, last) + if best_fitness == fi: + torch.save(ckpt, best) + if opt.save_period > 0 and epoch % opt.save_period == 0: + torch.save(ckpt, w / f'epoch{epoch}.pt') + del ckpt + callbacks.run('on_model_save', last, epoch, final_epoch, best_fitness, fi) + + # EarlyStopping + if RANK != -1: # if DDP training + broadcast_list = [stop if RANK == 0 else None] + dist.broadcast_object_list(broadcast_list, 0) # broadcast 'stop' to all ranks + if RANK != 0: + stop = broadcast_list[0] + if stop: + break # must break all DDP ranks + + # end epoch ---------------------------------------------------------------------------------------------------- + # end training ----------------------------------------------------------------------------------------------------- + if RANK in {-1, 0}: + LOGGER.info(f'\n{epoch - start_epoch + 1} epochs completed in {(time.time() - t0) / 3600:.3f} hours.') + for f in last, best: + if f.exists(): + strip_optimizer(f) # strip optimizers + if f is best: + LOGGER.info(f'\nValidating {f}...') + results, _, _ = validate.run( + data_dict, + batch_size=batch_size // WORLD_SIZE * 2, + imgsz=imgsz, + model=attempt_load(f, device).half(), + single_cls=single_cls, + dataloader=val_loader, + save_dir=save_dir, + save_json=is_coco, + verbose=True, + plots=plots, + callbacks=callbacks, + compute_loss=compute_loss) # val best model with plots + if is_coco: + callbacks.run('on_fit_epoch_end', list(mloss) + list(results) + lr, epoch, best_fitness, fi) + + callbacks.run('on_train_end', last, best, epoch, results) + + torch.cuda.empty_cache() + return results + + +def parse_opt(known=False): + parser = argparse.ArgumentParser() + # parser.add_argument('--weights', type=str, default=ROOT / 'yolo.pt', help='initial weights path') + # parser.add_argument('--cfg', type=str, default='', help='model.yaml path') + parser.add_argument('--weights', type=str, default='', help='initial weights path') + parser.add_argument('--cfg', type=str, default='yolo.yaml', help='model.yaml path') + parser.add_argument('--data', type=str, default=ROOT / 'data/coco.yaml', help='dataset.yaml path') + parser.add_argument('--hyp', type=str, default=ROOT / 'data/hyps/hyp.scratch-high.yaml', help='hyperparameters path') + parser.add_argument('--epochs', type=int, default=100, help='total training epochs') + parser.add_argument('--batch-size', type=int, default=16, help='total batch size for all GPUs, -1 for autobatch') + parser.add_argument('--imgsz', '--img', '--img-size', type=int, default=640, help='train, val image size (pixels)') + parser.add_argument('--rect', action='store_true', help='rectangular training') + parser.add_argument('--resume', nargs='?', const=True, default=False, help='resume most recent training') + parser.add_argument('--nosave', action='store_true', help='only save final checkpoint') + parser.add_argument('--noval', action='store_true', help='only validate final epoch') + parser.add_argument('--noautoanchor', action='store_true', help='disable AutoAnchor') + parser.add_argument('--noplots', action='store_true', help='save no plot files') + parser.add_argument('--evolve', type=int, nargs='?', const=300, help='evolve hyperparameters for x generations') + parser.add_argument('--bucket', type=str, default='', help='gsutil bucket') + parser.add_argument('--cache', type=str, nargs='?', const='ram', help='image --cache ram/disk') + parser.add_argument('--image-weights', action='store_true', help='use weighted image selection for training') + parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu') + parser.add_argument('--multi-scale', action='store_true', help='vary img-size +/- 50%%') + parser.add_argument('--single-cls', action='store_true', help='train multi-class data as single-class') + parser.add_argument('--optimizer', type=str, choices=['SGD', 'Adam', 'AdamW', 'LION'], default='SGD', help='optimizer') + parser.add_argument('--sync-bn', action='store_true', help='use SyncBatchNorm, only available in DDP mode') + parser.add_argument('--workers', type=int, default=8, help='max dataloader workers (per RANK in DDP mode)') + parser.add_argument('--project', default=ROOT / 'runs/train', help='save to project/name') + parser.add_argument('--name', default='exp', help='save to project/name') + parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment') + parser.add_argument('--quad', action='store_true', help='quad dataloader') + parser.add_argument('--cos-lr', action='store_true', help='cosine LR scheduler') + parser.add_argument('--flat-cos-lr', action='store_true', help='flat cosine LR scheduler') + parser.add_argument('--fixed-lr', action='store_true', help='fixed LR scheduler') + parser.add_argument('--label-smoothing', type=float, default=0.0, help='Label smoothing epsilon') + parser.add_argument('--patience', type=int, default=100, help='EarlyStopping patience (epochs without improvement)') + parser.add_argument('--freeze', nargs='+', type=int, default=[0], help='Freeze layers: backbone=10, first3=0 1 2') + parser.add_argument('--save-period', type=int, default=-1, help='Save checkpoint every x epochs (disabled if < 1)') + parser.add_argument('--seed', type=int, default=0, help='Global training seed') + parser.add_argument('--local_rank','--local-rank', type=int, default=-1, help='Automatic DDP Multi-GPU argument, do not modify') + parser.add_argument('--min-items', type=int, default=0, help='Experimental') + parser.add_argument('--close-mosaic', type=int, default=0, help='Experimental') + + # Logger arguments + parser.add_argument('--entity', default=None, help='Entity') + parser.add_argument('--upload_dataset', nargs='?', const=True, default=False, help='Upload data, "val" option') + parser.add_argument('--bbox_interval', type=int, default=-1, help='Set bounding-box image logging interval') + parser.add_argument('--artifact_alias', type=str, default='latest', help='Version of dataset artifact to use') + + return parser.parse_known_args()[0] if known else parser.parse_args() + + +def main(opt, callbacks=Callbacks()): + # Checks + if RANK in {-1, 0}: + print_args(vars(opt)) + #check_git_status() + #check_requirements() + + # Resume (from specified or most recent last.pt) + if opt.resume and not check_comet_resume(opt) and not opt.evolve: + last = Path(check_file(opt.resume) if isinstance(opt.resume, str) else get_latest_run()) + opt_yaml = last.parent.parent / 'opt.yaml' # train options yaml + opt_data = opt.data # original dataset + if opt_yaml.is_file(): + with open(opt_yaml, errors='ignore') as f: + d = yaml.safe_load(f) + else: + d = torch.load(last, map_location='cpu')['opt'] + opt = argparse.Namespace(**d) # replace + opt.cfg, opt.weights, opt.resume = '', str(last), True # reinstate + if is_url(opt_data): + opt.data = check_file(opt_data) # avoid HUB resume auth timeout + else: + opt.data, opt.cfg, opt.hyp, opt.weights, opt.project = \ + check_file(opt.data), check_yaml(opt.cfg), check_yaml(opt.hyp), str(opt.weights), str(opt.project) # checks + assert len(opt.cfg) or len(opt.weights), 'either --cfg or --weights must be specified' + if opt.evolve: + if opt.project == str(ROOT / 'runs/train'): # if default project name, rename to runs/evolve + opt.project = str(ROOT / 'runs/evolve') + opt.exist_ok, opt.resume = opt.resume, False # pass resume to exist_ok and disable resume + if opt.name == 'cfg': + opt.name = Path(opt.cfg).stem # use model.yaml as name + opt.save_dir = str(increment_path(Path(opt.project) / opt.name, exist_ok=opt.exist_ok)) + + # DDP mode + device = select_device(opt.device, batch_size=opt.batch_size) + if LOCAL_RANK != -1: + msg = 'is not compatible with YOLO Multi-GPU DDP training' + assert not opt.image_weights, f'--image-weights {msg}' + assert not opt.evolve, f'--evolve {msg}' + assert opt.batch_size != -1, f'AutoBatch with --batch-size -1 {msg}, please pass a valid --batch-size' + assert opt.batch_size % WORLD_SIZE == 0, f'--batch-size {opt.batch_size} must be multiple of WORLD_SIZE' + assert torch.cuda.device_count() > LOCAL_RANK, 'insufficient CUDA devices for DDP command' + torch.cuda.set_device(LOCAL_RANK) + device = torch.device('cuda', LOCAL_RANK) + dist.init_process_group(backend="nccl" if dist.is_nccl_available() else "gloo") + + # Train + if not opt.evolve: + train(opt.hyp, opt, device, callbacks) + + # Evolve hyperparameters (optional) + else: + # Hyperparameter evolution metadata (mutation scale 0-1, lower_limit, upper_limit) + meta = { + 'lr0': (1, 1e-5, 1e-1), # initial learning rate (SGD=1E-2, Adam=1E-3) + 'lrf': (1, 0.01, 1.0), # final OneCycleLR learning rate (lr0 * lrf) + 'momentum': (0.3, 0.6, 0.98), # SGD momentum/Adam beta1 + 'weight_decay': (1, 0.0, 0.001), # optimizer weight decay + 'warmup_epochs': (1, 0.0, 5.0), # warmup epochs (fractions ok) + 'warmup_momentum': (1, 0.0, 0.95), # warmup initial momentum + 'warmup_bias_lr': (1, 0.0, 0.2), # warmup initial bias lr + 'box': (1, 0.02, 0.2), # box loss gain + 'cls': (1, 0.2, 4.0), # cls loss gain + 'cls_pw': (1, 0.5, 2.0), # cls BCELoss positive_weight + 'obj': (1, 0.2, 4.0), # obj loss gain (scale with pixels) + 'obj_pw': (1, 0.5, 2.0), # obj BCELoss positive_weight + 'iou_t': (0, 0.1, 0.7), # IoU training threshold + 'anchor_t': (1, 2.0, 8.0), # anchor-multiple threshold + 'anchors': (2, 2.0, 10.0), # anchors per output grid (0 to ignore) + 'fl_gamma': (0, 0.0, 2.0), # focal loss gamma (efficientDet default gamma=1.5) + 'hsv_h': (1, 0.0, 0.1), # image HSV-Hue augmentation (fraction) + 'hsv_s': (1, 0.0, 0.9), # image HSV-Saturation augmentation (fraction) + 'hsv_v': (1, 0.0, 0.9), # image HSV-Value augmentation (fraction) + 'degrees': (1, 0.0, 45.0), # image rotation (+/- deg) + 'translate': (1, 0.0, 0.9), # image translation (+/- fraction) + 'scale': (1, 0.0, 0.9), # image scale (+/- gain) + 'shear': (1, 0.0, 10.0), # image shear (+/- deg) + 'perspective': (0, 0.0, 0.001), # image perspective (+/- fraction), range 0-0.001 + 'flipud': (1, 0.0, 1.0), # image flip up-down (probability) + 'fliplr': (0, 0.0, 1.0), # image flip left-right (probability) + 'mosaic': (1, 0.0, 1.0), # image mixup (probability) + 'mixup': (1, 0.0, 1.0), # image mixup (probability) + 'copy_paste': (1, 0.0, 1.0)} # segment copy-paste (probability) + + with open(opt.hyp, errors='ignore') as f: + hyp = yaml.safe_load(f) # load hyps dict + if 'anchors' not in hyp: # anchors commented in hyp.yaml + hyp['anchors'] = 3 + if opt.noautoanchor: + del hyp['anchors'], meta['anchors'] + opt.noval, opt.nosave, save_dir = True, True, Path(opt.save_dir) # only val/save final epoch + # ei = [isinstance(x, (int, float)) for x in hyp.values()] # evolvable indices + evolve_yaml, evolve_csv = save_dir / 'hyp_evolve.yaml', save_dir / 'evolve.csv' + if opt.bucket: + os.system(f'gsutil cp gs://{opt.bucket}/evolve.csv {evolve_csv}') # download evolve.csv if exists + + for _ in range(opt.evolve): # generations to evolve + if evolve_csv.exists(): # if evolve.csv exists: select best hyps and mutate + # Select parent(s) + parent = 'single' # parent selection method: 'single' or 'weighted' + x = np.loadtxt(evolve_csv, ndmin=2, delimiter=',', skiprows=1) + n = min(5, len(x)) # number of previous results to consider + x = x[np.argsort(-fitness(x))][:n] # top n mutations + w = fitness(x) - fitness(x).min() + 1E-6 # weights (sum > 0) + if parent == 'single' or len(x) == 1: + # x = x[random.randint(0, n - 1)] # random selection + x = x[random.choices(range(n), weights=w)[0]] # weighted selection + elif parent == 'weighted': + x = (x * w.reshape(n, 1)).sum(0) / w.sum() # weighted combination + + # Mutate + mp, s = 0.8, 0.2 # mutation probability, sigma + npr = np.random + npr.seed(int(time.time())) + g = np.array([meta[k][0] for k in hyp.keys()]) # gains 0-1 + ng = len(meta) + v = np.ones(ng) + while all(v == 1): # mutate until a change occurs (prevent duplicates) + v = (g * (npr.random(ng) < mp) * npr.randn(ng) * npr.random() * s + 1).clip(0.3, 3.0) + for i, k in enumerate(hyp.keys()): # plt.hist(v.ravel(), 300) + hyp[k] = float(x[i + 7] * v[i]) # mutate + + # Constrain to limits + for k, v in meta.items(): + hyp[k] = max(hyp[k], v[1]) # lower limit + hyp[k] = min(hyp[k], v[2]) # upper limit + hyp[k] = round(hyp[k], 5) # significant digits + + # Train mutation + results = train(hyp.copy(), opt, device, callbacks) + callbacks = Callbacks() + # Write mutation results + keys = ('metrics/precision', 'metrics/recall', 'metrics/mAP_0.5', 'metrics/mAP_0.5:0.95', 'val/box_loss', + 'val/obj_loss', 'val/cls_loss') + print_mutation(keys, results, hyp.copy(), save_dir, opt.bucket) + + # Plot results + plot_evolve(evolve_csv) + LOGGER.info(f'Hyperparameter evolution finished {opt.evolve} generations\n' + f"Results saved to {colorstr('bold', save_dir)}\n" + f'Usage example: $ python train.py --hyp {evolve_yaml}') + + +def run(**kwargs): + # Usage: import train; train.run(data='coco128.yaml', imgsz=320, weights='yolo.pt') + opt = parse_opt(True) + for k, v in kwargs.items(): + setattr(opt, k, v) + main(opt) + return opt + + +if __name__ == "__main__": + opt = parse_opt() + main(opt) diff --git a/cv/3d_detection/yolov9/pytorch/train_triple.py b/cv/3d_detection/yolov9/pytorch/train_triple.py new file mode 100644 index 000000000..4dbbc1eee --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/train_triple.py @@ -0,0 +1,636 @@ +import argparse +import math +import os +import random +import sys +import time +from copy import deepcopy +from datetime import datetime +from pathlib import Path + +import numpy as np +import torch +import torch.distributed as dist +import torch.nn as nn +import yaml +from torch.optim import lr_scheduler +from tqdm import tqdm + +FILE = Path(__file__).resolve() +ROOT = FILE.parents[0] # YOLO root directory +if str(ROOT) not in sys.path: + sys.path.append(str(ROOT)) # add ROOT to PATH +ROOT = Path(os.path.relpath(ROOT, Path.cwd())) # relative + +import val_triple as validate # for end-of-epoch mAP +from models.experimental import attempt_load +from models.yolo import Model +from utils.autoanchor import check_anchors +from utils.autobatch import check_train_batch_size +from utils.callbacks import Callbacks +from utils.dataloaders import create_dataloader +from utils.downloads import attempt_download, is_url +from utils.general import (LOGGER, TQDM_BAR_FORMAT, check_amp, check_dataset, check_file, check_git_info, + check_git_status, check_img_size, check_requirements, check_suffix, check_yaml, colorstr, + get_latest_run, increment_path, init_seeds, intersect_dicts, labels_to_class_weights, + labels_to_image_weights, methods, one_cycle, print_args, print_mutation, strip_optimizer, + yaml_save) +from utils.loggers import Loggers +from utils.loggers.comet.comet_utils import check_comet_resume +from utils.loss_tal_triple import ComputeLoss +from utils.metrics import fitness +from utils.plots import plot_evolve +from utils.torch_utils import (EarlyStopping, ModelEMA, de_parallel, select_device, smart_DDP, smart_optimizer, + smart_resume, torch_distributed_zero_first) + +LOCAL_RANK = int(os.getenv('LOCAL_RANK', -1)) # https://pytorch.org/docs/stable/elastic/run.html +RANK = int(os.getenv('RANK', -1)) +WORLD_SIZE = int(os.getenv('WORLD_SIZE', 1)) +GIT_INFO = None#check_git_info() + + +def train(hyp, opt, device, callbacks): # hyp is path/to/hyp.yaml or hyp dictionary + save_dir, epochs, batch_size, weights, single_cls, evolve, data, cfg, resume, noval, nosave, workers, freeze = \ + Path(opt.save_dir), opt.epochs, opt.batch_size, opt.weights, opt.single_cls, opt.evolve, opt.data, opt.cfg, \ + opt.resume, opt.noval, opt.nosave, opt.workers, opt.freeze + callbacks.run('on_pretrain_routine_start') + + # Directories + w = save_dir / 'weights' # weights dir + (w.parent if evolve else w).mkdir(parents=True, exist_ok=True) # make dir + last, best = w / 'last.pt', w / 'best.pt' + + # Hyperparameters + if isinstance(hyp, str): + with open(hyp, errors='ignore') as f: + hyp = yaml.safe_load(f) # load hyps dict + LOGGER.info(colorstr('hyperparameters: ') + ', '.join(f'{k}={v}' for k, v in hyp.items())) + hyp['anchor_t'] = 5.0 + opt.hyp = hyp.copy() # for saving hyps to checkpoints + + # Save run settings + if not evolve: + yaml_save(save_dir / 'hyp.yaml', hyp) + yaml_save(save_dir / 'opt.yaml', vars(opt)) + + # Loggers + data_dict = None + if RANK in {-1, 0}: + loggers = Loggers(save_dir, weights, opt, hyp, LOGGER) # loggers instance + + # Register actions + for k in methods(loggers): + callbacks.register_action(k, callback=getattr(loggers, k)) + + # Process custom dataset artifact link + data_dict = loggers.remote_dataset + if resume: # If resuming runs from remote artifact + weights, epochs, hyp, batch_size = opt.weights, opt.epochs, opt.hyp, opt.batch_size + + # Config + plots = not evolve and not opt.noplots # create plots + cuda = device.type != 'cpu' + init_seeds(opt.seed + 1 + RANK, deterministic=True) + with torch_distributed_zero_first(LOCAL_RANK): + data_dict = data_dict or check_dataset(data) # check if None + train_path, val_path = data_dict['train'], data_dict['val'] + nc = 1 if single_cls else int(data_dict['nc']) # number of classes + names = {0: 'item'} if single_cls and len(data_dict['names']) != 1 else data_dict['names'] # class names + #is_coco = isinstance(val_path, str) and val_path.endswith('coco/val2017.txt') # COCO dataset + is_coco = isinstance(val_path, str) and val_path.endswith('val2017.txt') # COCO dataset + + # Model + check_suffix(weights, '.pt') # check weights + pretrained = weights.endswith('.pt') + if pretrained: + with torch_distributed_zero_first(LOCAL_RANK): + weights = attempt_download(weights) # download if not found locally + ckpt = torch.load(weights, map_location='cpu') # load checkpoint to CPU to avoid CUDA memory leak + model = Model(cfg or ckpt['model'].yaml, ch=3, nc=nc, anchors=hyp.get('anchors')).to(device) # create + exclude = ['anchor'] if (cfg or hyp.get('anchors')) and not resume else [] # exclude keys + csd = ckpt['model'].float().state_dict() # checkpoint state_dict as FP32 + csd = intersect_dicts(csd, model.state_dict(), exclude=exclude) # intersect + model.load_state_dict(csd, strict=False) # load + LOGGER.info(f'Transferred {len(csd)}/{len(model.state_dict())} items from {weights}') # report + else: + model = Model(cfg, ch=3, nc=nc, anchors=hyp.get('anchors')).to(device) # create + amp = check_amp(model) # check AMP + + # Freeze + freeze = [f'model.{x}.' for x in (freeze if len(freeze) > 1 else range(freeze[0]))] # layers to freeze + for k, v in model.named_parameters(): + # v.requires_grad = True # train all layers TODO: uncomment this line as in master + # v.register_hook(lambda x: torch.nan_to_num(x)) # NaN to 0 (commented for erratic training results) + if any(x in k for x in freeze): + LOGGER.info(f'freezing {k}') + v.requires_grad = False + + # Image size + gs = max(int(model.stride.max()), 32) # grid size (max stride) + imgsz = check_img_size(opt.imgsz, gs, floor=gs * 2) # verify imgsz is gs-multiple + + # Batch size + if RANK == -1 and batch_size == -1: # single-GPU only, estimate best batch size + batch_size = check_train_batch_size(model, imgsz, amp) + loggers.on_params_update({"batch_size": batch_size}) + + # Optimizer + nbs = 64 # nominal batch size + accumulate = max(round(nbs / batch_size), 1) # accumulate loss before optimizing + hyp['weight_decay'] *= batch_size * accumulate / nbs # scale weight_decay + optimizer = smart_optimizer(model, opt.optimizer, hyp['lr0'], hyp['momentum'], hyp['weight_decay']) + + # Scheduler + if opt.cos_lr: + lf = one_cycle(1, hyp['lrf'], epochs) # cosine 1->hyp['lrf'] + else: + lf = lambda x: (1 - x / epochs) * (1.0 - hyp['lrf']) + hyp['lrf'] # linear + + # def lf(x): # saw + # return (1 - (x % 30) / 30) * (1 - x / epochs) * (1.0 - hyp['lrf']) + hyp['lrf'] + # + # def lf(x): # triangle start at min + # return 2 * abs(x / 30 - math.floor(x / 30 + 1 / 2)) * (1 - x / epochs) * (1.0 - hyp['lrf']) + hyp['lrf'] + # + # def lf(x): # triangle start at max + # return 2 * abs(x / 32 + .5 - math.floor(x / 32 + 1)) * (1 - x / epochs) * (1.0 - hyp['lrf']) + hyp['lrf'] + + scheduler = lr_scheduler.LambdaLR(optimizer, lr_lambda=lf) + # from utils.plots import plot_lr_scheduler; plot_lr_scheduler(optimizer, scheduler, epochs) + + # EMA + ema = ModelEMA(model) if RANK in {-1, 0} else None + + # Resume + best_fitness, start_epoch = 0.0, 0 + if pretrained: + if resume: + best_fitness, start_epoch, epochs = smart_resume(ckpt, optimizer, ema, weights, epochs, resume) + del ckpt, csd + + # DP mode + if cuda and RANK == -1 and torch.cuda.device_count() > 1: + LOGGER.warning('WARNING ⚠️ DP not recommended, use torch.distributed.run for best DDP Multi-GPU results.') + model = torch.nn.DataParallel(model) + + # SyncBatchNorm + if opt.sync_bn and cuda and RANK != -1: + model = torch.nn.SyncBatchNorm.convert_sync_batchnorm(model).to(device) + LOGGER.info('Using SyncBatchNorm()') + + # Trainloader + train_loader, dataset = create_dataloader(train_path, + imgsz, + batch_size // WORLD_SIZE, + gs, + single_cls, + hyp=hyp, + augment=True, + cache=None if opt.cache == 'val' else opt.cache, + rect=opt.rect, + rank=LOCAL_RANK, + workers=workers, + image_weights=opt.image_weights, + close_mosaic=opt.close_mosaic != 0, + quad=opt.quad, + prefix=colorstr('train: '), + shuffle=True, + min_items=opt.min_items) + labels = np.concatenate(dataset.labels, 0) + mlc = int(labels[:, 0].max()) # max label class + assert mlc < nc, f'Label class {mlc} exceeds nc={nc} in {data}. Possible class labels are 0-{nc - 1}' + + # Process 0 + if RANK in {-1, 0}: + val_loader = create_dataloader(val_path, + imgsz, + batch_size // WORLD_SIZE * 2, + gs, + single_cls, + hyp=hyp, + cache=None if noval else opt.cache, + rect=True, + rank=-1, + workers=workers * 2, + pad=0.5, + prefix=colorstr('val: '))[0] + + if not resume: + # if not opt.noautoanchor: + # check_anchors(dataset, model=model, thr=hyp['anchor_t'], imgsz=imgsz) # run AutoAnchor + model.half().float() # pre-reduce anchor precision + + callbacks.run('on_pretrain_routine_end', labels, names) + + # DDP mode + if cuda and RANK != -1: + model = smart_DDP(model) + + # Model attributes + nl = de_parallel(model).model[-1].nl # number of detection layers (to scale hyps) + #hyp['box'] *= 3 / nl # scale to layers + #hyp['cls'] *= nc / 80 * 3 / nl # scale to classes and layers + #hyp['obj'] *= (imgsz / 640) ** 2 * 3 / nl # scale to image size and layers + hyp['label_smoothing'] = opt.label_smoothing + model.nc = nc # attach number of classes to model + model.hyp = hyp # attach hyperparameters to model + model.class_weights = labels_to_class_weights(dataset.labels, nc).to(device) * nc # attach class weights + model.names = names + + # Start training + t0 = time.time() + nb = len(train_loader) # number of batches + nw = max(round(hyp['warmup_epochs'] * nb), 100) # number of warmup iterations, max(3 epochs, 100 iterations) + # nw = min(nw, (epochs - start_epoch) / 2 * nb) # limit warmup to < 1/2 of training + last_opt_step = -1 + maps = np.zeros(nc) # mAP per class + results = (0, 0, 0, 0, 0, 0, 0) # P, R, mAP@.5, mAP@.5-.95, val_loss(box, obj, cls) + scheduler.last_epoch = start_epoch - 1 # do not move + scaler = torch.cuda.amp.GradScaler(enabled=amp) + stopper, stop = EarlyStopping(patience=opt.patience), False + compute_loss = ComputeLoss(model) # init loss class + callbacks.run('on_train_start') + LOGGER.info(f'Image sizes {imgsz} train, {imgsz} val\n' + f'Using {train_loader.num_workers * WORLD_SIZE} dataloader workers\n' + f"Logging results to {colorstr('bold', save_dir)}\n" + f'Starting training for {epochs} epochs...') + for epoch in range(start_epoch, epochs): # epoch ------------------------------------------------------------------ + callbacks.run('on_train_epoch_start') + model.train() + + # Update image weights (optional, single-GPU only) + if opt.image_weights: + cw = model.class_weights.cpu().numpy() * (1 - maps) ** 2 / nc # class weights + iw = labels_to_image_weights(dataset.labels, nc=nc, class_weights=cw) # image weights + dataset.indices = random.choices(range(dataset.n), weights=iw, k=dataset.n) # rand weighted idx + if epoch == (epochs - opt.close_mosaic): + LOGGER.info("Closing dataloader mosaic") + dataset.mosaic = False + + # Update mosaic border (optional) + # b = int(random.uniform(0.25 * imgsz, 0.75 * imgsz + gs) // gs * gs) + # dataset.mosaic_border = [b - imgsz, -b] # height, width borders + + mloss = torch.zeros(3, device=device) # mean losses + if RANK != -1: + train_loader.sampler.set_epoch(epoch) + pbar = enumerate(train_loader) + LOGGER.info(('\n' + '%11s' * 7) % ('Epoch', 'GPU_mem', 'box_loss', 'cls_loss', 'dfl_loss', 'Instances', 'Size')) + if RANK in {-1, 0}: + pbar = tqdm(pbar, total=nb, bar_format=TQDM_BAR_FORMAT) # progress bar + optimizer.zero_grad() + for i, (imgs, targets, paths, _) in pbar: # batch ------------------------------------------------------------- + callbacks.run('on_train_batch_start') + ni = i + nb * epoch # number integrated batches (since train start) + imgs = imgs.to(device, non_blocking=True).float() / 255 # uint8 to float32, 0-255 to 0.0-1.0 + + # Warmup + if ni <= nw: + xi = [0, nw] # x interp + # compute_loss.gr = np.interp(ni, xi, [0.0, 1.0]) # iou loss ratio (obj_loss = 1.0 or iou) + accumulate = max(1, np.interp(ni, xi, [1, nbs / batch_size]).round()) + for j, x in enumerate(optimizer.param_groups): + # bias lr falls from 0.1 to lr0, all other lrs rise from 0.0 to lr0 + x['lr'] = np.interp(ni, xi, [hyp['warmup_bias_lr'] if j == 0 else 0.0, x['initial_lr'] * lf(epoch)]) + if 'momentum' in x: + x['momentum'] = np.interp(ni, xi, [hyp['warmup_momentum'], hyp['momentum']]) + + # Multi-scale + if opt.multi_scale: + sz = random.randrange(imgsz * 0.5, imgsz * 1.5 + gs) // gs * gs # size + sf = sz / max(imgs.shape[2:]) # scale factor + if sf != 1: + ns = [math.ceil(x * sf / gs) * gs for x in imgs.shape[2:]] # new shape (stretched to gs-multiple) + imgs = nn.functional.interpolate(imgs, size=ns, mode='bilinear', align_corners=False) + + # Forward + with torch.cuda.amp.autocast(amp): + pred = model(imgs) # forward + loss, loss_items = compute_loss(pred, targets.to(device)) # loss scaled by batch_size + if RANK != -1: + loss *= WORLD_SIZE # gradient averaged between devices in DDP mode + if opt.quad: + loss *= 4. + + # Backward + scaler.scale(loss).backward() + + # Optimize - https://pytorch.org/docs/master/notes/amp_examples.html + if ni - last_opt_step >= accumulate: + scaler.unscale_(optimizer) # unscale gradients + torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=10.0) # clip gradients + scaler.step(optimizer) # optimizer.step + scaler.update() + optimizer.zero_grad() + if ema: + ema.update(model) + last_opt_step = ni + + # Log + if RANK in {-1, 0}: + mloss = (mloss * i + loss_items) / (i + 1) # update mean losses + mem = f'{torch.cuda.memory_reserved() / 1E9 if torch.cuda.is_available() else 0:.3g}G' # (GB) + pbar.set_description(('%11s' * 2 + '%11.4g' * 5) % + (f'{epoch}/{epochs - 1}', mem, *mloss, targets.shape[0], imgs.shape[-1])) + callbacks.run('on_train_batch_end', model, ni, imgs, targets, paths, list(mloss)) + if callbacks.stop_training: + return + # end batch ------------------------------------------------------------------------------------------------ + + # Scheduler + lr = [x['lr'] for x in optimizer.param_groups] # for loggers + scheduler.step() + + if RANK in {-1, 0}: + # mAP + callbacks.run('on_train_epoch_end', epoch=epoch) + ema.update_attr(model, include=['yaml', 'nc', 'hyp', 'names', 'stride', 'class_weights']) + final_epoch = (epoch + 1 == epochs) or stopper.possible_stop + if not noval or final_epoch: # Calculate mAP + results, maps, _ = validate.run(data_dict, + batch_size=batch_size // WORLD_SIZE * 2, + imgsz=imgsz, + half=amp, + model=ema.ema, + single_cls=single_cls, + dataloader=val_loader, + save_dir=save_dir, + plots=False, + callbacks=callbacks, + compute_loss=compute_loss) + + # Update best mAP + fi = fitness(np.array(results).reshape(1, -1)) # weighted combination of [P, R, mAP@.5, mAP@.5-.95] + stop = stopper(epoch=epoch, fitness=fi) # early stop check + if fi > best_fitness: + best_fitness = fi + log_vals = list(mloss) + list(results) + lr + callbacks.run('on_fit_epoch_end', log_vals, epoch, best_fitness, fi) + + # Save model + if (not nosave) or (final_epoch and not evolve): # if save + ckpt = { + 'epoch': epoch, + 'best_fitness': best_fitness, + 'model': deepcopy(de_parallel(model)).half(), + 'ema': deepcopy(ema.ema).half(), + 'updates': ema.updates, + 'optimizer': optimizer.state_dict(), + 'opt': vars(opt), + 'git': GIT_INFO, # {remote, branch, commit} if a git repo + 'date': datetime.now().isoformat()} + + # Save last, best and delete + torch.save(ckpt, last) + if best_fitness == fi: + torch.save(ckpt, best) + if opt.save_period > 0 and epoch % opt.save_period == 0: + torch.save(ckpt, w / f'epoch{epoch}.pt') + del ckpt + callbacks.run('on_model_save', last, epoch, final_epoch, best_fitness, fi) + + # EarlyStopping + if RANK != -1: # if DDP training + broadcast_list = [stop if RANK == 0 else None] + dist.broadcast_object_list(broadcast_list, 0) # broadcast 'stop' to all ranks + if RANK != 0: + stop = broadcast_list[0] + if stop: + break # must break all DDP ranks + + # end epoch ---------------------------------------------------------------------------------------------------- + # end training ----------------------------------------------------------------------------------------------------- + if RANK in {-1, 0}: + LOGGER.info(f'\n{epoch - start_epoch + 1} epochs completed in {(time.time() - t0) / 3600:.3f} hours.') + for f in last, best: + if f.exists(): + strip_optimizer(f) # strip optimizers + if f is best: + LOGGER.info(f'\nValidating {f}...') + results, _, _ = validate.run( + data_dict, + batch_size=batch_size // WORLD_SIZE * 2, + imgsz=imgsz, + model=attempt_load(f, device).half(), + single_cls=single_cls, + dataloader=val_loader, + save_dir=save_dir, + save_json=is_coco, + verbose=True, + plots=plots, + callbacks=callbacks, + compute_loss=compute_loss) # val best model with plots + if is_coco: + callbacks.run('on_fit_epoch_end', list(mloss) + list(results) + lr, epoch, best_fitness, fi) + + callbacks.run('on_train_end', last, best, epoch, results) + + torch.cuda.empty_cache() + return results + + +def parse_opt(known=False): + parser = argparse.ArgumentParser() + # parser.add_argument('--weights', type=str, default=ROOT / 'yolo.pt', help='initial weights path') + # parser.add_argument('--cfg', type=str, default='', help='model.yaml path') + parser.add_argument('--weights', type=str, default='', help='initial weights path') + parser.add_argument('--cfg', type=str, default='yolo.yaml', help='model.yaml path') + parser.add_argument('--data', type=str, default=ROOT / 'data/coco.yaml', help='dataset.yaml path') + parser.add_argument('--hyp', type=str, default=ROOT / 'data/hyps/hyp.scratch-high.yaml', help='hyperparameters path') + parser.add_argument('--epochs', type=int, default=100, help='total training epochs') + parser.add_argument('--batch-size', type=int, default=16, help='total batch size for all GPUs, -1 for autobatch') + parser.add_argument('--imgsz', '--img', '--img-size', type=int, default=640, help='train, val image size (pixels)') + parser.add_argument('--rect', action='store_true', help='rectangular training') + parser.add_argument('--resume', nargs='?', const=True, default=False, help='resume most recent training') + parser.add_argument('--nosave', action='store_true', help='only save final checkpoint') + parser.add_argument('--noval', action='store_true', help='only validate final epoch') + parser.add_argument('--noautoanchor', action='store_true', help='disable AutoAnchor') + parser.add_argument('--noplots', action='store_true', help='save no plot files') + parser.add_argument('--evolve', type=int, nargs='?', const=300, help='evolve hyperparameters for x generations') + parser.add_argument('--bucket', type=str, default='', help='gsutil bucket') + parser.add_argument('--cache', type=str, nargs='?', const='ram', help='image --cache ram/disk') + parser.add_argument('--image-weights', action='store_true', help='use weighted image selection for training') + parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu') + parser.add_argument('--multi-scale', action='store_true', help='vary img-size +/- 50%%') + parser.add_argument('--single-cls', action='store_true', help='train multi-class data as single-class') + parser.add_argument('--optimizer', type=str, choices=['SGD', 'Adam', 'AdamW', 'LION'], default='SGD', help='optimizer') + parser.add_argument('--sync-bn', action='store_true', help='use SyncBatchNorm, only available in DDP mode') + parser.add_argument('--workers', type=int, default=8, help='max dataloader workers (per RANK in DDP mode)') + parser.add_argument('--project', default=ROOT / 'runs/train', help='save to project/name') + parser.add_argument('--name', default='exp', help='save to project/name') + parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment') + parser.add_argument('--quad', action='store_true', help='quad dataloader') + parser.add_argument('--cos-lr', action='store_true', help='cosine LR scheduler') + parser.add_argument('--label-smoothing', type=float, default=0.0, help='Label smoothing epsilon') + parser.add_argument('--patience', type=int, default=100, help='EarlyStopping patience (epochs without improvement)') + parser.add_argument('--freeze', nargs='+', type=int, default=[0], help='Freeze layers: backbone=10, first3=0 1 2') + parser.add_argument('--save-period', type=int, default=-1, help='Save checkpoint every x epochs (disabled if < 1)') + parser.add_argument('--seed', type=int, default=0, help='Global training seed') + parser.add_argument('--local_rank', type=int, default=-1, help='Automatic DDP Multi-GPU argument, do not modify') + parser.add_argument('--min-items', type=int, default=0, help='Experimental') + parser.add_argument('--close-mosaic', type=int, default=0, help='Experimental') + + # Logger arguments + parser.add_argument('--entity', default=None, help='Entity') + parser.add_argument('--upload_dataset', nargs='?', const=True, default=False, help='Upload data, "val" option') + parser.add_argument('--bbox_interval', type=int, default=-1, help='Set bounding-box image logging interval') + parser.add_argument('--artifact_alias', type=str, default='latest', help='Version of dataset artifact to use') + + return parser.parse_known_args()[0] if known else parser.parse_args() + + +def main(opt, callbacks=Callbacks()): + # Checks + if RANK in {-1, 0}: + print_args(vars(opt)) + #check_git_status() + #check_requirements() + + # Resume (from specified or most recent last.pt) + if opt.resume and not check_comet_resume(opt) and not opt.evolve: + last = Path(check_file(opt.resume) if isinstance(opt.resume, str) else get_latest_run()) + opt_yaml = last.parent.parent / 'opt.yaml' # train options yaml + opt_data = opt.data # original dataset + if opt_yaml.is_file(): + with open(opt_yaml, errors='ignore') as f: + d = yaml.safe_load(f) + else: + d = torch.load(last, map_location='cpu')['opt'] + opt = argparse.Namespace(**d) # replace + opt.cfg, opt.weights, opt.resume = '', str(last), True # reinstate + if is_url(opt_data): + opt.data = check_file(opt_data) # avoid HUB resume auth timeout + else: + opt.data, opt.cfg, opt.hyp, opt.weights, opt.project = \ + check_file(opt.data), check_yaml(opt.cfg), check_yaml(opt.hyp), str(opt.weights), str(opt.project) # checks + assert len(opt.cfg) or len(opt.weights), 'either --cfg or --weights must be specified' + if opt.evolve: + if opt.project == str(ROOT / 'runs/train'): # if default project name, rename to runs/evolve + opt.project = str(ROOT / 'runs/evolve') + opt.exist_ok, opt.resume = opt.resume, False # pass resume to exist_ok and disable resume + if opt.name == 'cfg': + opt.name = Path(opt.cfg).stem # use model.yaml as name + opt.save_dir = str(increment_path(Path(opt.project) / opt.name, exist_ok=opt.exist_ok)) + + # DDP mode + device = select_device(opt.device, batch_size=opt.batch_size) + if LOCAL_RANK != -1: + msg = 'is not compatible with YOLO Multi-GPU DDP training' + assert not opt.image_weights, f'--image-weights {msg}' + assert not opt.evolve, f'--evolve {msg}' + assert opt.batch_size != -1, f'AutoBatch with --batch-size -1 {msg}, please pass a valid --batch-size' + assert opt.batch_size % WORLD_SIZE == 0, f'--batch-size {opt.batch_size} must be multiple of WORLD_SIZE' + assert torch.cuda.device_count() > LOCAL_RANK, 'insufficient CUDA devices for DDP command' + torch.cuda.set_device(LOCAL_RANK) + device = torch.device('cuda', LOCAL_RANK) + dist.init_process_group(backend="nccl" if dist.is_nccl_available() else "gloo") + + # Train + if not opt.evolve: + train(opt.hyp, opt, device, callbacks) + + # Evolve hyperparameters (optional) + else: + # Hyperparameter evolution metadata (mutation scale 0-1, lower_limit, upper_limit) + meta = { + 'lr0': (1, 1e-5, 1e-1), # initial learning rate (SGD=1E-2, Adam=1E-3) + 'lrf': (1, 0.01, 1.0), # final OneCycleLR learning rate (lr0 * lrf) + 'momentum': (0.3, 0.6, 0.98), # SGD momentum/Adam beta1 + 'weight_decay': (1, 0.0, 0.001), # optimizer weight decay + 'warmup_epochs': (1, 0.0, 5.0), # warmup epochs (fractions ok) + 'warmup_momentum': (1, 0.0, 0.95), # warmup initial momentum + 'warmup_bias_lr': (1, 0.0, 0.2), # warmup initial bias lr + 'box': (1, 0.02, 0.2), # box loss gain + 'cls': (1, 0.2, 4.0), # cls loss gain + 'cls_pw': (1, 0.5, 2.0), # cls BCELoss positive_weight + 'obj': (1, 0.2, 4.0), # obj loss gain (scale with pixels) + 'obj_pw': (1, 0.5, 2.0), # obj BCELoss positive_weight + 'iou_t': (0, 0.1, 0.7), # IoU training threshold + 'anchor_t': (1, 2.0, 8.0), # anchor-multiple threshold + 'anchors': (2, 2.0, 10.0), # anchors per output grid (0 to ignore) + 'fl_gamma': (0, 0.0, 2.0), # focal loss gamma (efficientDet default gamma=1.5) + 'hsv_h': (1, 0.0, 0.1), # image HSV-Hue augmentation (fraction) + 'hsv_s': (1, 0.0, 0.9), # image HSV-Saturation augmentation (fraction) + 'hsv_v': (1, 0.0, 0.9), # image HSV-Value augmentation (fraction) + 'degrees': (1, 0.0, 45.0), # image rotation (+/- deg) + 'translate': (1, 0.0, 0.9), # image translation (+/- fraction) + 'scale': (1, 0.0, 0.9), # image scale (+/- gain) + 'shear': (1, 0.0, 10.0), # image shear (+/- deg) + 'perspective': (0, 0.0, 0.001), # image perspective (+/- fraction), range 0-0.001 + 'flipud': (1, 0.0, 1.0), # image flip up-down (probability) + 'fliplr': (0, 0.0, 1.0), # image flip left-right (probability) + 'mosaic': (1, 0.0, 1.0), # image mixup (probability) + 'mixup': (1, 0.0, 1.0), # image mixup (probability) + 'copy_paste': (1, 0.0, 1.0)} # segment copy-paste (probability) + + with open(opt.hyp, errors='ignore') as f: + hyp = yaml.safe_load(f) # load hyps dict + if 'anchors' not in hyp: # anchors commented in hyp.yaml + hyp['anchors'] = 3 + if opt.noautoanchor: + del hyp['anchors'], meta['anchors'] + opt.noval, opt.nosave, save_dir = True, True, Path(opt.save_dir) # only val/save final epoch + # ei = [isinstance(x, (int, float)) for x in hyp.values()] # evolvable indices + evolve_yaml, evolve_csv = save_dir / 'hyp_evolve.yaml', save_dir / 'evolve.csv' + if opt.bucket: + os.system(f'gsutil cp gs://{opt.bucket}/evolve.csv {evolve_csv}') # download evolve.csv if exists + + for _ in range(opt.evolve): # generations to evolve + if evolve_csv.exists(): # if evolve.csv exists: select best hyps and mutate + # Select parent(s) + parent = 'single' # parent selection method: 'single' or 'weighted' + x = np.loadtxt(evolve_csv, ndmin=2, delimiter=',', skiprows=1) + n = min(5, len(x)) # number of previous results to consider + x = x[np.argsort(-fitness(x))][:n] # top n mutations + w = fitness(x) - fitness(x).min() + 1E-6 # weights (sum > 0) + if parent == 'single' or len(x) == 1: + # x = x[random.randint(0, n - 1)] # random selection + x = x[random.choices(range(n), weights=w)[0]] # weighted selection + elif parent == 'weighted': + x = (x * w.reshape(n, 1)).sum(0) / w.sum() # weighted combination + + # Mutate + mp, s = 0.8, 0.2 # mutation probability, sigma + npr = np.random + npr.seed(int(time.time())) + g = np.array([meta[k][0] for k in hyp.keys()]) # gains 0-1 + ng = len(meta) + v = np.ones(ng) + while all(v == 1): # mutate until a change occurs (prevent duplicates) + v = (g * (npr.random(ng) < mp) * npr.randn(ng) * npr.random() * s + 1).clip(0.3, 3.0) + for i, k in enumerate(hyp.keys()): # plt.hist(v.ravel(), 300) + hyp[k] = float(x[i + 7] * v[i]) # mutate + + # Constrain to limits + for k, v in meta.items(): + hyp[k] = max(hyp[k], v[1]) # lower limit + hyp[k] = min(hyp[k], v[2]) # upper limit + hyp[k] = round(hyp[k], 5) # significant digits + + # Train mutation + results = train(hyp.copy(), opt, device, callbacks) + callbacks = Callbacks() + # Write mutation results + keys = ('metrics/precision', 'metrics/recall', 'metrics/mAP_0.5', 'metrics/mAP_0.5:0.95', 'val/box_loss', + 'val/obj_loss', 'val/cls_loss') + print_mutation(keys, results, hyp.copy(), save_dir, opt.bucket) + + # Plot results + plot_evolve(evolve_csv) + LOGGER.info(f'Hyperparameter evolution finished {opt.evolve} generations\n' + f"Results saved to {colorstr('bold', save_dir)}\n" + f'Usage example: $ python train.py --hyp {evolve_yaml}') + + +def run(**kwargs): + # Usage: import train; train.run(data='coco128.yaml', imgsz=320, weights='yolo.pt') + opt = parse_opt(True) + for k, v in kwargs.items(): + setattr(opt, k, v) + main(opt) + return opt + + +if __name__ == "__main__": + opt = parse_opt() + main(opt) diff --git a/cv/3d_detection/yolov9/pytorch/utils/__init__.py b/cv/3d_detection/yolov9/pytorch/utils/__init__.py new file mode 100644 index 000000000..3d1de89ab --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/utils/__init__.py @@ -0,0 +1,75 @@ +import contextlib +import platform +import threading + + +def emojis(str=''): + # Return platform-dependent emoji-safe version of string + return str.encode().decode('ascii', 'ignore') if platform.system() == 'Windows' else str + + +class TryExcept(contextlib.ContextDecorator): + # YOLOv5 TryExcept class. Usage: @TryExcept() decorator or 'with TryExcept():' context manager + def __init__(self, msg=''): + self.msg = msg + + def __enter__(self): + pass + + def __exit__(self, exc_type, value, traceback): + if value: + print(emojis(f"{self.msg}{': ' if self.msg else ''}{value}")) + return True + + +def threaded(func): + # Multi-threads a target function and returns thread. Usage: @threaded decorator + def wrapper(*args, **kwargs): + thread = threading.Thread(target=func, args=args, kwargs=kwargs, daemon=True) + thread.start() + return thread + + return wrapper + + +def join_threads(verbose=False): + # Join all daemon threads, i.e. atexit.register(lambda: join_threads()) + main_thread = threading.current_thread() + for t in threading.enumerate(): + if t is not main_thread: + if verbose: + print(f'Joining thread {t.name}') + t.join() + + +def notebook_init(verbose=True): + # Check system software and hardware + print('Checking setup...') + + import os + import shutil + + from utils.general import check_font, check_requirements, is_colab + from utils.torch_utils import select_device # imports + + check_font() + + import psutil + from IPython import display # to display images and clear console output + + if is_colab(): + shutil.rmtree('/content/sample_data', ignore_errors=True) # remove colab /sample_data directory + + # System info + if verbose: + gb = 1 << 30 # bytes to GiB (1024 ** 3) + ram = psutil.virtual_memory().total + total, used, free = shutil.disk_usage("/") + display.clear_output() + s = f'({os.cpu_count()} CPUs, {ram / gb:.1f} GB RAM, {(total - free) / gb:.1f}/{total / gb:.1f} GB disk)' + else: + s = '' + + select_device(newline=False) + print(emojis(f'Setup complete ✅ {s}')) + return display diff --git a/cv/3d_detection/yolov9/pytorch/utils/activations.py b/cv/3d_detection/yolov9/pytorch/utils/activations.py new file mode 100644 index 000000000..aeb00e6c7 --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/utils/activations.py @@ -0,0 +1,98 @@ +import torch +import torch.nn as nn +import torch.nn.functional as F + + +class SiLU(nn.Module): + # SiLU activation https://arxiv.org/pdf/1606.08415.pdf + @staticmethod + def forward(x): + return x * torch.sigmoid(x) + + +class Hardswish(nn.Module): + # Hard-SiLU activation + @staticmethod + def forward(x): + # return x * F.hardsigmoid(x) # for TorchScript and CoreML + return x * F.hardtanh(x + 3, 0.0, 6.0) / 6.0 # for TorchScript, CoreML and ONNX + + +class Mish(nn.Module): + # Mish activation https://github.com/digantamisra98/Mish + @staticmethod + def forward(x): + return x * F.softplus(x).tanh() + + +class MemoryEfficientMish(nn.Module): + # Mish activation memory-efficient + class F(torch.autograd.Function): + + @staticmethod + def forward(ctx, x): + ctx.save_for_backward(x) + return x.mul(torch.tanh(F.softplus(x))) # x * tanh(ln(1 + exp(x))) + + @staticmethod + def backward(ctx, grad_output): + x = ctx.saved_tensors[0] + sx = torch.sigmoid(x) + fx = F.softplus(x).tanh() + return grad_output * (fx + x * sx * (1 - fx * fx)) + + def forward(self, x): + return self.F.apply(x) + + +class FReLU(nn.Module): + # FReLU activation https://arxiv.org/abs/2007.11824 + def __init__(self, c1, k=3): # ch_in, kernel + super().__init__() + self.conv = nn.Conv2d(c1, c1, k, 1, 1, groups=c1, bias=False) + self.bn = nn.BatchNorm2d(c1) + + def forward(self, x): + return torch.max(x, self.bn(self.conv(x))) + + +class AconC(nn.Module): + r""" ACON activation (activate or not) + AconC: (p1*x-p2*x) * sigmoid(beta*(p1*x-p2*x)) + p2*x, beta is a learnable parameter + according to "Activate or Not: Learning Customized Activation" . + """ + + def __init__(self, c1): + super().__init__() + self.p1 = nn.Parameter(torch.randn(1, c1, 1, 1)) + self.p2 = nn.Parameter(torch.randn(1, c1, 1, 1)) + self.beta = nn.Parameter(torch.ones(1, c1, 1, 1)) + + def forward(self, x): + dpx = (self.p1 - self.p2) * x + return dpx * torch.sigmoid(self.beta * dpx) + self.p2 * x + + +class MetaAconC(nn.Module): + r""" ACON activation (activate or not) + MetaAconC: (p1*x-p2*x) * sigmoid(beta*(p1*x-p2*x)) + p2*x, beta is generated by a small network + according to "Activate or Not: Learning Customized Activation" . + """ + + def __init__(self, c1, k=1, s=1, r=16): # ch_in, kernel, stride, r + super().__init__() + c2 = max(r, c1 // r) + self.p1 = nn.Parameter(torch.randn(1, c1, 1, 1)) + self.p2 = nn.Parameter(torch.randn(1, c1, 1, 1)) + self.fc1 = nn.Conv2d(c1, c2, k, s, bias=True) + self.fc2 = nn.Conv2d(c2, c1, k, s, bias=True) + # self.bn1 = nn.BatchNorm2d(c2) + # self.bn2 = nn.BatchNorm2d(c1) + + def forward(self, x): + y = x.mean(dim=2, keepdims=True).mean(dim=3, keepdims=True) + # batch-size 1 bug/instabilities https://github.com/ultralytics/yolov5/issues/2891 + # beta = torch.sigmoid(self.bn2(self.fc2(self.bn1(self.fc1(y))))) # bug/unstable + beta = torch.sigmoid(self.fc2(self.fc1(y))) # bug patch BN layers removed + dpx = (self.p1 - self.p2) * x + return dpx * torch.sigmoid(beta * dpx) + self.p2 * x diff --git a/cv/3d_detection/yolov9/pytorch/utils/augmentations.py b/cv/3d_detection/yolov9/pytorch/utils/augmentations.py new file mode 100644 index 000000000..ad4c07fb6 --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/utils/augmentations.py @@ -0,0 +1,395 @@ +import math +import random + +import cv2 +import numpy as np +import torch +import torchvision.transforms as T +import torchvision.transforms.functional as TF + +from utils.general import LOGGER, check_version, colorstr, resample_segments, segment2box, xywhn2xyxy +from utils.metrics import bbox_ioa + +IMAGENET_MEAN = 0.485, 0.456, 0.406 # RGB mean +IMAGENET_STD = 0.229, 0.224, 0.225 # RGB standard deviation + + +class Albumentations: + # YOLOv5 Albumentations class (optional, only used if package is installed) + def __init__(self, size=640): + self.transform = None + prefix = colorstr('albumentations: ') + try: + import albumentations as A + check_version(A.__version__, '1.0.3', hard=True) # version requirement + + T = [ + A.RandomResizedCrop(height=size, width=size, scale=(0.8, 1.0), ratio=(0.9, 1.11), p=0.0), + A.Blur(p=0.01), + A.MedianBlur(p=0.01), + A.ToGray(p=0.01), + A.CLAHE(p=0.01), + A.RandomBrightnessContrast(p=0.0), + A.RandomGamma(p=0.0), + A.ImageCompression(quality_lower=75, p=0.0)] # transforms + self.transform = A.Compose(T, bbox_params=A.BboxParams(format='yolo', label_fields=['class_labels'])) + + LOGGER.info(prefix + ', '.join(f'{x}'.replace('always_apply=False, ', '') for x in T if x.p)) + except ImportError: # package not installed, skip + pass + except Exception as e: + LOGGER.info(f'{prefix}{e}') + + def __call__(self, im, labels, p=1.0): + if self.transform and random.random() < p: + new = self.transform(image=im, bboxes=labels[:, 1:], class_labels=labels[:, 0]) # transformed + im, labels = new['image'], np.array([[c, *b] for c, b in zip(new['class_labels'], new['bboxes'])]) + return im, labels + + +def normalize(x, mean=IMAGENET_MEAN, std=IMAGENET_STD, inplace=False): + # Denormalize RGB images x per ImageNet stats in BCHW format, i.e. = (x - mean) / std + return TF.normalize(x, mean, std, inplace=inplace) + + +def denormalize(x, mean=IMAGENET_MEAN, std=IMAGENET_STD): + # Denormalize RGB images x per ImageNet stats in BCHW format, i.e. = x * std + mean + for i in range(3): + x[:, i] = x[:, i] * std[i] + mean[i] + return x + + +def augment_hsv(im, hgain=0.5, sgain=0.5, vgain=0.5): + # HSV color-space augmentation + if hgain or sgain or vgain: + r = np.random.uniform(-1, 1, 3) * [hgain, sgain, vgain] + 1 # random gains + hue, sat, val = cv2.split(cv2.cvtColor(im, cv2.COLOR_BGR2HSV)) + dtype = im.dtype # uint8 + + x = np.arange(0, 256, dtype=r.dtype) + lut_hue = ((x * r[0]) % 180).astype(dtype) + lut_sat = np.clip(x * r[1], 0, 255).astype(dtype) + lut_val = np.clip(x * r[2], 0, 255).astype(dtype) + + im_hsv = cv2.merge((cv2.LUT(hue, lut_hue), cv2.LUT(sat, lut_sat), cv2.LUT(val, lut_val))) + cv2.cvtColor(im_hsv, cv2.COLOR_HSV2BGR, dst=im) # no return needed + + +def hist_equalize(im, clahe=True, bgr=False): + # Equalize histogram on BGR image 'im' with im.shape(n,m,3) and range 0-255 + yuv = cv2.cvtColor(im, cv2.COLOR_BGR2YUV if bgr else cv2.COLOR_RGB2YUV) + if clahe: + c = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8)) + yuv[:, :, 0] = c.apply(yuv[:, :, 0]) + else: + yuv[:, :, 0] = cv2.equalizeHist(yuv[:, :, 0]) # equalize Y channel histogram + return cv2.cvtColor(yuv, cv2.COLOR_YUV2BGR if bgr else cv2.COLOR_YUV2RGB) # convert YUV image to RGB + + +def replicate(im, labels): + # Replicate labels + h, w = im.shape[:2] + boxes = labels[:, 1:].astype(int) + x1, y1, x2, y2 = boxes.T + s = ((x2 - x1) + (y2 - y1)) / 2 # side length (pixels) + for i in s.argsort()[:round(s.size * 0.5)]: # smallest indices + x1b, y1b, x2b, y2b = boxes[i] + bh, bw = y2b - y1b, x2b - x1b + yc, xc = int(random.uniform(0, h - bh)), int(random.uniform(0, w - bw)) # offset x, y + x1a, y1a, x2a, y2a = [xc, yc, xc + bw, yc + bh] + im[y1a:y2a, x1a:x2a] = im[y1b:y2b, x1b:x2b] # im4[ymin:ymax, xmin:xmax] + labels = np.append(labels, [[labels[i, 0], x1a, y1a, x2a, y2a]], axis=0) + + return im, labels + + +def letterbox(im, new_shape=(640, 640), color=(114, 114, 114), auto=True, scaleFill=False, scaleup=True, stride=32): + # Resize and pad image while meeting stride-multiple constraints + shape = im.shape[:2] # current shape [height, width] + if isinstance(new_shape, int): + new_shape = (new_shape, new_shape) + + # Scale ratio (new / old) + r = min(new_shape[0] / shape[0], new_shape[1] / shape[1]) + if not scaleup: # only scale down, do not scale up (for better val mAP) + r = min(r, 1.0) + + # Compute padding + ratio = r, r # width, height ratios + new_unpad = int(round(shape[1] * r)), int(round(shape[0] * r)) + dw, dh = new_shape[1] - new_unpad[0], new_shape[0] - new_unpad[1] # wh padding + if auto: # minimum rectangle + dw, dh = np.mod(dw, stride), np.mod(dh, stride) # wh padding + elif scaleFill: # stretch + dw, dh = 0.0, 0.0 + new_unpad = (new_shape[1], new_shape[0]) + ratio = new_shape[1] / shape[1], new_shape[0] / shape[0] # width, height ratios + + dw /= 2 # divide padding into 2 sides + dh /= 2 + + if shape[::-1] != new_unpad: # resize + im = cv2.resize(im, new_unpad, interpolation=cv2.INTER_LINEAR) + top, bottom = int(round(dh - 0.1)), int(round(dh + 0.1)) + left, right = int(round(dw - 0.1)), int(round(dw + 0.1)) + im = cv2.copyMakeBorder(im, top, bottom, left, right, cv2.BORDER_CONSTANT, value=color) # add border + return im, ratio, (dw, dh) + + +def random_perspective(im, + targets=(), + segments=(), + degrees=10, + translate=.1, + scale=.1, + shear=10, + perspective=0.0, + border=(0, 0)): + # torchvision.transforms.RandomAffine(degrees=(-10, 10), translate=(0.1, 0.1), scale=(0.9, 1.1), shear=(-10, 10)) + # targets = [cls, xyxy] + + height = im.shape[0] + border[0] * 2 # shape(h,w,c) + width = im.shape[1] + border[1] * 2 + + # Center + C = np.eye(3) + C[0, 2] = -im.shape[1] / 2 # x translation (pixels) + C[1, 2] = -im.shape[0] / 2 # y translation (pixels) + + # Perspective + P = np.eye(3) + P[2, 0] = random.uniform(-perspective, perspective) # x perspective (about y) + P[2, 1] = random.uniform(-perspective, perspective) # y perspective (about x) + + # Rotation and Scale + R = np.eye(3) + a = random.uniform(-degrees, degrees) + # a += random.choice([-180, -90, 0, 90]) # add 90deg rotations to small rotations + s = random.uniform(1 - scale, 1 + scale) + # s = 2 ** random.uniform(-scale, scale) + R[:2] = cv2.getRotationMatrix2D(angle=a, center=(0, 0), scale=s) + + # Shear + S = np.eye(3) + S[0, 1] = math.tan(random.uniform(-shear, shear) * math.pi / 180) # x shear (deg) + S[1, 0] = math.tan(random.uniform(-shear, shear) * math.pi / 180) # y shear (deg) + + # Translation + T = np.eye(3) + T[0, 2] = random.uniform(0.5 - translate, 0.5 + translate) * width # x translation (pixels) + T[1, 2] = random.uniform(0.5 - translate, 0.5 + translate) * height # y translation (pixels) + + # Combined rotation matrix + M = T @ S @ R @ P @ C # order of operations (right to left) is IMPORTANT + if (border[0] != 0) or (border[1] != 0) or (M != np.eye(3)).any(): # image changed + if perspective: + im = cv2.warpPerspective(im, M, dsize=(width, height), borderValue=(114, 114, 114)) + else: # affine + im = cv2.warpAffine(im, M[:2], dsize=(width, height), borderValue=(114, 114, 114)) + + # Visualize + # import matplotlib.pyplot as plt + # ax = plt.subplots(1, 2, figsize=(12, 6))[1].ravel() + # ax[0].imshow(im[:, :, ::-1]) # base + # ax[1].imshow(im2[:, :, ::-1]) # warped + + # Transform label coordinates + n = len(targets) + if n: + use_segments = any(x.any() for x in segments) + new = np.zeros((n, 4)) + if use_segments: # warp segments + segments = resample_segments(segments) # upsample + for i, segment in enumerate(segments): + xy = np.ones((len(segment), 3)) + xy[:, :2] = segment + xy = xy @ M.T # transform + xy = xy[:, :2] / xy[:, 2:3] if perspective else xy[:, :2] # perspective rescale or affine + + # clip + new[i] = segment2box(xy, width, height) + + else: # warp boxes + xy = np.ones((n * 4, 3)) + xy[:, :2] = targets[:, [1, 2, 3, 4, 1, 4, 3, 2]].reshape(n * 4, 2) # x1y1, x2y2, x1y2, x2y1 + xy = xy @ M.T # transform + xy = (xy[:, :2] / xy[:, 2:3] if perspective else xy[:, :2]).reshape(n, 8) # perspective rescale or affine + + # create new boxes + x = xy[:, [0, 2, 4, 6]] + y = xy[:, [1, 3, 5, 7]] + new = np.concatenate((x.min(1), y.min(1), x.max(1), y.max(1))).reshape(4, n).T + + # clip + new[:, [0, 2]] = new[:, [0, 2]].clip(0, width) + new[:, [1, 3]] = new[:, [1, 3]].clip(0, height) + + # filter candidates + i = box_candidates(box1=targets[:, 1:5].T * s, box2=new.T, area_thr=0.01 if use_segments else 0.10) + targets = targets[i] + targets[:, 1:5] = new[i] + + return im, targets + + +def copy_paste(im, labels, segments, p=0.5): + # Implement Copy-Paste augmentation https://arxiv.org/abs/2012.07177, labels as nx5 np.array(cls, xyxy) + n = len(segments) + if p and n: + h, w, c = im.shape # height, width, channels + im_new = np.zeros(im.shape, np.uint8) + + # calculate ioa first then select indexes randomly + boxes = np.stack([w - labels[:, 3], labels[:, 2], w - labels[:, 1], labels[:, 4]], axis=-1) # (n, 4) + ioa = bbox_ioa(boxes, labels[:, 1:5]) # intersection over area + indexes = np.nonzero((ioa < 0.30).all(1))[0] # (N, ) + n = len(indexes) + for j in random.sample(list(indexes), k=round(p * n)): + l, box, s = labels[j], boxes[j], segments[j] + labels = np.concatenate((labels, [[l[0], *box]]), 0) + segments.append(np.concatenate((w - s[:, 0:1], s[:, 1:2]), 1)) + cv2.drawContours(im_new, [segments[j].astype(np.int32)], -1, (1, 1, 1), cv2.FILLED) + + result = cv2.flip(im, 1) # augment segments (flip left-right) + i = cv2.flip(im_new, 1).astype(bool) + im[i] = result[i] # cv2.imwrite('debug.jpg', im) # debug + + return im, labels, segments + + +def cutout(im, labels, p=0.5): + # Applies image cutout augmentation https://arxiv.org/abs/1708.04552 + if random.random() < p: + h, w = im.shape[:2] + scales = [0.5] * 1 + [0.25] * 2 + [0.125] * 4 + [0.0625] * 8 + [0.03125] * 16 # image size fraction + for s in scales: + mask_h = random.randint(1, int(h * s)) # create random masks + mask_w = random.randint(1, int(w * s)) + + # box + xmin = max(0, random.randint(0, w) - mask_w // 2) + ymin = max(0, random.randint(0, h) - mask_h // 2) + xmax = min(w, xmin + mask_w) + ymax = min(h, ymin + mask_h) + + # apply random color mask + im[ymin:ymax, xmin:xmax] = [random.randint(64, 191) for _ in range(3)] + + # return unobscured labels + if len(labels) and s > 0.03: + box = np.array([[xmin, ymin, xmax, ymax]], dtype=np.float32) + ioa = bbox_ioa(box, xywhn2xyxy(labels[:, 1:5], w, h))[0] # intersection over area + labels = labels[ioa < 0.60] # remove >60% obscured labels + + return labels + + +def mixup(im, labels, im2, labels2): + # Applies MixUp augmentation https://arxiv.org/pdf/1710.09412.pdf + r = np.random.beta(32.0, 32.0) # mixup ratio, alpha=beta=32.0 + im = (im * r + im2 * (1 - r)).astype(np.uint8) + labels = np.concatenate((labels, labels2), 0) + return im, labels + + +def box_candidates(box1, box2, wh_thr=2, ar_thr=100, area_thr=0.1, eps=1e-16): # box1(4,n), box2(4,n) + # Compute candidate boxes: box1 before augment, box2 after augment, wh_thr (pixels), aspect_ratio_thr, area_ratio + w1, h1 = box1[2] - box1[0], box1[3] - box1[1] + w2, h2 = box2[2] - box2[0], box2[3] - box2[1] + ar = np.maximum(w2 / (h2 + eps), h2 / (w2 + eps)) # aspect ratio + return (w2 > wh_thr) & (h2 > wh_thr) & (w2 * h2 / (w1 * h1 + eps) > area_thr) & (ar < ar_thr) # candidates + + +def classify_albumentations( + augment=True, + size=224, + scale=(0.08, 1.0), + ratio=(0.75, 1.0 / 0.75), # 0.75, 1.33 + hflip=0.5, + vflip=0.0, + jitter=0.4, + mean=IMAGENET_MEAN, + std=IMAGENET_STD, + auto_aug=False): + # YOLOv5 classification Albumentations (optional, only used if package is installed) + prefix = colorstr('albumentations: ') + try: + import albumentations as A + from albumentations.pytorch import ToTensorV2 + check_version(A.__version__, '1.0.3', hard=True) # version requirement + if augment: # Resize and crop + T = [A.RandomResizedCrop(height=size, width=size, scale=scale, ratio=ratio)] + if auto_aug: + # TODO: implement AugMix, AutoAug & RandAug in albumentation + LOGGER.info(f'{prefix}auto augmentations are currently not supported') + else: + if hflip > 0: + T += [A.HorizontalFlip(p=hflip)] + if vflip > 0: + T += [A.VerticalFlip(p=vflip)] + if jitter > 0: + color_jitter = (float(jitter),) * 3 # repeat value for brightness, contrast, satuaration, 0 hue + T += [A.ColorJitter(*color_jitter, 0)] + else: # Use fixed crop for eval set (reproducibility) + T = [A.SmallestMaxSize(max_size=size), A.CenterCrop(height=size, width=size)] + T += [A.Normalize(mean=mean, std=std), ToTensorV2()] # Normalize and convert to Tensor + LOGGER.info(prefix + ', '.join(f'{x}'.replace('always_apply=False, ', '') for x in T if x.p)) + return A.Compose(T) + + except ImportError: # package not installed, skip + LOGGER.warning(f'{prefix}⚠️ not found, install with `pip install albumentations` (recommended)') + except Exception as e: + LOGGER.info(f'{prefix}{e}') + + +def classify_transforms(size=224): + # Transforms to apply if albumentations not installed + assert isinstance(size, int), f'ERROR: classify_transforms size {size} must be integer, not (list, tuple)' + # T.Compose([T.ToTensor(), T.Resize(size), T.CenterCrop(size), T.Normalize(IMAGENET_MEAN, IMAGENET_STD)]) + return T.Compose([CenterCrop(size), ToTensor(), T.Normalize(IMAGENET_MEAN, IMAGENET_STD)]) + + +class LetterBox: + # YOLOv5 LetterBox class for image preprocessing, i.e. T.Compose([LetterBox(size), ToTensor()]) + def __init__(self, size=(640, 640), auto=False, stride=32): + super().__init__() + self.h, self.w = (size, size) if isinstance(size, int) else size + self.auto = auto # pass max size integer, automatically solve for short side using stride + self.stride = stride # used with auto + + def __call__(self, im): # im = np.array HWC + imh, imw = im.shape[:2] + r = min(self.h / imh, self.w / imw) # ratio of new/old + h, w = round(imh * r), round(imw * r) # resized image + hs, ws = (math.ceil(x / self.stride) * self.stride for x in (h, w)) if self.auto else self.h, self.w + top, left = round((hs - h) / 2 - 0.1), round((ws - w) / 2 - 0.1) + im_out = np.full((self.h, self.w, 3), 114, dtype=im.dtype) + im_out[top:top + h, left:left + w] = cv2.resize(im, (w, h), interpolation=cv2.INTER_LINEAR) + return im_out + + +class CenterCrop: + # YOLOv5 CenterCrop class for image preprocessing, i.e. T.Compose([CenterCrop(size), ToTensor()]) + def __init__(self, size=640): + super().__init__() + self.h, self.w = (size, size) if isinstance(size, int) else size + + def __call__(self, im): # im = np.array HWC + imh, imw = im.shape[:2] + m = min(imh, imw) # min dimension + top, left = (imh - m) // 2, (imw - m) // 2 + return cv2.resize(im[top:top + m, left:left + m], (self.w, self.h), interpolation=cv2.INTER_LINEAR) + + +class ToTensor: + # YOLOv5 ToTensor class for image preprocessing, i.e. T.Compose([LetterBox(size), ToTensor()]) + def __init__(self, half=False): + super().__init__() + self.half = half + + def __call__(self, im): # im = np.array HWC in BGR order + im = np.ascontiguousarray(im.transpose((2, 0, 1))[::-1]) # HWC to CHW -> BGR to RGB -> contiguous + im = torch.from_numpy(im) # to torch + im = im.half() if self.half else im.float() # uint8 to fp16/32 + im /= 255.0 # 0-255 to 0.0-1.0 + return im diff --git a/cv/3d_detection/yolov9/pytorch/utils/autoanchor.py b/cv/3d_detection/yolov9/pytorch/utils/autoanchor.py new file mode 100644 index 000000000..bd81af92c --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/utils/autoanchor.py @@ -0,0 +1,164 @@ +import random + +import numpy as np +import torch +import yaml +from tqdm import tqdm + +from utils import TryExcept +from utils.general import LOGGER, TQDM_BAR_FORMAT, colorstr + +PREFIX = colorstr('AutoAnchor: ') + + +def check_anchor_order(m): + # Check anchor order against stride order for YOLOv5 Detect() module m, and correct if necessary + a = m.anchors.prod(-1).mean(-1).view(-1) # mean anchor area per output layer + da = a[-1] - a[0] # delta a + ds = m.stride[-1] - m.stride[0] # delta s + if da and (da.sign() != ds.sign()): # same order + LOGGER.info(f'{PREFIX}Reversing anchor order') + m.anchors[:] = m.anchors.flip(0) + + +@TryExcept(f'{PREFIX}ERROR') +def check_anchors(dataset, model, thr=4.0, imgsz=640): + # Check anchor fit to data, recompute if necessary + m = model.module.model[-1] if hasattr(model, 'module') else model.model[-1] # Detect() + shapes = imgsz * dataset.shapes / dataset.shapes.max(1, keepdims=True) + scale = np.random.uniform(0.9, 1.1, size=(shapes.shape[0], 1)) # augment scale + wh = torch.tensor(np.concatenate([l[:, 3:5] * s for s, l in zip(shapes * scale, dataset.labels)])).float() # wh + + def metric(k): # compute metric + r = wh[:, None] / k[None] + x = torch.min(r, 1 / r).min(2)[0] # ratio metric + best = x.max(1)[0] # best_x + aat = (x > 1 / thr).float().sum(1).mean() # anchors above threshold + bpr = (best > 1 / thr).float().mean() # best possible recall + return bpr, aat + + stride = m.stride.to(m.anchors.device).view(-1, 1, 1) # model strides + anchors = m.anchors.clone() * stride # current anchors + bpr, aat = metric(anchors.cpu().view(-1, 2)) + s = f'\n{PREFIX}{aat:.2f} anchors/target, {bpr:.3f} Best Possible Recall (BPR). ' + if bpr > 0.98: # threshold to recompute + LOGGER.info(f'{s}Current anchors are a good fit to dataset ✅') + else: + LOGGER.info(f'{s}Anchors are a poor fit to dataset ⚠️, attempting to improve...') + na = m.anchors.numel() // 2 # number of anchors + anchors = kmean_anchors(dataset, n=na, img_size=imgsz, thr=thr, gen=1000, verbose=False) + new_bpr = metric(anchors)[0] + if new_bpr > bpr: # replace anchors + anchors = torch.tensor(anchors, device=m.anchors.device).type_as(m.anchors) + m.anchors[:] = anchors.clone().view_as(m.anchors) + check_anchor_order(m) # must be in pixel-space (not grid-space) + m.anchors /= stride + s = f'{PREFIX}Done ✅ (optional: update model *.yaml to use these anchors in the future)' + else: + s = f'{PREFIX}Done ⚠️ (original anchors better than new anchors, proceeding with original anchors)' + LOGGER.info(s) + + +def kmean_anchors(dataset='./data/coco128.yaml', n=9, img_size=640, thr=4.0, gen=1000, verbose=True): + """ Creates kmeans-evolved anchors from training dataset + + Arguments: + dataset: path to data.yaml, or a loaded dataset + n: number of anchors + img_size: image size used for training + thr: anchor-label wh ratio threshold hyperparameter hyp['anchor_t'] used for training, default=4.0 + gen: generations to evolve anchors using genetic algorithm + verbose: print all results + + Return: + k: kmeans evolved anchors + + Usage: + from utils.autoanchor import *; _ = kmean_anchors() + """ + from scipy.cluster.vq import kmeans + + npr = np.random + thr = 1 / thr + + def metric(k, wh): # compute metrics + r = wh[:, None] / k[None] + x = torch.min(r, 1 / r).min(2)[0] # ratio metric + # x = wh_iou(wh, torch.tensor(k)) # iou metric + return x, x.max(1)[0] # x, best_x + + def anchor_fitness(k): # mutation fitness + _, best = metric(torch.tensor(k, dtype=torch.float32), wh) + return (best * (best > thr).float()).mean() # fitness + + def print_results(k, verbose=True): + k = k[np.argsort(k.prod(1))] # sort small to large + x, best = metric(k, wh0) + bpr, aat = (best > thr).float().mean(), (x > thr).float().mean() * n # best possible recall, anch > thr + s = f'{PREFIX}thr={thr:.2f}: {bpr:.4f} best possible recall, {aat:.2f} anchors past thr\n' \ + f'{PREFIX}n={n}, img_size={img_size}, metric_all={x.mean():.3f}/{best.mean():.3f}-mean/best, ' \ + f'past_thr={x[x > thr].mean():.3f}-mean: ' + for x in k: + s += '%i,%i, ' % (round(x[0]), round(x[1])) + if verbose: + LOGGER.info(s[:-2]) + return k + + if isinstance(dataset, str): # *.yaml file + with open(dataset, errors='ignore') as f: + data_dict = yaml.safe_load(f) # model dict + from utils.dataloaders import LoadImagesAndLabels + dataset = LoadImagesAndLabels(data_dict['train'], augment=True, rect=True) + + # Get label wh + shapes = img_size * dataset.shapes / dataset.shapes.max(1, keepdims=True) + wh0 = np.concatenate([l[:, 3:5] * s for s, l in zip(shapes, dataset.labels)]) # wh + + # Filter + i = (wh0 < 3.0).any(1).sum() + if i: + LOGGER.info(f'{PREFIX}WARNING ⚠️ Extremely small objects found: {i} of {len(wh0)} labels are <3 pixels in size') + wh = wh0[(wh0 >= 2.0).any(1)].astype(np.float32) # filter > 2 pixels + # wh = wh * (npr.rand(wh.shape[0], 1) * 0.9 + 0.1) # multiply by random scale 0-1 + + # Kmeans init + try: + LOGGER.info(f'{PREFIX}Running kmeans for {n} anchors on {len(wh)} points...') + assert n <= len(wh) # apply overdetermined constraint + s = wh.std(0) # sigmas for whitening + k = kmeans(wh / s, n, iter=30)[0] * s # points + assert n == len(k) # kmeans may return fewer points than requested if wh is insufficient or too similar + except Exception: + LOGGER.warning(f'{PREFIX}WARNING ⚠️ switching strategies from kmeans to random init') + k = np.sort(npr.rand(n * 2)).reshape(n, 2) * img_size # random init + wh, wh0 = (torch.tensor(x, dtype=torch.float32) for x in (wh, wh0)) + k = print_results(k, verbose=False) + + # Plot + # k, d = [None] * 20, [None] * 20 + # for i in tqdm(range(1, 21)): + # k[i-1], d[i-1] = kmeans(wh / s, i) # points, mean distance + # fig, ax = plt.subplots(1, 2, figsize=(14, 7), tight_layout=True) + # ax = ax.ravel() + # ax[0].plot(np.arange(1, 21), np.array(d) ** 2, marker='.') + # fig, ax = plt.subplots(1, 2, figsize=(14, 7)) # plot wh + # ax[0].hist(wh[wh[:, 0]<100, 0],400) + # ax[1].hist(wh[wh[:, 1]<100, 1],400) + # fig.savefig('wh.png', dpi=200) + + # Evolve + f, sh, mp, s = anchor_fitness(k), k.shape, 0.9, 0.1 # fitness, generations, mutation prob, sigma + pbar = tqdm(range(gen), bar_format=TQDM_BAR_FORMAT) # progress bar + for _ in pbar: + v = np.ones(sh) + while (v == 1).all(): # mutate until a change occurs (prevent duplicates) + v = ((npr.random(sh) < mp) * random.random() * npr.randn(*sh) * s + 1).clip(0.3, 3.0) + kg = (k.copy() * v).clip(min=2.0) + fg = anchor_fitness(kg) + if fg > f: + f, k = fg, kg.copy() + pbar.desc = f'{PREFIX}Evolving anchors with Genetic Algorithm: fitness = {f:.4f}' + if verbose: + print_results(k, verbose) + + return print_results(k).astype(np.float32) diff --git a/cv/3d_detection/yolov9/pytorch/utils/autobatch.py b/cv/3d_detection/yolov9/pytorch/utils/autobatch.py new file mode 100644 index 000000000..a5f0d519e --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/utils/autobatch.py @@ -0,0 +1,67 @@ +from copy import deepcopy + +import numpy as np +import torch + +from utils.general import LOGGER, colorstr +from utils.torch_utils import profile + + +def check_train_batch_size(model, imgsz=640, amp=True): + # Check YOLOv5 training batch size + with torch.cuda.amp.autocast(amp): + return autobatch(deepcopy(model).train(), imgsz) # compute optimal batch size + + +def autobatch(model, imgsz=640, fraction=0.8, batch_size=16): + # Automatically estimate best YOLOv5 batch size to use `fraction` of available CUDA memory + # Usage: + # import torch + # from utils.autobatch import autobatch + # model = torch.hub.load('ultralytics/yolov5', 'yolov5s', autoshape=False) + # print(autobatch(model)) + + # Check device + prefix = colorstr('AutoBatch: ') + LOGGER.info(f'{prefix}Computing optimal batch size for --imgsz {imgsz}') + device = next(model.parameters()).device # get model device + if device.type == 'cpu': + LOGGER.info(f'{prefix}CUDA not detected, using default CPU batch-size {batch_size}') + return batch_size + if torch.backends.cudnn.benchmark: + LOGGER.info(f'{prefix} ⚠️ Requires torch.backends.cudnn.benchmark=False, using default batch-size {batch_size}') + return batch_size + + # Inspect CUDA memory + gb = 1 << 30 # bytes to GiB (1024 ** 3) + d = str(device).upper() # 'CUDA:0' + properties = torch.cuda.get_device_properties(device) # device properties + t = properties.total_memory / gb # GiB total + r = torch.cuda.memory_reserved(device) / gb # GiB reserved + a = torch.cuda.memory_allocated(device) / gb # GiB allocated + f = t - (r + a) # GiB free + LOGGER.info(f'{prefix}{d} ({properties.name}) {t:.2f}G total, {r:.2f}G reserved, {a:.2f}G allocated, {f:.2f}G free') + + # Profile batch sizes + batch_sizes = [1, 2, 4, 8, 16] + try: + img = [torch.empty(b, 3, imgsz, imgsz) for b in batch_sizes] + results = profile(img, model, n=3, device=device) + except Exception as e: + LOGGER.warning(f'{prefix}{e}') + + # Fit a solution + y = [x[2] for x in results if x] # memory [2] + p = np.polyfit(batch_sizes[:len(y)], y, deg=1) # first degree polynomial fit + b = int((f * fraction - p[1]) / p[0]) # y intercept (optimal batch size) + if None in results: # some sizes failed + i = results.index(None) # first fail index + if b >= batch_sizes[i]: # y intercept above failure point + b = batch_sizes[max(i - 1, 0)] # select prior safe point + if b < 1 or b > 1024: # b outside of safe range + b = batch_size + LOGGER.warning(f'{prefix}WARNING ⚠️ CUDA anomaly detected, recommend restart environment and retry command.') + + fraction = (np.polyval(p, b) + r + a) / t # actual fraction predicted + LOGGER.info(f'{prefix}Using batch-size {b} for {d} {t * fraction:.2f}G/{t:.2f}G ({fraction * 100:.0f}%) ✅') + return b diff --git a/cv/3d_detection/yolov9/pytorch/utils/callbacks.py b/cv/3d_detection/yolov9/pytorch/utils/callbacks.py new file mode 100644 index 000000000..893708bb7 --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/utils/callbacks.py @@ -0,0 +1,71 @@ +import threading + + +class Callbacks: + """" + Handles all registered callbacks for YOLOv5 Hooks + """ + + def __init__(self): + # Define the available callbacks + self._callbacks = { + 'on_pretrain_routine_start': [], + 'on_pretrain_routine_end': [], + 'on_train_start': [], + 'on_train_epoch_start': [], + 'on_train_batch_start': [], + 'optimizer_step': [], + 'on_before_zero_grad': [], + 'on_train_batch_end': [], + 'on_train_epoch_end': [], + 'on_val_start': [], + 'on_val_batch_start': [], + 'on_val_image_end': [], + 'on_val_batch_end': [], + 'on_val_end': [], + 'on_fit_epoch_end': [], # fit = train + val + 'on_model_save': [], + 'on_train_end': [], + 'on_params_update': [], + 'teardown': [],} + self.stop_training = False # set True to interrupt training + + def register_action(self, hook, name='', callback=None): + """ + Register a new action to a callback hook + + Args: + hook: The callback hook name to register the action to + name: The name of the action for later reference + callback: The callback to fire + """ + assert hook in self._callbacks, f"hook '{hook}' not found in callbacks {self._callbacks}" + assert callable(callback), f"callback '{callback}' is not callable" + self._callbacks[hook].append({'name': name, 'callback': callback}) + + def get_registered_actions(self, hook=None): + """" + Returns all the registered actions by callback hook + + Args: + hook: The name of the hook to check, defaults to all + """ + return self._callbacks[hook] if hook else self._callbacks + + def run(self, hook, *args, thread=False, **kwargs): + """ + Loop through the registered actions and fire all callbacks on main thread + + Args: + hook: The name of the hook to check, defaults to all + args: Arguments to receive from YOLOv5 + thread: (boolean) Run callbacks in daemon thread + kwargs: Keyword Arguments to receive from YOLOv5 + """ + + assert hook in self._callbacks, f"hook '{hook}' not found in callbacks {self._callbacks}" + for logger in self._callbacks[hook]: + if thread: + threading.Thread(target=logger['callback'], args=args, kwargs=kwargs, daemon=True).start() + else: + logger['callback'](*args, **kwargs) diff --git a/cv/3d_detection/yolov9/pytorch/utils/coco_utils.py b/cv/3d_detection/yolov9/pytorch/utils/coco_utils.py new file mode 100644 index 000000000..87fa6e935 --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/utils/coco_utils.py @@ -0,0 +1,108 @@ +import cv2 + +from pycocotools.coco import COCO +from pycocotools import mask as maskUtils + +# coco id: https://tech.amikelive.com/node-718/what-object-categories-labels-are-in-coco-dataset/ +all_instances_ids = [ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, + 11, 13, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 27, 28, + 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, + 61, 62, 63, 64, 65, 67, 70, + 72, 73, 74, 75, 76, 77, 78, 79, 80, + 81, 82, 84, 85, 86, 87, 88, 89, 90, +] + +all_stuff_ids = [ + 92, 93, 94, 95, 96, 97, 98, 99, 100, + 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, + 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, + 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, + 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, + 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, + 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, + 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, + 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, + 181, 182, + # other + 183, + # unlabeled + 0, +] + +# panoptic id: https://github.com/cocodataset/panopticapi/blob/master/panoptic_coco_categories.json +panoptic_stuff_ids = [ + 92, 93, 95, 100, + 107, 109, + 112, 118, 119, + 122, 125, 128, 130, + 133, 138, + 141, 144, 145, 147, 148, 149, + 151, 154, 155, 156, 159, + 161, 166, 168, + 171, 175, 176, 177, 178, 180, + 181, 184, 185, 186, 187, 188, 189, 190, + 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, + # unlabeled + 0, +] + +def getCocoIds(name = 'semantic'): + if 'instances' == name: + return all_instances_ids + elif 'stuff' == name: + return all_stuff_ids + elif 'panoptic' == name: + return all_instances_ids + panoptic_stuff_ids + else: # semantic + return all_instances_ids + all_stuff_ids + +def getMappingId(index, name = 'semantic'): + ids = getCocoIds(name = name) + return ids[index] + +def getMappingIndex(id, name = 'semantic'): + ids = getCocoIds(name = name) + return ids.index(id) + +# convert ann to rle encoded string +def annToRLE(ann, img_size): + h, w = img_size + segm = ann['segmentation'] + if list == type(segm): + # polygon -- a single object might consist of multiple parts + # we merge all parts into one mask rle code + rles = maskUtils.frPyObjects(segm, h, w) + rle = maskUtils.merge(rles) + elif list == type(segm['counts']): + # uncompressed RLE + rle = maskUtils.frPyObjects(segm, h, w) + else: + # rle + rle = ann['segmentation'] + return rle + +# decode ann to mask martix +def annToMask(ann, img_size): + rle = annToRLE(ann, img_size) + m = maskUtils.decode(rle) + return m + +# convert mask to polygans +def convert_to_polys(mask): + # opencv 3.2 + contours, hierarchy = cv2.findContours((mask).astype(np.uint8), cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) + + # before opencv 3.2 + # contours, hierarchy = cv2.findContours((mask).astype(np.uint8), cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) + + segmentation = [] + for contour in contours: + contour = contour.flatten().tolist() + if 4 < len(contour): + segmentation.append(contour) + + return segmentation diff --git a/cv/3d_detection/yolov9/pytorch/utils/dataloaders.py b/cv/3d_detection/yolov9/pytorch/utils/dataloaders.py new file mode 100644 index 000000000..776042999 --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/utils/dataloaders.py @@ -0,0 +1,1217 @@ +import contextlib +import glob +import hashlib +import json +import math +import os +import random +import shutil +import time +from itertools import repeat +from multiprocessing.pool import Pool, ThreadPool +from pathlib import Path +from threading import Thread +from urllib.parse import urlparse + +import numpy as np +import psutil +import torch +import torch.nn.functional as F +import torchvision +import yaml +from PIL import ExifTags, Image, ImageOps +from torch.utils.data import DataLoader, Dataset, dataloader, distributed +from tqdm import tqdm + +from utils.augmentations import (Albumentations, augment_hsv, classify_albumentations, classify_transforms, copy_paste, + letterbox, mixup, random_perspective) +from utils.general import (DATASETS_DIR, LOGGER, NUM_THREADS, TQDM_BAR_FORMAT, check_dataset, check_requirements, + check_yaml, clean_str, cv2, is_colab, is_kaggle, segments2boxes, unzip_file, xyn2xy, + xywh2xyxy, xywhn2xyxy, xyxy2xywhn) +from utils.torch_utils import torch_distributed_zero_first + +# Parameters +HELP_URL = 'See https://github.com/ultralytics/yolov5/wiki/Train-Custom-Data' +IMG_FORMATS = 'bmp', 'dng', 'jpeg', 'jpg', 'mpo', 'png', 'tif', 'tiff', 'webp', 'pfm' # include image suffixes +VID_FORMATS = 'asf', 'avi', 'gif', 'm4v', 'mkv', 'mov', 'mp4', 'mpeg', 'mpg', 'ts', 'wmv' # include video suffixes +LOCAL_RANK = int(os.getenv('LOCAL_RANK', -1)) # https://pytorch.org/docs/stable/elastic/run.html +RANK = int(os.getenv('RANK', -1)) +PIN_MEMORY = str(os.getenv('PIN_MEMORY', True)).lower() == 'true' # global pin_memory for dataloaders + +# Get orientation exif tag +for orientation in ExifTags.TAGS.keys(): + if ExifTags.TAGS[orientation] == 'Orientation': + break + + +def get_hash(paths): + # Returns a single hash value of a list of paths (files or dirs) + size = sum(os.path.getsize(p) for p in paths if os.path.exists(p)) # sizes + h = hashlib.md5(str(size).encode()) # hash sizes + h.update(''.join(paths).encode()) # hash paths + return h.hexdigest() # return hash + + +def exif_size(img): + # Returns exif-corrected PIL size + s = img.size # (width, height) + with contextlib.suppress(Exception): + rotation = dict(img._getexif().items())[orientation] + if rotation in [6, 8]: # rotation 270 or 90 + s = (s[1], s[0]) + return s + + +def exif_transpose(image): + """ + Transpose a PIL image accordingly if it has an EXIF Orientation tag. + Inplace version of https://github.com/python-pillow/Pillow/blob/master/src/PIL/ImageOps.py exif_transpose() + + :param image: The image to transpose. + :return: An image. + """ + exif = image.getexif() + orientation = exif.get(0x0112, 1) # default 1 + if orientation > 1: + method = { + 2: Image.FLIP_LEFT_RIGHT, + 3: Image.ROTATE_180, + 4: Image.FLIP_TOP_BOTTOM, + 5: Image.TRANSPOSE, + 6: Image.ROTATE_270, + 7: Image.TRANSVERSE, + 8: Image.ROTATE_90}.get(orientation) + if method is not None: + image = image.transpose(method) + del exif[0x0112] + image.info["exif"] = exif.tobytes() + return image + + +def seed_worker(worker_id): + # Set dataloader worker seed https://pytorch.org/docs/stable/notes/randomness.html#dataloader + worker_seed = torch.initial_seed() % 2 ** 32 + np.random.seed(worker_seed) + random.seed(worker_seed) + + +def create_dataloader(path, + imgsz, + batch_size, + stride, + single_cls=False, + hyp=None, + augment=False, + cache=False, + pad=0.0, + rect=False, + rank=-1, + workers=8, + image_weights=False, + close_mosaic=False, + quad=False, + min_items=0, + prefix='', + shuffle=False): + if rect and shuffle: + LOGGER.warning('WARNING ⚠️ --rect is incompatible with DataLoader shuffle, setting shuffle=False') + shuffle = False + with torch_distributed_zero_first(rank): # init dataset *.cache only once if DDP + dataset = LoadImagesAndLabels( + path, + imgsz, + batch_size, + augment=augment, # augmentation + hyp=hyp, # hyperparameters + rect=rect, # rectangular batches + cache_images=cache, + single_cls=single_cls, + stride=int(stride), + pad=pad, + image_weights=image_weights, + min_items=min_items, + prefix=prefix) + + batch_size = min(batch_size, len(dataset)) + nd = torch.cuda.device_count() # number of CUDA devices + nw = min([os.cpu_count() // max(nd, 1), batch_size if batch_size > 1 else 0, workers]) # number of workers + sampler = None if rank == -1 else distributed.DistributedSampler(dataset, shuffle=shuffle) + #loader = DataLoader if image_weights else InfiniteDataLoader # only DataLoader allows for attribute updates + loader = DataLoader if image_weights or close_mosaic else InfiniteDataLoader + generator = torch.Generator() + generator.manual_seed(6148914691236517205 + RANK) + return loader(dataset, + batch_size=batch_size, + shuffle=shuffle and sampler is None, + num_workers=nw, + sampler=sampler, + pin_memory=PIN_MEMORY, + collate_fn=LoadImagesAndLabels.collate_fn4 if quad else LoadImagesAndLabels.collate_fn, + worker_init_fn=seed_worker, + generator=generator), dataset + + +class InfiniteDataLoader(dataloader.DataLoader): + """ Dataloader that reuses workers + + Uses same syntax as vanilla DataLoader + """ + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + object.__setattr__(self, 'batch_sampler', _RepeatSampler(self.batch_sampler)) + self.iterator = super().__iter__() + + def __len__(self): + return len(self.batch_sampler.sampler) + + def __iter__(self): + for _ in range(len(self)): + yield next(self.iterator) + + +class _RepeatSampler: + """ Sampler that repeats forever + + Args: + sampler (Sampler) + """ + + def __init__(self, sampler): + self.sampler = sampler + + def __iter__(self): + while True: + yield from iter(self.sampler) + + +class LoadScreenshots: + # YOLOv5 screenshot dataloader, i.e. `python detect.py --source "screen 0 100 100 512 256"` + def __init__(self, source, img_size=640, stride=32, auto=True, transforms=None): + # source = [screen_number left top width height] (pixels) + check_requirements('mss') + import mss + + source, *params = source.split() + self.screen, left, top, width, height = 0, None, None, None, None # default to full screen 0 + if len(params) == 1: + self.screen = int(params[0]) + elif len(params) == 4: + left, top, width, height = (int(x) for x in params) + elif len(params) == 5: + self.screen, left, top, width, height = (int(x) for x in params) + self.img_size = img_size + self.stride = stride + self.transforms = transforms + self.auto = auto + self.mode = 'stream' + self.frame = 0 + self.sct = mss.mss() + + # Parse monitor shape + monitor = self.sct.monitors[self.screen] + self.top = monitor["top"] if top is None else (monitor["top"] + top) + self.left = monitor["left"] if left is None else (monitor["left"] + left) + self.width = width or monitor["width"] + self.height = height or monitor["height"] + self.monitor = {"left": self.left, "top": self.top, "width": self.width, "height": self.height} + + def __iter__(self): + return self + + def __next__(self): + # mss screen capture: get raw pixels from the screen as np array + im0 = np.array(self.sct.grab(self.monitor))[:, :, :3] # [:, :, :3] BGRA to BGR + s = f"screen {self.screen} (LTWH): {self.left},{self.top},{self.width},{self.height}: " + + if self.transforms: + im = self.transforms(im0) # transforms + else: + im = letterbox(im0, self.img_size, stride=self.stride, auto=self.auto)[0] # padded resize + im = im.transpose((2, 0, 1))[::-1] # HWC to CHW, BGR to RGB + im = np.ascontiguousarray(im) # contiguous + self.frame += 1 + return str(self.screen), im, im0, None, s # screen, img, original img, im0s, s + + +class LoadImages: + # YOLOv5 image/video dataloader, i.e. `python detect.py --source image.jpg/vid.mp4` + def __init__(self, path, img_size=640, stride=32, auto=True, transforms=None, vid_stride=1): + files = [] + for p in sorted(path) if isinstance(path, (list, tuple)) else [path]: + p = str(Path(p).resolve()) + if '*' in p: + files.extend(sorted(glob.glob(p, recursive=True))) # glob + elif os.path.isdir(p): + files.extend(sorted(glob.glob(os.path.join(p, '*.*')))) # dir + elif os.path.isfile(p): + files.append(p) # files + else: + raise FileNotFoundError(f'{p} does not exist') + + images = [x for x in files if x.split('.')[-1].lower() in IMG_FORMATS] + videos = [x for x in files if x.split('.')[-1].lower() in VID_FORMATS] + ni, nv = len(images), len(videos) + + self.img_size = img_size + self.stride = stride + self.files = images + videos + self.nf = ni + nv # number of files + self.video_flag = [False] * ni + [True] * nv + self.mode = 'image' + self.auto = auto + self.transforms = transforms # optional + self.vid_stride = vid_stride # video frame-rate stride + if any(videos): + self._new_video(videos[0]) # new video + else: + self.cap = None + assert self.nf > 0, f'No images or videos found in {p}. ' \ + f'Supported formats are:\nimages: {IMG_FORMATS}\nvideos: {VID_FORMATS}' + + def __iter__(self): + self.count = 0 + return self + + def __next__(self): + if self.count == self.nf: + raise StopIteration + path = self.files[self.count] + + if self.video_flag[self.count]: + # Read video + self.mode = 'video' + for _ in range(self.vid_stride): + self.cap.grab() + ret_val, im0 = self.cap.retrieve() + while not ret_val: + self.count += 1 + self.cap.release() + if self.count == self.nf: # last video + raise StopIteration + path = self.files[self.count] + self._new_video(path) + ret_val, im0 = self.cap.read() + + self.frame += 1 + # im0 = self._cv2_rotate(im0) # for use if cv2 autorotation is False + s = f'video {self.count + 1}/{self.nf} ({self.frame}/{self.frames}) {path}: ' + + else: + # Read image + self.count += 1 + im0 = cv2.imread(path) # BGR + assert im0 is not None, f'Image Not Found {path}' + s = f'image {self.count}/{self.nf} {path}: ' + + if self.transforms: + im = self.transforms(im0) # transforms + else: + im = letterbox(im0, self.img_size, stride=self.stride, auto=self.auto)[0] # padded resize + im = im.transpose((2, 0, 1))[::-1] # HWC to CHW, BGR to RGB + im = np.ascontiguousarray(im) # contiguous + + return path, im, im0, self.cap, s + + def _new_video(self, path): + # Create a new video capture object + self.frame = 0 + self.cap = cv2.VideoCapture(path) + self.frames = int(self.cap.get(cv2.CAP_PROP_FRAME_COUNT) / self.vid_stride) + self.orientation = int(self.cap.get(cv2.CAP_PROP_ORIENTATION_META)) # rotation degrees + # self.cap.set(cv2.CAP_PROP_ORIENTATION_AUTO, 0) # disable https://github.com/ultralytics/yolov5/issues/8493 + + def _cv2_rotate(self, im): + # Rotate a cv2 video manually + if self.orientation == 0: + return cv2.rotate(im, cv2.ROTATE_90_CLOCKWISE) + elif self.orientation == 180: + return cv2.rotate(im, cv2.ROTATE_90_COUNTERCLOCKWISE) + elif self.orientation == 90: + return cv2.rotate(im, cv2.ROTATE_180) + return im + + def __len__(self): + return self.nf # number of files + + +class LoadStreams: + # YOLOv5 streamloader, i.e. `python detect.py --source 'rtsp://example.com/media.mp4' # RTSP, RTMP, HTTP streams` + def __init__(self, sources='streams.txt', img_size=640, stride=32, auto=True, transforms=None, vid_stride=1): + torch.backends.cudnn.benchmark = True # faster for fixed-size inference + self.mode = 'stream' + self.img_size = img_size + self.stride = stride + self.vid_stride = vid_stride # video frame-rate stride + sources = Path(sources).read_text().rsplit() if os.path.isfile(sources) else [sources] + n = len(sources) + self.sources = [clean_str(x) for x in sources] # clean source names for later + self.imgs, self.fps, self.frames, self.threads = [None] * n, [0] * n, [0] * n, [None] * n + for i, s in enumerate(sources): # index, source + # Start thread to read frames from video stream + st = f'{i + 1}/{n}: {s}... ' + if urlparse(s).hostname in ('www.youtube.com', 'youtube.com', 'youtu.be'): # if source is YouTube video + # YouTube format i.e. 'https://www.youtube.com/watch?v=Zgi9g1ksQHc' or 'https://youtu.be/Zgi9g1ksQHc' + check_requirements(('pafy', 'youtube_dl==2020.12.2')) + import pafy + s = pafy.new(s).getbest(preftype="mp4").url # YouTube URL + s = eval(s) if s.isnumeric() else s # i.e. s = '0' local webcam + if s == 0: + assert not is_colab(), '--source 0 webcam unsupported on Colab. Rerun command in a local environment.' + assert not is_kaggle(), '--source 0 webcam unsupported on Kaggle. Rerun command in a local environment.' + cap = cv2.VideoCapture(s) + assert cap.isOpened(), f'{st}Failed to open {s}' + w = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) + h = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) + fps = cap.get(cv2.CAP_PROP_FPS) # warning: may return 0 or nan + self.frames[i] = max(int(cap.get(cv2.CAP_PROP_FRAME_COUNT)), 0) or float('inf') # infinite stream fallback + self.fps[i] = max((fps if math.isfinite(fps) else 0) % 100, 0) or 30 # 30 FPS fallback + + _, self.imgs[i] = cap.read() # guarantee first frame + self.threads[i] = Thread(target=self.update, args=([i, cap, s]), daemon=True) + LOGGER.info(f"{st} Success ({self.frames[i]} frames {w}x{h} at {self.fps[i]:.2f} FPS)") + self.threads[i].start() + LOGGER.info('') # newline + + # check for common shapes + s = np.stack([letterbox(x, img_size, stride=stride, auto=auto)[0].shape for x in self.imgs]) + self.rect = np.unique(s, axis=0).shape[0] == 1 # rect inference if all shapes equal + self.auto = auto and self.rect + self.transforms = transforms # optional + if not self.rect: + LOGGER.warning('WARNING ⚠️ Stream shapes differ. For optimal performance supply similarly-shaped streams.') + + def update(self, i, cap, stream): + # Read stream `i` frames in daemon thread + n, f = 0, self.frames[i] # frame number, frame array + while cap.isOpened() and n < f: + n += 1 + cap.grab() # .read() = .grab() followed by .retrieve() + if n % self.vid_stride == 0: + success, im = cap.retrieve() + if success: + self.imgs[i] = im + else: + LOGGER.warning('WARNING ⚠️ Video stream unresponsive, please check your IP camera connection.') + self.imgs[i] = np.zeros_like(self.imgs[i]) + cap.open(stream) # re-open stream if signal was lost + time.sleep(0.0) # wait time + + def __iter__(self): + self.count = -1 + return self + + def __next__(self): + self.count += 1 + if not all(x.is_alive() for x in self.threads) or cv2.waitKey(1) == ord('q'): # q to quit + cv2.destroyAllWindows() + raise StopIteration + + im0 = self.imgs.copy() + if self.transforms: + im = np.stack([self.transforms(x) for x in im0]) # transforms + else: + im = np.stack([letterbox(x, self.img_size, stride=self.stride, auto=self.auto)[0] for x in im0]) # resize + im = im[..., ::-1].transpose((0, 3, 1, 2)) # BGR to RGB, BHWC to BCHW + im = np.ascontiguousarray(im) # contiguous + + return self.sources, im, im0, None, '' + + def __len__(self): + return len(self.sources) # 1E12 frames = 32 streams at 30 FPS for 30 years + + +def img2label_paths(img_paths): + # Define label paths as a function of image paths + sa, sb = f'{os.sep}images{os.sep}', f'{os.sep}labels{os.sep}' # /images/, /labels/ substrings + return [sb.join(x.rsplit(sa, 1)).rsplit('.', 1)[0] + '.txt' for x in img_paths] + + +class LoadImagesAndLabels(Dataset): + # YOLOv5 train_loader/val_loader, loads images and labels for training and validation + cache_version = 0.6 # dataset labels *.cache version + rand_interp_methods = [cv2.INTER_NEAREST, cv2.INTER_LINEAR, cv2.INTER_CUBIC, cv2.INTER_AREA, cv2.INTER_LANCZOS4] + + def __init__(self, + path, + img_size=640, + batch_size=16, + augment=False, + hyp=None, + rect=False, + image_weights=False, + cache_images=False, + single_cls=False, + stride=32, + pad=0.0, + min_items=0, + prefix=''): + self.img_size = img_size + self.augment = augment + self.hyp = hyp + self.image_weights = image_weights + self.rect = False if image_weights else rect + self.mosaic = self.augment and not self.rect # load 4 images at a time into a mosaic (only during training) + self.mosaic_border = [-img_size // 2, -img_size // 2] + self.stride = stride + self.path = path + self.albumentations = Albumentations(size=img_size) if augment else None + + try: + f = [] # image files + for p in path if isinstance(path, list) else [path]: + p = Path(p) # os-agnostic + if p.is_dir(): # dir + f += glob.glob(str(p / '**' / '*.*'), recursive=True) + # f = list(p.rglob('*.*')) # pathlib + elif p.is_file(): # file + with open(p) as t: + t = t.read().strip().splitlines() + parent = str(p.parent) + os.sep + f += [x.replace('./', parent, 1) if x.startswith('./') else x for x in t] # to global path + # f += [p.parent / x.lstrip(os.sep) for x in t] # to global path (pathlib) + else: + raise FileNotFoundError(f'{prefix}{p} does not exist') + self.im_files = sorted(x.replace('/', os.sep) for x in f if x.split('.')[-1].lower() in IMG_FORMATS) + # self.img_files = sorted([x for x in f if x.suffix[1:].lower() in IMG_FORMATS]) # pathlib + assert self.im_files, f'{prefix}No images found' + except Exception as e: + raise Exception(f'{prefix}Error loading data from {path}: {e}\n{HELP_URL}') from e + + # Check cache + self.label_files = img2label_paths(self.im_files) # labels + cache_path = (p if p.is_file() else Path(self.label_files[0]).parent).with_suffix('.cache') + try: + cache, exists = np.load(cache_path, allow_pickle=True).item(), True # load dict + assert cache['version'] == self.cache_version # matches current version + assert cache['hash'] == get_hash(self.label_files + self.im_files) # identical hash + except Exception: + cache, exists = self.cache_labels(cache_path, prefix), False # run cache ops + + # Display cache + nf, nm, ne, nc, n = cache.pop('results') # found, missing, empty, corrupt, total + if exists and LOCAL_RANK in {-1, 0}: + d = f"Scanning {cache_path}... {nf} images, {nm + ne} backgrounds, {nc} corrupt" + tqdm(None, desc=prefix + d, total=n, initial=n, bar_format=TQDM_BAR_FORMAT) # display cache results + if cache['msgs']: + LOGGER.info('\n'.join(cache['msgs'])) # display warnings + assert nf > 0 or not augment, f'{prefix}No labels found in {cache_path}, can not start training. {HELP_URL}' + + # Read cache + [cache.pop(k) for k in ('hash', 'version', 'msgs')] # remove items + labels, shapes, self.segments = zip(*cache.values()) + nl = len(np.concatenate(labels, 0)) # number of labels + assert nl > 0 or not augment, f'{prefix}All labels empty in {cache_path}, can not start training. {HELP_URL}' + self.labels = list(labels) + self.shapes = np.array(shapes) + self.im_files = list(cache.keys()) # update + self.label_files = img2label_paths(cache.keys()) # update + + # Filter images + if min_items: + include = np.array([len(x) >= min_items for x in self.labels]).nonzero()[0].astype(int) + LOGGER.info(f'{prefix}{n - len(include)}/{n} images filtered from dataset') + self.im_files = [self.im_files[i] for i in include] + self.label_files = [self.label_files[i] for i in include] + self.labels = [self.labels[i] for i in include] + self.segments = [self.segments[i] for i in include] + self.shapes = self.shapes[include] # wh + + # Create indices + n = len(self.shapes) # number of images + bi = np.floor(np.arange(n) / batch_size).astype(int) # batch index + nb = bi[-1] + 1 # number of batches + self.batch = bi # batch index of image + self.n = n + self.indices = range(n) + + # Update labels + include_class = [] # filter labels to include only these classes (optional) + include_class_array = np.array(include_class).reshape(1, -1) + for i, (label, segment) in enumerate(zip(self.labels, self.segments)): + if include_class: + j = (label[:, 0:1] == include_class_array).any(1) + self.labels[i] = label[j] + if segment: + self.segments[i] = segment[j] + if single_cls: # single-class training, merge all classes into 0 + self.labels[i][:, 0] = 0 + + # Rectangular Training + if self.rect: + # Sort by aspect ratio + s = self.shapes # wh + ar = s[:, 1] / s[:, 0] # aspect ratio + irect = ar.argsort() + self.im_files = [self.im_files[i] for i in irect] + self.label_files = [self.label_files[i] for i in irect] + self.labels = [self.labels[i] for i in irect] + self.segments = [self.segments[i] for i in irect] + self.shapes = s[irect] # wh + ar = ar[irect] + + # Set training image shapes + shapes = [[1, 1]] * nb + for i in range(nb): + ari = ar[bi == i] + mini, maxi = ari.min(), ari.max() + if maxi < 1: + shapes[i] = [maxi, 1] + elif mini > 1: + shapes[i] = [1, 1 / mini] + + self.batch_shapes = np.ceil(np.array(shapes) * img_size / stride + pad).astype(int) * stride + + # Cache images into RAM/disk for faster training + if cache_images == 'ram' and not self.check_cache_ram(prefix=prefix): + cache_images = False + self.ims = [None] * n + self.npy_files = [Path(f).with_suffix('.npy') for f in self.im_files] + if cache_images: + b, gb = 0, 1 << 30 # bytes of cached images, bytes per gigabytes + self.im_hw0, self.im_hw = [None] * n, [None] * n + fcn = self.cache_images_to_disk if cache_images == 'disk' else self.load_image + results = ThreadPool(NUM_THREADS).imap(fcn, range(n)) + pbar = tqdm(enumerate(results), total=n, bar_format=TQDM_BAR_FORMAT, disable=LOCAL_RANK > 0) + for i, x in pbar: + if cache_images == 'disk': + b += self.npy_files[i].stat().st_size + else: # 'ram' + self.ims[i], self.im_hw0[i], self.im_hw[i] = x # im, hw_orig, hw_resized = load_image(self, i) + b += self.ims[i].nbytes + pbar.desc = f'{prefix}Caching images ({b / gb:.1f}GB {cache_images})' + pbar.close() + + def check_cache_ram(self, safety_margin=0.1, prefix=''): + # Check image caching requirements vs available memory + b, gb = 0, 1 << 30 # bytes of cached images, bytes per gigabytes + n = min(self.n, 30) # extrapolate from 30 random images + for _ in range(n): + im = cv2.imread(random.choice(self.im_files)) # sample image + ratio = self.img_size / max(im.shape[0], im.shape[1]) # max(h, w) # ratio + b += im.nbytes * ratio ** 2 + mem_required = b * self.n / n # GB required to cache dataset into RAM + mem = psutil.virtual_memory() + cache = mem_required * (1 + safety_margin) < mem.available # to cache or not to cache, that is the question + if not cache: + LOGGER.info(f"{prefix}{mem_required / gb:.1f}GB RAM required, " + f"{mem.available / gb:.1f}/{mem.total / gb:.1f}GB available, " + f"{'caching images ✅' if cache else 'not caching images ⚠️'}") + return cache + + def cache_labels(self, path=Path('./labels.cache'), prefix=''): + # Cache dataset labels, check images and read shapes + x = {} # dict + nm, nf, ne, nc, msgs = 0, 0, 0, 0, [] # number missing, found, empty, corrupt, messages + desc = f"{prefix}Scanning {path.parent / path.stem}..." + with Pool(NUM_THREADS) as pool: + pbar = tqdm(pool.imap(verify_image_label, zip(self.im_files, self.label_files, repeat(prefix))), + desc=desc, + total=len(self.im_files), + bar_format=TQDM_BAR_FORMAT) + for im_file, lb, shape, segments, nm_f, nf_f, ne_f, nc_f, msg in pbar: + nm += nm_f + nf += nf_f + ne += ne_f + nc += nc_f + if im_file: + x[im_file] = [lb, shape, segments] + if msg: + msgs.append(msg) + pbar.desc = f"{desc} {nf} images, {nm + ne} backgrounds, {nc} corrupt" + + pbar.close() + if msgs: + LOGGER.info('\n'.join(msgs)) + if nf == 0: + LOGGER.warning(f'{prefix}WARNING ⚠️ No labels found in {path}. {HELP_URL}') + x['hash'] = get_hash(self.label_files + self.im_files) + x['results'] = nf, nm, ne, nc, len(self.im_files) + x['msgs'] = msgs # warnings + x['version'] = self.cache_version # cache version + try: + np.save(path, x) # save cache for next time + path.with_suffix('.cache.npy').rename(path) # remove .npy suffix + LOGGER.info(f'{prefix}New cache created: {path}') + except Exception as e: + LOGGER.warning(f'{prefix}WARNING ⚠️ Cache directory {path.parent} is not writeable: {e}') # not writeable + return x + + def __len__(self): + return len(self.im_files) + + # def __iter__(self): + # self.count = -1 + # print('ran dataset iter') + # #self.shuffled_vector = np.random.permutation(self.nF) if self.augment else np.arange(self.nF) + # return self + + def __getitem__(self, index): + index = self.indices[index] # linear, shuffled, or image_weights + + hyp = self.hyp + mosaic = self.mosaic and random.random() < hyp['mosaic'] + if mosaic: + # Load mosaic + img, labels = self.load_mosaic(index) + shapes = None + + # MixUp augmentation + if random.random() < hyp['mixup']: + img, labels = mixup(img, labels, *self.load_mosaic(random.randint(0, self.n - 1))) + + else: + # Load image + img, (h0, w0), (h, w) = self.load_image(index) + + # Letterbox + shape = self.batch_shapes[self.batch[index]] if self.rect else self.img_size # final letterboxed shape + img, ratio, pad = letterbox(img, shape, auto=False, scaleup=self.augment) + shapes = (h0, w0), ((h / h0, w / w0), pad) # for COCO mAP rescaling + + labels = self.labels[index].copy() + if labels.size: # normalized xywh to pixel xyxy format + labels[:, 1:] = xywhn2xyxy(labels[:, 1:], ratio[0] * w, ratio[1] * h, padw=pad[0], padh=pad[1]) + + if self.augment: + img, labels = random_perspective(img, + labels, + degrees=hyp['degrees'], + translate=hyp['translate'], + scale=hyp['scale'], + shear=hyp['shear'], + perspective=hyp['perspective']) + + nl = len(labels) # number of labels + if nl: + labels[:, 1:5] = xyxy2xywhn(labels[:, 1:5], w=img.shape[1], h=img.shape[0], clip=True, eps=1E-3) + + if self.augment: + # Albumentations + img, labels = self.albumentations(img, labels) + nl = len(labels) # update after albumentations + + # HSV color-space + augment_hsv(img, hgain=hyp['hsv_h'], sgain=hyp['hsv_s'], vgain=hyp['hsv_v']) + + # Flip up-down + if random.random() < hyp['flipud']: + img = np.flipud(img) + if nl: + labels[:, 2] = 1 - labels[:, 2] + + # Flip left-right + if random.random() < hyp['fliplr']: + img = np.fliplr(img) + if nl: + labels[:, 1] = 1 - labels[:, 1] + + # Cutouts + # labels = cutout(img, labels, p=0.5) + # nl = len(labels) # update after cutout + + labels_out = torch.zeros((nl, 6)) + if nl: + labels_out[:, 1:] = torch.from_numpy(labels) + + # Convert + img = img.transpose((2, 0, 1))[::-1] # HWC to CHW, BGR to RGB + img = np.ascontiguousarray(img) + + return torch.from_numpy(img), labels_out, self.im_files[index], shapes + + def load_image(self, i): + # Loads 1 image from dataset index 'i', returns (im, original hw, resized hw) + im, f, fn = self.ims[i], self.im_files[i], self.npy_files[i], + if im is None: # not cached in RAM + if fn.exists(): # load npy + im = np.load(fn) + else: # read image + im = cv2.imread(f) # BGR + assert im is not None, f'Image Not Found {f}' + h0, w0 = im.shape[:2] # orig hw + r = self.img_size / max(h0, w0) # ratio + if r != 1: # if sizes are not equal + interp = cv2.INTER_LINEAR if (self.augment or r > 1) else cv2.INTER_AREA + im = cv2.resize(im, (int(w0 * r), int(h0 * r)), interpolation=interp) + return im, (h0, w0), im.shape[:2] # im, hw_original, hw_resized + return self.ims[i], self.im_hw0[i], self.im_hw[i] # im, hw_original, hw_resized + + def cache_images_to_disk(self, i): + # Saves an image as an *.npy file for faster loading + f = self.npy_files[i] + if not f.exists(): + np.save(f.as_posix(), cv2.imread(self.im_files[i])) + + def load_mosaic(self, index): + # YOLOv5 4-mosaic loader. Loads 1 image + 3 random images into a 4-image mosaic + labels4, segments4 = [], [] + s = self.img_size + yc, xc = (int(random.uniform(-x, 2 * s + x)) for x in self.mosaic_border) # mosaic center x, y + indices = [index] + random.choices(self.indices, k=3) # 3 additional image indices + random.shuffle(indices) + for i, index in enumerate(indices): + # Load image + img, _, (h, w) = self.load_image(index) + + # place img in img4 + if i == 0: # top left + img4 = np.full((s * 2, s * 2, img.shape[2]), 114, dtype=np.uint8) # base image with 4 tiles + x1a, y1a, x2a, y2a = max(xc - w, 0), max(yc - h, 0), xc, yc # xmin, ymin, xmax, ymax (large image) + x1b, y1b, x2b, y2b = w - (x2a - x1a), h - (y2a - y1a), w, h # xmin, ymin, xmax, ymax (small image) + elif i == 1: # top right + x1a, y1a, x2a, y2a = xc, max(yc - h, 0), min(xc + w, s * 2), yc + x1b, y1b, x2b, y2b = 0, h - (y2a - y1a), min(w, x2a - x1a), h + elif i == 2: # bottom left + x1a, y1a, x2a, y2a = max(xc - w, 0), yc, xc, min(s * 2, yc + h) + x1b, y1b, x2b, y2b = w - (x2a - x1a), 0, w, min(y2a - y1a, h) + elif i == 3: # bottom right + x1a, y1a, x2a, y2a = xc, yc, min(xc + w, s * 2), min(s * 2, yc + h) + x1b, y1b, x2b, y2b = 0, 0, min(w, x2a - x1a), min(y2a - y1a, h) + + img4[y1a:y2a, x1a:x2a] = img[y1b:y2b, x1b:x2b] # img4[ymin:ymax, xmin:xmax] + padw = x1a - x1b + padh = y1a - y1b + + # Labels + labels, segments = self.labels[index].copy(), self.segments[index].copy() + if labels.size: + labels[:, 1:] = xywhn2xyxy(labels[:, 1:], w, h, padw, padh) # normalized xywh to pixel xyxy format + segments = [xyn2xy(x, w, h, padw, padh) for x in segments] + labels4.append(labels) + segments4.extend(segments) + + # Concat/clip labels + labels4 = np.concatenate(labels4, 0) + for x in (labels4[:, 1:], *segments4): + np.clip(x, 0, 2 * s, out=x) # clip when using random_perspective() + # img4, labels4 = replicate(img4, labels4) # replicate + + # Augment + img4, labels4, segments4 = copy_paste(img4, labels4, segments4, p=self.hyp['copy_paste']) + img4, labels4 = random_perspective(img4, + labels4, + segments4, + degrees=self.hyp['degrees'], + translate=self.hyp['translate'], + scale=self.hyp['scale'], + shear=self.hyp['shear'], + perspective=self.hyp['perspective'], + border=self.mosaic_border) # border to remove + + return img4, labels4 + + def load_mosaic9(self, index): + # YOLOv5 9-mosaic loader. Loads 1 image + 8 random images into a 9-image mosaic + labels9, segments9 = [], [] + s = self.img_size + indices = [index] + random.choices(self.indices, k=8) # 8 additional image indices + random.shuffle(indices) + hp, wp = -1, -1 # height, width previous + for i, index in enumerate(indices): + # Load image + img, _, (h, w) = self.load_image(index) + + # place img in img9 + if i == 0: # center + img9 = np.full((s * 3, s * 3, img.shape[2]), 114, dtype=np.uint8) # base image with 4 tiles + h0, w0 = h, w + c = s, s, s + w, s + h # xmin, ymin, xmax, ymax (base) coordinates + elif i == 1: # top + c = s, s - h, s + w, s + elif i == 2: # top right + c = s + wp, s - h, s + wp + w, s + elif i == 3: # right + c = s + w0, s, s + w0 + w, s + h + elif i == 4: # bottom right + c = s + w0, s + hp, s + w0 + w, s + hp + h + elif i == 5: # bottom + c = s + w0 - w, s + h0, s + w0, s + h0 + h + elif i == 6: # bottom left + c = s + w0 - wp - w, s + h0, s + w0 - wp, s + h0 + h + elif i == 7: # left + c = s - w, s + h0 - h, s, s + h0 + elif i == 8: # top left + c = s - w, s + h0 - hp - h, s, s + h0 - hp + + padx, pady = c[:2] + x1, y1, x2, y2 = (max(x, 0) for x in c) # allocate coords + + # Labels + labels, segments = self.labels[index].copy(), self.segments[index].copy() + if labels.size: + labels[:, 1:] = xywhn2xyxy(labels[:, 1:], w, h, padx, pady) # normalized xywh to pixel xyxy format + segments = [xyn2xy(x, w, h, padx, pady) for x in segments] + labels9.append(labels) + segments9.extend(segments) + + # Image + img9[y1:y2, x1:x2] = img[y1 - pady:, x1 - padx:] # img9[ymin:ymax, xmin:xmax] + hp, wp = h, w # height, width previous + + # Offset + yc, xc = (int(random.uniform(0, s)) for _ in self.mosaic_border) # mosaic center x, y + img9 = img9[yc:yc + 2 * s, xc:xc + 2 * s] + + # Concat/clip labels + labels9 = np.concatenate(labels9, 0) + labels9[:, [1, 3]] -= xc + labels9[:, [2, 4]] -= yc + c = np.array([xc, yc]) # centers + segments9 = [x - c for x in segments9] + + for x in (labels9[:, 1:], *segments9): + np.clip(x, 0, 2 * s, out=x) # clip when using random_perspective() + # img9, labels9 = replicate(img9, labels9) # replicate + + # Augment + img9, labels9, segments9 = copy_paste(img9, labels9, segments9, p=self.hyp['copy_paste']) + img9, labels9 = random_perspective(img9, + labels9, + segments9, + degrees=self.hyp['degrees'], + translate=self.hyp['translate'], + scale=self.hyp['scale'], + shear=self.hyp['shear'], + perspective=self.hyp['perspective'], + border=self.mosaic_border) # border to remove + + return img9, labels9 + + @staticmethod + def collate_fn(batch): + im, label, path, shapes = zip(*batch) # transposed + for i, lb in enumerate(label): + lb[:, 0] = i # add target image index for build_targets() + return torch.stack(im, 0), torch.cat(label, 0), path, shapes + + @staticmethod + def collate_fn4(batch): + im, label, path, shapes = zip(*batch) # transposed + n = len(shapes) // 4 + im4, label4, path4, shapes4 = [], [], path[:n], shapes[:n] + + ho = torch.tensor([[0.0, 0, 0, 1, 0, 0]]) + wo = torch.tensor([[0.0, 0, 1, 0, 0, 0]]) + s = torch.tensor([[1, 1, 0.5, 0.5, 0.5, 0.5]]) # scale + for i in range(n): # zidane torch.zeros(16,3,720,1280) # BCHW + i *= 4 + if random.random() < 0.5: + im1 = F.interpolate(im[i].unsqueeze(0).float(), scale_factor=2.0, mode='bilinear', + align_corners=False)[0].type(im[i].type()) + lb = label[i] + else: + im1 = torch.cat((torch.cat((im[i], im[i + 1]), 1), torch.cat((im[i + 2], im[i + 3]), 1)), 2) + lb = torch.cat((label[i], label[i + 1] + ho, label[i + 2] + wo, label[i + 3] + ho + wo), 0) * s + im4.append(im1) + label4.append(lb) + + for i, lb in enumerate(label4): + lb[:, 0] = i # add target image index for build_targets() + + return torch.stack(im4, 0), torch.cat(label4, 0), path4, shapes4 + + +# Ancillary functions -------------------------------------------------------------------------------------------------- +def flatten_recursive(path=DATASETS_DIR / 'coco128'): + # Flatten a recursive directory by bringing all files to top level + new_path = Path(f'{str(path)}_flat') + if os.path.exists(new_path): + shutil.rmtree(new_path) # delete output folder + os.makedirs(new_path) # make new output folder + for file in tqdm(glob.glob(f'{str(Path(path))}/**/*.*', recursive=True)): + shutil.copyfile(file, new_path / Path(file).name) + + +def extract_boxes(path=DATASETS_DIR / 'coco128'): # from utils.dataloaders import *; extract_boxes() + # Convert detection dataset into classification dataset, with one directory per class + path = Path(path) # images dir + shutil.rmtree(path / 'classification') if (path / 'classification').is_dir() else None # remove existing + files = list(path.rglob('*.*')) + n = len(files) # number of files + for im_file in tqdm(files, total=n): + if im_file.suffix[1:] in IMG_FORMATS: + # image + im = cv2.imread(str(im_file))[..., ::-1] # BGR to RGB + h, w = im.shape[:2] + + # labels + lb_file = Path(img2label_paths([str(im_file)])[0]) + if Path(lb_file).exists(): + with open(lb_file) as f: + lb = np.array([x.split() for x in f.read().strip().splitlines()], dtype=np.float32) # labels + + for j, x in enumerate(lb): + c = int(x[0]) # class + f = (path / 'classifier') / f'{c}' / f'{path.stem}_{im_file.stem}_{j}.jpg' # new filename + if not f.parent.is_dir(): + f.parent.mkdir(parents=True) + + b = x[1:] * [w, h, w, h] # box + # b[2:] = b[2:].max() # rectangle to square + b[2:] = b[2:] * 1.2 + 3 # pad + b = xywh2xyxy(b.reshape(-1, 4)).ravel().astype(int) + + b[[0, 2]] = np.clip(b[[0, 2]], 0, w) # clip boxes outside of image + b[[1, 3]] = np.clip(b[[1, 3]], 0, h) + assert cv2.imwrite(str(f), im[b[1]:b[3], b[0]:b[2]]), f'box failure in {f}' + + +def autosplit(path=DATASETS_DIR / 'coco128/images', weights=(0.9, 0.1, 0.0), annotated_only=False): + """ Autosplit a dataset into train/val/test splits and save path/autosplit_*.txt files + Usage: from utils.dataloaders import *; autosplit() + Arguments + path: Path to images directory + weights: Train, val, test weights (list, tuple) + annotated_only: Only use images with an annotated txt file + """ + path = Path(path) # images dir + files = sorted(x for x in path.rglob('*.*') if x.suffix[1:].lower() in IMG_FORMATS) # image files only + n = len(files) # number of files + random.seed(0) # for reproducibility + indices = random.choices([0, 1, 2], weights=weights, k=n) # assign each image to a split + + txt = ['autosplit_train.txt', 'autosplit_val.txt', 'autosplit_test.txt'] # 3 txt files + for x in txt: + if (path.parent / x).exists(): + (path.parent / x).unlink() # remove existing + + print(f'Autosplitting images from {path}' + ', using *.txt labeled images only' * annotated_only) + for i, img in tqdm(zip(indices, files), total=n): + if not annotated_only or Path(img2label_paths([str(img)])[0]).exists(): # check label + with open(path.parent / txt[i], 'a') as f: + f.write(f'./{img.relative_to(path.parent).as_posix()}' + '\n') # add image to txt file + + +def verify_image_label(args): + # Verify one image-label pair + im_file, lb_file, prefix = args + nm, nf, ne, nc, msg, segments = 0, 0, 0, 0, '', [] # number (missing, found, empty, corrupt), message, segments + try: + # verify images + im = Image.open(im_file) + im.verify() # PIL verify + shape = exif_size(im) # image size + assert (shape[0] > 9) & (shape[1] > 9), f'image size {shape} <10 pixels' + assert im.format.lower() in IMG_FORMATS, f'invalid image format {im.format}' + if im.format.lower() in ('jpg', 'jpeg'): + with open(im_file, 'rb') as f: + f.seek(-2, 2) + if f.read() != b'\xff\xd9': # corrupt JPEG + ImageOps.exif_transpose(Image.open(im_file)).save(im_file, 'JPEG', subsampling=0, quality=100) + msg = f'{prefix}WARNING ⚠️ {im_file}: corrupt JPEG restored and saved' + + # verify labels + if os.path.isfile(lb_file): + nf = 1 # label found + with open(lb_file) as f: + lb = [x.split() for x in f.read().strip().splitlines() if len(x)] + if any(len(x) > 6 for x in lb): # is segment + classes = np.array([x[0] for x in lb], dtype=np.float32) + segments = [np.array(x[1:], dtype=np.float32).reshape(-1, 2) for x in lb] # (cls, xy1...) + lb = np.concatenate((classes.reshape(-1, 1), segments2boxes(segments)), 1) # (cls, xywh) + lb = np.array(lb, dtype=np.float32) + nl = len(lb) + if nl: + assert lb.shape[1] == 5, f'labels require 5 columns, {lb.shape[1]} columns detected' + assert (lb >= 0).all(), f'negative label values {lb[lb < 0]}' + assert (lb[:, 1:] <= 1).all(), f'non-normalized or out of bounds coordinates {lb[:, 1:][lb[:, 1:] > 1]}' + _, i = np.unique(lb, axis=0, return_index=True) + if len(i) < nl: # duplicate row check + lb = lb[i] # remove duplicates + if segments: + segments = [segments[x] for x in i] + msg = f'{prefix}WARNING ⚠️ {im_file}: {nl - len(i)} duplicate labels removed' + else: + ne = 1 # label empty + lb = np.zeros((0, 5), dtype=np.float32) + else: + nm = 1 # label missing + lb = np.zeros((0, 5), dtype=np.float32) + return im_file, lb, shape, segments, nm, nf, ne, nc, msg + except Exception as e: + nc = 1 + msg = f'{prefix}WARNING ⚠️ {im_file}: ignoring corrupt image/label: {e}' + return [None, None, None, None, nm, nf, ne, nc, msg] + + +class HUBDatasetStats(): + """ Class for generating HUB dataset JSON and `-hub` dataset directory + + Arguments + path: Path to data.yaml or data.zip (with data.yaml inside data.zip) + autodownload: Attempt to download dataset if not found locally + + Usage + from utils.dataloaders import HUBDatasetStats + stats = HUBDatasetStats('coco128.yaml', autodownload=True) # usage 1 + stats = HUBDatasetStats('path/to/coco128.zip') # usage 2 + stats.get_json(save=False) + stats.process_images() + """ + + def __init__(self, path='coco128.yaml', autodownload=False): + # Initialize class + zipped, data_dir, yaml_path = self._unzip(Path(path)) + try: + with open(check_yaml(yaml_path), errors='ignore') as f: + data = yaml.safe_load(f) # data dict + if zipped: + data['path'] = data_dir + except Exception as e: + raise Exception("error/HUB/dataset_stats/yaml_load") from e + + check_dataset(data, autodownload) # download dataset if missing + self.hub_dir = Path(data['path'] + '-hub') + self.im_dir = self.hub_dir / 'images' + self.im_dir.mkdir(parents=True, exist_ok=True) # makes /images + self.stats = {'nc': data['nc'], 'names': list(data['names'].values())} # statistics dictionary + self.data = data + + @staticmethod + def _find_yaml(dir): + # Return data.yaml file + files = list(dir.glob('*.yaml')) or list(dir.rglob('*.yaml')) # try root level first and then recursive + assert files, f'No *.yaml file found in {dir}' + if len(files) > 1: + files = [f for f in files if f.stem == dir.stem] # prefer *.yaml files that match dir name + assert files, f'Multiple *.yaml files found in {dir}, only 1 *.yaml file allowed' + assert len(files) == 1, f'Multiple *.yaml files found: {files}, only 1 *.yaml file allowed in {dir}' + return files[0] + + def _unzip(self, path): + # Unzip data.zip + if not str(path).endswith('.zip'): # path is data.yaml + return False, None, path + assert Path(path).is_file(), f'Error unzipping {path}, file not found' + unzip_file(path, path=path.parent) + dir = path.with_suffix('') # dataset directory == zip name + assert dir.is_dir(), f'Error unzipping {path}, {dir} not found. path/to/abc.zip MUST unzip to path/to/abc/' + return True, str(dir), self._find_yaml(dir) # zipped, data_dir, yaml_path + + def _hub_ops(self, f, max_dim=1920): + # HUB ops for 1 image 'f': resize and save at reduced quality in /dataset-hub for web/app viewing + f_new = self.im_dir / Path(f).name # dataset-hub image filename + try: # use PIL + im = Image.open(f) + r = max_dim / max(im.height, im.width) # ratio + if r < 1.0: # image too large + im = im.resize((int(im.width * r), int(im.height * r))) + im.save(f_new, 'JPEG', quality=50, optimize=True) # save + except Exception as e: # use OpenCV + LOGGER.info(f'WARNING ⚠️ HUB ops PIL failure {f}: {e}') + im = cv2.imread(f) + im_height, im_width = im.shape[:2] + r = max_dim / max(im_height, im_width) # ratio + if r < 1.0: # image too large + im = cv2.resize(im, (int(im_width * r), int(im_height * r)), interpolation=cv2.INTER_AREA) + cv2.imwrite(str(f_new), im) + + def get_json(self, save=False, verbose=False): + # Return dataset JSON for Ultralytics HUB + def _round(labels): + # Update labels to integer class and 6 decimal place floats + return [[int(c), *(round(x, 4) for x in points)] for c, *points in labels] + + for split in 'train', 'val', 'test': + if self.data.get(split) is None: + self.stats[split] = None # i.e. no test set + continue + dataset = LoadImagesAndLabels(self.data[split]) # load dataset + x = np.array([ + np.bincount(label[:, 0].astype(int), minlength=self.data['nc']) + for label in tqdm(dataset.labels, total=dataset.n, desc='Statistics')]) # shape(128x80) + self.stats[split] = { + 'instance_stats': { + 'total': int(x.sum()), + 'per_class': x.sum(0).tolist()}, + 'image_stats': { + 'total': dataset.n, + 'unlabelled': int(np.all(x == 0, 1).sum()), + 'per_class': (x > 0).sum(0).tolist()}, + 'labels': [{ + str(Path(k).name): _round(v.tolist())} for k, v in zip(dataset.im_files, dataset.labels)]} + + # Save, print and return + if save: + stats_path = self.hub_dir / 'stats.json' + print(f'Saving {stats_path.resolve()}...') + with open(stats_path, 'w') as f: + json.dump(self.stats, f) # save stats.json + if verbose: + print(json.dumps(self.stats, indent=2, sort_keys=False)) + return self.stats + + def process_images(self): + # Compress images for Ultralytics HUB + for split in 'train', 'val', 'test': + if self.data.get(split) is None: + continue + dataset = LoadImagesAndLabels(self.data[split]) # load dataset + desc = f'{split} images' + for _ in tqdm(ThreadPool(NUM_THREADS).imap(self._hub_ops, dataset.im_files), total=dataset.n, desc=desc): + pass + print(f'Done. All images saved to {self.im_dir}') + return self.im_dir + + +# Classification dataloaders ------------------------------------------------------------------------------------------- +class ClassificationDataset(torchvision.datasets.ImageFolder): + """ + YOLOv5 Classification Dataset. + Arguments + root: Dataset path + transform: torchvision transforms, used by default + album_transform: Albumentations transforms, used if installed + """ + + def __init__(self, root, augment, imgsz, cache=False): + super().__init__(root=root) + self.torch_transforms = classify_transforms(imgsz) + self.album_transforms = classify_albumentations(augment, imgsz) if augment else None + self.cache_ram = cache is True or cache == 'ram' + self.cache_disk = cache == 'disk' + self.samples = [list(x) + [Path(x[0]).with_suffix('.npy'), None] for x in self.samples] # file, index, npy, im + + def __getitem__(self, i): + f, j, fn, im = self.samples[i] # filename, index, filename.with_suffix('.npy'), image + if self.cache_ram and im is None: + im = self.samples[i][3] = cv2.imread(f) + elif self.cache_disk: + if not fn.exists(): # load npy + np.save(fn.as_posix(), cv2.imread(f)) + im = np.load(fn) + else: # read image + im = cv2.imread(f) # BGR + if self.album_transforms: + sample = self.album_transforms(image=cv2.cvtColor(im, cv2.COLOR_BGR2RGB))["image"] + else: + sample = self.torch_transforms(im) + return sample, j + + +def create_classification_dataloader(path, + imgsz=224, + batch_size=16, + augment=True, + cache=False, + rank=-1, + workers=8, + shuffle=True): + # Returns Dataloader object to be used with YOLOv5 Classifier + with torch_distributed_zero_first(rank): # init dataset *.cache only once if DDP + dataset = ClassificationDataset(root=path, imgsz=imgsz, augment=augment, cache=cache) + batch_size = min(batch_size, len(dataset)) + nd = torch.cuda.device_count() + nw = min([os.cpu_count() // max(nd, 1), batch_size if batch_size > 1 else 0, workers]) + sampler = None if rank == -1 else distributed.DistributedSampler(dataset, shuffle=shuffle) + generator = torch.Generator() + generator.manual_seed(6148914691236517205 + RANK) + return InfiniteDataLoader(dataset, + batch_size=batch_size, + shuffle=shuffle and sampler is None, + num_workers=nw, + sampler=sampler, + pin_memory=PIN_MEMORY, + worker_init_fn=seed_worker, + generator=generator) # or DataLoader(persistent_workers=True) diff --git a/cv/3d_detection/yolov9/pytorch/utils/downloads.py b/cv/3d_detection/yolov9/pytorch/utils/downloads.py new file mode 100644 index 000000000..a108313b3 --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/utils/downloads.py @@ -0,0 +1,103 @@ +import logging +import os +import subprocess +import urllib +from pathlib import Path + +import requests +import torch + + +def is_url(url, check=True): + # Check if string is URL and check if URL exists + try: + url = str(url) + result = urllib.parse.urlparse(url) + assert all([result.scheme, result.netloc]) # check if is url + return (urllib.request.urlopen(url).getcode() == 200) if check else True # check if exists online + except (AssertionError, urllib.request.HTTPError): + return False + + +def gsutil_getsize(url=''): + # gs://bucket/file size https://cloud.google.com/storage/docs/gsutil/commands/du + s = subprocess.check_output(f'gsutil du {url}', shell=True).decode('utf-8') + return eval(s.split(' ')[0]) if len(s) else 0 # bytes + + +def url_getsize(url='https://ultralytics.com/images/bus.jpg'): + # Return downloadable file size in bytes + response = requests.head(url, allow_redirects=True) + return int(response.headers.get('content-length', -1)) + + +def safe_download(file, url, url2=None, min_bytes=1E0, error_msg=''): + # Attempts to download file from url or url2, checks and removes incomplete downloads < min_bytes + from utils.general import LOGGER + + file = Path(file) + assert_msg = f"Downloaded file '{file}' does not exist or size is < min_bytes={min_bytes}" + try: # url1 + LOGGER.info(f'Downloading {url} to {file}...') + torch.hub.download_url_to_file(url, str(file), progress=LOGGER.level <= logging.INFO) + assert file.exists() and file.stat().st_size > min_bytes, assert_msg # check + except Exception as e: # url2 + if file.exists(): + file.unlink() # remove partial downloads + LOGGER.info(f'ERROR: {e}\nRe-attempting {url2 or url} to {file}...') + os.system(f"curl -# -L '{url2 or url}' -o '{file}' --retry 3 -C -") # curl download, retry and resume on fail + finally: + if not file.exists() or file.stat().st_size < min_bytes: # check + if file.exists(): + file.unlink() # remove partial downloads + LOGGER.info(f"ERROR: {assert_msg}\n{error_msg}") + LOGGER.info('') + + +def attempt_download(file, repo='ultralytics/yolov5', release='v7.0'): + # Attempt file download from GitHub release assets if not found locally. release = 'latest', 'v7.0', etc. + from utils.general import LOGGER + + def github_assets(repository, version='latest'): + # Return GitHub repo tag (i.e. 'v7.0') and assets (i.e. ['yolov5s.pt', 'yolov5m.pt', ...]) + if version != 'latest': + version = f'tags/{version}' # i.e. tags/v7.0 + response = requests.get(f'https://api.github.com/repos/{repository}/releases/{version}').json() # github api + return response['tag_name'], [x['name'] for x in response['assets']] # tag, assets + + file = Path(str(file).strip().replace("'", '')) + if not file.exists(): + # URL specified + name = Path(urllib.parse.unquote(str(file))).name # decode '%2F' to '/' etc. + if str(file).startswith(('http:/', 'https:/')): # download + url = str(file).replace(':/', '://') # Pathlib turns :// -> :/ + file = name.split('?')[0] # parse authentication https://url.com/file.txt?auth... + if Path(file).is_file(): + LOGGER.info(f'Found {url} locally at {file}') # file already exists + else: + safe_download(file=file, url=url, min_bytes=1E5) + return file + + # GitHub assets + assets = [f'yolov5{size}{suffix}.pt' for size in 'nsmlx' for suffix in ('', '6', '-cls', '-seg')] # default + try: + tag, assets = github_assets(repo, release) + except Exception: + try: + tag, assets = github_assets(repo) # latest release + except Exception: + try: + tag = subprocess.check_output('git tag', shell=True, stderr=subprocess.STDOUT).decode().split()[-1] + except Exception: + tag = release + + file.parent.mkdir(parents=True, exist_ok=True) # make parent dir (if required) + if name in assets: + url3 = 'https://drive.google.com/drive/folders/1EFQTEUeXWSFww0luse2jB9M1QNZQGwNl' # backup gdrive mirror + safe_download( + file, + url=f'https://github.com/{repo}/releases/download/{tag}/{name}', + min_bytes=1E5, + error_msg=f'{file} missing, try downloading from https://github.com/{repo}/releases/{tag} or {url3}') + + return str(file) diff --git a/cv/3d_detection/yolov9/pytorch/utils/general.py b/cv/3d_detection/yolov9/pytorch/utils/general.py new file mode 100644 index 000000000..efe78b29a --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/utils/general.py @@ -0,0 +1,1135 @@ +import contextlib +import glob +import inspect +import logging +import logging.config +import math +import os +import platform +import random +import re +import signal +import sys +import time +import urllib +from copy import deepcopy +from datetime import datetime +from itertools import repeat +from multiprocessing.pool import ThreadPool +from pathlib import Path +from subprocess import check_output +from tarfile import is_tarfile +from typing import Optional +from zipfile import ZipFile, is_zipfile + +import cv2 +import IPython +import numpy as np +import pandas as pd +import pkg_resources as pkg +import torch +import torchvision +import yaml + +from utils import TryExcept, emojis +from utils.downloads import gsutil_getsize +from utils.metrics import box_iou, fitness + +FILE = Path(__file__).resolve() +ROOT = FILE.parents[1] # YOLO root directory +RANK = int(os.getenv('RANK', -1)) + +# Settings +NUM_THREADS = min(8, max(1, os.cpu_count() - 1)) # number of YOLOv5 multiprocessing threads +DATASETS_DIR = Path(os.getenv('YOLOv5_DATASETS_DIR', ROOT.parent / 'datasets')) # global datasets directory +AUTOINSTALL = str(os.getenv('YOLOv5_AUTOINSTALL', True)).lower() == 'true' # global auto-install mode +VERBOSE = str(os.getenv('YOLOv5_VERBOSE', True)).lower() == 'true' # global verbose mode +TQDM_BAR_FORMAT = '{l_bar}{bar:10}| {n_fmt}/{total_fmt} {elapsed}' # tqdm bar format +FONT = 'Arial.ttf' # https://ultralytics.com/assets/Arial.ttf + +torch.set_printoptions(linewidth=320, precision=5, profile='long') +np.set_printoptions(linewidth=320, formatter={'float_kind': '{:11.5g}'.format}) # format short g, %precision=5 +pd.options.display.max_columns = 10 +cv2.setNumThreads(0) # prevent OpenCV from multithreading (incompatible with PyTorch DataLoader) +os.environ['NUMEXPR_MAX_THREADS'] = str(NUM_THREADS) # NumExpr max threads +os.environ['OMP_NUM_THREADS'] = '1' if platform.system() == 'darwin' else str(NUM_THREADS) # OpenMP (PyTorch and SciPy) + + +def is_ascii(s=''): + # Is string composed of all ASCII (no UTF) characters? (note str().isascii() introduced in python 3.7) + s = str(s) # convert list, tuple, None, etc. to str + return len(s.encode().decode('ascii', 'ignore')) == len(s) + + +def is_chinese(s='人工智能'): + # Is string composed of any Chinese characters? + return bool(re.search('[\u4e00-\u9fff]', str(s))) + + +def is_colab(): + # Is environment a Google Colab instance? + return 'google.colab' in sys.modules + + +def is_notebook(): + # Is environment a Jupyter notebook? Verified on Colab, Jupyterlab, Kaggle, Paperspace + ipython_type = str(type(IPython.get_ipython())) + return 'colab' in ipython_type or 'zmqshell' in ipython_type + + +def is_kaggle(): + # Is environment a Kaggle Notebook? + return os.environ.get('PWD') == '/kaggle/working' and os.environ.get('KAGGLE_URL_BASE') == 'https://www.kaggle.com' + + +def is_docker() -> bool: + """Check if the process runs inside a docker container.""" + if Path("/.dockerenv").exists(): + return True + try: # check if docker is in control groups + with open("/proc/self/cgroup") as file: + return any("docker" in line for line in file) + except OSError: + return False + + +def is_writeable(dir, test=False): + # Return True if directory has write permissions, test opening a file with write permissions if test=True + if not test: + return os.access(dir, os.W_OK) # possible issues on Windows + file = Path(dir) / 'tmp.txt' + try: + with open(file, 'w'): # open file with write permissions + pass + file.unlink() # remove file + return True + except OSError: + return False + + +LOGGING_NAME = "yolov5" + + +def set_logging(name=LOGGING_NAME, verbose=True): + # sets up logging for the given name + rank = int(os.getenv('RANK', -1)) # rank in world for Multi-GPU trainings + level = logging.INFO if verbose and rank in {-1, 0} else logging.ERROR + logging.config.dictConfig({ + "version": 1, + "disable_existing_loggers": False, + "formatters": { + name: { + "format": "%(message)s"}}, + "handlers": { + name: { + "class": "logging.StreamHandler", + "formatter": name, + "level": level,}}, + "loggers": { + name: { + "level": level, + "handlers": [name], + "propagate": False,}}}) + + +set_logging(LOGGING_NAME) # run before defining LOGGER +LOGGER = logging.getLogger(LOGGING_NAME) # define globally (used in train.py, val.py, detect.py, etc.) +if platform.system() == 'Windows': + for fn in LOGGER.info, LOGGER.warning: + setattr(LOGGER, fn.__name__, lambda x: fn(emojis(x))) # emoji safe logging + + +def user_config_dir(dir='Ultralytics', env_var='YOLOV5_CONFIG_DIR'): + # Return path of user configuration directory. Prefer environment variable if exists. Make dir if required. + env = os.getenv(env_var) + if env: + path = Path(env) # use environment variable + else: + cfg = {'Windows': 'AppData/Roaming', 'Linux': '.config', 'Darwin': 'Library/Application Support'} # 3 OS dirs + path = Path.home() / cfg.get(platform.system(), '') # OS-specific config dir + path = (path if is_writeable(path) else Path('/tmp')) / dir # GCP and AWS lambda fix, only /tmp is writeable + path.mkdir(exist_ok=True) # make if required + return path + + +CONFIG_DIR = user_config_dir() # Ultralytics settings dir + + +class Profile(contextlib.ContextDecorator): + # YOLO Profile class. Usage: @Profile() decorator or 'with Profile():' context manager + def __init__(self, t=0.0): + self.t = t + self.cuda = torch.cuda.is_available() + + def __enter__(self): + self.start = self.time() + return self + + def __exit__(self, type, value, traceback): + self.dt = self.time() - self.start # delta-time + self.t += self.dt # accumulate dt + + def time(self): + if self.cuda: + torch.cuda.synchronize() + return time.time() + + +class Timeout(contextlib.ContextDecorator): + # YOLO Timeout class. Usage: @Timeout(seconds) decorator or 'with Timeout(seconds):' context manager + def __init__(self, seconds, *, timeout_msg='', suppress_timeout_errors=True): + self.seconds = int(seconds) + self.timeout_message = timeout_msg + self.suppress = bool(suppress_timeout_errors) + + def _timeout_handler(self, signum, frame): + raise TimeoutError(self.timeout_message) + + def __enter__(self): + if platform.system() != 'Windows': # not supported on Windows + signal.signal(signal.SIGALRM, self._timeout_handler) # Set handler for SIGALRM + signal.alarm(self.seconds) # start countdown for SIGALRM to be raised + + def __exit__(self, exc_type, exc_val, exc_tb): + if platform.system() != 'Windows': + signal.alarm(0) # Cancel SIGALRM if it's scheduled + if self.suppress and exc_type is TimeoutError: # Suppress TimeoutError + return True + + +class WorkingDirectory(contextlib.ContextDecorator): + # Usage: @WorkingDirectory(dir) decorator or 'with WorkingDirectory(dir):' context manager + def __init__(self, new_dir): + self.dir = new_dir # new dir + self.cwd = Path.cwd().resolve() # current dir + + def __enter__(self): + os.chdir(self.dir) + + def __exit__(self, exc_type, exc_val, exc_tb): + os.chdir(self.cwd) + + +def methods(instance): + # Get class/instance methods + return [f for f in dir(instance) if callable(getattr(instance, f)) and not f.startswith("__")] + + +def print_args(args: Optional[dict] = None, show_file=True, show_func=False): + # Print function arguments (optional args dict) + x = inspect.currentframe().f_back # previous frame + file, _, func, _, _ = inspect.getframeinfo(x) + if args is None: # get args automatically + args, _, _, frm = inspect.getargvalues(x) + args = {k: v for k, v in frm.items() if k in args} + try: + file = Path(file).resolve().relative_to(ROOT).with_suffix('') + except ValueError: + file = Path(file).stem + s = (f'{file}: ' if show_file else '') + (f'{func}: ' if show_func else '') + LOGGER.info(colorstr(s) + ', '.join(f'{k}={v}' for k, v in args.items())) + + +def init_seeds(seed=0, deterministic=False): + # Initialize random number generator (RNG) seeds https://pytorch.org/docs/stable/notes/randomness.html + random.seed(seed) + np.random.seed(seed) + torch.manual_seed(seed) + torch.cuda.manual_seed(seed) + torch.cuda.manual_seed_all(seed) # for Multi-GPU, exception safe + # torch.backends.cudnn.benchmark = True # AutoBatch problem https://github.com/ultralytics/yolov5/issues/9287 + if deterministic and check_version(torch.__version__, '1.12.0'): # https://github.com/ultralytics/yolov5/pull/8213 + torch.use_deterministic_algorithms(True) + torch.backends.cudnn.deterministic = True + os.environ['CUBLAS_WORKSPACE_CONFIG'] = ':4096:8' + os.environ['PYTHONHASHSEED'] = str(seed) + + +def intersect_dicts(da, db, exclude=()): + # Dictionary intersection of matching keys and shapes, omitting 'exclude' keys, using da values + return {k: v for k, v in da.items() if k in db and all(x not in k for x in exclude) and v.shape == db[k].shape} + + +def get_default_args(func): + # Get func() default arguments + signature = inspect.signature(func) + return {k: v.default for k, v in signature.parameters.items() if v.default is not inspect.Parameter.empty} + + +def get_latest_run(search_dir='.'): + # Return path to most recent 'last.pt' in /runs (i.e. to --resume from) + last_list = glob.glob(f'{search_dir}/**/last*.pt', recursive=True) + return max(last_list, key=os.path.getctime) if last_list else '' + + +def file_age(path=__file__): + # Return days since last file update + dt = (datetime.now() - datetime.fromtimestamp(Path(path).stat().st_mtime)) # delta + return dt.days # + dt.seconds / 86400 # fractional days + + +def file_date(path=__file__): + # Return human-readable file modification date, i.e. '2021-3-26' + t = datetime.fromtimestamp(Path(path).stat().st_mtime) + return f'{t.year}-{t.month}-{t.day}' + + +def file_size(path): + # Return file/dir size (MB) + mb = 1 << 20 # bytes to MiB (1024 ** 2) + path = Path(path) + if path.is_file(): + return path.stat().st_size / mb + elif path.is_dir(): + return sum(f.stat().st_size for f in path.glob('**/*') if f.is_file()) / mb + else: + return 0.0 + + +def check_online(): + # Check internet connectivity + import socket + + def run_once(): + # Check once + try: + socket.create_connection(("1.1.1.1", 443), 5) # check host accessibility + return True + except OSError: + return False + + return run_once() or run_once() # check twice to increase robustness to intermittent connectivity issues + + +def git_describe(path=ROOT): # path must be a directory + # Return human-readable git description, i.e. v5.0-5-g3e25f1e https://git-scm.com/docs/git-describe + try: + assert (Path(path) / '.git').is_dir() + return check_output(f'git -C {path} describe --tags --long --always', shell=True).decode()[:-1] + except Exception: + return '' + + +@TryExcept() +@WorkingDirectory(ROOT) +def check_git_status(repo='WongKinYiu/yolov9', branch='main'): + # YOLO status check, recommend 'git pull' if code is out of date + url = f'https://github.com/{repo}' + msg = f', for updates see {url}' + s = colorstr('github: ') # string + assert Path('.git').exists(), s + 'skipping check (not a git repository)' + msg + assert check_online(), s + 'skipping check (offline)' + msg + + splits = re.split(pattern=r'\s', string=check_output('git remote -v', shell=True).decode()) + matches = [repo in s for s in splits] + if any(matches): + remote = splits[matches.index(True) - 1] + else: + remote = 'ultralytics' + check_output(f'git remote add {remote} {url}', shell=True) + check_output(f'git fetch {remote}', shell=True, timeout=5) # git fetch + local_branch = check_output('git rev-parse --abbrev-ref HEAD', shell=True).decode().strip() # checked out + n = int(check_output(f'git rev-list {local_branch}..{remote}/{branch} --count', shell=True)) # commits behind + if n > 0: + pull = 'git pull' if remote == 'origin' else f'git pull {remote} {branch}' + s += f"⚠️ YOLO is out of date by {n} commit{'s' * (n > 1)}. Use `{pull}` or `git clone {url}` to update." + else: + s += f'up to date with {url} ✅' + LOGGER.info(s) + + +@WorkingDirectory(ROOT) +def check_git_info(path='.'): + # YOLO git info check, return {remote, branch, commit} + check_requirements('gitpython') + import git + try: + repo = git.Repo(path) + remote = repo.remotes.origin.url.replace('.git', '') # i.e. 'https://github.com/WongKinYiu/yolov9' + commit = repo.head.commit.hexsha # i.e. '3134699c73af83aac2a481435550b968d5792c0d' + try: + branch = repo.active_branch.name # i.e. 'main' + except TypeError: # not on any branch + branch = None # i.e. 'detached HEAD' state + return {'remote': remote, 'branch': branch, 'commit': commit} + except git.exc.InvalidGitRepositoryError: # path is not a git dir + return {'remote': None, 'branch': None, 'commit': None} + + +def check_python(minimum='3.7.0'): + # Check current python version vs. required python version + check_version(platform.python_version(), minimum, name='Python ', hard=True) + + +def check_version(current='0.0.0', minimum='0.0.0', name='version ', pinned=False, hard=False, verbose=False): + # Check version vs. required version + current, minimum = (pkg.parse_version(x) for x in (current, minimum)) + result = (current == minimum) if pinned else (current >= minimum) # bool + s = f'WARNING ⚠️ {name}{minimum} is required by YOLO, but {name}{current} is currently installed' # string + if hard: + assert result, emojis(s) # assert min requirements met + if verbose and not result: + LOGGER.warning(s) + return result + + +@TryExcept() +def check_requirements(requirements=ROOT / 'requirements.txt', exclude=(), install=True, cmds=''): + # Check installed dependencies meet YOLO requirements (pass *.txt file or list of packages or single package str) + prefix = colorstr('red', 'bold', 'requirements:') + check_python() # check python version + if isinstance(requirements, Path): # requirements.txt file + file = requirements.resolve() + assert file.exists(), f"{prefix} {file} not found, check failed." + with file.open() as f: + requirements = [f'{x.name}{x.specifier}' for x in pkg.parse_requirements(f) if x.name not in exclude] + elif isinstance(requirements, str): + requirements = [requirements] + + s = '' + n = 0 + for r in requirements: + try: + pkg.require(r) + except (pkg.VersionConflict, pkg.DistributionNotFound): # exception if requirements not met + s += f'"{r}" ' + n += 1 + + if s and install and AUTOINSTALL: # check environment variable + LOGGER.info(f"{prefix} YOLO requirement{'s' * (n > 1)} {s}not found, attempting AutoUpdate...") + try: + # assert check_online(), "AutoUpdate skipped (offline)" + LOGGER.info(check_output(f'pip install {s} {cmds}', shell=True).decode()) + source = file if 'file' in locals() else requirements + s = f"{prefix} {n} package{'s' * (n > 1)} updated per {source}\n" \ + f"{prefix} ⚠️ {colorstr('bold', 'Restart runtime or rerun command for updates to take effect')}\n" + LOGGER.info(s) + except Exception as e: + LOGGER.warning(f'{prefix} ❌ {e}') + + +def check_img_size(imgsz, s=32, floor=0): + # Verify image size is a multiple of stride s in each dimension + if isinstance(imgsz, int): # integer i.e. img_size=640 + new_size = max(make_divisible(imgsz, int(s)), floor) + else: # list i.e. img_size=[640, 480] + imgsz = list(imgsz) # convert to list if tuple + new_size = [max(make_divisible(x, int(s)), floor) for x in imgsz] + if new_size != imgsz: + LOGGER.warning(f'WARNING ⚠️ --img-size {imgsz} must be multiple of max stride {s}, updating to {new_size}') + return new_size + + +def check_imshow(warn=False): + # Check if environment supports image displays + try: + assert not is_notebook() + assert not is_docker() + cv2.imshow('test', np.zeros((1, 1, 3))) + cv2.waitKey(1) + cv2.destroyAllWindows() + cv2.waitKey(1) + return True + except Exception as e: + if warn: + LOGGER.warning(f'WARNING ⚠️ Environment does not support cv2.imshow() or PIL Image.show()\n{e}') + return False + + +def check_suffix(file='yolo.pt', suffix=('.pt',), msg=''): + # Check file(s) for acceptable suffix + if file and suffix: + if isinstance(suffix, str): + suffix = [suffix] + for f in file if isinstance(file, (list, tuple)) else [file]: + s = Path(f).suffix.lower() # file suffix + if len(s): + assert s in suffix, f"{msg}{f} acceptable suffix is {suffix}" + + +def check_yaml(file, suffix=('.yaml', '.yml')): + # Search/download YAML file (if necessary) and return path, checking suffix + return check_file(file, suffix) + + +def check_file(file, suffix=''): + # Search/download file (if necessary) and return path + check_suffix(file, suffix) # optional + file = str(file) # convert to str() + if os.path.isfile(file) or not file: # exists + return file + elif file.startswith(('http:/', 'https:/')): # download + url = file # warning: Pathlib turns :// -> :/ + file = Path(urllib.parse.unquote(file).split('?')[0]).name # '%2F' to '/', split https://url.com/file.txt?auth + if os.path.isfile(file): + LOGGER.info(f'Found {url} locally at {file}') # file already exists + else: + LOGGER.info(f'Downloading {url} to {file}...') + torch.hub.download_url_to_file(url, file) + assert Path(file).exists() and Path(file).stat().st_size > 0, f'File download failed: {url}' # check + return file + elif file.startswith('clearml://'): # ClearML Dataset ID + assert 'clearml' in sys.modules, "ClearML is not installed, so cannot use ClearML dataset. Try running 'pip install clearml'." + return file + else: # search + files = [] + for d in 'data', 'models', 'utils': # search directories + files.extend(glob.glob(str(ROOT / d / '**' / file), recursive=True)) # find file + assert len(files), f'File not found: {file}' # assert file was found + assert len(files) == 1, f"Multiple files match '{file}', specify exact path: {files}" # assert unique + return files[0] # return file + + +def check_font(font=FONT, progress=False): + # Download font to CONFIG_DIR if necessary + font = Path(font) + file = CONFIG_DIR / font.name + if not font.exists() and not file.exists(): + url = f'https://ultralytics.com/assets/{font.name}' + LOGGER.info(f'Downloading {url} to {file}...') + torch.hub.download_url_to_file(url, str(file), progress=progress) + + +def check_dataset(data, autodownload=True): + # Download, check and/or unzip dataset if not found locally + + # Download (optional) + extract_dir = '' + if isinstance(data, (str, Path)) and (is_zipfile(data) or is_tarfile(data)): + download(data, dir=f'{DATASETS_DIR}/{Path(data).stem}', unzip=True, delete=False, curl=False, threads=1) + data = next((DATASETS_DIR / Path(data).stem).rglob('*.yaml')) + extract_dir, autodownload = data.parent, False + + # Read yaml (optional) + if isinstance(data, (str, Path)): + data = yaml_load(data) # dictionary + + # Checks + for k in 'train', 'val', 'names': + assert k in data, emojis(f"data.yaml '{k}:' field missing ❌") + if isinstance(data['names'], (list, tuple)): # old array format + data['names'] = dict(enumerate(data['names'])) # convert to dict + assert all(isinstance(k, int) for k in data['names'].keys()), 'data.yaml names keys must be integers, i.e. 2: car' + data['nc'] = len(data['names']) + + # Resolve paths + path = Path(extract_dir or data.get('path') or '') # optional 'path' default to '.' + if not path.is_absolute(): + path = (ROOT / path).resolve() + data['path'] = path # download scripts + for k in 'train', 'val', 'test': + if data.get(k): # prepend path + if isinstance(data[k], str): + x = (path / data[k]).resolve() + if not x.exists() and data[k].startswith('../'): + x = (path / data[k][3:]).resolve() + data[k] = str(x) + else: + data[k] = [str((path / x).resolve()) for x in data[k]] + + # Parse yaml + train, val, test, s = (data.get(x) for x in ('train', 'val', 'test', 'download')) + if val: + val = [Path(x).resolve() for x in (val if isinstance(val, list) else [val])] # val path + if not all(x.exists() for x in val): + LOGGER.info('\nDataset not found ⚠️, missing paths %s' % [str(x) for x in val if not x.exists()]) + if not s or not autodownload: + raise Exception('Dataset not found ❌') + t = time.time() + if s.startswith('http') and s.endswith('.zip'): # URL + f = Path(s).name # filename + LOGGER.info(f'Downloading {s} to {f}...') + torch.hub.download_url_to_file(s, f) + Path(DATASETS_DIR).mkdir(parents=True, exist_ok=True) # create root + unzip_file(f, path=DATASETS_DIR) # unzip + Path(f).unlink() # remove zip + r = None # success + elif s.startswith('bash '): # bash script + LOGGER.info(f'Running {s} ...') + r = os.system(s) + else: # python script + r = exec(s, {'yaml': data}) # return None + dt = f'({round(time.time() - t, 1)}s)' + s = f"success ✅ {dt}, saved to {colorstr('bold', DATASETS_DIR)}" if r in (0, None) else f"failure {dt} ❌" + LOGGER.info(f"Dataset download {s}") + check_font('Arial.ttf' if is_ascii(data['names']) else 'Arial.Unicode.ttf', progress=True) # download fonts + return data # dictionary + + +def check_amp(model): + # Check PyTorch Automatic Mixed Precision (AMP) functionality. Return True on correct operation + from models.common import AutoShape, DetectMultiBackend + + def amp_allclose(model, im): + # All close FP32 vs AMP results + m = AutoShape(model, verbose=False) # model + a = m(im).xywhn[0] # FP32 inference + m.amp = True + b = m(im).xywhn[0] # AMP inference + return a.shape == b.shape and torch.allclose(a, b, atol=0.1) # close to 10% absolute tolerance + + prefix = colorstr('AMP: ') + device = next(model.parameters()).device # get model device + if device.type in ('cpu', 'mps'): + return False # AMP only used on CUDA devices + f = ROOT / 'data' / 'images' / 'bus.jpg' # image to check + im = f if f.exists() else 'https://ultralytics.com/images/bus.jpg' if check_online() else np.ones((640, 640, 3)) + try: + #assert amp_allclose(deepcopy(model), im) or amp_allclose(DetectMultiBackend('yolo.pt', device), im) + LOGGER.info(f'{prefix}checks passed ✅') + return True + except Exception: + help_url = 'https://github.com/ultralytics/yolov5/issues/7908' + LOGGER.warning(f'{prefix}checks failed ❌, disabling Automatic Mixed Precision. See {help_url}') + return False + + +def yaml_load(file='data.yaml'): + # Single-line safe yaml loading + with open(file, errors='ignore') as f: + return yaml.safe_load(f) + + +def yaml_save(file='data.yaml', data={}): + # Single-line safe yaml saving + with open(file, 'w') as f: + yaml.safe_dump({k: str(v) if isinstance(v, Path) else v for k, v in data.items()}, f, sort_keys=False) + + +def unzip_file(file, path=None, exclude=('.DS_Store', '__MACOSX')): + # Unzip a *.zip file to path/, excluding files containing strings in exclude list + if path is None: + path = Path(file).parent # default path + with ZipFile(file) as zipObj: + for f in zipObj.namelist(): # list all archived filenames in the zip + if all(x not in f for x in exclude): + zipObj.extract(f, path=path) + + +def url2file(url): + # Convert URL to filename, i.e. https://url.com/file.txt?auth -> file.txt + url = str(Path(url)).replace(':/', '://') # Pathlib turns :// -> :/ + return Path(urllib.parse.unquote(url)).name.split('?')[0] # '%2F' to '/', split https://url.com/file.txt?auth + + +def download(url, dir='.', unzip=True, delete=True, curl=False, threads=1, retry=3): + # Multithreaded file download and unzip function, used in data.yaml for autodownload + def download_one(url, dir): + # Download 1 file + success = True + if os.path.isfile(url): + f = Path(url) # filename + else: # does not exist + f = dir / Path(url).name + LOGGER.info(f'Downloading {url} to {f}...') + for i in range(retry + 1): + if curl: + s = 'sS' if threads > 1 else '' # silent + r = os.system( + f'curl -# -{s}L "{url}" -o "{f}" --retry 9 -C -') # curl download with retry, continue + success = r == 0 + else: + torch.hub.download_url_to_file(url, f, progress=threads == 1) # torch download + success = f.is_file() + if success: + break + elif i < retry: + LOGGER.warning(f'⚠️ Download failure, retrying {i + 1}/{retry} {url}...') + else: + LOGGER.warning(f'❌ Failed to download {url}...') + + if unzip and success and (f.suffix == '.gz' or is_zipfile(f) or is_tarfile(f)): + LOGGER.info(f'Unzipping {f}...') + if is_zipfile(f): + unzip_file(f, dir) # unzip + elif is_tarfile(f): + os.system(f'tar xf {f} --directory {f.parent}') # unzip + elif f.suffix == '.gz': + os.system(f'tar xfz {f} --directory {f.parent}') # unzip + if delete: + f.unlink() # remove zip + + dir = Path(dir) + dir.mkdir(parents=True, exist_ok=True) # make directory + if threads > 1: + pool = ThreadPool(threads) + pool.imap(lambda x: download_one(*x), zip(url, repeat(dir))) # multithreaded + pool.close() + pool.join() + else: + for u in [url] if isinstance(url, (str, Path)) else url: + download_one(u, dir) + + +def make_divisible(x, divisor): + # Returns nearest x divisible by divisor + if isinstance(divisor, torch.Tensor): + divisor = int(divisor.max()) # to int + return math.ceil(x / divisor) * divisor + + +def clean_str(s): + # Cleans a string by replacing special characters with underscore _ + return re.sub(pattern="[|@#!¡·$€%&()=?¿^*;:,¨´><+]", repl="_", string=s) + + +def one_cycle(y1=0.0, y2=1.0, steps=100): + # lambda function for sinusoidal ramp from y1 to y2 https://arxiv.org/pdf/1812.01187.pdf + return lambda x: ((1 - math.cos(x * math.pi / steps)) / 2) * (y2 - y1) + y1 + + +def one_flat_cycle(y1=0.0, y2=1.0, steps=100): + # lambda function for sinusoidal ramp from y1 to y2 https://arxiv.org/pdf/1812.01187.pdf + #return lambda x: ((1 - math.cos(x * math.pi / steps)) / 2) * (y2 - y1) + y1 + return lambda x: ((1 - math.cos((x - (steps // 2)) * math.pi / (steps // 2))) / 2) * (y2 - y1) + y1 if (x > (steps // 2)) else y1 + + +def colorstr(*input): + # Colors a string https://en.wikipedia.org/wiki/ANSI_escape_code, i.e. colorstr('blue', 'hello world') + *args, string = input if len(input) > 1 else ('blue', 'bold', input[0]) # color arguments, string + colors = { + 'black': '\033[30m', # basic colors + 'red': '\033[31m', + 'green': '\033[32m', + 'yellow': '\033[33m', + 'blue': '\033[34m', + 'magenta': '\033[35m', + 'cyan': '\033[36m', + 'white': '\033[37m', + 'bright_black': '\033[90m', # bright colors + 'bright_red': '\033[91m', + 'bright_green': '\033[92m', + 'bright_yellow': '\033[93m', + 'bright_blue': '\033[94m', + 'bright_magenta': '\033[95m', + 'bright_cyan': '\033[96m', + 'bright_white': '\033[97m', + 'end': '\033[0m', # misc + 'bold': '\033[1m', + 'underline': '\033[4m'} + return ''.join(colors[x] for x in args) + f'{string}' + colors['end'] + + +def labels_to_class_weights(labels, nc=80): + # Get class weights (inverse frequency) from training labels + if labels[0] is None: # no labels loaded + return torch.Tensor() + + labels = np.concatenate(labels, 0) # labels.shape = (866643, 5) for COCO + classes = labels[:, 0].astype(int) # labels = [class xywh] + weights = np.bincount(classes, minlength=nc) # occurrences per class + + # Prepend gridpoint count (for uCE training) + # gpi = ((320 / 32 * np.array([1, 2, 4])) ** 2 * 3).sum() # gridpoints per image + # weights = np.hstack([gpi * len(labels) - weights.sum() * 9, weights * 9]) ** 0.5 # prepend gridpoints to start + + weights[weights == 0] = 1 # replace empty bins with 1 + weights = 1 / weights # number of targets per class + weights /= weights.sum() # normalize + return torch.from_numpy(weights).float() + + +def labels_to_image_weights(labels, nc=80, class_weights=np.ones(80)): + # Produces image weights based on class_weights and image contents + # Usage: index = random.choices(range(n), weights=image_weights, k=1) # weighted image sample + class_counts = np.array([np.bincount(x[:, 0].astype(int), minlength=nc) for x in labels]) + return (class_weights.reshape(1, nc) * class_counts).sum(1) + + +def coco80_to_coco91_class(): # converts 80-index (val2014) to 91-index (paper) + # https://tech.amikelive.com/node-718/what-object-categories-labels-are-in-coco-dataset/ + # a = np.loadtxt('data/coco.names', dtype='str', delimiter='\n') + # b = np.loadtxt('data/coco_paper.names', dtype='str', delimiter='\n') + # x1 = [list(a[i] == b).index(True) + 1 for i in range(80)] # darknet to coco + # x2 = [list(b[i] == a).index(True) if any(b[i] == a) else None for i in range(91)] # coco to darknet + return [ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 27, 28, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 67, 70, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 84, 85, 86, 87, 88, 89, 90] + + +def xyxy2xywh(x): + # Convert nx4 boxes from [x1, y1, x2, y2] to [x, y, w, h] where xy1=top-left, xy2=bottom-right + y = x.clone() if isinstance(x, torch.Tensor) else np.copy(x) + y[..., 0] = (x[..., 0] + x[..., 2]) / 2 # x center + y[..., 1] = (x[..., 1] + x[..., 3]) / 2 # y center + y[..., 2] = x[..., 2] - x[..., 0] # width + y[..., 3] = x[..., 3] - x[..., 1] # height + return y + + +def xywh2xyxy(x): + # Convert nx4 boxes from [x, y, w, h] to [x1, y1, x2, y2] where xy1=top-left, xy2=bottom-right + y = x.clone() if isinstance(x, torch.Tensor) else np.copy(x) + y[..., 0] = x[..., 0] - x[..., 2] / 2 # top left x + y[..., 1] = x[..., 1] - x[..., 3] / 2 # top left y + y[..., 2] = x[..., 0] + x[..., 2] / 2 # bottom right x + y[..., 3] = x[..., 1] + x[..., 3] / 2 # bottom right y + return y + + +def xywhn2xyxy(x, w=640, h=640, padw=0, padh=0): + # Convert nx4 boxes from [x, y, w, h] normalized to [x1, y1, x2, y2] where xy1=top-left, xy2=bottom-right + y = x.clone() if isinstance(x, torch.Tensor) else np.copy(x) + y[..., 0] = w * (x[..., 0] - x[..., 2] / 2) + padw # top left x + y[..., 1] = h * (x[..., 1] - x[..., 3] / 2) + padh # top left y + y[..., 2] = w * (x[..., 0] + x[..., 2] / 2) + padw # bottom right x + y[..., 3] = h * (x[..., 1] + x[..., 3] / 2) + padh # bottom right y + return y + + +def xyxy2xywhn(x, w=640, h=640, clip=False, eps=0.0): + # Convert nx4 boxes from [x1, y1, x2, y2] to [x, y, w, h] normalized where xy1=top-left, xy2=bottom-right + if clip: + clip_boxes(x, (h - eps, w - eps)) # warning: inplace clip + y = x.clone() if isinstance(x, torch.Tensor) else np.copy(x) + y[..., 0] = ((x[..., 0] + x[..., 2]) / 2) / w # x center + y[..., 1] = ((x[..., 1] + x[..., 3]) / 2) / h # y center + y[..., 2] = (x[..., 2] - x[..., 0]) / w # width + y[..., 3] = (x[..., 3] - x[..., 1]) / h # height + return y + + +def xyn2xy(x, w=640, h=640, padw=0, padh=0): + # Convert normalized segments into pixel segments, shape (n,2) + y = x.clone() if isinstance(x, torch.Tensor) else np.copy(x) + y[..., 0] = w * x[..., 0] + padw # top left x + y[..., 1] = h * x[..., 1] + padh # top left y + return y + + +def segment2box(segment, width=640, height=640): + # Convert 1 segment label to 1 box label, applying inside-image constraint, i.e. (xy1, xy2, ...) to (xyxy) + x, y = segment.T # segment xy + inside = (x >= 0) & (y >= 0) & (x <= width) & (y <= height) + x, y, = x[inside], y[inside] + return np.array([x.min(), y.min(), x.max(), y.max()]) if any(x) else np.zeros((1, 4)) # xyxy + + +def segments2boxes(segments): + # Convert segment labels to box labels, i.e. (cls, xy1, xy2, ...) to (cls, xywh) + boxes = [] + for s in segments: + x, y = s.T # segment xy + boxes.append([x.min(), y.min(), x.max(), y.max()]) # cls, xyxy + return xyxy2xywh(np.array(boxes)) # cls, xywh + + +def resample_segments(segments, n=1000): + # Up-sample an (n,2) segment + for i, s in enumerate(segments): + s = np.concatenate((s, s[0:1, :]), axis=0) + x = np.linspace(0, len(s) - 1, n) + xp = np.arange(len(s)) + segments[i] = np.concatenate([np.interp(x, xp, s[:, i]) for i in range(2)]).reshape(2, -1).T # segment xy + return segments + + +def scale_boxes(img1_shape, boxes, img0_shape, ratio_pad=None): + # Rescale boxes (xyxy) from img1_shape to img0_shape + if ratio_pad is None: # calculate from img0_shape + gain = min(img1_shape[0] / img0_shape[0], img1_shape[1] / img0_shape[1]) # gain = old / new + pad = (img1_shape[1] - img0_shape[1] * gain) / 2, (img1_shape[0] - img0_shape[0] * gain) / 2 # wh padding + else: + gain = ratio_pad[0][0] + pad = ratio_pad[1] + + boxes[:, [0, 2]] -= pad[0] # x padding + boxes[:, [1, 3]] -= pad[1] # y padding + boxes[:, :4] /= gain + clip_boxes(boxes, img0_shape) + return boxes + + +def scale_segments(img1_shape, segments, img0_shape, ratio_pad=None, normalize=False): + # Rescale coords (xyxy) from img1_shape to img0_shape + if ratio_pad is None: # calculate from img0_shape + gain = min(img1_shape[0] / img0_shape[0], img1_shape[1] / img0_shape[1]) # gain = old / new + pad = (img1_shape[1] - img0_shape[1] * gain) / 2, (img1_shape[0] - img0_shape[0] * gain) / 2 # wh padding + else: + gain = ratio_pad[0][0] + pad = ratio_pad[1] + + segments[:, 0] -= pad[0] # x padding + segments[:, 1] -= pad[1] # y padding + segments /= gain + clip_segments(segments, img0_shape) + if normalize: + segments[:, 0] /= img0_shape[1] # width + segments[:, 1] /= img0_shape[0] # height + return segments + + +def clip_boxes(boxes, shape): + # Clip boxes (xyxy) to image shape (height, width) + if isinstance(boxes, torch.Tensor): # faster individually + boxes[:, 0].clamp_(0, shape[1]) # x1 + boxes[:, 1].clamp_(0, shape[0]) # y1 + boxes[:, 2].clamp_(0, shape[1]) # x2 + boxes[:, 3].clamp_(0, shape[0]) # y2 + else: # np.array (faster grouped) + boxes[:, [0, 2]] = boxes[:, [0, 2]].clip(0, shape[1]) # x1, x2 + boxes[:, [1, 3]] = boxes[:, [1, 3]].clip(0, shape[0]) # y1, y2 + + +def clip_segments(segments, shape): + # Clip segments (xy1,xy2,...) to image shape (height, width) + if isinstance(segments, torch.Tensor): # faster individually + segments[:, 0].clamp_(0, shape[1]) # x + segments[:, 1].clamp_(0, shape[0]) # y + else: # np.array (faster grouped) + segments[:, 0] = segments[:, 0].clip(0, shape[1]) # x + segments[:, 1] = segments[:, 1].clip(0, shape[0]) # y + + +def non_max_suppression( + prediction, + conf_thres=0.25, + iou_thres=0.45, + classes=None, + agnostic=False, + multi_label=False, + labels=(), + max_det=300, + nm=0, # number of masks +): + """Non-Maximum Suppression (NMS) on inference results to reject overlapping detections + + Returns: + list of detections, on (n,6) tensor per image [xyxy, conf, cls] + """ + + if isinstance(prediction, (list, tuple)): # YOLO model in validation model, output = (inference_out, loss_out) + prediction = prediction[0] # select only inference output + + device = prediction.device + mps = 'mps' in device.type # Apple MPS + if mps: # MPS not fully supported yet, convert tensors to CPU before NMS + prediction = prediction.cpu() + bs = prediction.shape[0] # batch size + nc = prediction.shape[1] - nm - 4 # number of classes + mi = 4 + nc # mask start index + xc = prediction[:, 4:mi].amax(1) > conf_thres # candidates + + # Checks + assert 0 <= conf_thres <= 1, f'Invalid Confidence threshold {conf_thres}, valid values are between 0.0 and 1.0' + assert 0 <= iou_thres <= 1, f'Invalid IoU {iou_thres}, valid values are between 0.0 and 1.0' + + # Settings + # min_wh = 2 # (pixels) minimum box width and height + max_wh = 7680 # (pixels) maximum box width and height + max_nms = 30000 # maximum number of boxes into torchvision.ops.nms() + time_limit = 2.5 + 0.05 * bs # seconds to quit after + redundant = True # require redundant detections + multi_label &= nc > 1 # multiple labels per box (adds 0.5ms/img) + merge = False # use merge-NMS + + t = time.time() + output = [torch.zeros((0, 6 + nm), device=prediction.device)] * bs + for xi, x in enumerate(prediction): # image index, image inference + # Apply constraints + # x[((x[:, 2:4] < min_wh) | (x[:, 2:4] > max_wh)).any(1), 4] = 0 # width-height + x = x.T[xc[xi]] # confidence + + # Cat apriori labels if autolabelling + if labels and len(labels[xi]): + lb = labels[xi] + v = torch.zeros((len(lb), nc + nm + 5), device=x.device) + v[:, :4] = lb[:, 1:5] # box + v[range(len(lb)), lb[:, 0].long() + 4] = 1.0 # cls + x = torch.cat((x, v), 0) + + # If none remain process next image + if not x.shape[0]: + continue + + # Detections matrix nx6 (xyxy, conf, cls) + box, cls, mask = x.split((4, nc, nm), 1) + box = xywh2xyxy(box) # center_x, center_y, width, height) to (x1, y1, x2, y2) + if multi_label: + i, j = (cls > conf_thres).nonzero(as_tuple=False).T + x = torch.cat((box[i], x[i, 4 + j, None], j[:, None].float(), mask[i]), 1) + else: # best class only + conf, j = cls.max(1, keepdim=True) + x = torch.cat((box, conf, j.float(), mask), 1)[conf.view(-1) > conf_thres] + + # Filter by class + if classes is not None: + x = x[(x[:, 5:6] == torch.tensor(classes, device=x.device)).any(1)] + + # Apply finite constraint + # if not torch.isfinite(x).all(): + # x = x[torch.isfinite(x).all(1)] + + # Check shape + n = x.shape[0] # number of boxes + if not n: # no boxes + continue + elif n > max_nms: # excess boxes + x = x[x[:, 4].argsort(descending=True)[:max_nms]] # sort by confidence + else: + x = x[x[:, 4].argsort(descending=True)] # sort by confidence + + # Batched NMS + c = x[:, 5:6] * (0 if agnostic else max_wh) # classes + boxes, scores = x[:, :4] + c, x[:, 4] # boxes (offset by class), scores + i = torchvision.ops.nms(boxes, scores, iou_thres) # NMS + if i.shape[0] > max_det: # limit detections + i = i[:max_det] + if merge and (1 < n < 3E3): # Merge NMS (boxes merged using weighted mean) + # update boxes as boxes(i,4) = weights(i,n) * boxes(n,4) + iou = box_iou(boxes[i], boxes) > iou_thres # iou matrix + weights = iou * scores[None] # box weights + x[i, :4] = torch.mm(weights, x[:, :4]).float() / weights.sum(1, keepdim=True) # merged boxes + if redundant: + i = i[iou.sum(1) > 1] # require redundancy + + output[xi] = x[i] + if mps: + output[xi] = output[xi].to(device) + if (time.time() - t) > time_limit: + LOGGER.warning(f'WARNING ⚠️ NMS time limit {time_limit:.3f}s exceeded') + break # time limit exceeded + + return output + + +def strip_optimizer(f='best.pt', s=''): # from utils.general import *; strip_optimizer() + # Strip optimizer from 'f' to finalize training, optionally save as 's' + x = torch.load(f, map_location=torch.device('cpu')) + if x.get('ema'): + x['model'] = x['ema'] # replace model with ema + for k in 'optimizer', 'best_fitness', 'ema', 'updates': # keys + x[k] = None + x['epoch'] = -1 + x['model'].half() # to FP16 + for p in x['model'].parameters(): + p.requires_grad = False + torch.save(x, s or f) + mb = os.path.getsize(s or f) / 1E6 # filesize + LOGGER.info(f"Optimizer stripped from {f},{f' saved as {s},' if s else ''} {mb:.1f}MB") + + +def print_mutation(keys, results, hyp, save_dir, bucket, prefix=colorstr('evolve: ')): + evolve_csv = save_dir / 'evolve.csv' + evolve_yaml = save_dir / 'hyp_evolve.yaml' + keys = tuple(keys) + tuple(hyp.keys()) # [results + hyps] + keys = tuple(x.strip() for x in keys) + vals = results + tuple(hyp.values()) + n = len(keys) + + # Download (optional) + if bucket: + url = f'gs://{bucket}/evolve.csv' + if gsutil_getsize(url) > (evolve_csv.stat().st_size if evolve_csv.exists() else 0): + os.system(f'gsutil cp {url} {save_dir}') # download evolve.csv if larger than local + + # Log to evolve.csv + s = '' if evolve_csv.exists() else (('%20s,' * n % keys).rstrip(',') + '\n') # add header + with open(evolve_csv, 'a') as f: + f.write(s + ('%20.5g,' * n % vals).rstrip(',') + '\n') + + # Save yaml + with open(evolve_yaml, 'w') as f: + data = pd.read_csv(evolve_csv) + data = data.rename(columns=lambda x: x.strip()) # strip keys + i = np.argmax(fitness(data.values[:, :4])) # + generations = len(data) + f.write('# YOLO Hyperparameter Evolution Results\n' + f'# Best generation: {i}\n' + + f'# Last generation: {generations - 1}\n' + '# ' + ', '.join(f'{x.strip():>20s}' for x in keys[:7]) + + '\n' + '# ' + ', '.join(f'{x:>20.5g}' for x in data.values[i, :7]) + '\n\n') + yaml.safe_dump(data.loc[i][7:].to_dict(), f, sort_keys=False) + + # Print to screen + LOGGER.info(prefix + f'{generations} generations finished, current result:\n' + prefix + + ', '.join(f'{x.strip():>20s}' for x in keys) + '\n' + prefix + ', '.join(f'{x:20.5g}' + for x in vals) + '\n\n') + + if bucket: + os.system(f'gsutil cp {evolve_csv} {evolve_yaml} gs://{bucket}') # upload + + +def apply_classifier(x, model, img, im0): + # Apply a second stage classifier to YOLO outputs + # Example model = torchvision.models.__dict__['efficientnet_b0'](pretrained=True).to(device).eval() + im0 = [im0] if isinstance(im0, np.ndarray) else im0 + for i, d in enumerate(x): # per image + if d is not None and len(d): + d = d.clone() + + # Reshape and pad cutouts + b = xyxy2xywh(d[:, :4]) # boxes + b[:, 2:] = b[:, 2:].max(1)[0].unsqueeze(1) # rectangle to square + b[:, 2:] = b[:, 2:] * 1.3 + 30 # pad + d[:, :4] = xywh2xyxy(b).long() + + # Rescale boxes from img_size to im0 size + scale_boxes(img.shape[2:], d[:, :4], im0[i].shape) + + # Classes + pred_cls1 = d[:, 5].long() + ims = [] + for a in d: + cutout = im0[i][int(a[1]):int(a[3]), int(a[0]):int(a[2])] + im = cv2.resize(cutout, (224, 224)) # BGR + + im = im[:, :, ::-1].transpose(2, 0, 1) # BGR to RGB, to 3x416x416 + im = np.ascontiguousarray(im, dtype=np.float32) # uint8 to float32 + im /= 255 # 0 - 255 to 0.0 - 1.0 + ims.append(im) + + pred_cls2 = model(torch.Tensor(ims).to(d.device)).argmax(1) # classifier prediction + x[i] = x[i][pred_cls1 == pred_cls2] # retain matching class detections + + return x + + +def increment_path(path, exist_ok=False, sep='', mkdir=False): + # Increment file or directory path, i.e. runs/exp --> runs/exp{sep}2, runs/exp{sep}3, ... etc. + path = Path(path) # os-agnostic + if path.exists() and not exist_ok: + path, suffix = (path.with_suffix(''), path.suffix) if path.is_file() else (path, '') + + # Method 1 + for n in range(2, 9999): + p = f'{path}{sep}{n}{suffix}' # increment path + if not os.path.exists(p): # + break + path = Path(p) + + # Method 2 (deprecated) + # dirs = glob.glob(f"{path}{sep}*") # similar paths + # matches = [re.search(rf"{path.stem}{sep}(\d+)", d) for d in dirs] + # i = [int(m.groups()[0]) for m in matches if m] # indices + # n = max(i) + 1 if i else 2 # increment number + # path = Path(f"{path}{sep}{n}{suffix}") # increment path + + if mkdir: + path.mkdir(parents=True, exist_ok=True) # make directory + + return path + + +# OpenCV Chinese-friendly functions ------------------------------------------------------------------------------------ +imshow_ = cv2.imshow # copy to avoid recursion errors + + +def imread(path, flags=cv2.IMREAD_COLOR): + return cv2.imdecode(np.fromfile(path, np.uint8), flags) + + +def imwrite(path, im): + try: + cv2.imencode(Path(path).suffix, im)[1].tofile(path) + return True + except Exception: + return False + + +def imshow(path, im): + imshow_(path.encode('unicode_escape').decode(), im) + + +cv2.imread, cv2.imwrite, cv2.imshow = imread, imwrite, imshow # redefine + +# Variables ------------------------------------------------------------------------------------------------------------ diff --git a/cv/3d_detection/yolov9/pytorch/utils/lion.py b/cv/3d_detection/yolov9/pytorch/utils/lion.py new file mode 100644 index 000000000..63651cff2 --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/utils/lion.py @@ -0,0 +1,67 @@ +"""PyTorch implementation of the Lion optimizer.""" +import torch +from torch.optim.optimizer import Optimizer + + +class Lion(Optimizer): + r"""Implements Lion algorithm.""" + + def __init__(self, params, lr=1e-4, betas=(0.9, 0.99), weight_decay=0.0): + """Initialize the hyperparameters. + Args: + params (iterable): iterable of parameters to optimize or dicts defining + parameter groups + lr (float, optional): learning rate (default: 1e-4) + betas (Tuple[float, float], optional): coefficients used for computing + running averages of gradient and its square (default: (0.9, 0.99)) + weight_decay (float, optional): weight decay coefficient (default: 0) + """ + + if not 0.0 <= lr: + raise ValueError('Invalid learning rate: {}'.format(lr)) + if not 0.0 <= betas[0] < 1.0: + raise ValueError('Invalid beta parameter at index 0: {}'.format(betas[0])) + if not 0.0 <= betas[1] < 1.0: + raise ValueError('Invalid beta parameter at index 1: {}'.format(betas[1])) + defaults = dict(lr=lr, betas=betas, weight_decay=weight_decay) + super().__init__(params, defaults) + + @torch.no_grad() + def step(self, closure=None): + """Performs a single optimization step. + Args: + closure (callable, optional): A closure that reevaluates the model + and returns the loss. + Returns: + the loss. + """ + loss = None + if closure is not None: + with torch.enable_grad(): + loss = closure() + + for group in self.param_groups: + for p in group['params']: + if p.grad is None: + continue + + # Perform stepweight decay + p.data.mul_(1 - group['lr'] * group['weight_decay']) + + grad = p.grad + state = self.state[p] + # State initialization + if len(state) == 0: + # Exponential moving average of gradient values + state['exp_avg'] = torch.zeros_like(p) + + exp_avg = state['exp_avg'] + beta1, beta2 = group['betas'] + + # Weight update + update = exp_avg * beta1 + grad * (1 - beta1) + p.add_(torch.sign(update), alpha=-group['lr']) + # Decay the momentum running average coefficient + exp_avg.mul_(beta2).add_(grad, alpha=1 - beta2) + + return loss \ No newline at end of file diff --git a/cv/3d_detection/yolov9/pytorch/utils/loggers/__init__.py b/cv/3d_detection/yolov9/pytorch/utils/loggers/__init__.py new file mode 100644 index 000000000..8fc8377ab --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/utils/loggers/__init__.py @@ -0,0 +1,399 @@ +import os +import warnings +from pathlib import Path + +import pkg_resources as pkg +import torch +from torch.utils.tensorboard import SummaryWriter + +from utils.general import LOGGER, colorstr, cv2 +from utils.loggers.clearml.clearml_utils import ClearmlLogger +from utils.loggers.wandb.wandb_utils import WandbLogger +from utils.plots import plot_images, plot_labels, plot_results +from utils.torch_utils import de_parallel + +LOGGERS = ('csv', 'tb', 'wandb', 'clearml', 'comet') # *.csv, TensorBoard, Weights & Biases, ClearML +RANK = int(os.getenv('RANK', -1)) + +try: + import wandb + + assert hasattr(wandb, '__version__') # verify package import not local dir + if pkg.parse_version(wandb.__version__) >= pkg.parse_version('0.12.2') and RANK in {0, -1}: + try: + wandb_login_success = wandb.login(timeout=30) + except wandb.errors.UsageError: # known non-TTY terminal issue + wandb_login_success = False + if not wandb_login_success: + wandb = None +except (ImportError, AssertionError): + wandb = None + +try: + import clearml + + assert hasattr(clearml, '__version__') # verify package import not local dir +except (ImportError, AssertionError): + clearml = None + +try: + if RANK not in [0, -1]: + comet_ml = None + else: + import comet_ml + + assert hasattr(comet_ml, '__version__') # verify package import not local dir + from utils.loggers.comet import CometLogger + +except (ModuleNotFoundError, ImportError, AssertionError): + comet_ml = None + + +class Loggers(): + # YOLO Loggers class + def __init__(self, save_dir=None, weights=None, opt=None, hyp=None, logger=None, include=LOGGERS): + self.save_dir = save_dir + self.weights = weights + self.opt = opt + self.hyp = hyp + self.plots = not opt.noplots # plot results + self.logger = logger # for printing results to console + self.include = include + self.keys = [ + 'train/box_loss', + 'train/cls_loss', + 'train/dfl_loss', # train loss + 'metrics/precision', + 'metrics/recall', + 'metrics/mAP_0.5', + 'metrics/mAP_0.5:0.95', # metrics + 'val/box_loss', + 'val/cls_loss', + 'val/dfl_loss', # val loss + 'x/lr0', + 'x/lr1', + 'x/lr2'] # params + self.best_keys = ['best/epoch', 'best/precision', 'best/recall', 'best/mAP_0.5', 'best/mAP_0.5:0.95'] + for k in LOGGERS: + setattr(self, k, None) # init empty logger dictionary + self.csv = True # always log to csv + + # Messages + # if not wandb: + # prefix = colorstr('Weights & Biases: ') + # s = f"{prefix}run 'pip install wandb' to automatically track and visualize YOLO 🚀 runs in Weights & Biases" + # self.logger.info(s) + if not clearml: + prefix = colorstr('ClearML: ') + s = f"{prefix}run 'pip install clearml' to automatically track, visualize and remotely train YOLO 🚀 in ClearML" + self.logger.info(s) + if not comet_ml: + prefix = colorstr('Comet: ') + s = f"{prefix}run 'pip install comet_ml' to automatically track and visualize YOLO 🚀 runs in Comet" + self.logger.info(s) + # TensorBoard + s = self.save_dir + if 'tb' in self.include and not self.opt.evolve: + prefix = colorstr('TensorBoard: ') + self.logger.info(f"{prefix}Start with 'tensorboard --logdir {s.parent}', view at http://localhost:6006/") + self.tb = SummaryWriter(str(s)) + + # W&B + if wandb and 'wandb' in self.include: + wandb_artifact_resume = isinstance(self.opt.resume, str) and self.opt.resume.startswith('wandb-artifact://') + run_id = torch.load(self.weights).get('wandb_id') if self.opt.resume and not wandb_artifact_resume else None + self.opt.hyp = self.hyp # add hyperparameters + self.wandb = WandbLogger(self.opt, run_id) + # temp warn. because nested artifacts not supported after 0.12.10 + # if pkg.parse_version(wandb.__version__) >= pkg.parse_version('0.12.11'): + # s = "YOLO temporarily requires wandb version 0.12.10 or below. Some features may not work as expected." + # self.logger.warning(s) + else: + self.wandb = None + + # ClearML + if clearml and 'clearml' in self.include: + self.clearml = ClearmlLogger(self.opt, self.hyp) + else: + self.clearml = None + + # Comet + if comet_ml and 'comet' in self.include: + if isinstance(self.opt.resume, str) and self.opt.resume.startswith("comet://"): + run_id = self.opt.resume.split("/")[-1] + self.comet_logger = CometLogger(self.opt, self.hyp, run_id=run_id) + + else: + self.comet_logger = CometLogger(self.opt, self.hyp) + + else: + self.comet_logger = None + + @property + def remote_dataset(self): + # Get data_dict if custom dataset artifact link is provided + data_dict = None + if self.clearml: + data_dict = self.clearml.data_dict + if self.wandb: + data_dict = self.wandb.data_dict + if self.comet_logger: + data_dict = self.comet_logger.data_dict + + return data_dict + + def on_train_start(self): + if self.comet_logger: + self.comet_logger.on_train_start() + + def on_pretrain_routine_start(self): + if self.comet_logger: + self.comet_logger.on_pretrain_routine_start() + + def on_pretrain_routine_end(self, labels, names): + # Callback runs on pre-train routine end + if self.plots: + plot_labels(labels, names, self.save_dir) + paths = self.save_dir.glob('*labels*.jpg') # training labels + if self.wandb: + self.wandb.log({"Labels": [wandb.Image(str(x), caption=x.name) for x in paths]}) + # if self.clearml: + # pass # ClearML saves these images automatically using hooks + if self.comet_logger: + self.comet_logger.on_pretrain_routine_end(paths) + + def on_train_batch_end(self, model, ni, imgs, targets, paths, vals): + log_dict = dict(zip(self.keys[0:3], vals)) + # Callback runs on train batch end + # ni: number integrated batches (since train start) + if self.plots: + if ni < 3: + f = self.save_dir / f'train_batch{ni}.jpg' # filename + plot_images(imgs, targets, paths, f) + if ni == 0 and self.tb and not self.opt.sync_bn: + log_tensorboard_graph(self.tb, model, imgsz=(self.opt.imgsz, self.opt.imgsz)) + if ni == 10 and (self.wandb or self.clearml): + files = sorted(self.save_dir.glob('train*.jpg')) + if self.wandb: + self.wandb.log({'Mosaics': [wandb.Image(str(f), caption=f.name) for f in files if f.exists()]}) + if self.clearml: + self.clearml.log_debug_samples(files, title='Mosaics') + + if self.comet_logger: + self.comet_logger.on_train_batch_end(log_dict, step=ni) + + def on_train_epoch_end(self, epoch): + # Callback runs on train epoch end + if self.wandb: + self.wandb.current_epoch = epoch + 1 + + if self.comet_logger: + self.comet_logger.on_train_epoch_end(epoch) + + def on_val_start(self): + if self.comet_logger: + self.comet_logger.on_val_start() + + def on_val_image_end(self, pred, predn, path, names, im): + # Callback runs on val image end + if self.wandb: + self.wandb.val_one_image(pred, predn, path, names, im) + if self.clearml: + self.clearml.log_image_with_boxes(path, pred, names, im) + + def on_val_batch_end(self, batch_i, im, targets, paths, shapes, out): + if self.comet_logger: + self.comet_logger.on_val_batch_end(batch_i, im, targets, paths, shapes, out) + + def on_val_end(self, nt, tp, fp, p, r, f1, ap, ap50, ap_class, confusion_matrix): + # Callback runs on val end + if self.wandb or self.clearml: + files = sorted(self.save_dir.glob('val*.jpg')) + if self.wandb: + self.wandb.log({"Validation": [wandb.Image(str(f), caption=f.name) for f in files]}) + if self.clearml: + self.clearml.log_debug_samples(files, title='Validation') + + if self.comet_logger: + self.comet_logger.on_val_end(nt, tp, fp, p, r, f1, ap, ap50, ap_class, confusion_matrix) + + def on_fit_epoch_end(self, vals, epoch, best_fitness, fi): + # Callback runs at the end of each fit (train+val) epoch + x = dict(zip(self.keys, vals)) + if self.csv: + file = self.save_dir / 'results.csv' + n = len(x) + 1 # number of cols + s = '' if file.exists() else (('%20s,' * n % tuple(['epoch'] + self.keys)).rstrip(',') + '\n') # add header + with open(file, 'a') as f: + f.write(s + ('%20.5g,' * n % tuple([epoch] + vals)).rstrip(',') + '\n') + + if self.tb: + for k, v in x.items(): + self.tb.add_scalar(k, v, epoch) + elif self.clearml: # log to ClearML if TensorBoard not used + for k, v in x.items(): + title, series = k.split('/') + self.clearml.task.get_logger().report_scalar(title, series, v, epoch) + + if self.wandb: + if best_fitness == fi: + best_results = [epoch] + vals[3:7] + for i, name in enumerate(self.best_keys): + self.wandb.wandb_run.summary[name] = best_results[i] # log best results in the summary + self.wandb.log(x) + self.wandb.end_epoch(best_result=best_fitness == fi) + + if self.clearml: + self.clearml.current_epoch_logged_images = set() # reset epoch image limit + self.clearml.current_epoch += 1 + + if self.comet_logger: + self.comet_logger.on_fit_epoch_end(x, epoch=epoch) + + def on_model_save(self, last, epoch, final_epoch, best_fitness, fi): + # Callback runs on model save event + if (epoch + 1) % self.opt.save_period == 0 and not final_epoch and self.opt.save_period != -1: + if self.wandb: + self.wandb.log_model(last.parent, self.opt, epoch, fi, best_model=best_fitness == fi) + if self.clearml: + self.clearml.task.update_output_model(model_path=str(last), + model_name='Latest Model', + auto_delete_file=False) + + if self.comet_logger: + self.comet_logger.on_model_save(last, epoch, final_epoch, best_fitness, fi) + + def on_train_end(self, last, best, epoch, results): + # Callback runs on training end, i.e. saving best model + if self.plots: + plot_results(file=self.save_dir / 'results.csv') # save results.png + files = ['results.png', 'confusion_matrix.png', *(f'{x}_curve.png' for x in ('F1', 'PR', 'P', 'R'))] + files = [(self.save_dir / f) for f in files if (self.save_dir / f).exists()] # filter + self.logger.info(f"Results saved to {colorstr('bold', self.save_dir)}") + + if self.tb and not self.clearml: # These images are already captured by ClearML by now, we don't want doubles + for f in files: + self.tb.add_image(f.stem, cv2.imread(str(f))[..., ::-1], epoch, dataformats='HWC') + + if self.wandb: + self.wandb.log(dict(zip(self.keys[3:10], results))) + self.wandb.log({"Results": [wandb.Image(str(f), caption=f.name) for f in files]}) + # Calling wandb.log. TODO: Refactor this into WandbLogger.log_model + if not self.opt.evolve: + wandb.log_artifact(str(best if best.exists() else last), + type='model', + name=f'run_{self.wandb.wandb_run.id}_model', + aliases=['latest', 'best', 'stripped']) + self.wandb.finish_run() + + if self.clearml and not self.opt.evolve: + self.clearml.task.update_output_model(model_path=str(best if best.exists() else last), + name='Best Model', + auto_delete_file=False) + + if self.comet_logger: + final_results = dict(zip(self.keys[3:10], results)) + self.comet_logger.on_train_end(files, self.save_dir, last, best, epoch, final_results) + + def on_params_update(self, params: dict): + # Update hyperparams or configs of the experiment + if self.wandb: + self.wandb.wandb_run.config.update(params, allow_val_change=True) + if self.comet_logger: + self.comet_logger.on_params_update(params) + + +class GenericLogger: + """ + YOLO General purpose logger for non-task specific logging + Usage: from utils.loggers import GenericLogger; logger = GenericLogger(...) + Arguments + opt: Run arguments + console_logger: Console logger + include: loggers to include + """ + + def __init__(self, opt, console_logger, include=('tb', 'wandb')): + # init default loggers + self.save_dir = Path(opt.save_dir) + self.include = include + self.console_logger = console_logger + self.csv = self.save_dir / 'results.csv' # CSV logger + if 'tb' in self.include: + prefix = colorstr('TensorBoard: ') + self.console_logger.info( + f"{prefix}Start with 'tensorboard --logdir {self.save_dir.parent}', view at http://localhost:6006/") + self.tb = SummaryWriter(str(self.save_dir)) + + if wandb and 'wandb' in self.include: + self.wandb = wandb.init(project=web_project_name(str(opt.project)), + name=None if opt.name == "exp" else opt.name, + config=opt) + else: + self.wandb = None + + def log_metrics(self, metrics, epoch): + # Log metrics dictionary to all loggers + if self.csv: + keys, vals = list(metrics.keys()), list(metrics.values()) + n = len(metrics) + 1 # number of cols + s = '' if self.csv.exists() else (('%23s,' * n % tuple(['epoch'] + keys)).rstrip(',') + '\n') # header + with open(self.csv, 'a') as f: + f.write(s + ('%23.5g,' * n % tuple([epoch] + vals)).rstrip(',') + '\n') + + if self.tb: + for k, v in metrics.items(): + self.tb.add_scalar(k, v, epoch) + + if self.wandb: + self.wandb.log(metrics, step=epoch) + + def log_images(self, files, name='Images', epoch=0): + # Log images to all loggers + files = [Path(f) for f in (files if isinstance(files, (tuple, list)) else [files])] # to Path + files = [f for f in files if f.exists()] # filter by exists + + if self.tb: + for f in files: + self.tb.add_image(f.stem, cv2.imread(str(f))[..., ::-1], epoch, dataformats='HWC') + + if self.wandb: + self.wandb.log({name: [wandb.Image(str(f), caption=f.name) for f in files]}, step=epoch) + + def log_graph(self, model, imgsz=(640, 640)): + # Log model graph to all loggers + if self.tb: + log_tensorboard_graph(self.tb, model, imgsz) + + def log_model(self, model_path, epoch=0, metadata={}): + # Log model to all loggers + if self.wandb: + art = wandb.Artifact(name=f"run_{wandb.run.id}_model", type="model", metadata=metadata) + art.add_file(str(model_path)) + wandb.log_artifact(art) + + def update_params(self, params): + # Update the paramters logged + if self.wandb: + wandb.run.config.update(params, allow_val_change=True) + + +def log_tensorboard_graph(tb, model, imgsz=(640, 640)): + # Log model graph to TensorBoard + try: + p = next(model.parameters()) # for device, type + imgsz = (imgsz, imgsz) if isinstance(imgsz, int) else imgsz # expand + im = torch.zeros((1, 3, *imgsz)).to(p.device).type_as(p) # input image (WARNING: must be zeros, not empty) + with warnings.catch_warnings(): + warnings.simplefilter('ignore') # suppress jit trace warning + tb.add_graph(torch.jit.trace(de_parallel(model), im, strict=False), []) + except Exception as e: + LOGGER.warning(f'WARNING ⚠️ TensorBoard graph visualization failure {e}') + + +def web_project_name(project): + # Convert local project name to web project name + if not project.startswith('runs/train'): + return project + suffix = '-Classify' if project.endswith('-cls') else '-Segment' if project.endswith('-seg') else '' + return f'YOLO{suffix}' diff --git a/cv/3d_detection/yolov9/pytorch/utils/loggers/clearml/__init__.py b/cv/3d_detection/yolov9/pytorch/utils/loggers/clearml/__init__.py new file mode 100644 index 000000000..84952a816 --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/utils/loggers/clearml/__init__.py @@ -0,0 +1 @@ +# init \ No newline at end of file diff --git a/cv/3d_detection/yolov9/pytorch/utils/loggers/clearml/clearml_utils.py b/cv/3d_detection/yolov9/pytorch/utils/loggers/clearml/clearml_utils.py new file mode 100644 index 000000000..fe5f597a8 --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/utils/loggers/clearml/clearml_utils.py @@ -0,0 +1,157 @@ +"""Main Logger class for ClearML experiment tracking.""" +import glob +import re +from pathlib import Path + +import numpy as np +import yaml + +from utils.plots import Annotator, colors + +try: + import clearml + from clearml import Dataset, Task + + assert hasattr(clearml, '__version__') # verify package import not local dir +except (ImportError, AssertionError): + clearml = None + + +def construct_dataset(clearml_info_string): + """Load in a clearml dataset and fill the internal data_dict with its contents. + """ + dataset_id = clearml_info_string.replace('clearml://', '') + dataset = Dataset.get(dataset_id=dataset_id) + dataset_root_path = Path(dataset.get_local_copy()) + + # We'll search for the yaml file definition in the dataset + yaml_filenames = list(glob.glob(str(dataset_root_path / "*.yaml")) + glob.glob(str(dataset_root_path / "*.yml"))) + if len(yaml_filenames) > 1: + raise ValueError('More than one yaml file was found in the dataset root, cannot determine which one contains ' + 'the dataset definition this way.') + elif len(yaml_filenames) == 0: + raise ValueError('No yaml definition found in dataset root path, check that there is a correct yaml file ' + 'inside the dataset root path.') + with open(yaml_filenames[0]) as f: + dataset_definition = yaml.safe_load(f) + + assert set(dataset_definition.keys()).issuperset( + {'train', 'test', 'val', 'nc', 'names'} + ), "The right keys were not found in the yaml file, make sure it at least has the following keys: ('train', 'test', 'val', 'nc', 'names')" + + data_dict = dict() + data_dict['train'] = str( + (dataset_root_path / dataset_definition['train']).resolve()) if dataset_definition['train'] else None + data_dict['test'] = str( + (dataset_root_path / dataset_definition['test']).resolve()) if dataset_definition['test'] else None + data_dict['val'] = str( + (dataset_root_path / dataset_definition['val']).resolve()) if dataset_definition['val'] else None + data_dict['nc'] = dataset_definition['nc'] + data_dict['names'] = dataset_definition['names'] + + return data_dict + + +class ClearmlLogger: + """Log training runs, datasets, models, and predictions to ClearML. + + This logger sends information to ClearML at app.clear.ml or to your own hosted server. By default, + this information includes hyperparameters, system configuration and metrics, model metrics, code information and + basic data metrics and analyses. + + By providing additional command line arguments to train.py, datasets, + models and predictions can also be logged. + """ + + def __init__(self, opt, hyp): + """ + - Initialize ClearML Task, this object will capture the experiment + - Upload dataset version to ClearML Data if opt.upload_dataset is True + + arguments: + opt (namespace) -- Commandline arguments for this run + hyp (dict) -- Hyperparameters for this run + + """ + self.current_epoch = 0 + # Keep tracked of amount of logged images to enforce a limit + self.current_epoch_logged_images = set() + # Maximum number of images to log to clearML per epoch + self.max_imgs_to_log_per_epoch = 16 + # Get the interval of epochs when bounding box images should be logged + self.bbox_interval = opt.bbox_interval + self.clearml = clearml + self.task = None + self.data_dict = None + if self.clearml: + self.task = Task.init( + project_name=opt.project if opt.project != 'runs/train' else 'YOLOv5', + task_name=opt.name if opt.name != 'exp' else 'Training', + tags=['YOLOv5'], + output_uri=True, + auto_connect_frameworks={'pytorch': False} + # We disconnect pytorch auto-detection, because we added manual model save points in the code + ) + # ClearML's hooks will already grab all general parameters + # Only the hyperparameters coming from the yaml config file + # will have to be added manually! + self.task.connect(hyp, name='Hyperparameters') + + # Get ClearML Dataset Version if requested + if opt.data.startswith('clearml://'): + # data_dict should have the following keys: + # names, nc (number of classes), test, train, val (all three relative paths to ../datasets) + self.data_dict = construct_dataset(opt.data) + # Set data to data_dict because wandb will crash without this information and opt is the best way + # to give it to them + opt.data = self.data_dict + + def log_debug_samples(self, files, title='Debug Samples'): + """ + Log files (images) as debug samples in the ClearML task. + + arguments: + files (List(PosixPath)) a list of file paths in PosixPath format + title (str) A title that groups together images with the same values + """ + for f in files: + if f.exists(): + it = re.search(r'_batch(\d+)', f.name) + iteration = int(it.groups()[0]) if it else 0 + self.task.get_logger().report_image(title=title, + series=f.name.replace(it.group(), ''), + local_path=str(f), + iteration=iteration) + + def log_image_with_boxes(self, image_path, boxes, class_names, image, conf_threshold=0.25): + """ + Draw the bounding boxes on a single image and report the result as a ClearML debug sample. + + arguments: + image_path (PosixPath) the path the original image file + boxes (list): list of scaled predictions in the format - [xmin, ymin, xmax, ymax, confidence, class] + class_names (dict): dict containing mapping of class int to class name + image (Tensor): A torch tensor containing the actual image data + """ + if len(self.current_epoch_logged_images) < self.max_imgs_to_log_per_epoch and self.current_epoch >= 0: + # Log every bbox_interval times and deduplicate for any intermittend extra eval runs + if self.current_epoch % self.bbox_interval == 0 and image_path not in self.current_epoch_logged_images: + im = np.ascontiguousarray(np.moveaxis(image.mul(255).clamp(0, 255).byte().cpu().numpy(), 0, 2)) + annotator = Annotator(im=im, pil=True) + for i, (conf, class_nr, box) in enumerate(zip(boxes[:, 4], boxes[:, 5], boxes[:, :4])): + color = colors(i) + + class_name = class_names[int(class_nr)] + confidence_percentage = round(float(conf) * 100, 2) + label = f"{class_name}: {confidence_percentage}%" + + if conf > conf_threshold: + annotator.rectangle(box.cpu().numpy(), outline=color) + annotator.box_label(box.cpu().numpy(), label=label, color=color) + + annotated_image = annotator.result() + self.task.get_logger().report_image(title='Bounding Boxes', + series=image_path.name, + iteration=self.current_epoch, + image=annotated_image) + self.current_epoch_logged_images.add(image_path) diff --git a/cv/3d_detection/yolov9/pytorch/utils/loggers/clearml/hpo.py b/cv/3d_detection/yolov9/pytorch/utils/loggers/clearml/hpo.py new file mode 100644 index 000000000..ee518b0fb --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/utils/loggers/clearml/hpo.py @@ -0,0 +1,84 @@ +from clearml import Task +# Connecting ClearML with the current process, +# from here on everything is logged automatically +from clearml.automation import HyperParameterOptimizer, UniformParameterRange +from clearml.automation.optuna import OptimizerOptuna + +task = Task.init(project_name='Hyper-Parameter Optimization', + task_name='YOLOv5', + task_type=Task.TaskTypes.optimizer, + reuse_last_task_id=False) + +# Example use case: +optimizer = HyperParameterOptimizer( + # This is the experiment we want to optimize + base_task_id='', + # here we define the hyper-parameters to optimize + # Notice: The parameter name should exactly match what you see in the UI: / + # For Example, here we see in the base experiment a section Named: "General" + # under it a parameter named "batch_size", this becomes "General/batch_size" + # If you have `argparse` for example, then arguments will appear under the "Args" section, + # and you should instead pass "Args/batch_size" + hyper_parameters=[ + UniformParameterRange('Hyperparameters/lr0', min_value=1e-5, max_value=1e-1), + UniformParameterRange('Hyperparameters/lrf', min_value=0.01, max_value=1.0), + UniformParameterRange('Hyperparameters/momentum', min_value=0.6, max_value=0.98), + UniformParameterRange('Hyperparameters/weight_decay', min_value=0.0, max_value=0.001), + UniformParameterRange('Hyperparameters/warmup_epochs', min_value=0.0, max_value=5.0), + UniformParameterRange('Hyperparameters/warmup_momentum', min_value=0.0, max_value=0.95), + UniformParameterRange('Hyperparameters/warmup_bias_lr', min_value=0.0, max_value=0.2), + UniformParameterRange('Hyperparameters/box', min_value=0.02, max_value=0.2), + UniformParameterRange('Hyperparameters/cls', min_value=0.2, max_value=4.0), + UniformParameterRange('Hyperparameters/cls_pw', min_value=0.5, max_value=2.0), + UniformParameterRange('Hyperparameters/obj', min_value=0.2, max_value=4.0), + UniformParameterRange('Hyperparameters/obj_pw', min_value=0.5, max_value=2.0), + UniformParameterRange('Hyperparameters/iou_t', min_value=0.1, max_value=0.7), + UniformParameterRange('Hyperparameters/anchor_t', min_value=2.0, max_value=8.0), + UniformParameterRange('Hyperparameters/fl_gamma', min_value=0.0, max_value=4.0), + UniformParameterRange('Hyperparameters/hsv_h', min_value=0.0, max_value=0.1), + UniformParameterRange('Hyperparameters/hsv_s', min_value=0.0, max_value=0.9), + UniformParameterRange('Hyperparameters/hsv_v', min_value=0.0, max_value=0.9), + UniformParameterRange('Hyperparameters/degrees', min_value=0.0, max_value=45.0), + UniformParameterRange('Hyperparameters/translate', min_value=0.0, max_value=0.9), + UniformParameterRange('Hyperparameters/scale', min_value=0.0, max_value=0.9), + UniformParameterRange('Hyperparameters/shear', min_value=0.0, max_value=10.0), + UniformParameterRange('Hyperparameters/perspective', min_value=0.0, max_value=0.001), + UniformParameterRange('Hyperparameters/flipud', min_value=0.0, max_value=1.0), + UniformParameterRange('Hyperparameters/fliplr', min_value=0.0, max_value=1.0), + UniformParameterRange('Hyperparameters/mosaic', min_value=0.0, max_value=1.0), + UniformParameterRange('Hyperparameters/mixup', min_value=0.0, max_value=1.0), + UniformParameterRange('Hyperparameters/copy_paste', min_value=0.0, max_value=1.0)], + # this is the objective metric we want to maximize/minimize + objective_metric_title='metrics', + objective_metric_series='mAP_0.5', + # now we decide if we want to maximize it or minimize it (accuracy we maximize) + objective_metric_sign='max', + # let us limit the number of concurrent experiments, + # this in turn will make sure we do dont bombard the scheduler with experiments. + # if we have an auto-scaler connected, this, by proxy, will limit the number of machine + max_number_of_concurrent_tasks=1, + # this is the optimizer class (actually doing the optimization) + # Currently, we can choose from GridSearch, RandomSearch or OptimizerBOHB (Bayesian optimization Hyper-Band) + optimizer_class=OptimizerOptuna, + # If specified only the top K performing Tasks will be kept, the others will be automatically archived + save_top_k_tasks_only=5, # 5, + compute_time_limit=None, + total_max_jobs=20, + min_iteration_per_job=None, + max_iteration_per_job=None, +) + +# report every 10 seconds, this is way too often, but we are testing here +optimizer.set_report_period(10 / 60) +# You can also use the line below instead to run all the optimizer tasks locally, without using queues or agent +# an_optimizer.start_locally(job_complete_callback=job_complete_callback) +# set the time limit for the optimization process (2 hours) +optimizer.set_time_limit(in_minutes=120.0) +# Start the optimization process in the local environment +optimizer.start_locally() +# wait until process is done (notice we are controlling the optimization process in the background) +optimizer.wait() +# make sure background optimization stopped +optimizer.stop() + +print('We are done, good bye') diff --git a/cv/3d_detection/yolov9/pytorch/utils/loggers/comet/__init__.py b/cv/3d_detection/yolov9/pytorch/utils/loggers/comet/__init__.py new file mode 100644 index 000000000..b0318f88d --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/utils/loggers/comet/__init__.py @@ -0,0 +1,508 @@ +import glob +import json +import logging +import os +import sys +from pathlib import Path + +logger = logging.getLogger(__name__) + +FILE = Path(__file__).resolve() +ROOT = FILE.parents[3] # YOLOv5 root directory +if str(ROOT) not in sys.path: + sys.path.append(str(ROOT)) # add ROOT to PATH + +try: + import comet_ml + + # Project Configuration + config = comet_ml.config.get_config() + COMET_PROJECT_NAME = config.get_string(os.getenv("COMET_PROJECT_NAME"), "comet.project_name", default="yolov5") +except (ModuleNotFoundError, ImportError): + comet_ml = None + COMET_PROJECT_NAME = None + +import PIL +import torch +import torchvision.transforms as T +import yaml + +from utils.dataloaders import img2label_paths +from utils.general import check_dataset, scale_boxes, xywh2xyxy +from utils.metrics import box_iou + +COMET_PREFIX = "comet://" + +COMET_MODE = os.getenv("COMET_MODE", "online") + +# Model Saving Settings +COMET_MODEL_NAME = os.getenv("COMET_MODEL_NAME", "yolov5") + +# Dataset Artifact Settings +COMET_UPLOAD_DATASET = os.getenv("COMET_UPLOAD_DATASET", "false").lower() == "true" + +# Evaluation Settings +COMET_LOG_CONFUSION_MATRIX = os.getenv("COMET_LOG_CONFUSION_MATRIX", "true").lower() == "true" +COMET_LOG_PREDICTIONS = os.getenv("COMET_LOG_PREDICTIONS", "true").lower() == "true" +COMET_MAX_IMAGE_UPLOADS = int(os.getenv("COMET_MAX_IMAGE_UPLOADS", 100)) + +# Confusion Matrix Settings +CONF_THRES = float(os.getenv("CONF_THRES", 0.001)) +IOU_THRES = float(os.getenv("IOU_THRES", 0.6)) + +# Batch Logging Settings +COMET_LOG_BATCH_METRICS = os.getenv("COMET_LOG_BATCH_METRICS", "false").lower() == "true" +COMET_BATCH_LOGGING_INTERVAL = os.getenv("COMET_BATCH_LOGGING_INTERVAL", 1) +COMET_PREDICTION_LOGGING_INTERVAL = os.getenv("COMET_PREDICTION_LOGGING_INTERVAL", 1) +COMET_LOG_PER_CLASS_METRICS = os.getenv("COMET_LOG_PER_CLASS_METRICS", "false").lower() == "true" + +RANK = int(os.getenv("RANK", -1)) + +to_pil = T.ToPILImage() + + +class CometLogger: + """Log metrics, parameters, source code, models and much more + with Comet + """ + + def __init__(self, opt, hyp, run_id=None, job_type="Training", **experiment_kwargs) -> None: + self.job_type = job_type + self.opt = opt + self.hyp = hyp + + # Comet Flags + self.comet_mode = COMET_MODE + + self.save_model = opt.save_period > -1 + self.model_name = COMET_MODEL_NAME + + # Batch Logging Settings + self.log_batch_metrics = COMET_LOG_BATCH_METRICS + self.comet_log_batch_interval = COMET_BATCH_LOGGING_INTERVAL + + # Dataset Artifact Settings + self.upload_dataset = self.opt.upload_dataset if self.opt.upload_dataset else COMET_UPLOAD_DATASET + self.resume = self.opt.resume + + # Default parameters to pass to Experiment objects + self.default_experiment_kwargs = { + "log_code": False, + "log_env_gpu": True, + "log_env_cpu": True, + "project_name": COMET_PROJECT_NAME,} + self.default_experiment_kwargs.update(experiment_kwargs) + self.experiment = self._get_experiment(self.comet_mode, run_id) + + self.data_dict = self.check_dataset(self.opt.data) + self.class_names = self.data_dict["names"] + self.num_classes = self.data_dict["nc"] + + self.logged_images_count = 0 + self.max_images = COMET_MAX_IMAGE_UPLOADS + + if run_id is None: + self.experiment.log_other("Created from", "YOLOv5") + if not isinstance(self.experiment, comet_ml.OfflineExperiment): + workspace, project_name, experiment_id = self.experiment.url.split("/")[-3:] + self.experiment.log_other( + "Run Path", + f"{workspace}/{project_name}/{experiment_id}", + ) + self.log_parameters(vars(opt)) + self.log_parameters(self.opt.hyp) + self.log_asset_data( + self.opt.hyp, + name="hyperparameters.json", + metadata={"type": "hyp-config-file"}, + ) + self.log_asset( + f"{self.opt.save_dir}/opt.yaml", + metadata={"type": "opt-config-file"}, + ) + + self.comet_log_confusion_matrix = COMET_LOG_CONFUSION_MATRIX + + if hasattr(self.opt, "conf_thres"): + self.conf_thres = self.opt.conf_thres + else: + self.conf_thres = CONF_THRES + if hasattr(self.opt, "iou_thres"): + self.iou_thres = self.opt.iou_thres + else: + self.iou_thres = IOU_THRES + + self.log_parameters({"val_iou_threshold": self.iou_thres, "val_conf_threshold": self.conf_thres}) + + self.comet_log_predictions = COMET_LOG_PREDICTIONS + if self.opt.bbox_interval == -1: + self.comet_log_prediction_interval = 1 if self.opt.epochs < 10 else self.opt.epochs // 10 + else: + self.comet_log_prediction_interval = self.opt.bbox_interval + + if self.comet_log_predictions: + self.metadata_dict = {} + self.logged_image_names = [] + + self.comet_log_per_class_metrics = COMET_LOG_PER_CLASS_METRICS + + self.experiment.log_others({ + "comet_mode": COMET_MODE, + "comet_max_image_uploads": COMET_MAX_IMAGE_UPLOADS, + "comet_log_per_class_metrics": COMET_LOG_PER_CLASS_METRICS, + "comet_log_batch_metrics": COMET_LOG_BATCH_METRICS, + "comet_log_confusion_matrix": COMET_LOG_CONFUSION_MATRIX, + "comet_model_name": COMET_MODEL_NAME,}) + + # Check if running the Experiment with the Comet Optimizer + if hasattr(self.opt, "comet_optimizer_id"): + self.experiment.log_other("optimizer_id", self.opt.comet_optimizer_id) + self.experiment.log_other("optimizer_objective", self.opt.comet_optimizer_objective) + self.experiment.log_other("optimizer_metric", self.opt.comet_optimizer_metric) + self.experiment.log_other("optimizer_parameters", json.dumps(self.hyp)) + + def _get_experiment(self, mode, experiment_id=None): + if mode == "offline": + if experiment_id is not None: + return comet_ml.ExistingOfflineExperiment( + previous_experiment=experiment_id, + **self.default_experiment_kwargs, + ) + + return comet_ml.OfflineExperiment(**self.default_experiment_kwargs,) + + else: + try: + if experiment_id is not None: + return comet_ml.ExistingExperiment( + previous_experiment=experiment_id, + **self.default_experiment_kwargs, + ) + + return comet_ml.Experiment(**self.default_experiment_kwargs) + + except ValueError: + logger.warning("COMET WARNING: " + "Comet credentials have not been set. " + "Comet will default to offline logging. " + "Please set your credentials to enable online logging.") + return self._get_experiment("offline", experiment_id) + + return + + def log_metrics(self, log_dict, **kwargs): + self.experiment.log_metrics(log_dict, **kwargs) + + def log_parameters(self, log_dict, **kwargs): + self.experiment.log_parameters(log_dict, **kwargs) + + def log_asset(self, asset_path, **kwargs): + self.experiment.log_asset(asset_path, **kwargs) + + def log_asset_data(self, asset, **kwargs): + self.experiment.log_asset_data(asset, **kwargs) + + def log_image(self, img, **kwargs): + self.experiment.log_image(img, **kwargs) + + def log_model(self, path, opt, epoch, fitness_score, best_model=False): + if not self.save_model: + return + + model_metadata = { + "fitness_score": fitness_score[-1], + "epochs_trained": epoch + 1, + "save_period": opt.save_period, + "total_epochs": opt.epochs,} + + model_files = glob.glob(f"{path}/*.pt") + for model_path in model_files: + name = Path(model_path).name + + self.experiment.log_model( + self.model_name, + file_or_folder=model_path, + file_name=name, + metadata=model_metadata, + overwrite=True, + ) + + def check_dataset(self, data_file): + with open(data_file) as f: + data_config = yaml.safe_load(f) + + if data_config['path'].startswith(COMET_PREFIX): + path = data_config['path'].replace(COMET_PREFIX, "") + data_dict = self.download_dataset_artifact(path) + + return data_dict + + self.log_asset(self.opt.data, metadata={"type": "data-config-file"}) + + return check_dataset(data_file) + + def log_predictions(self, image, labelsn, path, shape, predn): + if self.logged_images_count >= self.max_images: + return + detections = predn[predn[:, 4] > self.conf_thres] + iou = box_iou(labelsn[:, 1:], detections[:, :4]) + mask, _ = torch.where(iou > self.iou_thres) + if len(mask) == 0: + return + + filtered_detections = detections[mask] + filtered_labels = labelsn[mask] + + image_id = path.split("/")[-1].split(".")[0] + image_name = f"{image_id}_curr_epoch_{self.experiment.curr_epoch}" + if image_name not in self.logged_image_names: + native_scale_image = PIL.Image.open(path) + self.log_image(native_scale_image, name=image_name) + self.logged_image_names.append(image_name) + + metadata = [] + for cls, *xyxy in filtered_labels.tolist(): + metadata.append({ + "label": f"{self.class_names[int(cls)]}-gt", + "score": 100, + "box": { + "x": xyxy[0], + "y": xyxy[1], + "x2": xyxy[2], + "y2": xyxy[3]},}) + for *xyxy, conf, cls in filtered_detections.tolist(): + metadata.append({ + "label": f"{self.class_names[int(cls)]}", + "score": conf * 100, + "box": { + "x": xyxy[0], + "y": xyxy[1], + "x2": xyxy[2], + "y2": xyxy[3]},}) + + self.metadata_dict[image_name] = metadata + self.logged_images_count += 1 + + return + + def preprocess_prediction(self, image, labels, shape, pred): + nl, _ = labels.shape[0], pred.shape[0] + + # Predictions + if self.opt.single_cls: + pred[:, 5] = 0 + + predn = pred.clone() + scale_boxes(image.shape[1:], predn[:, :4], shape[0], shape[1]) + + labelsn = None + if nl: + tbox = xywh2xyxy(labels[:, 1:5]) # target boxes + scale_boxes(image.shape[1:], tbox, shape[0], shape[1]) # native-space labels + labelsn = torch.cat((labels[:, 0:1], tbox), 1) # native-space labels + scale_boxes(image.shape[1:], predn[:, :4], shape[0], shape[1]) # native-space pred + + return predn, labelsn + + def add_assets_to_artifact(self, artifact, path, asset_path, split): + img_paths = sorted(glob.glob(f"{asset_path}/*")) + label_paths = img2label_paths(img_paths) + + for image_file, label_file in zip(img_paths, label_paths): + image_logical_path, label_logical_path = map(lambda x: os.path.relpath(x, path), [image_file, label_file]) + + try: + artifact.add(image_file, logical_path=image_logical_path, metadata={"split": split}) + artifact.add(label_file, logical_path=label_logical_path, metadata={"split": split}) + except ValueError as e: + logger.error('COMET ERROR: Error adding file to Artifact. Skipping file.') + logger.error(f"COMET ERROR: {e}") + continue + + return artifact + + def upload_dataset_artifact(self): + dataset_name = self.data_dict.get("dataset_name", "yolov5-dataset") + path = str((ROOT / Path(self.data_dict["path"])).resolve()) + + metadata = self.data_dict.copy() + for key in ["train", "val", "test"]: + split_path = metadata.get(key) + if split_path is not None: + metadata[key] = split_path.replace(path, "") + + artifact = comet_ml.Artifact(name=dataset_name, artifact_type="dataset", metadata=metadata) + for key in metadata.keys(): + if key in ["train", "val", "test"]: + if isinstance(self.upload_dataset, str) and (key != self.upload_dataset): + continue + + asset_path = self.data_dict.get(key) + if asset_path is not None: + artifact = self.add_assets_to_artifact(artifact, path, asset_path, key) + + self.experiment.log_artifact(artifact) + + return + + def download_dataset_artifact(self, artifact_path): + logged_artifact = self.experiment.get_artifact(artifact_path) + artifact_save_dir = str(Path(self.opt.save_dir) / logged_artifact.name) + logged_artifact.download(artifact_save_dir) + + metadata = logged_artifact.metadata + data_dict = metadata.copy() + data_dict["path"] = artifact_save_dir + + metadata_names = metadata.get("names") + if type(metadata_names) == dict: + data_dict["names"] = {int(k): v for k, v in metadata.get("names").items()} + elif type(metadata_names) == list: + data_dict["names"] = {int(k): v for k, v in zip(range(len(metadata_names)), metadata_names)} + else: + raise "Invalid 'names' field in dataset yaml file. Please use a list or dictionary" + + data_dict = self.update_data_paths(data_dict) + return data_dict + + def update_data_paths(self, data_dict): + path = data_dict.get("path", "") + + for split in ["train", "val", "test"]: + if data_dict.get(split): + split_path = data_dict.get(split) + data_dict[split] = (f"{path}/{split_path}" if isinstance(split, str) else [ + f"{path}/{x}" for x in split_path]) + + return data_dict + + def on_pretrain_routine_end(self, paths): + if self.opt.resume: + return + + for path in paths: + self.log_asset(str(path)) + + if self.upload_dataset: + if not self.resume: + self.upload_dataset_artifact() + + return + + def on_train_start(self): + self.log_parameters(self.hyp) + + def on_train_epoch_start(self): + return + + def on_train_epoch_end(self, epoch): + self.experiment.curr_epoch = epoch + + return + + def on_train_batch_start(self): + return + + def on_train_batch_end(self, log_dict, step): + self.experiment.curr_step = step + if self.log_batch_metrics and (step % self.comet_log_batch_interval == 0): + self.log_metrics(log_dict, step=step) + + return + + def on_train_end(self, files, save_dir, last, best, epoch, results): + if self.comet_log_predictions: + curr_epoch = self.experiment.curr_epoch + self.experiment.log_asset_data(self.metadata_dict, "image-metadata.json", epoch=curr_epoch) + + for f in files: + self.log_asset(f, metadata={"epoch": epoch}) + self.log_asset(f"{save_dir}/results.csv", metadata={"epoch": epoch}) + + if not self.opt.evolve: + model_path = str(best if best.exists() else last) + name = Path(model_path).name + if self.save_model: + self.experiment.log_model( + self.model_name, + file_or_folder=model_path, + file_name=name, + overwrite=True, + ) + + # Check if running Experiment with Comet Optimizer + if hasattr(self.opt, 'comet_optimizer_id'): + metric = results.get(self.opt.comet_optimizer_metric) + self.experiment.log_other('optimizer_metric_value', metric) + + self.finish_run() + + def on_val_start(self): + return + + def on_val_batch_start(self): + return + + def on_val_batch_end(self, batch_i, images, targets, paths, shapes, outputs): + if not (self.comet_log_predictions and ((batch_i + 1) % self.comet_log_prediction_interval == 0)): + return + + for si, pred in enumerate(outputs): + if len(pred) == 0: + continue + + image = images[si] + labels = targets[targets[:, 0] == si, 1:] + shape = shapes[si] + path = paths[si] + predn, labelsn = self.preprocess_prediction(image, labels, shape, pred) + if labelsn is not None: + self.log_predictions(image, labelsn, path, shape, predn) + + return + + def on_val_end(self, nt, tp, fp, p, r, f1, ap, ap50, ap_class, confusion_matrix): + if self.comet_log_per_class_metrics: + if self.num_classes > 1: + for i, c in enumerate(ap_class): + class_name = self.class_names[c] + self.experiment.log_metrics( + { + 'mAP@.5': ap50[i], + 'mAP@.5:.95': ap[i], + 'precision': p[i], + 'recall': r[i], + 'f1': f1[i], + 'true_positives': tp[i], + 'false_positives': fp[i], + 'support': nt[c]}, + prefix=class_name) + + if self.comet_log_confusion_matrix: + epoch = self.experiment.curr_epoch + class_names = list(self.class_names.values()) + class_names.append("background") + num_classes = len(class_names) + + self.experiment.log_confusion_matrix( + matrix=confusion_matrix.matrix, + max_categories=num_classes, + labels=class_names, + epoch=epoch, + column_label='Actual Category', + row_label='Predicted Category', + file_name=f"confusion-matrix-epoch-{epoch}.json", + ) + + def on_fit_epoch_end(self, result, epoch): + self.log_metrics(result, epoch=epoch) + + def on_model_save(self, last, epoch, final_epoch, best_fitness, fi): + if ((epoch + 1) % self.opt.save_period == 0 and not final_epoch) and self.opt.save_period != -1: + self.log_model(last.parent, self.opt, epoch, fi, best_model=best_fitness == fi) + + def on_params_update(self, params): + self.log_parameters(params) + + def finish_run(self): + self.experiment.end() diff --git a/cv/3d_detection/yolov9/pytorch/utils/loggers/comet/comet_utils.py b/cv/3d_detection/yolov9/pytorch/utils/loggers/comet/comet_utils.py new file mode 100644 index 000000000..3cbd45156 --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/utils/loggers/comet/comet_utils.py @@ -0,0 +1,150 @@ +import logging +import os +from urllib.parse import urlparse + +try: + import comet_ml +except (ModuleNotFoundError, ImportError): + comet_ml = None + +import yaml + +logger = logging.getLogger(__name__) + +COMET_PREFIX = "comet://" +COMET_MODEL_NAME = os.getenv("COMET_MODEL_NAME", "yolov5") +COMET_DEFAULT_CHECKPOINT_FILENAME = os.getenv("COMET_DEFAULT_CHECKPOINT_FILENAME", "last.pt") + + +def download_model_checkpoint(opt, experiment): + model_dir = f"{opt.project}/{experiment.name}" + os.makedirs(model_dir, exist_ok=True) + + model_name = COMET_MODEL_NAME + model_asset_list = experiment.get_model_asset_list(model_name) + + if len(model_asset_list) == 0: + logger.error(f"COMET ERROR: No checkpoints found for model name : {model_name}") + return + + model_asset_list = sorted( + model_asset_list, + key=lambda x: x["step"], + reverse=True, + ) + logged_checkpoint_map = {asset["fileName"]: asset["assetId"] for asset in model_asset_list} + + resource_url = urlparse(opt.weights) + checkpoint_filename = resource_url.query + + if checkpoint_filename: + asset_id = logged_checkpoint_map.get(checkpoint_filename) + else: + asset_id = logged_checkpoint_map.get(COMET_DEFAULT_CHECKPOINT_FILENAME) + checkpoint_filename = COMET_DEFAULT_CHECKPOINT_FILENAME + + if asset_id is None: + logger.error(f"COMET ERROR: Checkpoint {checkpoint_filename} not found in the given Experiment") + return + + try: + logger.info(f"COMET INFO: Downloading checkpoint {checkpoint_filename}") + asset_filename = checkpoint_filename + + model_binary = experiment.get_asset(asset_id, return_type="binary", stream=False) + model_download_path = f"{model_dir}/{asset_filename}" + with open(model_download_path, "wb") as f: + f.write(model_binary) + + opt.weights = model_download_path + + except Exception as e: + logger.warning("COMET WARNING: Unable to download checkpoint from Comet") + logger.exception(e) + + +def set_opt_parameters(opt, experiment): + """Update the opts Namespace with parameters + from Comet's ExistingExperiment when resuming a run + + Args: + opt (argparse.Namespace): Namespace of command line options + experiment (comet_ml.APIExperiment): Comet API Experiment object + """ + asset_list = experiment.get_asset_list() + resume_string = opt.resume + + for asset in asset_list: + if asset["fileName"] == "opt.yaml": + asset_id = asset["assetId"] + asset_binary = experiment.get_asset(asset_id, return_type="binary", stream=False) + opt_dict = yaml.safe_load(asset_binary) + for key, value in opt_dict.items(): + setattr(opt, key, value) + opt.resume = resume_string + + # Save hyperparameters to YAML file + # Necessary to pass checks in training script + save_dir = f"{opt.project}/{experiment.name}" + os.makedirs(save_dir, exist_ok=True) + + hyp_yaml_path = f"{save_dir}/hyp.yaml" + with open(hyp_yaml_path, "w") as f: + yaml.dump(opt.hyp, f) + opt.hyp = hyp_yaml_path + + +def check_comet_weights(opt): + """Downloads model weights from Comet and updates the + weights path to point to saved weights location + + Args: + opt (argparse.Namespace): Command Line arguments passed + to YOLOv5 training script + + Returns: + None/bool: Return True if weights are successfully downloaded + else return None + """ + if comet_ml is None: + return + + if isinstance(opt.weights, str): + if opt.weights.startswith(COMET_PREFIX): + api = comet_ml.API() + resource = urlparse(opt.weights) + experiment_path = f"{resource.netloc}{resource.path}" + experiment = api.get(experiment_path) + download_model_checkpoint(opt, experiment) + return True + + return None + + +def check_comet_resume(opt): + """Restores run parameters to its original state based on the model checkpoint + and logged Experiment parameters. + + Args: + opt (argparse.Namespace): Command Line arguments passed + to YOLOv5 training script + + Returns: + None/bool: Return True if the run is restored successfully + else return None + """ + if comet_ml is None: + return + + if isinstance(opt.resume, str): + if opt.resume.startswith(COMET_PREFIX): + api = comet_ml.API() + resource = urlparse(opt.resume) + experiment_path = f"{resource.netloc}{resource.path}" + experiment = api.get(experiment_path) + set_opt_parameters(opt, experiment) + download_model_checkpoint(opt, experiment) + + return True + + return None diff --git a/cv/3d_detection/yolov9/pytorch/utils/loggers/comet/hpo.py b/cv/3d_detection/yolov9/pytorch/utils/loggers/comet/hpo.py new file mode 100644 index 000000000..7dd5c92e8 --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/utils/loggers/comet/hpo.py @@ -0,0 +1,118 @@ +import argparse +import json +import logging +import os +import sys +from pathlib import Path + +import comet_ml + +logger = logging.getLogger(__name__) + +FILE = Path(__file__).resolve() +ROOT = FILE.parents[3] # YOLOv5 root directory +if str(ROOT) not in sys.path: + sys.path.append(str(ROOT)) # add ROOT to PATH + +from train import train +from utils.callbacks import Callbacks +from utils.general import increment_path +from utils.torch_utils import select_device + +# Project Configuration +config = comet_ml.config.get_config() +COMET_PROJECT_NAME = config.get_string(os.getenv("COMET_PROJECT_NAME"), "comet.project_name", default="yolov5") + + +def get_args(known=False): + parser = argparse.ArgumentParser() + parser.add_argument('--weights', type=str, default=ROOT / 'yolov5s.pt', help='initial weights path') + parser.add_argument('--cfg', type=str, default='', help='model.yaml path') + parser.add_argument('--data', type=str, default=ROOT / 'data/coco128.yaml', help='dataset.yaml path') + parser.add_argument('--hyp', type=str, default=ROOT / 'data/hyps/hyp.scratch-low.yaml', help='hyperparameters path') + parser.add_argument('--epochs', type=int, default=300, help='total training epochs') + parser.add_argument('--batch-size', type=int, default=16, help='total batch size for all GPUs, -1 for autobatch') + parser.add_argument('--imgsz', '--img', '--img-size', type=int, default=640, help='train, val image size (pixels)') + parser.add_argument('--rect', action='store_true', help='rectangular training') + parser.add_argument('--resume', nargs='?', const=True, default=False, help='resume most recent training') + parser.add_argument('--nosave', action='store_true', help='only save final checkpoint') + parser.add_argument('--noval', action='store_true', help='only validate final epoch') + parser.add_argument('--noautoanchor', action='store_true', help='disable AutoAnchor') + parser.add_argument('--noplots', action='store_true', help='save no plot files') + parser.add_argument('--evolve', type=int, nargs='?', const=300, help='evolve hyperparameters for x generations') + parser.add_argument('--bucket', type=str, default='', help='gsutil bucket') + parser.add_argument('--cache', type=str, nargs='?', const='ram', help='--cache images in "ram" (default) or "disk"') + parser.add_argument('--image-weights', action='store_true', help='use weighted image selection for training') + parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu') + parser.add_argument('--multi-scale', action='store_true', help='vary img-size +/- 50%%') + parser.add_argument('--single-cls', action='store_true', help='train multi-class data as single-class') + parser.add_argument('--optimizer', type=str, choices=['SGD', 'Adam', 'AdamW'], default='SGD', help='optimizer') + parser.add_argument('--sync-bn', action='store_true', help='use SyncBatchNorm, only available in DDP mode') + parser.add_argument('--workers', type=int, default=8, help='max dataloader workers (per RANK in DDP mode)') + parser.add_argument('--project', default=ROOT / 'runs/train', help='save to project/name') + parser.add_argument('--name', default='exp', help='save to project/name') + parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment') + parser.add_argument('--quad', action='store_true', help='quad dataloader') + parser.add_argument('--cos-lr', action='store_true', help='cosine LR scheduler') + parser.add_argument('--label-smoothing', type=float, default=0.0, help='Label smoothing epsilon') + parser.add_argument('--patience', type=int, default=100, help='EarlyStopping patience (epochs without improvement)') + parser.add_argument('--freeze', nargs='+', type=int, default=[0], help='Freeze layers: backbone=10, first3=0 1 2') + parser.add_argument('--save-period', type=int, default=-1, help='Save checkpoint every x epochs (disabled if < 1)') + parser.add_argument('--seed', type=int, default=0, help='Global training seed') + parser.add_argument('--local_rank', type=int, default=-1, help='Automatic DDP Multi-GPU argument, do not modify') + + # Weights & Biases arguments + parser.add_argument('--entity', default=None, help='W&B: Entity') + parser.add_argument('--upload_dataset', nargs='?', const=True, default=False, help='W&B: Upload data, "val" option') + parser.add_argument('--bbox_interval', type=int, default=-1, help='W&B: Set bounding-box image logging interval') + parser.add_argument('--artifact_alias', type=str, default='latest', help='W&B: Version of dataset artifact to use') + + # Comet Arguments + parser.add_argument("--comet_optimizer_config", type=str, help="Comet: Path to a Comet Optimizer Config File.") + parser.add_argument("--comet_optimizer_id", type=str, help="Comet: ID of the Comet Optimizer sweep.") + parser.add_argument("--comet_optimizer_objective", type=str, help="Comet: Set to 'minimize' or 'maximize'.") + parser.add_argument("--comet_optimizer_metric", type=str, help="Comet: Metric to Optimize.") + parser.add_argument("--comet_optimizer_workers", + type=int, + default=1, + help="Comet: Number of Parallel Workers to use with the Comet Optimizer.") + + return parser.parse_known_args()[0] if known else parser.parse_args() + + +def run(parameters, opt): + hyp_dict = {k: v for k, v in parameters.items() if k not in ["epochs", "batch_size"]} + + opt.save_dir = str(increment_path(Path(opt.project) / opt.name, exist_ok=opt.exist_ok or opt.evolve)) + opt.batch_size = parameters.get("batch_size") + opt.epochs = parameters.get("epochs") + + device = select_device(opt.device, batch_size=opt.batch_size) + train(hyp_dict, opt, device, callbacks=Callbacks()) + + +if __name__ == "__main__": + opt = get_args(known=True) + + opt.weights = str(opt.weights) + opt.cfg = str(opt.cfg) + opt.data = str(opt.data) + opt.project = str(opt.project) + + optimizer_id = os.getenv("COMET_OPTIMIZER_ID") + if optimizer_id is None: + with open(opt.comet_optimizer_config) as f: + optimizer_config = json.load(f) + optimizer = comet_ml.Optimizer(optimizer_config) + else: + optimizer = comet_ml.Optimizer(optimizer_id) + + opt.comet_optimizer_id = optimizer.id + status = optimizer.status() + + opt.comet_optimizer_objective = status["spec"]["objective"] + opt.comet_optimizer_metric = status["spec"]["metric"] + + logger.info("COMET INFO: Starting Hyperparameter Sweep") + for parameter in optimizer.get_parameters(): + run(parameter["parameters"], opt) diff --git a/cv/3d_detection/yolov9/pytorch/utils/loggers/comet/optimizer_config.json b/cv/3d_detection/yolov9/pytorch/utils/loggers/comet/optimizer_config.json new file mode 100644 index 000000000..83ddddab6 --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/utils/loggers/comet/optimizer_config.json @@ -0,0 +1,209 @@ +{ + "algorithm": "random", + "parameters": { + "anchor_t": { + "type": "discrete", + "values": [ + 2, + 8 + ] + }, + "batch_size": { + "type": "discrete", + "values": [ + 16, + 32, + 64 + ] + }, + "box": { + "type": "discrete", + "values": [ + 0.02, + 0.2 + ] + }, + "cls": { + "type": "discrete", + "values": [ + 0.2 + ] + }, + "cls_pw": { + "type": "discrete", + "values": [ + 0.5 + ] + }, + "copy_paste": { + "type": "discrete", + "values": [ + 1 + ] + }, + "degrees": { + "type": "discrete", + "values": [ + 0, + 45 + ] + }, + "epochs": { + "type": "discrete", + "values": [ + 5 + ] + }, + "fl_gamma": { + "type": "discrete", + "values": [ + 0 + ] + }, + "fliplr": { + "type": "discrete", + "values": [ + 0 + ] + }, + "flipud": { + "type": "discrete", + "values": [ + 0 + ] + }, + "hsv_h": { + "type": "discrete", + "values": [ + 0 + ] + }, + "hsv_s": { + "type": "discrete", + "values": [ + 0 + ] + }, + "hsv_v": { + "type": "discrete", + "values": [ + 0 + ] + }, + "iou_t": { + "type": "discrete", + "values": [ + 0.7 + ] + }, + "lr0": { + "type": "discrete", + "values": [ + 1e-05, + 0.1 + ] + }, + "lrf": { + "type": "discrete", + "values": [ + 0.01, + 1 + ] + }, + "mixup": { + "type": "discrete", + "values": [ + 1 + ] + }, + "momentum": { + "type": "discrete", + "values": [ + 0.6 + ] + }, + "mosaic": { + "type": "discrete", + "values": [ + 0 + ] + }, + "obj": { + "type": "discrete", + "values": [ + 0.2 + ] + }, + "obj_pw": { + "type": "discrete", + "values": [ + 0.5 + ] + }, + "optimizer": { + "type": "categorical", + "values": [ + "SGD", + "Adam", + "AdamW" + ] + }, + "perspective": { + "type": "discrete", + "values": [ + 0 + ] + }, + "scale": { + "type": "discrete", + "values": [ + 0 + ] + }, + "shear": { + "type": "discrete", + "values": [ + 0 + ] + }, + "translate": { + "type": "discrete", + "values": [ + 0 + ] + }, + "warmup_bias_lr": { + "type": "discrete", + "values": [ + 0, + 0.2 + ] + }, + "warmup_epochs": { + "type": "discrete", + "values": [ + 5 + ] + }, + "warmup_momentum": { + "type": "discrete", + "values": [ + 0, + 0.95 + ] + }, + "weight_decay": { + "type": "discrete", + "values": [ + 0, + 0.001 + ] + } + }, + "spec": { + "maxCombo": 0, + "metric": "metrics/mAP_0.5", + "objective": "maximize" + }, + "trials": 1 +} diff --git a/cv/3d_detection/yolov9/pytorch/utils/loggers/wandb/__init__.py b/cv/3d_detection/yolov9/pytorch/utils/loggers/wandb/__init__.py new file mode 100644 index 000000000..84952a816 --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/utils/loggers/wandb/__init__.py @@ -0,0 +1 @@ +# init \ No newline at end of file diff --git a/cv/3d_detection/yolov9/pytorch/utils/loggers/wandb/log_dataset.py b/cv/3d_detection/yolov9/pytorch/utils/loggers/wandb/log_dataset.py new file mode 100644 index 000000000..06e81fb69 --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/utils/loggers/wandb/log_dataset.py @@ -0,0 +1,27 @@ +import argparse + +from wandb_utils import WandbLogger + +from utils.general import LOGGER + +WANDB_ARTIFACT_PREFIX = 'wandb-artifact://' + + +def create_dataset_artifact(opt): + logger = WandbLogger(opt, None, job_type='Dataset Creation') # TODO: return value unused + if not logger.wandb: + LOGGER.info("install wandb using `pip install wandb` to log the dataset") + + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument('--data', type=str, default='data/coco128.yaml', help='data.yaml path') + parser.add_argument('--single-cls', action='store_true', help='train as single-class dataset') + parser.add_argument('--project', type=str, default='YOLOv5', help='name of W&B Project') + parser.add_argument('--entity', default=None, help='W&B entity') + parser.add_argument('--name', type=str, default='log dataset', help='name of W&B run') + + opt = parser.parse_args() + opt.resume = False # Explicitly disallow resume check for dataset upload job + + create_dataset_artifact(opt) diff --git a/cv/3d_detection/yolov9/pytorch/utils/loggers/wandb/sweep.py b/cv/3d_detection/yolov9/pytorch/utils/loggers/wandb/sweep.py new file mode 100644 index 000000000..d49ea6f27 --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/utils/loggers/wandb/sweep.py @@ -0,0 +1,41 @@ +import sys +from pathlib import Path + +import wandb + +FILE = Path(__file__).resolve() +ROOT = FILE.parents[3] # YOLOv5 root directory +if str(ROOT) not in sys.path: + sys.path.append(str(ROOT)) # add ROOT to PATH + +from train import parse_opt, train +from utils.callbacks import Callbacks +from utils.general import increment_path +from utils.torch_utils import select_device + + +def sweep(): + wandb.init() + # Get hyp dict from sweep agent. Copy because train() modifies parameters which confused wandb. + hyp_dict = vars(wandb.config).get("_items").copy() + + # Workaround: get necessary opt args + opt = parse_opt(known=True) + opt.batch_size = hyp_dict.get("batch_size") + opt.save_dir = str(increment_path(Path(opt.project) / opt.name, exist_ok=opt.exist_ok or opt.evolve)) + opt.epochs = hyp_dict.get("epochs") + opt.nosave = True + opt.data = hyp_dict.get("data") + opt.weights = str(opt.weights) + opt.cfg = str(opt.cfg) + opt.data = str(opt.data) + opt.hyp = str(opt.hyp) + opt.project = str(opt.project) + device = select_device(opt.device, batch_size=opt.batch_size) + + # train + train(hyp_dict, opt, device, callbacks=Callbacks()) + + +if __name__ == "__main__": + sweep() diff --git a/cv/3d_detection/yolov9/pytorch/utils/loggers/wandb/sweep.yaml b/cv/3d_detection/yolov9/pytorch/utils/loggers/wandb/sweep.yaml new file mode 100644 index 000000000..688b1ea02 --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/utils/loggers/wandb/sweep.yaml @@ -0,0 +1,143 @@ +# Hyperparameters for training +# To set range- +# Provide min and max values as: +# parameter: +# +# min: scalar +# max: scalar +# OR +# +# Set a specific list of search space- +# parameter: +# values: [scalar1, scalar2, scalar3...] +# +# You can use grid, bayesian and hyperopt search strategy +# For more info on configuring sweeps visit - https://docs.wandb.ai/guides/sweeps/configuration + +program: utils/loggers/wandb/sweep.py +method: random +metric: + name: metrics/mAP_0.5 + goal: maximize + +parameters: + # hyperparameters: set either min, max range or values list + data: + value: "data/coco128.yaml" + batch_size: + values: [64] + epochs: + values: [10] + + lr0: + distribution: uniform + min: 1e-5 + max: 1e-1 + lrf: + distribution: uniform + min: 0.01 + max: 1.0 + momentum: + distribution: uniform + min: 0.6 + max: 0.98 + weight_decay: + distribution: uniform + min: 0.0 + max: 0.001 + warmup_epochs: + distribution: uniform + min: 0.0 + max: 5.0 + warmup_momentum: + distribution: uniform + min: 0.0 + max: 0.95 + warmup_bias_lr: + distribution: uniform + min: 0.0 + max: 0.2 + box: + distribution: uniform + min: 0.02 + max: 0.2 + cls: + distribution: uniform + min: 0.2 + max: 4.0 + cls_pw: + distribution: uniform + min: 0.5 + max: 2.0 + obj: + distribution: uniform + min: 0.2 + max: 4.0 + obj_pw: + distribution: uniform + min: 0.5 + max: 2.0 + iou_t: + distribution: uniform + min: 0.1 + max: 0.7 + anchor_t: + distribution: uniform + min: 2.0 + max: 8.0 + fl_gamma: + distribution: uniform + min: 0.0 + max: 4.0 + hsv_h: + distribution: uniform + min: 0.0 + max: 0.1 + hsv_s: + distribution: uniform + min: 0.0 + max: 0.9 + hsv_v: + distribution: uniform + min: 0.0 + max: 0.9 + degrees: + distribution: uniform + min: 0.0 + max: 45.0 + translate: + distribution: uniform + min: 0.0 + max: 0.9 + scale: + distribution: uniform + min: 0.0 + max: 0.9 + shear: + distribution: uniform + min: 0.0 + max: 10.0 + perspective: + distribution: uniform + min: 0.0 + max: 0.001 + flipud: + distribution: uniform + min: 0.0 + max: 1.0 + fliplr: + distribution: uniform + min: 0.0 + max: 1.0 + mosaic: + distribution: uniform + min: 0.0 + max: 1.0 + mixup: + distribution: uniform + min: 0.0 + max: 1.0 + copy_paste: + distribution: uniform + min: 0.0 + max: 1.0 diff --git a/cv/3d_detection/yolov9/pytorch/utils/loggers/wandb/wandb_utils.py b/cv/3d_detection/yolov9/pytorch/utils/loggers/wandb/wandb_utils.py new file mode 100644 index 000000000..238f4edbf --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/utils/loggers/wandb/wandb_utils.py @@ -0,0 +1,589 @@ +"""Utilities and tools for tracking runs with Weights & Biases.""" + +import logging +import os +import sys +from contextlib import contextmanager +from pathlib import Path +from typing import Dict + +import yaml +from tqdm import tqdm + +FILE = Path(__file__).resolve() +ROOT = FILE.parents[3] # YOLOv5 root directory +if str(ROOT) not in sys.path: + sys.path.append(str(ROOT)) # add ROOT to PATH + +from utils.dataloaders import LoadImagesAndLabels, img2label_paths +from utils.general import LOGGER, check_dataset, check_file + +try: + import wandb + + assert hasattr(wandb, '__version__') # verify package import not local dir +except (ImportError, AssertionError): + wandb = None + +RANK = int(os.getenv('RANK', -1)) +WANDB_ARTIFACT_PREFIX = 'wandb-artifact://' + + +def remove_prefix(from_string, prefix=WANDB_ARTIFACT_PREFIX): + return from_string[len(prefix):] + + +def check_wandb_config_file(data_config_file): + wandb_config = '_wandb.'.join(data_config_file.rsplit('.', 1)) # updated data.yaml path + if Path(wandb_config).is_file(): + return wandb_config + return data_config_file + + +def check_wandb_dataset(data_file): + is_trainset_wandb_artifact = False + is_valset_wandb_artifact = False + if isinstance(data_file, dict): + # In that case another dataset manager has already processed it and we don't have to + return data_file + if check_file(data_file) and data_file.endswith('.yaml'): + with open(data_file, errors='ignore') as f: + data_dict = yaml.safe_load(f) + is_trainset_wandb_artifact = isinstance(data_dict['train'], + str) and data_dict['train'].startswith(WANDB_ARTIFACT_PREFIX) + is_valset_wandb_artifact = isinstance(data_dict['val'], + str) and data_dict['val'].startswith(WANDB_ARTIFACT_PREFIX) + if is_trainset_wandb_artifact or is_valset_wandb_artifact: + return data_dict + else: + return check_dataset(data_file) + + +def get_run_info(run_path): + run_path = Path(remove_prefix(run_path, WANDB_ARTIFACT_PREFIX)) + run_id = run_path.stem + project = run_path.parent.stem + entity = run_path.parent.parent.stem + model_artifact_name = 'run_' + run_id + '_model' + return entity, project, run_id, model_artifact_name + + +def check_wandb_resume(opt): + process_wandb_config_ddp_mode(opt) if RANK not in [-1, 0] else None + if isinstance(opt.resume, str): + if opt.resume.startswith(WANDB_ARTIFACT_PREFIX): + if RANK not in [-1, 0]: # For resuming DDP runs + entity, project, run_id, model_artifact_name = get_run_info(opt.resume) + api = wandb.Api() + artifact = api.artifact(entity + '/' + project + '/' + model_artifact_name + ':latest') + modeldir = artifact.download() + opt.weights = str(Path(modeldir) / "last.pt") + return True + return None + + +def process_wandb_config_ddp_mode(opt): + with open(check_file(opt.data), errors='ignore') as f: + data_dict = yaml.safe_load(f) # data dict + train_dir, val_dir = None, None + if isinstance(data_dict['train'], str) and data_dict['train'].startswith(WANDB_ARTIFACT_PREFIX): + api = wandb.Api() + train_artifact = api.artifact(remove_prefix(data_dict['train']) + ':' + opt.artifact_alias) + train_dir = train_artifact.download() + train_path = Path(train_dir) / 'data/images/' + data_dict['train'] = str(train_path) + + if isinstance(data_dict['val'], str) and data_dict['val'].startswith(WANDB_ARTIFACT_PREFIX): + api = wandb.Api() + val_artifact = api.artifact(remove_prefix(data_dict['val']) + ':' + opt.artifact_alias) + val_dir = val_artifact.download() + val_path = Path(val_dir) / 'data/images/' + data_dict['val'] = str(val_path) + if train_dir or val_dir: + ddp_data_path = str(Path(val_dir) / 'wandb_local_data.yaml') + with open(ddp_data_path, 'w') as f: + yaml.safe_dump(data_dict, f) + opt.data = ddp_data_path + + +class WandbLogger(): + """Log training runs, datasets, models, and predictions to Weights & Biases. + + This logger sends information to W&B at wandb.ai. By default, this information + includes hyperparameters, system configuration and metrics, model metrics, + and basic data metrics and analyses. + + By providing additional command line arguments to train.py, datasets, + models and predictions can also be logged. + + For more on how this logger is used, see the Weights & Biases documentation: + https://docs.wandb.com/guides/integrations/yolov5 + """ + + def __init__(self, opt, run_id=None, job_type='Training'): + """ + - Initialize WandbLogger instance + - Upload dataset if opt.upload_dataset is True + - Setup training processes if job_type is 'Training' + + arguments: + opt (namespace) -- Commandline arguments for this run + run_id (str) -- Run ID of W&B run to be resumed + job_type (str) -- To set the job_type for this run + + """ + # Temporary-fix + if opt.upload_dataset: + opt.upload_dataset = False + # LOGGER.info("Uploading Dataset functionality is not being supported temporarily due to a bug.") + + # Pre-training routine -- + self.job_type = job_type + self.wandb, self.wandb_run = wandb, None if not wandb else wandb.run + self.val_artifact, self.train_artifact = None, None + self.train_artifact_path, self.val_artifact_path = None, None + self.result_artifact = None + self.val_table, self.result_table = None, None + self.bbox_media_panel_images = [] + self.val_table_path_map = None + self.max_imgs_to_log = 16 + self.wandb_artifact_data_dict = None + self.data_dict = None + # It's more elegant to stick to 1 wandb.init call, + # but useful config data is overwritten in the WandbLogger's wandb.init call + if isinstance(opt.resume, str): # checks resume from artifact + if opt.resume.startswith(WANDB_ARTIFACT_PREFIX): + entity, project, run_id, model_artifact_name = get_run_info(opt.resume) + model_artifact_name = WANDB_ARTIFACT_PREFIX + model_artifact_name + assert wandb, 'install wandb to resume wandb runs' + # Resume wandb-artifact:// runs here| workaround for not overwriting wandb.config + self.wandb_run = wandb.init(id=run_id, + project=project, + entity=entity, + resume='allow', + allow_val_change=True) + opt.resume = model_artifact_name + elif self.wandb: + self.wandb_run = wandb.init(config=opt, + resume="allow", + project='YOLOv5' if opt.project == 'runs/train' else Path(opt.project).stem, + entity=opt.entity, + name=opt.name if opt.name != 'exp' else None, + job_type=job_type, + id=run_id, + allow_val_change=True) if not wandb.run else wandb.run + if self.wandb_run: + if self.job_type == 'Training': + if opt.upload_dataset: + if not opt.resume: + self.wandb_artifact_data_dict = self.check_and_upload_dataset(opt) + + if isinstance(opt.data, dict): + # This means another dataset manager has already processed the dataset info (e.g. ClearML) + # and they will have stored the already processed dict in opt.data + self.data_dict = opt.data + elif opt.resume: + # resume from artifact + if isinstance(opt.resume, str) and opt.resume.startswith(WANDB_ARTIFACT_PREFIX): + self.data_dict = dict(self.wandb_run.config.data_dict) + else: # local resume + self.data_dict = check_wandb_dataset(opt.data) + else: + self.data_dict = check_wandb_dataset(opt.data) + self.wandb_artifact_data_dict = self.wandb_artifact_data_dict or self.data_dict + + # write data_dict to config. useful for resuming from artifacts. Do this only when not resuming. + self.wandb_run.config.update({'data_dict': self.wandb_artifact_data_dict}, allow_val_change=True) + self.setup_training(opt) + + if self.job_type == 'Dataset Creation': + self.wandb_run.config.update({"upload_dataset": True}) + self.data_dict = self.check_and_upload_dataset(opt) + + def check_and_upload_dataset(self, opt): + """ + Check if the dataset format is compatible and upload it as W&B artifact + + arguments: + opt (namespace)-- Commandline arguments for current run + + returns: + Updated dataset info dictionary where local dataset paths are replaced by WAND_ARFACT_PREFIX links. + """ + assert wandb, 'Install wandb to upload dataset' + config_path = self.log_dataset_artifact(opt.data, opt.single_cls, + 'YOLOv5' if opt.project == 'runs/train' else Path(opt.project).stem) + with open(config_path, errors='ignore') as f: + wandb_data_dict = yaml.safe_load(f) + return wandb_data_dict + + def setup_training(self, opt): + """ + Setup the necessary processes for training YOLO models: + - Attempt to download model checkpoint and dataset artifacts if opt.resume stats with WANDB_ARTIFACT_PREFIX + - Update data_dict, to contain info of previous run if resumed and the paths of dataset artifact if downloaded + - Setup log_dict, initialize bbox_interval + + arguments: + opt (namespace) -- commandline arguments for this run + + """ + self.log_dict, self.current_epoch = {}, 0 + self.bbox_interval = opt.bbox_interval + if isinstance(opt.resume, str): + modeldir, _ = self.download_model_artifact(opt) + if modeldir: + self.weights = Path(modeldir) / "last.pt" + config = self.wandb_run.config + opt.weights, opt.save_period, opt.batch_size, opt.bbox_interval, opt.epochs, opt.hyp, opt.imgsz = str( + self.weights), config.save_period, config.batch_size, config.bbox_interval, config.epochs,\ + config.hyp, config.imgsz + data_dict = self.data_dict + if self.val_artifact is None: # If --upload_dataset is set, use the existing artifact, don't download + self.train_artifact_path, self.train_artifact = self.download_dataset_artifact( + data_dict.get('train'), opt.artifact_alias) + self.val_artifact_path, self.val_artifact = self.download_dataset_artifact( + data_dict.get('val'), opt.artifact_alias) + + if self.train_artifact_path is not None: + train_path = Path(self.train_artifact_path) / 'data/images/' + data_dict['train'] = str(train_path) + if self.val_artifact_path is not None: + val_path = Path(self.val_artifact_path) / 'data/images/' + data_dict['val'] = str(val_path) + + if self.val_artifact is not None: + self.result_artifact = wandb.Artifact("run_" + wandb.run.id + "_progress", "evaluation") + columns = ["epoch", "id", "ground truth", "prediction"] + columns.extend(self.data_dict['names']) + self.result_table = wandb.Table(columns) + self.val_table = self.val_artifact.get("val") + if self.val_table_path_map is None: + self.map_val_table_path() + if opt.bbox_interval == -1: + self.bbox_interval = opt.bbox_interval = (opt.epochs // 10) if opt.epochs > 10 else 1 + if opt.evolve or opt.noplots: + self.bbox_interval = opt.bbox_interval = opt.epochs + 1 # disable bbox_interval + train_from_artifact = self.train_artifact_path is not None and self.val_artifact_path is not None + # Update the the data_dict to point to local artifacts dir + if train_from_artifact: + self.data_dict = data_dict + + def download_dataset_artifact(self, path, alias): + """ + download the model checkpoint artifact if the path starts with WANDB_ARTIFACT_PREFIX + + arguments: + path -- path of the dataset to be used for training + alias (str)-- alias of the artifact to be download/used for training + + returns: + (str, wandb.Artifact) -- path of the downladed dataset and it's corresponding artifact object if dataset + is found otherwise returns (None, None) + """ + if isinstance(path, str) and path.startswith(WANDB_ARTIFACT_PREFIX): + artifact_path = Path(remove_prefix(path, WANDB_ARTIFACT_PREFIX) + ":" + alias) + dataset_artifact = wandb.use_artifact(artifact_path.as_posix().replace("\\", "/")) + assert dataset_artifact is not None, "'Error: W&B dataset artifact doesn\'t exist'" + datadir = dataset_artifact.download() + return datadir, dataset_artifact + return None, None + + def download_model_artifact(self, opt): + """ + download the model checkpoint artifact if the resume path starts with WANDB_ARTIFACT_PREFIX + + arguments: + opt (namespace) -- Commandline arguments for this run + """ + if opt.resume.startswith(WANDB_ARTIFACT_PREFIX): + model_artifact = wandb.use_artifact(remove_prefix(opt.resume, WANDB_ARTIFACT_PREFIX) + ":latest") + assert model_artifact is not None, 'Error: W&B model artifact doesn\'t exist' + modeldir = model_artifact.download() + # epochs_trained = model_artifact.metadata.get('epochs_trained') + total_epochs = model_artifact.metadata.get('total_epochs') + is_finished = total_epochs is None + assert not is_finished, 'training is finished, can only resume incomplete runs.' + return modeldir, model_artifact + return None, None + + def log_model(self, path, opt, epoch, fitness_score, best_model=False): + """ + Log the model checkpoint as W&B artifact + + arguments: + path (Path) -- Path of directory containing the checkpoints + opt (namespace) -- Command line arguments for this run + epoch (int) -- Current epoch number + fitness_score (float) -- fitness score for current epoch + best_model (boolean) -- Boolean representing if the current checkpoint is the best yet. + """ + model_artifact = wandb.Artifact('run_' + wandb.run.id + '_model', + type='model', + metadata={ + 'original_url': str(path), + 'epochs_trained': epoch + 1, + 'save period': opt.save_period, + 'project': opt.project, + 'total_epochs': opt.epochs, + 'fitness_score': fitness_score}) + model_artifact.add_file(str(path / 'last.pt'), name='last.pt') + wandb.log_artifact(model_artifact, + aliases=['latest', 'last', 'epoch ' + str(self.current_epoch), 'best' if best_model else '']) + LOGGER.info(f"Saving model artifact on epoch {epoch + 1}") + + def log_dataset_artifact(self, data_file, single_cls, project, overwrite_config=False): + """ + Log the dataset as W&B artifact and return the new data file with W&B links + + arguments: + data_file (str) -- the .yaml file with information about the dataset like - path, classes etc. + single_class (boolean) -- train multi-class data as single-class + project (str) -- project name. Used to construct the artifact path + overwrite_config (boolean) -- overwrites the data.yaml file if set to true otherwise creates a new + file with _wandb postfix. Eg -> data_wandb.yaml + + returns: + the new .yaml file with artifact links. it can be used to start training directly from artifacts + """ + upload_dataset = self.wandb_run.config.upload_dataset + log_val_only = isinstance(upload_dataset, str) and upload_dataset == 'val' + self.data_dict = check_dataset(data_file) # parse and check + data = dict(self.data_dict) + nc, names = (1, ['item']) if single_cls else (int(data['nc']), data['names']) + names = {k: v for k, v in enumerate(names)} # to index dictionary + + # log train set + if not log_val_only: + self.train_artifact = self.create_dataset_table(LoadImagesAndLabels(data['train'], rect=True, batch_size=1), + names, + name='train') if data.get('train') else None + if data.get('train'): + data['train'] = WANDB_ARTIFACT_PREFIX + str(Path(project) / 'train') + + self.val_artifact = self.create_dataset_table( + LoadImagesAndLabels(data['val'], rect=True, batch_size=1), names, name='val') if data.get('val') else None + if data.get('val'): + data['val'] = WANDB_ARTIFACT_PREFIX + str(Path(project) / 'val') + + path = Path(data_file) + # create a _wandb.yaml file with artifacts links if both train and test set are logged + if not log_val_only: + path = (path.stem if overwrite_config else path.stem + '_wandb') + '.yaml' # updated data.yaml path + path = ROOT / 'data' / path + data.pop('download', None) + data.pop('path', None) + with open(path, 'w') as f: + yaml.safe_dump(data, f) + LOGGER.info(f"Created dataset config file {path}") + + if self.job_type == 'Training': # builds correct artifact pipeline graph + if not log_val_only: + self.wandb_run.log_artifact( + self.train_artifact) # calling use_artifact downloads the dataset. NOT NEEDED! + self.wandb_run.use_artifact(self.val_artifact) + self.val_artifact.wait() + self.val_table = self.val_artifact.get('val') + self.map_val_table_path() + else: + self.wandb_run.log_artifact(self.train_artifact) + self.wandb_run.log_artifact(self.val_artifact) + return path + + def map_val_table_path(self): + """ + Map the validation dataset Table like name of file -> it's id in the W&B Table. + Useful for - referencing artifacts for evaluation. + """ + self.val_table_path_map = {} + LOGGER.info("Mapping dataset") + for i, data in enumerate(tqdm(self.val_table.data)): + self.val_table_path_map[data[3]] = data[0] + + def create_dataset_table(self, dataset: LoadImagesAndLabels, class_to_id: Dict[int, str], name: str = 'dataset'): + """ + Create and return W&B artifact containing W&B Table of the dataset. + + arguments: + dataset -- instance of LoadImagesAndLabels class used to iterate over the data to build Table + class_to_id -- hash map that maps class ids to labels + name -- name of the artifact + + returns: + dataset artifact to be logged or used + """ + # TODO: Explore multiprocessing to slpit this loop parallely| This is essential for speeding up the the logging + artifact = wandb.Artifact(name=name, type="dataset") + img_files = tqdm([dataset.path]) if isinstance(dataset.path, str) and Path(dataset.path).is_dir() else None + img_files = tqdm(dataset.im_files) if not img_files else img_files + for img_file in img_files: + if Path(img_file).is_dir(): + artifact.add_dir(img_file, name='data/images') + labels_path = 'labels'.join(dataset.path.rsplit('images', 1)) + artifact.add_dir(labels_path, name='data/labels') + else: + artifact.add_file(img_file, name='data/images/' + Path(img_file).name) + label_file = Path(img2label_paths([img_file])[0]) + artifact.add_file(str(label_file), name='data/labels/' + + label_file.name) if label_file.exists() else None + table = wandb.Table(columns=["id", "train_image", "Classes", "name"]) + class_set = wandb.Classes([{'id': id, 'name': name} for id, name in class_to_id.items()]) + for si, (img, labels, paths, shapes) in enumerate(tqdm(dataset)): + box_data, img_classes = [], {} + for cls, *xywh in labels[:, 1:].tolist(): + cls = int(cls) + box_data.append({ + "position": { + "middle": [xywh[0], xywh[1]], + "width": xywh[2], + "height": xywh[3]}, + "class_id": cls, + "box_caption": "%s" % (class_to_id[cls])}) + img_classes[cls] = class_to_id[cls] + boxes = {"ground_truth": {"box_data": box_data, "class_labels": class_to_id}} # inference-space + table.add_data(si, wandb.Image(paths, classes=class_set, boxes=boxes), list(img_classes.values()), + Path(paths).name) + artifact.add(table, name) + return artifact + + def log_training_progress(self, predn, path, names): + """ + Build evaluation Table. Uses reference from validation dataset table. + + arguments: + predn (list): list of predictions in the native space in the format - [xmin, ymin, xmax, ymax, confidence, class] + path (str): local path of the current evaluation image + names (dict(int, str)): hash map that maps class ids to labels + """ + class_set = wandb.Classes([{'id': id, 'name': name} for id, name in names.items()]) + box_data = [] + avg_conf_per_class = [0] * len(self.data_dict['names']) + pred_class_count = {} + for *xyxy, conf, cls in predn.tolist(): + if conf >= 0.25: + cls = int(cls) + box_data.append({ + "position": { + "minX": xyxy[0], + "minY": xyxy[1], + "maxX": xyxy[2], + "maxY": xyxy[3]}, + "class_id": cls, + "box_caption": f"{names[cls]} {conf:.3f}", + "scores": { + "class_score": conf}, + "domain": "pixel"}) + avg_conf_per_class[cls] += conf + + if cls in pred_class_count: + pred_class_count[cls] += 1 + else: + pred_class_count[cls] = 1 + + for pred_class in pred_class_count.keys(): + avg_conf_per_class[pred_class] = avg_conf_per_class[pred_class] / pred_class_count[pred_class] + + boxes = {"predictions": {"box_data": box_data, "class_labels": names}} # inference-space + id = self.val_table_path_map[Path(path).name] + self.result_table.add_data(self.current_epoch, id, self.val_table.data[id][1], + wandb.Image(self.val_table.data[id][1], boxes=boxes, classes=class_set), + *avg_conf_per_class) + + def val_one_image(self, pred, predn, path, names, im): + """ + Log validation data for one image. updates the result Table if validation dataset is uploaded and log bbox media panel + + arguments: + pred (list): list of scaled predictions in the format - [xmin, ymin, xmax, ymax, confidence, class] + predn (list): list of predictions in the native space - [xmin, ymin, xmax, ymax, confidence, class] + path (str): local path of the current evaluation image + """ + if self.val_table and self.result_table: # Log Table if Val dataset is uploaded as artifact + self.log_training_progress(predn, path, names) + + if len(self.bbox_media_panel_images) < self.max_imgs_to_log and self.current_epoch > 0: + if self.current_epoch % self.bbox_interval == 0: + box_data = [{ + "position": { + "minX": xyxy[0], + "minY": xyxy[1], + "maxX": xyxy[2], + "maxY": xyxy[3]}, + "class_id": int(cls), + "box_caption": f"{names[int(cls)]} {conf:.3f}", + "scores": { + "class_score": conf}, + "domain": "pixel"} for *xyxy, conf, cls in pred.tolist()] + boxes = {"predictions": {"box_data": box_data, "class_labels": names}} # inference-space + self.bbox_media_panel_images.append(wandb.Image(im, boxes=boxes, caption=path.name)) + + def log(self, log_dict): + """ + save the metrics to the logging dictionary + + arguments: + log_dict (Dict) -- metrics/media to be logged in current step + """ + if self.wandb_run: + for key, value in log_dict.items(): + self.log_dict[key] = value + + def end_epoch(self, best_result=False): + """ + commit the log_dict, model artifacts and Tables to W&B and flush the log_dict. + + arguments: + best_result (boolean): Boolean representing if the result of this evaluation is best or not + """ + if self.wandb_run: + with all_logging_disabled(): + if self.bbox_media_panel_images: + self.log_dict["BoundingBoxDebugger"] = self.bbox_media_panel_images + try: + wandb.log(self.log_dict) + except BaseException as e: + LOGGER.info( + f"An error occurred in wandb logger. The training will proceed without interruption. More info\n{e}" + ) + self.wandb_run.finish() + self.wandb_run = None + + self.log_dict = {} + self.bbox_media_panel_images = [] + if self.result_artifact: + self.result_artifact.add(self.result_table, 'result') + wandb.log_artifact(self.result_artifact, + aliases=[ + 'latest', 'last', 'epoch ' + str(self.current_epoch), + ('best' if best_result else '')]) + + wandb.log({"evaluation": self.result_table}) + columns = ["epoch", "id", "ground truth", "prediction"] + columns.extend(self.data_dict['names']) + self.result_table = wandb.Table(columns) + self.result_artifact = wandb.Artifact("run_" + wandb.run.id + "_progress", "evaluation") + + def finish_run(self): + """ + Log metrics if any and finish the current W&B run + """ + if self.wandb_run: + if self.log_dict: + with all_logging_disabled(): + wandb.log(self.log_dict) + wandb.run.finish() + + +@contextmanager +def all_logging_disabled(highest_level=logging.CRITICAL): + """ source - https://gist.github.com/simon-weber/7853144 + A context manager that will prevent any logging messages triggered during the body from being processed. + :param highest_level: the maximum logging level in use. + This would only need to be changed if a custom level greater than CRITICAL is defined. + """ + previous_level = logging.root.manager.disable + logging.disable(highest_level) + try: + yield + finally: + logging.disable(previous_level) diff --git a/cv/3d_detection/yolov9/pytorch/utils/loss.py b/cv/3d_detection/yolov9/pytorch/utils/loss.py new file mode 100644 index 000000000..0ec21f8ae --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/utils/loss.py @@ -0,0 +1,363 @@ +import torch +import torch.nn as nn +import torch.nn.functional as F + +from utils.metrics import bbox_iou +from utils.torch_utils import de_parallel + + +def smooth_BCE(eps=0.1): # https://github.com/ultralytics/yolov3/issues/238#issuecomment-598028441 + # return positive, negative label smoothing BCE targets + return 1.0 - 0.5 * eps, 0.5 * eps + + +class BCEBlurWithLogitsLoss(nn.Module): + # BCEwithLogitLoss() with reduced missing label effects. + def __init__(self, alpha=0.05): + super().__init__() + self.loss_fcn = nn.BCEWithLogitsLoss(reduction='none') # must be nn.BCEWithLogitsLoss() + self.alpha = alpha + + def forward(self, pred, true): + loss = self.loss_fcn(pred, true) + pred = torch.sigmoid(pred) # prob from logits + dx = pred - true # reduce only missing label effects + # dx = (pred - true).abs() # reduce missing label and false label effects + alpha_factor = 1 - torch.exp((dx - 1) / (self.alpha + 1e-4)) + loss *= alpha_factor + return loss.mean() + + +class FocalLoss(nn.Module): + # Wraps focal loss around existing loss_fcn(), i.e. criteria = FocalLoss(nn.BCEWithLogitsLoss(), gamma=1.5) + def __init__(self, loss_fcn, gamma=1.5, alpha=0.25): + super().__init__() + self.loss_fcn = loss_fcn # must be nn.BCEWithLogitsLoss() + self.gamma = gamma + self.alpha = alpha + self.reduction = loss_fcn.reduction + self.loss_fcn.reduction = 'none' # required to apply FL to each element + + def forward(self, pred, true): + loss = self.loss_fcn(pred, true) + # p_t = torch.exp(-loss) + # loss *= self.alpha * (1.000001 - p_t) ** self.gamma # non-zero power for gradient stability + + # TF implementation https://github.com/tensorflow/addons/blob/v0.7.1/tensorflow_addons/losses/focal_loss.py + pred_prob = torch.sigmoid(pred) # prob from logits + p_t = true * pred_prob + (1 - true) * (1 - pred_prob) + alpha_factor = true * self.alpha + (1 - true) * (1 - self.alpha) + modulating_factor = (1.0 - p_t) ** self.gamma + loss *= alpha_factor * modulating_factor + + if self.reduction == 'mean': + return loss.mean() + elif self.reduction == 'sum': + return loss.sum() + else: # 'none' + return loss + + +class QFocalLoss(nn.Module): + # Wraps Quality focal loss around existing loss_fcn(), i.e. criteria = FocalLoss(nn.BCEWithLogitsLoss(), gamma=1.5) + def __init__(self, loss_fcn, gamma=1.5, alpha=0.25): + super().__init__() + self.loss_fcn = loss_fcn # must be nn.BCEWithLogitsLoss() + self.gamma = gamma + self.alpha = alpha + self.reduction = loss_fcn.reduction + self.loss_fcn.reduction = 'none' # required to apply FL to each element + + def forward(self, pred, true): + loss = self.loss_fcn(pred, true) + + pred_prob = torch.sigmoid(pred) # prob from logits + alpha_factor = true * self.alpha + (1 - true) * (1 - self.alpha) + modulating_factor = torch.abs(true - pred_prob) ** self.gamma + loss *= alpha_factor * modulating_factor + + if self.reduction == 'mean': + return loss.mean() + elif self.reduction == 'sum': + return loss.sum() + else: # 'none' + return loss + + +class ComputeLoss: + sort_obj_iou = False + + # Compute losses + def __init__(self, model, autobalance=False): + device = next(model.parameters()).device # get model device + h = model.hyp # hyperparameters + + # Define criteria + BCEcls = nn.BCEWithLogitsLoss(pos_weight=torch.tensor([h['cls_pw']], device=device)) + BCEobj = nn.BCEWithLogitsLoss(pos_weight=torch.tensor([h['obj_pw']], device=device)) + + # Class label smoothing https://arxiv.org/pdf/1902.04103.pdf eqn 3 + self.cp, self.cn = smooth_BCE(eps=h.get('label_smoothing', 0.0)) # positive, negative BCE targets + + # Focal loss + g = h['fl_gamma'] # focal loss gamma + if g > 0: + BCEcls, BCEobj = FocalLoss(BCEcls, g), FocalLoss(BCEobj, g) + + m = de_parallel(model).model[-1] # Detect() module + self.balance = {3: [4.0, 1.0, 0.4]}.get(m.nl, [4.0, 1.0, 0.25, 0.06, 0.02]) # P3-P7 + self.ssi = list(m.stride).index(16) if autobalance else 0 # stride 16 index + self.BCEcls, self.BCEobj, self.gr, self.hyp, self.autobalance = BCEcls, BCEobj, 1.0, h, autobalance + self.nc = m.nc # number of classes + self.nl = m.nl # number of layers + self.anchors = m.anchors + self.device = device + + def __call__(self, p, targets): # predictions, targets + bs = p[0].shape[0] # batch size + loss = torch.zeros(3, device=self.device) # [box, obj, cls] losses + tcls, tbox, indices = self.build_targets(p, targets) # targets + + # Losses + for i, pi in enumerate(p): # layer index, layer predictions + b, gj, gi = indices[i] # image, anchor, gridy, gridx + tobj = torch.zeros((pi.shape[0], pi.shape[2], pi.shape[3]), dtype=pi.dtype, device=self.device) # tgt obj + + n_labels = b.shape[0] # number of labels + if n_labels: + # pxy, pwh, _, pcls = pi[b, a, gj, gi].tensor_split((2, 4, 5), dim=1) # faster, requires torch 1.8.0 + pxy, pwh, _, pcls = pi[b, :, gj, gi].split((2, 2, 1, self.nc), 1) # target-subset of predictions + + # Regression + # pwh = (pwh.sigmoid() * 2) ** 2 * anchors[i] + # pwh = (0.0 + (pwh - 1.09861).sigmoid() * 4) * anchors[i] + # pwh = (0.33333 + (pwh - 1.09861).sigmoid() * 2.66667) * anchors[i] + # pwh = (0.25 + (pwh - 1.38629).sigmoid() * 3.75) * anchors[i] + # pwh = (0.20 + (pwh - 1.60944).sigmoid() * 4.8) * anchors[i] + # pwh = (0.16667 + (pwh - 1.79175).sigmoid() * 5.83333) * anchors[i] + pxy = pxy.sigmoid() * 1.6 - 0.3 + pwh = (0.2 + pwh.sigmoid() * 4.8) * self.anchors[i] + pbox = torch.cat((pxy, pwh), 1) # predicted box + iou = bbox_iou(pbox, tbox[i], CIoU=True).squeeze() # iou(prediction, target) + loss[0] += (1.0 - iou).mean() # box loss + + # Objectness + iou = iou.detach().clamp(0).type(tobj.dtype) + if self.sort_obj_iou: + j = iou.argsort() + b, gj, gi, iou = b[j], gj[j], gi[j], iou[j] + if self.gr < 1: + iou = (1.0 - self.gr) + self.gr * iou + tobj[b, gj, gi] = iou # iou ratio + + # Classification + if self.nc > 1: # cls loss (only if multiple classes) + t = torch.full_like(pcls, self.cn, device=self.device) # targets + t[range(n_labels), tcls[i]] = self.cp + loss[2] += self.BCEcls(pcls, t) # cls loss + + obji = self.BCEobj(pi[:, 4], tobj) + loss[1] += obji * self.balance[i] # obj loss + if self.autobalance: + self.balance[i] = self.balance[i] * 0.9999 + 0.0001 / obji.detach().item() + + if self.autobalance: + self.balance = [x / self.balance[self.ssi] for x in self.balance] + loss[0] *= self.hyp['box'] + loss[1] *= self.hyp['obj'] + loss[2] *= self.hyp['cls'] + return loss.sum() * bs, loss.detach() # [box, obj, cls] losses + + def build_targets(self, p, targets): + # Build targets for compute_loss(), input targets(image,class,x,y,w,h) + nt = targets.shape[0] # number of anchors, targets + tcls, tbox, indices = [], [], [] + gain = torch.ones(6, device=self.device) # normalized to gridspace gain + + g = 0.3 # bias + off = torch.tensor( + [ + [0, 0], + [1, 0], + [0, 1], + [-1, 0], + [0, -1], # j,k,l,m + # [1, 1], [1, -1], [-1, 1], [-1, -1], # jk,jm,lk,lm + ], + device=self.device).float() * g # offsets + + for i in range(self.nl): + shape = p[i].shape + gain[2:6] = torch.tensor(shape)[[3, 2, 3, 2]] # xyxy gain + + # Match targets to anchors + t = targets * gain # shape(3,n,7) + if nt: + # Matches + r = t[..., 4:6] / self.anchors[i] # wh ratio + j = torch.max(r, 1 / r).max(1)[0] < self.hyp['anchor_t'] # compare + # j = wh_iou(anchors, t[:, 4:6]) > model.hyp['iou_t'] # iou(3,n)=wh_iou(anchors(3,2), gwh(n,2)) + t = t[j] # filter + + # Offsets + gxy = t[:, 2:4] # grid xy + gxi = gain[[2, 3]] - gxy # inverse + j, k = ((gxy % 1 < g) & (gxy > 1)).T + l, m = ((gxi % 1 < g) & (gxi > 1)).T + j = torch.stack((torch.ones_like(j), j, k, l, m)) + t = t.repeat((5, 1, 1))[j] + offsets = (torch.zeros_like(gxy)[None] + off[:, None])[j] + else: + t = targets[0] + offsets = 0 + + # Define + bc, gxy, gwh = t.chunk(3, 1) # (image, class), grid xy, grid wh + b, c = bc.long().T # image, class + gij = (gxy - offsets).long() + gi, gj = gij.T # grid indices + + # Append + indices.append((b, gj.clamp_(0, shape[2] - 1), gi.clamp_(0, shape[3] - 1))) # image, grid_y, grid_x indices + tbox.append(torch.cat((gxy - gij, gwh), 1)) # box + tcls.append(c) # class + + return tcls, tbox, indices + + +class ComputeLoss_NEW: + sort_obj_iou = False + + # Compute losses + def __init__(self, model, autobalance=False): + device = next(model.parameters()).device # get model device + h = model.hyp # hyperparameters + + # Define criteria + BCEcls = nn.BCEWithLogitsLoss(pos_weight=torch.tensor([h['cls_pw']], device=device)) + BCEobj = nn.BCEWithLogitsLoss(pos_weight=torch.tensor([h['obj_pw']], device=device)) + + # Class label smoothing https://arxiv.org/pdf/1902.04103.pdf eqn 3 + self.cp, self.cn = smooth_BCE(eps=h.get('label_smoothing', 0.0)) # positive, negative BCE targets + + # Focal loss + g = h['fl_gamma'] # focal loss gamma + if g > 0: + BCEcls, BCEobj = FocalLoss(BCEcls, g), FocalLoss(BCEobj, g) + + m = de_parallel(model).model[-1] # Detect() module + self.balance = {3: [4.0, 1.0, 0.4]}.get(m.nl, [4.0, 1.0, 0.25, 0.06, 0.02]) # P3-P7 + self.ssi = list(m.stride).index(16) if autobalance else 0 # stride 16 index + self.BCEcls, self.BCEobj, self.gr, self.hyp, self.autobalance = BCEcls, BCEobj, 1.0, h, autobalance + self.nc = m.nc # number of classes + self.nl = m.nl # number of layers + self.anchors = m.anchors + self.device = device + self.BCE_base = nn.BCEWithLogitsLoss(reduction='none') + + def __call__(self, p, targets): # predictions, targets + tcls, tbox, indices = self.build_targets(p, targets) # targets + bs = p[0].shape[0] # batch size + n_labels = targets.shape[0] # number of labels + loss = torch.zeros(3, device=self.device) # [box, obj, cls] losses + + # Compute all losses + all_loss = [] + for i, pi in enumerate(p): # layer index, layer predictions + b, gj, gi = indices[i] # image, anchor, gridy, gridx + if n_labels: + pxy, pwh, pobj, pcls = pi[b, :, gj, gi].split((2, 2, 1, self.nc), 2) # target-subset of predictions + + # Regression + pbox = torch.cat((pxy.sigmoid() * 1.6 - 0.3, (0.2 + pwh.sigmoid() * 4.8) * self.anchors[i]), 2) + iou = bbox_iou(pbox, tbox[i], CIoU=True).squeeze() # iou(predicted_box, target_box) + obj_target = iou.detach().clamp(0).type(pi.dtype) # objectness targets + + all_loss.append([(1.0 - iou) * self.hyp['box'], + self.BCE_base(pobj.squeeze(), torch.ones_like(obj_target)) * self.hyp['obj'], + self.BCE_base(pcls, F.one_hot(tcls[i], self.nc).float()).mean(2) * self.hyp['cls'], + obj_target, + tbox[i][..., 2] > 0.0]) # valid + + # Lowest 3 losses per label + n_assign = 4 # top n matches + cat_loss = [torch.cat(x, 1) for x in zip(*all_loss)] + ij = torch.zeros_like(cat_loss[0]).bool() # top 3 mask + sum_loss = cat_loss[0] + cat_loss[2] + for col in torch.argsort(sum_loss, dim=1).T[:n_assign]: + # ij[range(n_labels), col] = True + ij[range(n_labels), col] = cat_loss[4][range(n_labels), col] + loss[0] = cat_loss[0][ij].mean() * self.nl # box loss + loss[2] = cat_loss[2][ij].mean() * self.nl # cls loss + + # Obj loss + for i, (h, pi) in enumerate(zip(ij.chunk(self.nl, 1), p)): # layer index, layer predictions + b, gj, gi = indices[i] # image, anchor, gridy, gridx + tobj = torch.zeros((pi.shape[0], pi.shape[2], pi.shape[3]), dtype=pi.dtype, device=self.device) # obj + if n_labels: # if any labels + tobj[b[h], gj[h], gi[h]] = all_loss[i][3][h] + loss[1] += self.BCEobj(pi[:, 4], tobj) * (self.balance[i] * self.hyp['obj']) + + return loss.sum() * bs, loss.detach() # [box, obj, cls] losses + + def build_targets(self, p, targets): + # Build targets for compute_loss(), input targets(image,class,x,y,w,h) + nt = targets.shape[0] # number of anchors, targets + tcls, tbox, indices = [], [], [] + gain = torch.ones(6, device=self.device) # normalized to gridspace gain + + g = 0.3 # bias + off = torch.tensor( + [ + [0, 0], + [1, 0], + [0, 1], + [-1, 0], + [0, -1], # j,k,l,m + # [1, 1], [1, -1], [-1, 1], [-1, -1], # jk,jm,lk,lm + ], + device=self.device).float() # offsets + + for i in range(self.nl): + shape = p[i].shape + gain[2:6] = torch.tensor(shape)[[3, 2, 3, 2]] # xyxy gain + + # Match targets to anchors + t = targets * gain # shape(3,n,7) + if nt: + # # Matches + r = t[..., 4:6] / self.anchors[i] # wh ratio + a = torch.max(r, 1 / r).max(1)[0] < self.hyp['anchor_t'] # compare + # a = wh_iou(anchors, t[:, 4:6]) > model.hyp['iou_t'] # iou(3,n)=wh_iou(anchors(3,2), gwh(n,2)) + # t = t[a] # filter + + # # Offsets + gxy = t[:, 2:4] # grid xy + gxi = gain[[2, 3]] - gxy # inverse + j, k = ((gxy % 1 < g) & (gxy > 1)).T + l, m = ((gxi % 1 < g) & (gxi > 1)).T + j = torch.stack((torch.ones_like(j), j, k, l, m)) & a + t = t.repeat((5, 1, 1)) + offsets = torch.zeros_like(gxy)[None] + off[:, None] + t[..., 4:6][~j] = 0.0 # move unsuitable targets far away + else: + t = targets[0] + offsets = 0 + + # Define + bc, gxy, gwh = t.chunk(3, 2) # (image, class), grid xy, grid wh + b, c = bc.long().transpose(0, 2).contiguous() # image, class + gij = (gxy - offsets).long() + gi, gj = gij.transpose(0, 2).contiguous() # grid indices + + # Append + indices.append((b, gj.clamp_(0, shape[2] - 1), gi.clamp_(0, shape[3] - 1))) # image, grid_y, grid_x indices + tbox.append(torch.cat((gxy - gij, gwh), 2).permute(1, 0, 2).contiguous()) # box + tcls.append(c) # class + + # # Unique + # n1 = torch.cat((b.view(-1, 1), tbox[i].view(-1, 4)), 1).shape[0] + # n2 = tbox[i].view(-1, 4).unique(dim=0).shape[0] + # print(f'targets-unique {n1}-{n2} diff={n1-n2}') + + return tcls, tbox, indices diff --git a/cv/3d_detection/yolov9/pytorch/utils/loss_tal.py b/cv/3d_detection/yolov9/pytorch/utils/loss_tal.py new file mode 100644 index 000000000..9f20c787b --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/utils/loss_tal.py @@ -0,0 +1,215 @@ +import os + +import torch +import torch.nn as nn +import torch.nn.functional as F + +from utils.general import xywh2xyxy +from utils.metrics import bbox_iou +from utils.tal.anchor_generator import dist2bbox, make_anchors, bbox2dist +from utils.tal.assigner import TaskAlignedAssigner +from utils.torch_utils import de_parallel + + +def smooth_BCE(eps=0.1): # https://github.com/ultralytics/yolov3/issues/238#issuecomment-598028441 + # return positive, negative label smoothing BCE targets + return 1.0 - 0.5 * eps, 0.5 * eps + + +class VarifocalLoss(nn.Module): + # Varifocal loss by Zhang et al. https://arxiv.org/abs/2008.13367 + def __init__(self): + super().__init__() + + def forward(self, pred_score, gt_score, label, alpha=0.75, gamma=2.0): + weight = alpha * pred_score.sigmoid().pow(gamma) * (1 - label) + gt_score * label + with torch.cuda.amp.autocast(enabled=False): + loss = (F.binary_cross_entropy_with_logits(pred_score.float(), gt_score.float(), + reduction="none") * weight).sum() + return loss + + +class FocalLoss(nn.Module): + # Wraps focal loss around existing loss_fcn(), i.e. criteria = FocalLoss(nn.BCEWithLogitsLoss(), gamma=1.5) + def __init__(self, loss_fcn, gamma=1.5, alpha=0.25): + super().__init__() + self.loss_fcn = loss_fcn # must be nn.BCEWithLogitsLoss() + self.gamma = gamma + self.alpha = alpha + self.reduction = loss_fcn.reduction + self.loss_fcn.reduction = "none" # required to apply FL to each element + + def forward(self, pred, true): + loss = self.loss_fcn(pred, true) + # p_t = torch.exp(-loss) + # loss *= self.alpha * (1.000001 - p_t) ** self.gamma # non-zero power for gradient stability + + # TF implementation https://github.com/tensorflow/addons/blob/v0.7.1/tensorflow_addons/losses/focal_loss.py + pred_prob = torch.sigmoid(pred) # prob from logits + p_t = true * pred_prob + (1 - true) * (1 - pred_prob) + alpha_factor = true * self.alpha + (1 - true) * (1 - self.alpha) + modulating_factor = (1.0 - p_t) ** self.gamma + loss *= alpha_factor * modulating_factor + + if self.reduction == "mean": + return loss.mean() + elif self.reduction == "sum": + return loss.sum() + else: # 'none' + return loss + + +class BboxLoss(nn.Module): + def __init__(self, reg_max, use_dfl=False): + super().__init__() + self.reg_max = reg_max + self.use_dfl = use_dfl + + def forward(self, pred_dist, pred_bboxes, anchor_points, target_bboxes, target_scores, target_scores_sum, fg_mask): + # iou loss + bbox_mask = fg_mask.unsqueeze(-1).repeat([1, 1, 4]) # (b, h*w, 4) + pred_bboxes_pos = torch.masked_select(pred_bboxes, bbox_mask).view(-1, 4) + target_bboxes_pos = torch.masked_select(target_bboxes, bbox_mask).view(-1, 4) + bbox_weight = torch.masked_select(target_scores.sum(-1), fg_mask).unsqueeze(-1) + + iou = bbox_iou(pred_bboxes_pos, target_bboxes_pos, xywh=False, CIoU=True) + loss_iou = 1.0 - iou + + loss_iou *= bbox_weight + loss_iou = loss_iou.sum() / target_scores_sum + + # dfl loss + if self.use_dfl: + dist_mask = fg_mask.unsqueeze(-1).repeat([1, 1, (self.reg_max + 1) * 4]) + pred_dist_pos = torch.masked_select(pred_dist, dist_mask).view(-1, 4, self.reg_max + 1) + target_ltrb = bbox2dist(anchor_points, target_bboxes, self.reg_max) + target_ltrb_pos = torch.masked_select(target_ltrb, bbox_mask).view(-1, 4) + loss_dfl = self._df_loss(pred_dist_pos, target_ltrb_pos) * bbox_weight + loss_dfl = loss_dfl.sum() / target_scores_sum + else: + loss_dfl = torch.tensor(0.0).to(pred_dist.device) + + return loss_iou, loss_dfl, iou + + def _df_loss(self, pred_dist, target): + target_left = target.to(torch.long) + target_right = target_left + 1 + weight_left = target_right.to(torch.float) - target + weight_right = 1 - weight_left + loss_left = F.cross_entropy(pred_dist.view(-1, self.reg_max + 1), target_left.view(-1), reduction="none").view( + target_left.shape) * weight_left + loss_right = F.cross_entropy(pred_dist.view(-1, self.reg_max + 1), target_right.view(-1), + reduction="none").view(target_left.shape) * weight_right + return (loss_left + loss_right).mean(-1, keepdim=True) + + +class ComputeLoss: + # Compute losses + def __init__(self, model, use_dfl=True): + device = next(model.parameters()).device # get model device + h = model.hyp # hyperparameters + + # Define criteria + BCEcls = nn.BCEWithLogitsLoss(pos_weight=torch.tensor([h["cls_pw"]], device=device), reduction='none') + + # Class label smoothing https://arxiv.org/pdf/1902.04103.pdf eqn 3 + self.cp, self.cn = smooth_BCE(eps=h.get("label_smoothing", 0.0)) # positive, negative BCE targets + + # Focal loss + g = h["fl_gamma"] # focal loss gamma + if g > 0: + BCEcls = FocalLoss(BCEcls, g) + + m = de_parallel(model).model[-1] # Detect() module + self.balance = {3: [4.0, 1.0, 0.4]}.get(m.nl, [4.0, 1.0, 0.25, 0.06, 0.02]) # P3-P7 + self.BCEcls = BCEcls + self.hyp = h + self.stride = m.stride # model strides + self.nc = m.nc # number of classes + self.nl = m.nl # number of layers + self.no = m.no + self.reg_max = m.reg_max + self.device = device + + self.assigner = TaskAlignedAssigner(topk=int(os.getenv('YOLOM', 10)), + num_classes=self.nc, + alpha=float(os.getenv('YOLOA', 0.5)), + beta=float(os.getenv('YOLOB', 6.0))) + self.bbox_loss = BboxLoss(m.reg_max - 1, use_dfl=use_dfl).to(device) + self.proj = torch.arange(m.reg_max).float().to(device) # / 120.0 + self.use_dfl = use_dfl + + def preprocess(self, targets, batch_size, scale_tensor): + if targets.shape[0] == 0: + out = torch.zeros(batch_size, 0, 5, device=self.device) + else: + i = targets[:, 0] # image index + _, counts = i.unique(return_counts=True) + out = torch.zeros(batch_size, counts.max(), 5, device=self.device) + for j in range(batch_size): + matches = i == j + n = matches.sum() + if n: + out[j, :n] = targets[matches, 1:] + out[..., 1:5] = xywh2xyxy(out[..., 1:5].mul_(scale_tensor)) + return out + + def bbox_decode(self, anchor_points, pred_dist): + if self.use_dfl: + b, a, c = pred_dist.shape # batch, anchors, channels + pred_dist = pred_dist.view(b, a, 4, c // 4).softmax(3).matmul(self.proj.type(pred_dist.dtype)) + # pred_dist = pred_dist.view(b, a, c // 4, 4).transpose(2,3).softmax(3).matmul(self.proj.type(pred_dist.dtype)) + # pred_dist = (pred_dist.view(b, a, c // 4, 4).softmax(2) * self.proj.type(pred_dist.dtype).view(1, 1, -1, 1)).sum(2) + return dist2bbox(pred_dist, anchor_points, xywh=False) + + def __call__(self, p, targets, img=None, epoch=0): + loss = torch.zeros(3, device=self.device) # box, cls, dfl + feats = p[1] if isinstance(p, tuple) else p + pred_distri, pred_scores = torch.cat([xi.view(feats[0].shape[0], self.no, -1) for xi in feats], 2).split( + (self.reg_max * 4, self.nc), 1) + pred_scores = pred_scores.permute(0, 2, 1).contiguous() + pred_distri = pred_distri.permute(0, 2, 1).contiguous() + + dtype = pred_scores.dtype + batch_size, grid_size = pred_scores.shape[:2] + imgsz = torch.tensor(feats[0].shape[2:], device=self.device, dtype=dtype) * self.stride[0] # image size (h,w) + anchor_points, stride_tensor = make_anchors(feats, self.stride, 0.5) + + # targets + targets = self.preprocess(targets, batch_size, scale_tensor=imgsz[[1, 0, 1, 0]]) + gt_labels, gt_bboxes = targets.split((1, 4), 2) # cls, xyxy + mask_gt = gt_bboxes.sum(2, keepdim=True).gt_(0) + + # pboxes + pred_bboxes = self.bbox_decode(anchor_points, pred_distri) # xyxy, (b, h*w, 4) + + target_labels, target_bboxes, target_scores, fg_mask = self.assigner( + pred_scores.detach().sigmoid(), + (pred_bboxes.detach() * stride_tensor).type(gt_bboxes.dtype), + anchor_points * stride_tensor, + gt_labels, + gt_bboxes, + mask_gt) + + target_bboxes /= stride_tensor + target_scores_sum = max(target_scores.sum(), 1) + + # cls loss + # loss[1] = self.varifocal_loss(pred_scores, target_scores, target_labels) / target_scores_sum # VFL way + loss[1] = self.BCEcls(pred_scores, target_scores.to(dtype)).sum() / target_scores_sum # BCE + + # bbox loss + if fg_mask.sum(): + loss[0], loss[2], iou = self.bbox_loss(pred_distri, + pred_bboxes, + anchor_points, + target_bboxes, + target_scores, + target_scores_sum, + fg_mask) + + loss[0] *= 7.5 # box gain + loss[1] *= 0.5 # cls gain + loss[2] *= 1.5 # dfl gain + + return loss.sum() * batch_size, loss.detach() # loss(box, cls, dfl) diff --git a/cv/3d_detection/yolov9/pytorch/utils/loss_tal_dual.py b/cv/3d_detection/yolov9/pytorch/utils/loss_tal_dual.py new file mode 100644 index 000000000..259e7888d --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/utils/loss_tal_dual.py @@ -0,0 +1,385 @@ +import os + +import torch +import torch.nn as nn +import torch.nn.functional as F + +from utils.general import xywh2xyxy +from utils.metrics import bbox_iou +from utils.tal.anchor_generator import dist2bbox, make_anchors, bbox2dist +from utils.tal.assigner import TaskAlignedAssigner +from utils.torch_utils import de_parallel + + +def smooth_BCE(eps=0.1): # https://github.com/ultralytics/yolov3/issues/238#issuecomment-598028441 + # return positive, negative label smoothing BCE targets + return 1.0 - 0.5 * eps, 0.5 * eps + + +class VarifocalLoss(nn.Module): + # Varifocal loss by Zhang et al. https://arxiv.org/abs/2008.13367 + def __init__(self): + super().__init__() + + def forward(self, pred_score, gt_score, label, alpha=0.75, gamma=2.0): + weight = alpha * pred_score.sigmoid().pow(gamma) * (1 - label) + gt_score * label + with torch.cuda.amp.autocast(enabled=False): + loss = (F.binary_cross_entropy_with_logits(pred_score.float(), gt_score.float(), + reduction="none") * weight).sum() + return loss + + +class FocalLoss(nn.Module): + # Wraps focal loss around existing loss_fcn(), i.e. criteria = FocalLoss(nn.BCEWithLogitsLoss(), gamma=1.5) + def __init__(self, loss_fcn, gamma=1.5, alpha=0.25): + super().__init__() + self.loss_fcn = loss_fcn # must be nn.BCEWithLogitsLoss() + self.gamma = gamma + self.alpha = alpha + self.reduction = loss_fcn.reduction + self.loss_fcn.reduction = "none" # required to apply FL to each element + + def forward(self, pred, true): + loss = self.loss_fcn(pred, true) + # p_t = torch.exp(-loss) + # loss *= self.alpha * (1.000001 - p_t) ** self.gamma # non-zero power for gradient stability + + # TF implementation https://github.com/tensorflow/addons/blob/v0.7.1/tensorflow_addons/losses/focal_loss.py + pred_prob = torch.sigmoid(pred) # prob from logits + p_t = true * pred_prob + (1 - true) * (1 - pred_prob) + alpha_factor = true * self.alpha + (1 - true) * (1 - self.alpha) + modulating_factor = (1.0 - p_t) ** self.gamma + loss *= alpha_factor * modulating_factor + + if self.reduction == "mean": + return loss.mean() + elif self.reduction == "sum": + return loss.sum() + else: # 'none' + return loss + + +class BboxLoss(nn.Module): + def __init__(self, reg_max, use_dfl=False): + super().__init__() + self.reg_max = reg_max + self.use_dfl = use_dfl + + def forward(self, pred_dist, pred_bboxes, anchor_points, target_bboxes, target_scores, target_scores_sum, fg_mask): + # iou loss + bbox_mask = fg_mask.unsqueeze(-1).repeat([1, 1, 4]) # (b, h*w, 4) + pred_bboxes_pos = torch.masked_select(pred_bboxes, bbox_mask).view(-1, 4) + target_bboxes_pos = torch.masked_select(target_bboxes, bbox_mask).view(-1, 4) + bbox_weight = torch.masked_select(target_scores.sum(-1), fg_mask).unsqueeze(-1) + + iou = bbox_iou(pred_bboxes_pos, target_bboxes_pos, xywh=False, CIoU=True) + loss_iou = 1.0 - iou + + loss_iou *= bbox_weight + loss_iou = loss_iou.sum() / target_scores_sum + + # dfl loss + if self.use_dfl: + dist_mask = fg_mask.unsqueeze(-1).repeat([1, 1, (self.reg_max + 1) * 4]) + pred_dist_pos = torch.masked_select(pred_dist, dist_mask).view(-1, 4, self.reg_max + 1) + target_ltrb = bbox2dist(anchor_points, target_bboxes, self.reg_max) + target_ltrb_pos = torch.masked_select(target_ltrb, bbox_mask).view(-1, 4) + loss_dfl = self._df_loss(pred_dist_pos, target_ltrb_pos) * bbox_weight + loss_dfl = loss_dfl.sum() / target_scores_sum + else: + loss_dfl = torch.tensor(0.0).to(pred_dist.device) + + return loss_iou, loss_dfl, iou + + def _df_loss(self, pred_dist, target): + target_left = target.to(torch.long) + target_right = target_left + 1 + weight_left = target_right.to(torch.float) - target + weight_right = 1 - weight_left + loss_left = F.cross_entropy(pred_dist.view(-1, self.reg_max + 1), target_left.view(-1), reduction="none").view( + target_left.shape) * weight_left + loss_right = F.cross_entropy(pred_dist.view(-1, self.reg_max + 1), target_right.view(-1), + reduction="none").view(target_left.shape) * weight_right + return (loss_left + loss_right).mean(-1, keepdim=True) + + +class ComputeLoss: + # Compute losses + def __init__(self, model, use_dfl=True): + device = next(model.parameters()).device # get model device + h = model.hyp # hyperparameters + + # Define criteria + BCEcls = nn.BCEWithLogitsLoss(pos_weight=torch.tensor([h["cls_pw"]], device=device), reduction='none') + + # Class label smoothing https://arxiv.org/pdf/1902.04103.pdf eqn 3 + self.cp, self.cn = smooth_BCE(eps=h.get("label_smoothing", 0.0)) # positive, negative BCE targets + + # Focal loss + g = h["fl_gamma"] # focal loss gamma + if g > 0: + BCEcls = FocalLoss(BCEcls, g) + + m = de_parallel(model).model[-1] # Detect() module + self.balance = {3: [4.0, 1.0, 0.4]}.get(m.nl, [4.0, 1.0, 0.25, 0.06, 0.02]) # P3-P7 + self.BCEcls = BCEcls + self.hyp = h + self.stride = m.stride # model strides + self.nc = m.nc # number of classes + self.nl = m.nl # number of layers + self.no = m.no + self.reg_max = m.reg_max + self.device = device + + self.assigner = TaskAlignedAssigner(topk=int(os.getenv('YOLOM', 10)), + num_classes=self.nc, + alpha=float(os.getenv('YOLOA', 0.5)), + beta=float(os.getenv('YOLOB', 6.0))) + self.assigner2 = TaskAlignedAssigner(topk=int(os.getenv('YOLOM', 10)), + num_classes=self.nc, + alpha=float(os.getenv('YOLOA', 0.5)), + beta=float(os.getenv('YOLOB', 6.0))) + self.bbox_loss = BboxLoss(m.reg_max - 1, use_dfl=use_dfl).to(device) + self.bbox_loss2 = BboxLoss(m.reg_max - 1, use_dfl=use_dfl).to(device) + self.proj = torch.arange(m.reg_max).float().to(device) # / 120.0 + self.use_dfl = use_dfl + + def preprocess(self, targets, batch_size, scale_tensor): + if targets.shape[0] == 0: + out = torch.zeros(batch_size, 0, 5, device=self.device) + else: + i = targets[:, 0] # image index + _, counts = i.unique(return_counts=True) + out = torch.zeros(batch_size, counts.max(), 5, device=self.device) + for j in range(batch_size): + matches = i == j + n = matches.sum() + if n: + out[j, :n] = targets[matches, 1:] + out[..., 1:5] = xywh2xyxy(out[..., 1:5].mul_(scale_tensor)) + return out + + def bbox_decode(self, anchor_points, pred_dist): + if self.use_dfl: + b, a, c = pred_dist.shape # batch, anchors, channels + pred_dist = pred_dist.view(b, a, 4, c // 4).softmax(3).matmul(self.proj.type(pred_dist.dtype)) + # pred_dist = pred_dist.view(b, a, c // 4, 4).transpose(2,3).softmax(3).matmul(self.proj.type(pred_dist.dtype)) + # pred_dist = (pred_dist.view(b, a, c // 4, 4).softmax(2) * self.proj.type(pred_dist.dtype).view(1, 1, -1, 1)).sum(2) + return dist2bbox(pred_dist, anchor_points, xywh=False) + + def __call__(self, p, targets, img=None, epoch=0): + loss = torch.zeros(3, device=self.device) # box, cls, dfl + feats = p[1][0] if isinstance(p, tuple) else p[0] + feats2 = p[1][1] if isinstance(p, tuple) else p[1] + + pred_distri, pred_scores = torch.cat([xi.view(feats[0].shape[0], self.no, -1) for xi in feats], 2).split( + (self.reg_max * 4, self.nc), 1) + pred_scores = pred_scores.permute(0, 2, 1).contiguous() + pred_distri = pred_distri.permute(0, 2, 1).contiguous() + + pred_distri2, pred_scores2 = torch.cat([xi.view(feats2[0].shape[0], self.no, -1) for xi in feats2], 2).split( + (self.reg_max * 4, self.nc), 1) + pred_scores2 = pred_scores2.permute(0, 2, 1).contiguous() + pred_distri2 = pred_distri2.permute(0, 2, 1).contiguous() + + dtype = pred_scores.dtype + batch_size, grid_size = pred_scores.shape[:2] + imgsz = torch.tensor(feats[0].shape[2:], device=self.device, dtype=dtype) * self.stride[0] # image size (h,w) + anchor_points, stride_tensor = make_anchors(feats, self.stride, 0.5) + + # targets + targets = self.preprocess(targets, batch_size, scale_tensor=imgsz[[1, 0, 1, 0]]) + gt_labels, gt_bboxes = targets.split((1, 4), 2) # cls, xyxy + mask_gt = gt_bboxes.sum(2, keepdim=True).gt_(0) + + # pboxes + pred_bboxes = self.bbox_decode(anchor_points, pred_distri) # xyxy, (b, h*w, 4) + pred_bboxes2 = self.bbox_decode(anchor_points, pred_distri2) # xyxy, (b, h*w, 4) + + target_labels, target_bboxes, target_scores, fg_mask = self.assigner( + pred_scores.detach().sigmoid(), + (pred_bboxes.detach() * stride_tensor).type(gt_bboxes.dtype), + anchor_points * stride_tensor, + gt_labels, + gt_bboxes, + mask_gt) + target_labels2, target_bboxes2, target_scores2, fg_mask2 = self.assigner2( + pred_scores2.detach().sigmoid(), + (pred_bboxes2.detach() * stride_tensor).type(gt_bboxes.dtype), + anchor_points * stride_tensor, + gt_labels, + gt_bboxes, + mask_gt) + + target_bboxes /= stride_tensor + target_scores_sum = max(target_scores.sum(), 1) + target_bboxes2 /= stride_tensor + target_scores_sum2 = max(target_scores2.sum(), 1) + + # cls loss + # loss[1] = self.varifocal_loss(pred_scores, target_scores, target_labels) / target_scores_sum # VFL way + loss[1] = self.BCEcls(pred_scores, target_scores.to(dtype)).sum() / target_scores_sum # BCE + loss[1] *= 0.25 + loss[1] += self.BCEcls(pred_scores2, target_scores2.to(dtype)).sum() / target_scores_sum2 # BCE + + # bbox loss + if fg_mask.sum(): + loss[0], loss[2], iou = self.bbox_loss(pred_distri, + pred_bboxes, + anchor_points, + target_bboxes, + target_scores, + target_scores_sum, + fg_mask) + loss[0] *= 0.25 + loss[2] *= 0.25 + if fg_mask2.sum(): + loss0_, loss2_, iou2 = self.bbox_loss2(pred_distri2, + pred_bboxes2, + anchor_points, + target_bboxes2, + target_scores2, + target_scores_sum2, + fg_mask2) + loss[0] += loss0_ + loss[2] += loss2_ + + loss[0] *= 7.5 # box gain + loss[1] *= 0.5 # cls gain + loss[2] *= 1.5 # dfl gain + + return loss.sum() * batch_size, loss.detach() # loss(box, cls, dfl) + + +class ComputeLossLH: + # Compute losses + def __init__(self, model, use_dfl=True): + device = next(model.parameters()).device # get model device + h = model.hyp # hyperparameters + + # Define criteria + BCEcls = nn.BCEWithLogitsLoss(pos_weight=torch.tensor([h["cls_pw"]], device=device), reduction='none') + + # Class label smoothing https://arxiv.org/pdf/1902.04103.pdf eqn 3 + self.cp, self.cn = smooth_BCE(eps=h.get("label_smoothing", 0.0)) # positive, negative BCE targets + + # Focal loss + g = h["fl_gamma"] # focal loss gamma + if g > 0: + BCEcls = FocalLoss(BCEcls, g) + + m = de_parallel(model).model[-1] # Detect() module + self.balance = {3: [4.0, 1.0, 0.4]}.get(m.nl, [4.0, 1.0, 0.25, 0.06, 0.02]) # P3-P7 + self.BCEcls = BCEcls + self.hyp = h + self.stride = m.stride # model strides + self.nc = m.nc # number of classes + self.nl = m.nl # number of layers + self.no = m.no + self.reg_max = m.reg_max + self.device = device + + self.assigner = TaskAlignedAssigner(topk=int(os.getenv('YOLOM', 10)), + num_classes=self.nc, + alpha=float(os.getenv('YOLOA', 0.5)), + beta=float(os.getenv('YOLOB', 6.0))) + self.bbox_loss = BboxLoss(m.reg_max - 1, use_dfl=use_dfl).to(device) + self.proj = torch.arange(m.reg_max).float().to(device) # / 120.0 + self.use_dfl = use_dfl + + def preprocess(self, targets, batch_size, scale_tensor): + if targets.shape[0] == 0: + out = torch.zeros(batch_size, 0, 5, device=self.device) + else: + i = targets[:, 0] # image index + _, counts = i.unique(return_counts=True) + out = torch.zeros(batch_size, counts.max(), 5, device=self.device) + for j in range(batch_size): + matches = i == j + n = matches.sum() + if n: + out[j, :n] = targets[matches, 1:] + out[..., 1:5] = xywh2xyxy(out[..., 1:5].mul_(scale_tensor)) + return out + + def bbox_decode(self, anchor_points, pred_dist): + if self.use_dfl: + b, a, c = pred_dist.shape # batch, anchors, channels + pred_dist = pred_dist.view(b, a, 4, c // 4).softmax(3).matmul(self.proj.type(pred_dist.dtype)) + # pred_dist = pred_dist.view(b, a, c // 4, 4).transpose(2,3).softmax(3).matmul(self.proj.type(pred_dist.dtype)) + # pred_dist = (pred_dist.view(b, a, c // 4, 4).softmax(2) * self.proj.type(pred_dist.dtype).view(1, 1, -1, 1)).sum(2) + return dist2bbox(pred_dist, anchor_points, xywh=False) + + def __call__(self, p, targets, img=None, epoch=0): + loss = torch.zeros(3, device=self.device) # box, cls, dfl + feats = p[1][0] if isinstance(p, tuple) else p[0] + feats2 = p[1][1] if isinstance(p, tuple) else p[1] + + pred_distri, pred_scores = torch.cat([xi.view(feats[0].shape[0], self.no, -1) for xi in feats], 2).split( + (self.reg_max * 4, self.nc), 1) + pred_scores = pred_scores.permute(0, 2, 1).contiguous() + pred_distri = pred_distri.permute(0, 2, 1).contiguous() + + pred_distri2, pred_scores2 = torch.cat([xi.view(feats2[0].shape[0], self.no, -1) for xi in feats2], 2).split( + (self.reg_max * 4, self.nc), 1) + pred_scores2 = pred_scores2.permute(0, 2, 1).contiguous() + pred_distri2 = pred_distri2.permute(0, 2, 1).contiguous() + + dtype = pred_scores.dtype + batch_size, grid_size = pred_scores.shape[:2] + imgsz = torch.tensor(feats[0].shape[2:], device=self.device, dtype=dtype) * self.stride[0] # image size (h,w) + anchor_points, stride_tensor = make_anchors(feats, self.stride, 0.5) + + # targets + targets = self.preprocess(targets, batch_size, scale_tensor=imgsz[[1, 0, 1, 0]]) + gt_labels, gt_bboxes = targets.split((1, 4), 2) # cls, xyxy + mask_gt = gt_bboxes.sum(2, keepdim=True).gt_(0) + + # pboxes + pred_bboxes = self.bbox_decode(anchor_points, pred_distri) # xyxy, (b, h*w, 4) + pred_bboxes2 = self.bbox_decode(anchor_points, pred_distri2) # xyxy, (b, h*w, 4) + + target_labels, target_bboxes, target_scores, fg_mask = self.assigner( + pred_scores2.detach().sigmoid(), + (pred_bboxes2.detach() * stride_tensor).type(gt_bboxes.dtype), + anchor_points * stride_tensor, + gt_labels, + gt_bboxes, + mask_gt) + + target_bboxes /= stride_tensor + target_scores_sum = target_scores.sum() + + # cls loss + # loss[1] = self.varifocal_loss(pred_scores, target_scores, target_labels) / target_scores_sum # VFL way + loss[1] = self.BCEcls(pred_scores, target_scores.to(dtype)).sum() / target_scores_sum # BCE + loss[1] *= 0.25 + loss[1] += self.BCEcls(pred_scores2, target_scores.to(dtype)).sum() / target_scores_sum # BCE + + # bbox loss + if fg_mask.sum(): + loss[0], loss[2], iou = self.bbox_loss(pred_distri, + pred_bboxes, + anchor_points, + target_bboxes, + target_scores, + target_scores_sum, + fg_mask) + loss[0] *= 0.25 + loss[2] *= 0.25 + if fg_mask.sum(): + loss0_, loss2_, iou2 = self.bbox_loss(pred_distri2, + pred_bboxes2, + anchor_points, + target_bboxes, + target_scores, + target_scores_sum, + fg_mask) + loss[0] += loss0_ + loss[2] += loss2_ + + loss[0] *= 7.5 # box gain + loss[1] *= 0.5 # cls gain + loss[2] *= 1.5 # dfl gain + + return loss.sum() * batch_size, loss.detach() # loss(box, cls, dfl) diff --git a/cv/3d_detection/yolov9/pytorch/utils/loss_tal_triple.py b/cv/3d_detection/yolov9/pytorch/utils/loss_tal_triple.py new file mode 100644 index 000000000..1ed821983 --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/utils/loss_tal_triple.py @@ -0,0 +1,282 @@ +import os + +import torch +import torch.nn as nn +import torch.nn.functional as F + +from utils.general import xywh2xyxy +from utils.metrics import bbox_iou +from utils.tal.anchor_generator import dist2bbox, make_anchors, bbox2dist +from utils.tal.assigner import TaskAlignedAssigner +from utils.torch_utils import de_parallel + + +def smooth_BCE(eps=0.1): # https://github.com/ultralytics/yolov3/issues/238#issuecomment-598028441 + # return positive, negative label smoothing BCE targets + return 1.0 - 0.5 * eps, 0.5 * eps + + +class VarifocalLoss(nn.Module): + # Varifocal loss by Zhang et al. https://arxiv.org/abs/2008.13367 + def __init__(self): + super().__init__() + + def forward(self, pred_score, gt_score, label, alpha=0.75, gamma=2.0): + weight = alpha * pred_score.sigmoid().pow(gamma) * (1 - label) + gt_score * label + with torch.cuda.amp.autocast(enabled=False): + loss = (F.binary_cross_entropy_with_logits(pred_score.float(), gt_score.float(), + reduction="none") * weight).sum() + return loss + + +class FocalLoss(nn.Module): + # Wraps focal loss around existing loss_fcn(), i.e. criteria = FocalLoss(nn.BCEWithLogitsLoss(), gamma=1.5) + def __init__(self, loss_fcn, gamma=1.5, alpha=0.25): + super().__init__() + self.loss_fcn = loss_fcn # must be nn.BCEWithLogitsLoss() + self.gamma = gamma + self.alpha = alpha + self.reduction = loss_fcn.reduction + self.loss_fcn.reduction = "none" # required to apply FL to each element + + def forward(self, pred, true): + loss = self.loss_fcn(pred, true) + # p_t = torch.exp(-loss) + # loss *= self.alpha * (1.000001 - p_t) ** self.gamma # non-zero power for gradient stability + + # TF implementation https://github.com/tensorflow/addons/blob/v0.7.1/tensorflow_addons/losses/focal_loss.py + pred_prob = torch.sigmoid(pred) # prob from logits + p_t = true * pred_prob + (1 - true) * (1 - pred_prob) + alpha_factor = true * self.alpha + (1 - true) * (1 - self.alpha) + modulating_factor = (1.0 - p_t) ** self.gamma + loss *= alpha_factor * modulating_factor + + if self.reduction == "mean": + return loss.mean() + elif self.reduction == "sum": + return loss.sum() + else: # 'none' + return loss + + +class BboxLoss(nn.Module): + def __init__(self, reg_max, use_dfl=False): + super().__init__() + self.reg_max = reg_max + self.use_dfl = use_dfl + + def forward(self, pred_dist, pred_bboxes, anchor_points, target_bboxes, target_scores, target_scores_sum, fg_mask): + # iou loss + bbox_mask = fg_mask.unsqueeze(-1).repeat([1, 1, 4]) # (b, h*w, 4) + pred_bboxes_pos = torch.masked_select(pred_bboxes, bbox_mask).view(-1, 4) + target_bboxes_pos = torch.masked_select(target_bboxes, bbox_mask).view(-1, 4) + bbox_weight = torch.masked_select(target_scores.sum(-1), fg_mask).unsqueeze(-1) + + iou = bbox_iou(pred_bboxes_pos, target_bboxes_pos, xywh=False, CIoU=True) + loss_iou = 1.0 - iou + + loss_iou *= bbox_weight + loss_iou = loss_iou.sum() / target_scores_sum + + # dfl loss + if self.use_dfl: + dist_mask = fg_mask.unsqueeze(-1).repeat([1, 1, (self.reg_max + 1) * 4]) + pred_dist_pos = torch.masked_select(pred_dist, dist_mask).view(-1, 4, self.reg_max + 1) + target_ltrb = bbox2dist(anchor_points, target_bboxes, self.reg_max) + target_ltrb_pos = torch.masked_select(target_ltrb, bbox_mask).view(-1, 4) + loss_dfl = self._df_loss(pred_dist_pos, target_ltrb_pos) * bbox_weight + loss_dfl = loss_dfl.sum() / target_scores_sum + else: + loss_dfl = torch.tensor(0.0).to(pred_dist.device) + + return loss_iou, loss_dfl, iou + + def _df_loss(self, pred_dist, target): + target_left = target.to(torch.long) + target_right = target_left + 1 + weight_left = target_right.to(torch.float) - target + weight_right = 1 - weight_left + loss_left = F.cross_entropy(pred_dist.view(-1, self.reg_max + 1), target_left.view(-1), reduction="none").view( + target_left.shape) * weight_left + loss_right = F.cross_entropy(pred_dist.view(-1, self.reg_max + 1), target_right.view(-1), + reduction="none").view(target_left.shape) * weight_right + return (loss_left + loss_right).mean(-1, keepdim=True) + + +class ComputeLoss: + # Compute losses + def __init__(self, model, use_dfl=True): + device = next(model.parameters()).device # get model device + h = model.hyp # hyperparameters + + # Define criteria + BCEcls = nn.BCEWithLogitsLoss(pos_weight=torch.tensor([h["cls_pw"]], device=device), reduction='none') + + # Class label smoothing https://arxiv.org/pdf/1902.04103.pdf eqn 3 + self.cp, self.cn = smooth_BCE(eps=h.get("label_smoothing", 0.0)) # positive, negative BCE targets + + # Focal loss + g = h["fl_gamma"] # focal loss gamma + if g > 0: + BCEcls = FocalLoss(BCEcls, g) + + m = de_parallel(model).model[-1] # Detect() module + self.balance = {3: [4.0, 1.0, 0.4]}.get(m.nl, [4.0, 1.0, 0.25, 0.06, 0.02]) # P3-P7 + self.BCEcls = BCEcls + self.hyp = h + self.stride = m.stride # model strides + self.nc = m.nc # number of classes + self.nl = m.nl # number of layers + self.no = m.no + self.reg_max = m.reg_max + self.device = device + + self.assigner = TaskAlignedAssigner(topk=int(os.getenv('YOLOM', 10)), + num_classes=self.nc, + alpha=float(os.getenv('YOLOA', 0.5)), + beta=float(os.getenv('YOLOB', 6.0))) + self.assigner2 = TaskAlignedAssigner(topk=int(os.getenv('YOLOM', 10)), + num_classes=self.nc, + alpha=float(os.getenv('YOLOA', 0.5)), + beta=float(os.getenv('YOLOB', 6.0))) + self.assigner3 = TaskAlignedAssigner(topk=int(os.getenv('YOLOM', 10)), + num_classes=self.nc, + alpha=float(os.getenv('YOLOA', 0.5)), + beta=float(os.getenv('YOLOB', 6.0))) + self.bbox_loss = BboxLoss(m.reg_max - 1, use_dfl=use_dfl).to(device) + self.bbox_loss2 = BboxLoss(m.reg_max - 1, use_dfl=use_dfl).to(device) + self.bbox_loss3 = BboxLoss(m.reg_max - 1, use_dfl=use_dfl).to(device) + self.proj = torch.arange(m.reg_max).float().to(device) # / 120.0 + self.use_dfl = use_dfl + + def preprocess(self, targets, batch_size, scale_tensor): + if targets.shape[0] == 0: + out = torch.zeros(batch_size, 0, 5, device=self.device) + else: + i = targets[:, 0] # image index + _, counts = i.unique(return_counts=True) + out = torch.zeros(batch_size, counts.max(), 5, device=self.device) + for j in range(batch_size): + matches = i == j + n = matches.sum() + if n: + out[j, :n] = targets[matches, 1:] + out[..., 1:5] = xywh2xyxy(out[..., 1:5].mul_(scale_tensor)) + return out + + def bbox_decode(self, anchor_points, pred_dist): + if self.use_dfl: + b, a, c = pred_dist.shape # batch, anchors, channels + pred_dist = pred_dist.view(b, a, 4, c // 4).softmax(3).matmul(self.proj.type(pred_dist.dtype)) + # pred_dist = pred_dist.view(b, a, c // 4, 4).transpose(2,3).softmax(3).matmul(self.proj.type(pred_dist.dtype)) + # pred_dist = (pred_dist.view(b, a, c // 4, 4).softmax(2) * self.proj.type(pred_dist.dtype).view(1, 1, -1, 1)).sum(2) + return dist2bbox(pred_dist, anchor_points, xywh=False) + + def __call__(self, p, targets, img=None, epoch=0): + loss = torch.zeros(3, device=self.device) # box, cls, dfl + feats = p[1][0] if isinstance(p, tuple) else p[0] + feats2 = p[1][1] if isinstance(p, tuple) else p[1] + feats3 = p[1][2] if isinstance(p, tuple) else p[2] + + pred_distri, pred_scores = torch.cat([xi.view(feats[0].shape[0], self.no, -1) for xi in feats], 2).split( + (self.reg_max * 4, self.nc), 1) + pred_scores = pred_scores.permute(0, 2, 1).contiguous() + pred_distri = pred_distri.permute(0, 2, 1).contiguous() + + pred_distri2, pred_scores2 = torch.cat([xi.view(feats2[0].shape[0], self.no, -1) for xi in feats2], 2).split( + (self.reg_max * 4, self.nc), 1) + pred_scores2 = pred_scores2.permute(0, 2, 1).contiguous() + pred_distri2 = pred_distri2.permute(0, 2, 1).contiguous() + + pred_distri3, pred_scores3 = torch.cat([xi.view(feats3[0].shape[0], self.no, -1) for xi in feats3], 2).split( + (self.reg_max * 4, self.nc), 1) + pred_scores3 = pred_scores3.permute(0, 2, 1).contiguous() + pred_distri3 = pred_distri3.permute(0, 2, 1).contiguous() + + dtype = pred_scores.dtype + batch_size, grid_size = pred_scores.shape[:2] + imgsz = torch.tensor(feats[0].shape[2:], device=self.device, dtype=dtype) * self.stride[0] # image size (h,w) + anchor_points, stride_tensor = make_anchors(feats, self.stride, 0.5) + + # targets + targets = self.preprocess(targets, batch_size, scale_tensor=imgsz[[1, 0, 1, 0]]) + gt_labels, gt_bboxes = targets.split((1, 4), 2) # cls, xyxy + mask_gt = gt_bboxes.sum(2, keepdim=True).gt_(0) + + # pboxes + pred_bboxes = self.bbox_decode(anchor_points, pred_distri) # xyxy, (b, h*w, 4) + pred_bboxes2 = self.bbox_decode(anchor_points, pred_distri2) # xyxy, (b, h*w, 4) + pred_bboxes3 = self.bbox_decode(anchor_points, pred_distri3) # xyxy, (b, h*w, 4) + + target_labels, target_bboxes, target_scores, fg_mask = self.assigner( + pred_scores.detach().sigmoid(), + (pred_bboxes.detach() * stride_tensor).type(gt_bboxes.dtype), + anchor_points * stride_tensor, + gt_labels, + gt_bboxes, + mask_gt) + target_labels2, target_bboxes2, target_scores2, fg_mask2 = self.assigner2( + pred_scores2.detach().sigmoid(), + (pred_bboxes2.detach() * stride_tensor).type(gt_bboxes.dtype), + anchor_points * stride_tensor, + gt_labels, + gt_bboxes, + mask_gt) + target_labels3, target_bboxes3, target_scores3, fg_mask3 = self.assigner3( + pred_scores3.detach().sigmoid(), + (pred_bboxes3.detach() * stride_tensor).type(gt_bboxes.dtype), + anchor_points * stride_tensor, + gt_labels, + gt_bboxes, + mask_gt) + + target_bboxes /= stride_tensor + target_scores_sum = max(target_scores.sum(), 1) + target_bboxes2 /= stride_tensor + target_scores_sum2 = max(target_scores2.sum(), 1) + target_bboxes3 /= stride_tensor + target_scores_sum3 = max(target_scores3.sum(), 1) + + # cls loss + # loss[1] = self.varifocal_loss(pred_scores, target_scores, target_labels) / target_scores_sum # VFL way + loss[1] = 0.25 * self.BCEcls(pred_scores, target_scores.to(dtype)).sum() / target_scores_sum # BCE + loss[1] += 0.25 * self.BCEcls(pred_scores2, target_scores2.to(dtype)).sum() / target_scores_sum2 # BCE + loss[1] += self.BCEcls(pred_scores3, target_scores3.to(dtype)).sum() / target_scores_sum3 # BCE + + # bbox loss + if fg_mask.sum(): + loss[0], loss[2], iou = self.bbox_loss(pred_distri, + pred_bboxes, + anchor_points, + target_bboxes, + target_scores, + target_scores_sum, + fg_mask) + loss[0] *= 0.25 + loss[2] *= 0.25 + if fg_mask2.sum(): + loss0_, loss2_, iou2 = self.bbox_loss2(pred_distri2, + pred_bboxes2, + anchor_points, + target_bboxes2, + target_scores2, + target_scores_sum2, + fg_mask2) + loss[0] += 0.25 * loss0_ + loss[2] += 0.25 * loss2_ + if fg_mask3.sum(): + loss0__, loss2__, iou3 = self.bbox_loss3(pred_distri3, + pred_bboxes3, + anchor_points, + target_bboxes3, + target_scores3, + target_scores_sum3, + fg_mask3) + loss[0] += loss0__ + loss[2] += loss2__ + + loss[0] *= 7.5 # box gain + loss[1] *= 0.5 # cls gain + loss[2] *= 1.5 # dfl gain + + return loss.sum() * batch_size, loss.detach() # loss(box, cls, dfl) diff --git a/cv/3d_detection/yolov9/pytorch/utils/metrics.py b/cv/3d_detection/yolov9/pytorch/utils/metrics.py new file mode 100644 index 000000000..1229f2b10 --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/utils/metrics.py @@ -0,0 +1,397 @@ +import math +import warnings +from pathlib import Path + +import matplotlib.pyplot as plt +import numpy as np +import torch + +from utils import TryExcept, threaded + + +def fitness(x): + # Model fitness as a weighted combination of metrics + w = [0.0, 0.0, 0.1, 0.9] # weights for [P, R, mAP@0.5, mAP@0.5:0.95] + return (x[:, :4] * w).sum(1) + + +def smooth(y, f=0.05): + # Box filter of fraction f + nf = round(len(y) * f * 2) // 2 + 1 # number of filter elements (must be odd) + p = np.ones(nf // 2) # ones padding + yp = np.concatenate((p * y[0], y, p * y[-1]), 0) # y padded + return np.convolve(yp, np.ones(nf) / nf, mode='valid') # y-smoothed + + +def ap_per_class(tp, conf, pred_cls, target_cls, plot=False, save_dir='.', names=(), eps=1e-16, prefix=""): + """ Compute the average precision, given the recall and precision curves. + Source: https://github.com/rafaelpadilla/Object-Detection-Metrics. + # Arguments + tp: True positives (nparray, nx1 or nx10). + conf: Objectness value from 0-1 (nparray). + pred_cls: Predicted object classes (nparray). + target_cls: True object classes (nparray). + plot: Plot precision-recall curve at mAP@0.5 + save_dir: Plot save directory + # Returns + The average precision as computed in py-faster-rcnn. + """ + + # Sort by objectness + i = np.argsort(-conf) + tp, conf, pred_cls = tp[i], conf[i], pred_cls[i] + + # Find unique classes + unique_classes, nt = np.unique(target_cls, return_counts=True) + nc = unique_classes.shape[0] # number of classes, number of detections + + # Create Precision-Recall curve and compute AP for each class + px, py = np.linspace(0, 1, 1000), [] # for plotting + ap, p, r = np.zeros((nc, tp.shape[1])), np.zeros((nc, 1000)), np.zeros((nc, 1000)) + for ci, c in enumerate(unique_classes): + i = pred_cls == c + n_l = nt[ci] # number of labels + n_p = i.sum() # number of predictions + if n_p == 0 or n_l == 0: + continue + + # Accumulate FPs and TPs + fpc = (1 - tp[i]).cumsum(0) + tpc = tp[i].cumsum(0) + + # Recall + recall = tpc / (n_l + eps) # recall curve + r[ci] = np.interp(-px, -conf[i], recall[:, 0], left=0) # negative x, xp because xp decreases + + # Precision + precision = tpc / (tpc + fpc) # precision curve + p[ci] = np.interp(-px, -conf[i], precision[:, 0], left=1) # p at pr_score + + # AP from recall-precision curve + for j in range(tp.shape[1]): + ap[ci, j], mpre, mrec = compute_ap(recall[:, j], precision[:, j]) + if plot and j == 0: + py.append(np.interp(px, mrec, mpre)) # precision at mAP@0.5 + + # Compute F1 (harmonic mean of precision and recall) + f1 = 2 * p * r / (p + r + eps) + names = [v for k, v in names.items() if k in unique_classes] # list: only classes that have data + names = dict(enumerate(names)) # to dict + if plot: + plot_pr_curve(px, py, ap, Path(save_dir) / f'{prefix}PR_curve.png', names) + plot_mc_curve(px, f1, Path(save_dir) / f'{prefix}F1_curve.png', names, ylabel='F1') + plot_mc_curve(px, p, Path(save_dir) / f'{prefix}P_curve.png', names, ylabel='Precision') + plot_mc_curve(px, r, Path(save_dir) / f'{prefix}R_curve.png', names, ylabel='Recall') + + i = smooth(f1.mean(0), 0.1).argmax() # max F1 index + p, r, f1 = p[:, i], r[:, i], f1[:, i] + tp = (r * nt).round() # true positives + fp = (tp / (p + eps) - tp).round() # false positives + return tp, fp, p, r, f1, ap, unique_classes.astype(int) + + +def compute_ap(recall, precision): + """ Compute the average precision, given the recall and precision curves + # Arguments + recall: The recall curve (list) + precision: The precision curve (list) + # Returns + Average precision, precision curve, recall curve + """ + + # Append sentinel values to beginning and end + mrec = np.concatenate(([0.0], recall, [1.0])) + mpre = np.concatenate(([1.0], precision, [0.0])) + + # Compute the precision envelope + mpre = np.flip(np.maximum.accumulate(np.flip(mpre))) + + # Integrate area under curve + method = 'interp' # methods: 'continuous', 'interp' + if method == 'interp': + x = np.linspace(0, 1, 101) # 101-point interp (COCO) + ap = np.trapz(np.interp(x, mrec, mpre), x) # integrate + else: # 'continuous' + i = np.where(mrec[1:] != mrec[:-1])[0] # points where x axis (recall) changes + ap = np.sum((mrec[i + 1] - mrec[i]) * mpre[i + 1]) # area under curve + + return ap, mpre, mrec + + +class ConfusionMatrix: + # Updated version of https://github.com/kaanakan/object_detection_confusion_matrix + def __init__(self, nc, conf=0.25, iou_thres=0.45): + self.matrix = np.zeros((nc + 1, nc + 1)) + self.nc = nc # number of classes + self.conf = conf + self.iou_thres = iou_thres + + def process_batch(self, detections, labels): + """ + Return intersection-over-union (Jaccard index) of boxes. + Both sets of boxes are expected to be in (x1, y1, x2, y2) format. + Arguments: + detections (Array[N, 6]), x1, y1, x2, y2, conf, class + labels (Array[M, 5]), class, x1, y1, x2, y2 + Returns: + None, updates confusion matrix accordingly + """ + if detections is None: + gt_classes = labels.int() + for gc in gt_classes: + self.matrix[self.nc, gc] += 1 # background FN + return + + detections = detections[detections[:, 4] > self.conf] + gt_classes = labels[:, 0].int() + detection_classes = detections[:, 5].int() + iou = box_iou(labels[:, 1:], detections[:, :4]) + + x = torch.where(iou > self.iou_thres) + if x[0].shape[0]: + matches = torch.cat((torch.stack(x, 1), iou[x[0], x[1]][:, None]), 1).cpu().numpy() + if x[0].shape[0] > 1: + matches = matches[matches[:, 2].argsort()[::-1]] + matches = matches[np.unique(matches[:, 1], return_index=True)[1]] + matches = matches[matches[:, 2].argsort()[::-1]] + matches = matches[np.unique(matches[:, 0], return_index=True)[1]] + else: + matches = np.zeros((0, 3)) + + n = matches.shape[0] > 0 + m0, m1, _ = matches.transpose().astype(int) + for i, gc in enumerate(gt_classes): + j = m0 == i + if n and sum(j) == 1: + self.matrix[detection_classes[m1[j]], gc] += 1 # correct + else: + self.matrix[self.nc, gc] += 1 # true background + + if n: + for i, dc in enumerate(detection_classes): + if not any(m1 == i): + self.matrix[dc, self.nc] += 1 # predicted background + + def matrix(self): + return self.matrix + + def tp_fp(self): + tp = self.matrix.diagonal() # true positives + fp = self.matrix.sum(1) - tp # false positives + # fn = self.matrix.sum(0) - tp # false negatives (missed detections) + return tp[:-1], fp[:-1] # remove background class + + @TryExcept('WARNING ⚠️ ConfusionMatrix plot failure') + def plot(self, normalize=True, save_dir='', names=()): + import seaborn as sn + + array = self.matrix / ((self.matrix.sum(0).reshape(1, -1) + 1E-9) if normalize else 1) # normalize columns + array[array < 0.005] = np.nan # don't annotate (would appear as 0.00) + + fig, ax = plt.subplots(1, 1, figsize=(12, 9), tight_layout=True) + nc, nn = self.nc, len(names) # number of classes, names + sn.set(font_scale=1.0 if nc < 50 else 0.8) # for label size + labels = (0 < nn < 99) and (nn == nc) # apply names to ticklabels + ticklabels = (names + ['background']) if labels else "auto" + with warnings.catch_warnings(): + warnings.simplefilter('ignore') # suppress empty matrix RuntimeWarning: All-NaN slice encountered + sn.heatmap(array, + ax=ax, + annot=nc < 30, + annot_kws={ + "size": 8}, + cmap='Blues', + fmt='.2f', + square=True, + vmin=0.0, + xticklabels=ticklabels, + yticklabels=ticklabels).set_facecolor((1, 1, 1)) + ax.set_ylabel('True') + ax.set_ylabel('Predicted') + ax.set_title('Confusion Matrix') + fig.savefig(Path(save_dir) / 'confusion_matrix.png', dpi=250) + plt.close(fig) + + def print(self): + for i in range(self.nc + 1): + print(' '.join(map(str, self.matrix[i]))) + + +class WIoU_Scale: + ''' monotonous: { + None: origin v1 + True: monotonic FM v2 + False: non-monotonic FM v3 + } + momentum: The momentum of running mean''' + + iou_mean = 1. + monotonous = False + _momentum = 1 - 0.5 ** (1 / 7000) + _is_train = True + + def __init__(self, iou): + self.iou = iou + self._update(self) + + @classmethod + def _update(cls, self): + if cls._is_train: cls.iou_mean = (1 - cls._momentum) * cls.iou_mean + \ + cls._momentum * self.iou.detach().mean().item() + + @classmethod + def _scaled_loss(cls, self, gamma=1.9, delta=3): + if isinstance(self.monotonous, bool): + if self.monotonous: + return (self.iou.detach() / self.iou_mean).sqrt() + else: + beta = self.iou.detach() / self.iou_mean + alpha = delta * torch.pow(gamma, beta - delta) + return beta / alpha + return 1 + + +def bbox_iou(box1, box2, xywh=True, GIoU=False, DIoU=False, CIoU=False, MDPIoU=False, feat_h=640, feat_w=640, eps=1e-7): + # Returns Intersection over Union (IoU) of box1(1,4) to box2(n,4) + + # Get the coordinates of bounding boxes + if xywh: # transform from xywh to xyxy + (x1, y1, w1, h1), (x2, y2, w2, h2) = box1.chunk(4, -1), box2.chunk(4, -1) + w1_, h1_, w2_, h2_ = w1 / 2, h1 / 2, w2 / 2, h2 / 2 + b1_x1, b1_x2, b1_y1, b1_y2 = x1 - w1_, x1 + w1_, y1 - h1_, y1 + h1_ + b2_x1, b2_x2, b2_y1, b2_y2 = x2 - w2_, x2 + w2_, y2 - h2_, y2 + h2_ + else: # x1, y1, x2, y2 = box1 + b1_x1, b1_y1, b1_x2, b1_y2 = box1.chunk(4, -1) + b2_x1, b2_y1, b2_x2, b2_y2 = box2.chunk(4, -1) + w1, h1 = b1_x2 - b1_x1, b1_y2 - b1_y1 + eps + w2, h2 = b2_x2 - b2_x1, b2_y2 - b2_y1 + eps + + # Intersection area + inter = (torch.min(b1_x2, b2_x2) - torch.max(b1_x1, b2_x1)).clamp(0) * \ + (torch.min(b1_y2, b2_y2) - torch.max(b1_y1, b2_y1)).clamp(0) + + # Union Area + union = w1 * h1 + w2 * h2 - inter + eps + + # IoU + iou = inter / union + if CIoU or DIoU or GIoU: + cw = torch.max(b1_x2, b2_x2) - torch.min(b1_x1, b2_x1) # convex (smallest enclosing box) width + ch = torch.max(b1_y2, b2_y2) - torch.min(b1_y1, b2_y1) # convex height + if CIoU or DIoU: # Distance or Complete IoU https://arxiv.org/abs/1911.08287v1 + c2 = cw ** 2 + ch ** 2 + eps # convex diagonal squared + rho2 = ((b2_x1 + b2_x2 - b1_x1 - b1_x2) ** 2 + (b2_y1 + b2_y2 - b1_y1 - b1_y2) ** 2) / 4 # center dist ** 2 + if CIoU: # https://github.com/Zzh-tju/DIoU-SSD-pytorch/blob/master/utils/box/box_utils.py#L47 + v = (4 / math.pi ** 2) * torch.pow(torch.atan(w2 / h2) - torch.atan(w1 / h1), 2) + with torch.no_grad(): + alpha = v / (v - iou + (1 + eps)) + return iou - (rho2 / c2 + v * alpha) # CIoU + return iou - rho2 / c2 # DIoU + c_area = cw * ch + eps # convex area + return iou - (c_area - union) / c_area # GIoU https://arxiv.org/pdf/1902.09630.pdf + elif MDPIoU: + d1 = (b2_x1 - b1_x1) ** 2 + (b2_y1 - b1_y1) ** 2 + d2 = (b2_x2 - b1_x2) ** 2 + (b2_y2 - b1_y2) ** 2 + mpdiou_hw_pow = feat_h ** 2 + feat_w ** 2 + return iou - d1 / mpdiou_hw_pow - d2 / mpdiou_hw_pow # MPDIoU + return iou # IoU + + +def box_iou(box1, box2, eps=1e-7): + # https://github.com/pytorch/vision/blob/master/torchvision/ops/boxes.py + """ + Return intersection-over-union (Jaccard index) of boxes. + Both sets of boxes are expected to be in (x1, y1, x2, y2) format. + Arguments: + box1 (Tensor[N, 4]) + box2 (Tensor[M, 4]) + Returns: + iou (Tensor[N, M]): the NxM matrix containing the pairwise + IoU values for every element in boxes1 and boxes2 + """ + + # inter(N,M) = (rb(N,M,2) - lt(N,M,2)).clamp(0).prod(2) + (a1, a2), (b1, b2) = box1.unsqueeze(1).chunk(2, 2), box2.unsqueeze(0).chunk(2, 2) + inter = (torch.min(a2, b2) - torch.max(a1, b1)).clamp(0).prod(2) + + # IoU = inter / (area1 + area2 - inter) + return inter / ((a2 - a1).prod(2) + (b2 - b1).prod(2) - inter + eps) + + +def bbox_ioa(box1, box2, eps=1e-7): + """Returns the intersection over box2 area given box1, box2. Boxes are x1y1x2y2 + box1: np.array of shape(nx4) + box2: np.array of shape(mx4) + returns: np.array of shape(nxm) + """ + + # Get the coordinates of bounding boxes + b1_x1, b1_y1, b1_x2, b1_y2 = box1.T + b2_x1, b2_y1, b2_x2, b2_y2 = box2.T + + # Intersection area + inter_area = (np.minimum(b1_x2[:, None], b2_x2) - np.maximum(b1_x1[:, None], b2_x1)).clip(0) * \ + (np.minimum(b1_y2[:, None], b2_y2) - np.maximum(b1_y1[:, None], b2_y1)).clip(0) + + # box2 area + box2_area = (b2_x2 - b2_x1) * (b2_y2 - b2_y1) + eps + + # Intersection over box2 area + return inter_area / box2_area + + +def wh_iou(wh1, wh2, eps=1e-7): + # Returns the nxm IoU matrix. wh1 is nx2, wh2 is mx2 + wh1 = wh1[:, None] # [N,1,2] + wh2 = wh2[None] # [1,M,2] + inter = torch.min(wh1, wh2).prod(2) # [N,M] + return inter / (wh1.prod(2) + wh2.prod(2) - inter + eps) # iou = inter / (area1 + area2 - inter) + + +# Plots ---------------------------------------------------------------------------------------------------------------- + + +@threaded +def plot_pr_curve(px, py, ap, save_dir=Path('pr_curve.png'), names=()): + # Precision-recall curve + fig, ax = plt.subplots(1, 1, figsize=(9, 6), tight_layout=True) + py = np.stack(py, axis=1) + + if 0 < len(names) < 21: # display per-class legend if < 21 classes + for i, y in enumerate(py.T): + ax.plot(px, y, linewidth=1, label=f'{names[i]} {ap[i, 0]:.3f}') # plot(recall, precision) + else: + ax.plot(px, py, linewidth=1, color='grey') # plot(recall, precision) + + ax.plot(px, py.mean(1), linewidth=3, color='blue', label='all classes %.3f mAP@0.5' % ap[:, 0].mean()) + ax.set_xlabel('Recall') + ax.set_ylabel('Precision') + ax.set_xlim(0, 1) + ax.set_ylim(0, 1) + ax.legend(bbox_to_anchor=(1.04, 1), loc="upper left") + ax.set_title('Precision-Recall Curve') + fig.savefig(save_dir, dpi=250) + plt.close(fig) + + +@threaded +def plot_mc_curve(px, py, save_dir=Path('mc_curve.png'), names=(), xlabel='Confidence', ylabel='Metric'): + # Metric-confidence curve + fig, ax = plt.subplots(1, 1, figsize=(9, 6), tight_layout=True) + + if 0 < len(names) < 21: # display per-class legend if < 21 classes + for i, y in enumerate(py): + ax.plot(px, y, linewidth=1, label=f'{names[i]}') # plot(confidence, metric) + else: + ax.plot(px, py.T, linewidth=1, color='grey') # plot(confidence, metric) + + y = smooth(py.mean(0), 0.05) + ax.plot(px, y, linewidth=3, color='blue', label=f'all classes {y.max():.2f} at {px[y.argmax()]:.3f}') + ax.set_xlabel(xlabel) + ax.set_ylabel(ylabel) + ax.set_xlim(0, 1) + ax.set_ylim(0, 1) + ax.legend(bbox_to_anchor=(1.04, 1), loc="upper left") + ax.set_title(f'{ylabel}-Confidence Curve') + fig.savefig(save_dir, dpi=250) + plt.close(fig) diff --git a/cv/3d_detection/yolov9/pytorch/utils/panoptic/__init__.py b/cv/3d_detection/yolov9/pytorch/utils/panoptic/__init__.py new file mode 100644 index 000000000..84952a816 --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/utils/panoptic/__init__.py @@ -0,0 +1 @@ +# init \ No newline at end of file diff --git a/cv/3d_detection/yolov9/pytorch/utils/panoptic/augmentations.py b/cv/3d_detection/yolov9/pytorch/utils/panoptic/augmentations.py new file mode 100644 index 000000000..8e0a95cb8 --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/utils/panoptic/augmentations.py @@ -0,0 +1,183 @@ +import math +import random + +import cv2 +import numpy as np + +from ..augmentations import box_candidates +from ..general import resample_segments, segment2box +from ..metrics import bbox_ioa + + +def mixup(im, labels, segments, seg_cls, semantic_masks, im2, labels2, segments2, seg_cls2, semantic_masks2): + # Applies MixUp augmentation https://arxiv.org/pdf/1710.09412.pdf + r = np.random.beta(32.0, 32.0) # mixup ratio, alpha=beta=32.0 + im = (im * r + im2 * (1 - r)).astype(np.uint8) + labels = np.concatenate((labels, labels2), 0) + segments = np.concatenate((segments, segments2), 0) + seg_cls = np.concatenate((seg_cls, seg_cls2), 0) + semantic_masks = np.concatenate((semantic_masks, semantic_masks2), 0) + return im, labels, segments, seg_cls, semantic_masks + + +def random_perspective(im, + targets=(), + segments=(), + semantic_masks = (), + degrees=10, + translate=.1, + scale=.1, + shear=10, + perspective=0.0, + border=(0, 0)): + # torchvision.transforms.RandomAffine(degrees=(-10, 10), translate=(.1, .1), scale=(.9, 1.1), shear=(-10, 10)) + # targets = [cls, xyxy] + + height = im.shape[0] + border[0] * 2 # shape(h,w,c) + width = im.shape[1] + border[1] * 2 + + # Center + C = np.eye(3) + C[0, 2] = -im.shape[1] / 2 # x translation (pixels) + C[1, 2] = -im.shape[0] / 2 # y translation (pixels) + + # Perspective + P = np.eye(3) + P[2, 0] = random.uniform(-perspective, perspective) # x perspective (about y) + P[2, 1] = random.uniform(-perspective, perspective) # y perspective (about x) + + # Rotation and Scale + R = np.eye(3) + a = random.uniform(-degrees, degrees) + # a += random.choice([-180, -90, 0, 90]) # add 90deg rotations to small rotations + s = random.uniform(1 - scale, 1 + scale) + # s = 2 ** random.uniform(-scale, scale) + R[:2] = cv2.getRotationMatrix2D(angle=a, center=(0, 0), scale=s) + + # Shear + S = np.eye(3) + S[0, 1] = math.tan(random.uniform(-shear, shear) * math.pi / 180) # x shear (deg) + S[1, 0] = math.tan(random.uniform(-shear, shear) * math.pi / 180) # y shear (deg) + + # Translation + T = np.eye(3) + T[0, 2] = (random.uniform(0.5 - translate, 0.5 + translate) * width) # x translation (pixels) + T[1, 2] = (random.uniform(0.5 - translate, 0.5 + translate) * height) # y translation (pixels) + + # Combined rotation matrix + M = T @ S @ R @ P @ C # order of operations (right to left) is IMPORTANT + if (border[0] != 0) or (border[1] != 0) or (M != np.eye(3)).any(): # image changed + if perspective: + im = cv2.warpPerspective(im, M, dsize=(width, height), borderValue=(114, 114, 114)) + else: # affine + im = cv2.warpAffine(im, M[:2], dsize=(width, height), borderValue=(114, 114, 114)) + + # Visualize + # import matplotlib.pyplot as plt + # ax = plt.subplots(1, 2, figsize=(12, 6))[1].ravel() + # ax[0].imshow(im[:, :, ::-1]) # base + # ax[1].imshow(im2[:, :, ::-1]) # warped + + # Transform label coordinates + n = len(targets) + new_segments = [] + new_semantic_masks = [] + if n: + new = np.zeros((n, 4)) + segments = resample_segments(segments) # upsample + for i, segment in enumerate(segments): + xy = np.ones((len(segment), 3)) + xy[:, :2] = segment + xy = xy @ M.T # transform + xy = (xy[:, :2] / xy[:, 2:3] if perspective else xy[:, :2]) # perspective rescale or affine + + # clip + new[i] = segment2box(xy, width, height) + new_segments.append(xy) + + semantic_masks = resample_segments(semantic_masks) + for i, semantic_mask in enumerate(semantic_masks): + #if i < n: + # xy = np.ones((len(segments[i]), 3)) + # xy[:, :2] = segments[i] + # xy = xy @ M.T # transform + # xy = (xy[:, :2] / xy[:, 2:3] if perspective else xy[:, :2]) # perspective rescale or affine + + # new[i] = segment2box(xy, width, height) + # new_segments.append(xy) + + xy_s = np.ones((len(semantic_mask), 3)) + xy_s[:, :2] = semantic_mask + xy_s = xy_s @ M.T # transform + xy_s = (xy_s[:, :2] / xy_s[:, 2:3] if perspective else xy_s[:, :2]) # perspective rescale or affine + + new_semantic_masks.append(xy_s) + + # filter candidates + i = box_candidates(box1=targets[:, 1:5].T * s, box2=new.T, area_thr=0.01) + targets = targets[i] + targets[:, 1:5] = new[i] + new_segments = np.array(new_segments)[i] + new_semantic_masks = np.array(new_semantic_masks) + + return im, targets, new_segments, new_semantic_masks + + +def letterbox(im, new_shape=(640, 640), color=(114, 114, 114), auto=True, scaleFill=False, scaleup=True, stride=32): + # Resize and pad image while meeting stride-multiple constraints + shape = im.shape[:2] # current shape [height, width] + if isinstance(new_shape, int): + new_shape = (new_shape, new_shape) + + # Scale ratio (new / old) + r = min(new_shape[0] / shape[0], new_shape[1] / shape[1]) + if not scaleup: # only scale down, do not scale up (for better val mAP) + r = min(r, 1.0) + + # Compute padding + ratio = r, r # width, height ratios + new_unpad = int(round(shape[1] * r)), int(round(shape[0] * r)) + dw, dh = new_shape[1] - new_unpad[0], new_shape[0] - new_unpad[1] # wh padding + if auto: # minimum rectangle + dw, dh = np.mod(dw, stride), np.mod(dh, stride) # wh padding + elif scaleFill: # stretch + dw, dh = 0.0, 0.0 + new_unpad = (new_shape[1], new_shape[0]) + ratio = new_shape[1] / shape[1], new_shape[0] / shape[0] # width, height ratios + + dw /= 2 # divide padding into 2 sides + dh /= 2 + + if shape[::-1] != new_unpad: # resize + im = cv2.resize(im, new_unpad, interpolation=cv2.INTER_LINEAR) + top, bottom = int(round(dh - 0.1)), int(round(dh + 0.1)) + left, right = int(round(dw - 0.1)), int(round(dw + 0.1)) + im = cv2.copyMakeBorder(im, top, bottom, left, right, cv2.BORDER_CONSTANT, value=color) # add border + return im, ratio, (dw, dh) + + +def copy_paste(im, labels, segments, seg_cls, semantic_masks, p=0.5): + # Implement Copy-Paste augmentation https://arxiv.org/abs/2012.07177, labels as nx5 np.array(cls, xyxy) + n = len(segments) + if p and n: + h, w, _ = im.shape # height, width, channels + im_new = np.zeros(im.shape, np.uint8) + + # calculate ioa first then select indexes randomly + boxes = np.stack([w - labels[:, 3], labels[:, 2], w - labels[:, 1], labels[:, 4]], axis=-1) # (n, 4) + ioa = bbox_ioa(boxes, labels[:, 1:5]) # intersection over area + indexes = np.nonzero((ioa < 0.30).all(1))[0] # (N, ) + n = len(indexes) + for j in random.sample(list(indexes), k=round(p * n)): + l, box, s = labels[j], boxes[j], segments[j] + labels = np.concatenate((labels, [[l[0], *box]]), 0) + segments.append(np.concatenate((w - s[:, 0:1], s[:, 1:2]), 1)) + seg_cls.append(l[0].astype(int)) + semantic_masks.append(np.concatenate((w - s[:, 0:1], s[:, 1:2]), 1)) + cv2.drawContours(im_new, [segments[j].astype(np.int32)], -1, (1, 1, 1), cv2.FILLED) + + result = cv2.flip(im, 1) # augment segments (flip left-right) + i = cv2.flip(im_new, 1).astype(bool) + im[i] = result[i] # cv2.imwrite('debug.jpg', im) # debug + + return im, labels, segments, seg_cls, semantic_masks \ No newline at end of file diff --git a/cv/3d_detection/yolov9/pytorch/utils/panoptic/dataloaders.py b/cv/3d_detection/yolov9/pytorch/utils/panoptic/dataloaders.py new file mode 100644 index 000000000..6f2b1d72b --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/utils/panoptic/dataloaders.py @@ -0,0 +1,478 @@ +import os +import random + +import pickle +from pathlib import Path + +from itertools import repeat +from multiprocessing.pool import Pool, ThreadPool + +import cv2 +import numpy as np +import torch +from torch.utils.data import DataLoader, distributed +from tqdm import tqdm + +from ..augmentations import augment_hsv +from ..dataloaders import InfiniteDataLoader, LoadImagesAndLabels, seed_worker, get_hash, verify_image_label, HELP_URL, TQDM_BAR_FORMAT, LOCAL_RANK +from ..general import NUM_THREADS, LOGGER, xyn2xy, xywhn2xyxy, xyxy2xywhn +from ..torch_utils import torch_distributed_zero_first +from ..coco_utils import annToMask, getCocoIds +from .augmentations import mixup, random_perspective, copy_paste, letterbox + +RANK = int(os.getenv('RANK', -1)) + + +def create_dataloader(path, + imgsz, + batch_size, + stride, + single_cls=False, + hyp=None, + augment=False, + cache=False, + pad=0.0, + rect=False, + rank=-1, + workers=8, + image_weights=False, + close_mosaic=False, + quad=False, + prefix='', + shuffle=False, + mask_downsample_ratio=1, + overlap_mask=False): + if rect and shuffle: + LOGGER.warning('WARNING ⚠️ --rect is incompatible with DataLoader shuffle, setting shuffle=False') + shuffle = False + with torch_distributed_zero_first(rank): # init dataset *.cache only once if DDP + dataset = LoadImagesAndLabelsAndMasks( + path, + imgsz, + batch_size, + augment=augment, # augmentation + hyp=hyp, # hyperparameters + rect=rect, # rectangular batches + cache_images=cache, + single_cls=single_cls, + stride=int(stride), + pad=pad, + image_weights=image_weights, + prefix=prefix, + downsample_ratio=mask_downsample_ratio, + overlap=overlap_mask) + + batch_size = min(batch_size, len(dataset)) + nd = torch.cuda.device_count() # number of CUDA devices + nw = min([os.cpu_count() // max(nd, 1), batch_size if batch_size > 1 else 0, workers]) # number of workers + sampler = None if rank == -1 else distributed.DistributedSampler(dataset, shuffle=shuffle) + #loader = DataLoader if image_weights else InfiniteDataLoader # only DataLoader allows for attribute updates + loader = DataLoader if image_weights or close_mosaic else InfiniteDataLoader + generator = torch.Generator() + generator.manual_seed(6148914691236517205 + RANK) + return loader( + dataset, + batch_size=batch_size, + shuffle=shuffle and sampler is None, + num_workers=nw, + sampler=sampler, + pin_memory=True, + collate_fn=LoadImagesAndLabelsAndMasks.collate_fn4 if quad else LoadImagesAndLabelsAndMasks.collate_fn, + worker_init_fn=seed_worker, + generator=generator, + ), dataset + +def img2stuff_paths(img_paths): + # Define label paths as a function of image paths + sa, sb = f'{os.sep}images{os.sep}', f'{os.sep}stuff{os.sep}' # /images/, /segmentations/ substrings + return [sb.join(x.rsplit(sa, 1)).rsplit('.', 1)[0] + '.txt' for x in img_paths] + + +class LoadImagesAndLabelsAndMasks(LoadImagesAndLabels): # for training/testing + + def __init__( + self, + path, + img_size=640, + batch_size=16, + augment=False, + hyp=None, + rect=False, + image_weights=False, + cache_images=False, + single_cls=False, + stride=32, + pad=0, + min_items=0, + prefix="", + downsample_ratio=1, + overlap=False, + ): + super().__init__( + path, + img_size, + batch_size, + augment, + hyp, + rect, + image_weights, + cache_images, + single_cls, + stride, + pad, + min_items, + prefix) + self.downsample_ratio = downsample_ratio + self.overlap = overlap + + # semantic segmentation + self.coco_ids = getCocoIds() + + # Check cache + self.seg_files = img2stuff_paths(self.im_files) # labels + p = Path(path) + cache_path = (p.with_suffix('') if p.is_file() else Path(self.seg_files[0]).parent) + cache_path = Path(str(cache_path) + '_stuff').with_suffix('.cache') + try: + cache, exists = np.load(cache_path, allow_pickle = True).item(), True # load dict + #assert cache['version'] == self.cache_version # matches current version + #assert cache['hash'] == get_hash(self.seg_files + self.im_files) # identical hash + except Exception: + cache, exists = self.cache_seg_labels(cache_path, prefix), False # run cache ops + + # Display cache + nf, nm, ne, nc, n = cache.pop('results') # found, missing, empty, corrupt, total + if exists and LOCAL_RANK in {-1, 0}: + d = f"Scanning '{cache_path}' images and labels... {nf} found, {nm} missing, {ne} empty, {nc} corrupt" + tqdm(None, desc = (prefix + d), total = n, initial = n, bar_format = TQDM_BAR_FORMAT) # display cache results + if cache['msgs']: + LOGGER.info('\n'.join(cache['msgs'])) # display warnings + assert (0 < nf) or (not augment), f'{prefix}No labels found in {cache_path}, can not start training. {HELP_URL}' + + # Read cache + [cache.pop(k) for k in ('hash', 'version', 'msgs')] # remove items + seg_labels, _, self.semantic_masks = zip(*cache.values()) + nl = len(np.concatenate(seg_labels, 0)) # number of labels + assert nl > 0 or not augment, f'{prefix}All labels empty in {cache_path}, can not start training. {HELP_URL}' + + # Update labels + self.seg_cls = [] + include_class = [] # filter labels to include only these classes (optional) + include_class_array = np.array(include_class).reshape(1, -1) + for i, (label, semantic_masks) in enumerate(zip(seg_labels, self.semantic_masks)): + self.seg_cls.append((label[:, 0].astype(int)).tolist()) + if include_class: + j = (label[:, 0:1] == include_class_array).any(1) + if semantic_masks: + self.semantic_masks[i] = semantic_masks[j] + if single_cls: # single-class training, merge all classes into 0 + if semantic_masks: + self.semantic_masks[i][:, 0] = 0 + + def __getitem__(self, index): + index = self.indices[index] # linear, shuffled, or image_weights + + hyp = self.hyp + mosaic = self.mosaic and random.random() < hyp['mosaic'] + masks = [] + if mosaic: + # Load mosaic + img, labels, segments, seg_cls, semantic_masks = self.load_mosaic(index) + shapes = None + + # MixUp augmentation + if random.random() < hyp["mixup"]: + img, labels, segments, seg_cls, semantic_masks = mixup(img, labels, segments, seg_cls, semantic_masks, + *self.load_mosaic(random.randint(0, self.n - 1))) + + else: + # Load image + img, (h0, w0), (h, w) = self.load_image(index) + + # Letterbox + shape = self.batch_shapes[self.batch[index]] if self.rect else self.img_size # final letterboxed shape + img, ratio, pad = letterbox(img, shape, auto=False, scaleup=self.augment) + shapes = (h0, w0), ((h / h0, w / w0), pad) # for COCO mAP rescaling + + labels = self.labels[index].copy() + # [array, array, ....], array.shape=(num_points, 2), xyxyxyxy + segments = self.segments[index].copy() + if len(segments): + for i_s in range(len(segments)): + segments[i_s] = xyn2xy( + segments[i_s], + ratio[0] * w, + ratio[1] * h, + padw=pad[0], + padh=pad[1], + ) + + seg_cls = self.seg_cls[index].copy() + semantic_masks = self.semantic_masks[index].copy() + #semantic_masks = [xyn2xy(x, ratio[0] * w, ratio[1] * h, padw = pad[0], padh = pad[1]) for x in semantic_masks] + if len(semantic_masks): + for ss in range(len(semantic_masks)): + semantic_masks[ss] = xyn2xy( + semantic_masks[ss], + ratio[0] * w, + ratio[1] * h, + padw = pad[0], + padh = pad[1], + ) + + if labels.size: # normalized xywh to pixel xyxy format + labels[:, 1:] = xywhn2xyxy(labels[:, 1:], ratio[0] * w, ratio[1] * h, padw=pad[0], padh=pad[1]) + + if self.augment: + img, labels, segments, semantic_masks = random_perspective( + img, + labels, + segments=segments, + semantic_masks = semantic_masks, + degrees=hyp["degrees"], + translate=hyp["translate"], + scale=hyp["scale"], + shear=hyp["shear"], + perspective=hyp["perspective"]) + + nl = len(labels) # number of labels + if nl: + labels[:, 1:5] = xyxy2xywhn(labels[:, 1:5], w=img.shape[1], h=img.shape[0], clip=True, eps=1e-3) + if self.overlap: + masks, sorted_idx = polygons2masks_overlap(img.shape[:2], + segments, + downsample_ratio=self.downsample_ratio) + masks = masks[None] # (640, 640) -> (1, 640, 640) + labels = labels[sorted_idx] + else: + masks = polygons2masks(img.shape[:2], segments, color=1, downsample_ratio=self.downsample_ratio) + + masks = (torch.from_numpy(masks) if len(masks) else torch.zeros(1 if self.overlap else nl, img.shape[0] // + self.downsample_ratio, img.shape[1] // + self.downsample_ratio)) + semantic_masks = polygons2masks(img.shape[:2], semantic_masks, color = 1, downsample_ratio=self.downsample_ratio) + #semantic_masks = polygons2masks(img.shape[:2], semantic_masks, color = 1, downsample_ratio=1) + semantic_masks = torch.from_numpy(semantic_masks) + # TODO: albumentations support + if self.augment: + # Albumentations + # there are some augmentation that won't change boxes and masks, + # so just be it for now. + img, labels = self.albumentations(img, labels) + nl = len(labels) # update after albumentations + ns = len(semantic_masks) + + # HSV color-space + augment_hsv(img, hgain=hyp["hsv_h"], sgain=hyp["hsv_s"], vgain=hyp["hsv_v"]) + + # Flip up-down + if random.random() < hyp["flipud"]: + img = np.flipud(img) + if nl: + labels[:, 2] = 1 - labels[:, 2] + masks = torch.flip(masks, dims=[1]) + if ns: + semantic_masks = torch.flip(semantic_masks, dims = [1]) + + # Flip left-right + if random.random() < hyp["fliplr"]: + img = np.fliplr(img) + if nl: + labels[:, 1] = 1 - labels[:, 1] + masks = torch.flip(masks, dims=[2]) + if ns: + semantic_masks = torch.flip(semantic_masks, dims = [2]) + + # Cutouts # labels = cutout(img, labels, p=0.5) + + labels_out = torch.zeros((nl, 6)) + if nl: + labels_out[:, 1:] = torch.from_numpy(labels) + + # Combine semantic masks + semantic_seg_masks = torch.zeros((len(self.coco_ids), img.shape[0] // self.downsample_ratio, + img.shape[1] // self.downsample_ratio), dtype = torch.uint8) + #semantic_seg_masks = torch.zeros((len(self.coco_ids), img.shape[0], img.shape[1]), dtype = torch.uint8) + for cls_id, semantic_mask in zip(seg_cls, semantic_masks): + semantic_seg_masks[cls_id] = (semantic_seg_masks[cls_id].logical_or(semantic_mask)).int() + + + # Convert + img = img.transpose((2, 0, 1))[::-1] # HWC to CHW, BGR to RGB + img = np.ascontiguousarray(img) + + return (torch.from_numpy(img), labels_out, self.im_files[index], shapes, masks, semantic_seg_masks) + + def load_mosaic(self, index): + # YOLO 4-mosaic loader. Loads 1 image + 3 random images into a 4-image mosaic + labels4, segments4, seg_cls, semantic_masks4 = [], [], [], [] + s = self.img_size + yc, xc = (int(random.uniform(-x, 2 * s + x)) for x in self.mosaic_border) # mosaic center x, y + + # 3 additional image indices + indices = [index] + random.choices(self.indices, k=3) # 3 additional image indices + for i, index in enumerate(indices): + # Load image + img, _, (h, w) = self.load_image(index) + + # place img in img4 + if i == 0: # top left + img4 = np.full((s * 2, s * 2, img.shape[2]), 114, dtype=np.uint8) # base image with 4 tiles + x1a, y1a, x2a, y2a = max(xc - w, 0), max(yc - h, 0), xc, yc # xmin, ymin, xmax, ymax (large image) + x1b, y1b, x2b, y2b = w - (x2a - x1a), h - (y2a - y1a), w, h # xmin, ymin, xmax, ymax (small image) + elif i == 1: # top right + x1a, y1a, x2a, y2a = xc, max(yc - h, 0), min(xc + w, s * 2), yc + x1b, y1b, x2b, y2b = 0, h - (y2a - y1a), min(w, x2a - x1a), h + elif i == 2: # bottom left + x1a, y1a, x2a, y2a = max(xc - w, 0), yc, xc, min(s * 2, yc + h) + x1b, y1b, x2b, y2b = w - (x2a - x1a), 0, w, min(y2a - y1a, h) + elif i == 3: # bottom right + x1a, y1a, x2a, y2a = xc, yc, min(xc + w, s * 2), min(s * 2, yc + h) + x1b, y1b, x2b, y2b = 0, 0, min(w, x2a - x1a), min(y2a - y1a, h) + + img4[y1a:y2a, x1a:x2a] = img[y1b:y2b, x1b:x2b] # img4[ymin:ymax, xmin:xmax] + padw = x1a - x1b + padh = y1a - y1b + + labels, segments, semantic_masks = self.labels[index].copy(), self.segments[index].copy(), self.semantic_masks[index].copy() + + if labels.size: + labels[:, 1:] = xywhn2xyxy(labels[:, 1:], w, h, padw, padh) # normalized xywh to pixel xyxy format + segments = [xyn2xy(x, w, h, padw, padh) for x in segments] + semantic_masks = [xyn2xy(x, w, h, padw, padh) for x in semantic_masks] + labels4.append(labels) + segments4.extend(segments) + seg_cls.extend(self.seg_cls[index].copy()) + semantic_masks4.extend(semantic_masks) + + # Concat/clip labels + labels4 = np.concatenate(labels4, 0) + for i in range(len(semantic_masks4)): + if i < len(segments4): + np.clip(labels4[:, 1:][i], 0, 2 * s, out = labels4[:, 1:][i]) + np.clip(segments4[i], 0, 2 * s, out = segments4[i]) + np.clip(semantic_masks4[i], 0, 2 * s, out = semantic_masks4[i]) + # img4, labels4 = replicate(img4, labels4) # replicate + + # 3 additional image indices + # Augment + img4, labels4, segments4, seg_cls, semantic_masks4 = copy_paste(img4, labels4, segments4, seg_cls, semantic_masks4, p=self.hyp["copy_paste"]) + img4, labels4, segments4, semantic_masks4 = random_perspective(img4, + labels4, + segments4, + semantic_masks4, + degrees=self.hyp["degrees"], + translate=self.hyp["translate"], + scale=self.hyp["scale"], + shear=self.hyp["shear"], + perspective=self.hyp["perspective"], + border=self.mosaic_border) # border to remove + + return img4, labels4, segments4, seg_cls, semantic_masks4 + + def cache_seg_labels(self, path = Path('./labels_stuff.cache'), prefix = ''): + # Cache dataset labels, check images and read shapes + x = {} # dict + nm, nf, ne, nc, msgs = 0, 0, 0, 0, [] # number missing, found, empty, corrupt, messages + desc = f"{prefix}Scanning '{path.parent / path.stem}' images and labels..." + with Pool(NUM_THREADS) as pool: + pbar = tqdm(pool.imap(verify_image_label, zip(self.im_files, self.seg_files, repeat(prefix))), + desc = desc, + total = len(self.im_files), + bar_format = TQDM_BAR_FORMAT) + for im_file, lb, shape, segments, nm_f, nf_f, ne_f, nc_f, msg in pbar: + nm += nm_f + nf += nf_f + ne += ne_f + nc += nc_f + if im_file: + x[im_file] = [lb, shape, segments] + if msg: + msgs.append(msg) + pbar.desc = f"{desc}{nf} found, {nm} missing, {ne} empty, {nc} corrupt" + + pbar.close() + if msgs: + LOGGER.info('\n'.join(msgs)) + if nf == 0: + LOGGER.warning(f'{prefix}WARNING: No labels found in {path}. {HELP_URL}') + x['hash'] = get_hash(self.seg_files + self.im_files) + x['results'] = nf, nm, ne, nc, len(self.im_files) + x['msgs'] = msgs # warnings + x['version'] = self.cache_version # cache version + try: + np.save(path, x) # save cache for next time + path.with_suffix('.cache.npy').rename(path) # remove .npy suffix + LOGGER.info(f'{prefix}New cache created: {path}') + except Exception as e: + LOGGER.warning(f'{prefix}WARNING: Cache directory {path.parent} is not writeable: {e}') # not writeable + return x + + @staticmethod + def collate_fn(batch): + img, label, path, shapes, masks, semantic_masks = zip(*batch) # transposed + batched_masks = torch.cat(masks, 0) + for i, l in enumerate(label): + l[:, 0] = i # add target image index for build_targets() + return torch.stack(img, 0), torch.cat(label, 0), path, shapes, batched_masks, torch.stack(semantic_masks, 0) + + + +def polygon2mask(img_size, polygons, color=1, downsample_ratio=1): + """ + Args: + img_size (tuple): The image size. + polygons (np.ndarray): [N, M], N is the number of polygons, + M is the number of points(Be divided by 2). + """ + mask = np.zeros(img_size, dtype=np.uint8) + polygons = np.asarray(polygons) + polygons = polygons.astype(np.int32) + shape = polygons.shape + polygons = polygons.reshape(shape[0], -1, 2) + cv2.fillPoly(mask, polygons, color=color) + nh, nw = (img_size[0] // downsample_ratio, img_size[1] // downsample_ratio) + # NOTE: fillPoly firstly then resize is trying the keep the same way + # of loss calculation when mask-ratio=1. + mask = cv2.resize(mask, (nw, nh)) + return mask + + +def polygons2masks(img_size, polygons, color, downsample_ratio=1): + """ + Args: + img_size (tuple): The image size. + polygons (list[np.ndarray]): each polygon is [N, M], + N is the number of polygons, + M is the number of points(Be divided by 2). + """ + masks = [] + for si in range(len(polygons)): + mask = polygon2mask(img_size, [polygons[si].reshape(-1)], color, downsample_ratio) + masks.append(mask) + return np.array(masks) + + +def polygons2masks_overlap(img_size, segments, downsample_ratio=1): + """Return a (640, 640) overlap mask.""" + masks = np.zeros((img_size[0] // downsample_ratio, img_size[1] // downsample_ratio), + dtype=np.int32 if len(segments) > 255 else np.uint8) + areas = [] + ms = [] + for si in range(len(segments)): + mask = polygon2mask( + img_size, + [segments[si].reshape(-1)], + downsample_ratio=downsample_ratio, + color=1, + ) + ms.append(mask) + areas.append(mask.sum()) + areas = np.asarray(areas) + index = np.argsort(-areas) + ms = np.array(ms)[index] + for i in range(len(segments)): + mask = ms[i] * (i + 1) + masks = masks + mask + masks = np.clip(masks, a_min=0, a_max=i + 1) + return masks, index diff --git a/cv/3d_detection/yolov9/pytorch/utils/panoptic/general.py b/cv/3d_detection/yolov9/pytorch/utils/panoptic/general.py new file mode 100644 index 000000000..b526333dc --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/utils/panoptic/general.py @@ -0,0 +1,137 @@ +import cv2 +import numpy as np +import torch +import torch.nn.functional as F + + +def crop_mask(masks, boxes): + """ + "Crop" predicted masks by zeroing out everything not in the predicted bbox. + Vectorized by Chong (thanks Chong). + + Args: + - masks should be a size [h, w, n] tensor of masks + - boxes should be a size [n, 4] tensor of bbox coords in relative point form + """ + + n, h, w = masks.shape + x1, y1, x2, y2 = torch.chunk(boxes[:, :, None], 4, 1) # x1 shape(1,1,n) + r = torch.arange(w, device=masks.device, dtype=x1.dtype)[None, None, :] # rows shape(1,w,1) + c = torch.arange(h, device=masks.device, dtype=x1.dtype)[None, :, None] # cols shape(h,1,1) + + return masks * ((r >= x1) * (r < x2) * (c >= y1) * (c < y2)) + + +def process_mask_upsample(protos, masks_in, bboxes, shape): + """ + Crop after upsample. + proto_out: [mask_dim, mask_h, mask_w] + out_masks: [n, mask_dim], n is number of masks after nms + bboxes: [n, 4], n is number of masks after nms + shape:input_image_size, (h, w) + + return: h, w, n + """ + + c, mh, mw = protos.shape # CHW + masks = (masks_in @ protos.float().view(c, -1)).sigmoid().view(-1, mh, mw) + masks = F.interpolate(masks[None], shape, mode='bilinear', align_corners=False)[0] # CHW + masks = crop_mask(masks, bboxes) # CHW + return masks.gt_(0.5) + + +def process_mask(protos, masks_in, bboxes, shape, upsample=False): + """ + Crop before upsample. + proto_out: [mask_dim, mask_h, mask_w] + out_masks: [n, mask_dim], n is number of masks after nms + bboxes: [n, 4], n is number of masks after nms + shape:input_image_size, (h, w) + + return: h, w, n + """ + + c, mh, mw = protos.shape # CHW + ih, iw = shape + masks = (masks_in @ protos.float().view(c, -1)).sigmoid().view(-1, mh, mw) # CHW + + downsampled_bboxes = bboxes.clone() + downsampled_bboxes[:, 0] *= mw / iw + downsampled_bboxes[:, 2] *= mw / iw + downsampled_bboxes[:, 3] *= mh / ih + downsampled_bboxes[:, 1] *= mh / ih + + masks = crop_mask(masks, downsampled_bboxes) # CHW + if upsample: + masks = F.interpolate(masks[None], shape, mode='bilinear', align_corners=False)[0] # CHW + return masks.gt_(0.5) + + +def scale_image(im1_shape, masks, im0_shape, ratio_pad=None): + """ + img1_shape: model input shape, [h, w] + img0_shape: origin pic shape, [h, w, 3] + masks: [h, w, num] + """ + # Rescale coordinates (xyxy) from im1_shape to im0_shape + if ratio_pad is None: # calculate from im0_shape + gain = min(im1_shape[0] / im0_shape[0], im1_shape[1] / im0_shape[1]) # gain = old / new + pad = (im1_shape[1] - im0_shape[1] * gain) / 2, (im1_shape[0] - im0_shape[0] * gain) / 2 # wh padding + else: + pad = ratio_pad[1] + top, left = int(pad[1]), int(pad[0]) # y, x + bottom, right = int(im1_shape[0] - pad[1]), int(im1_shape[1] - pad[0]) + + if len(masks.shape) < 2: + raise ValueError(f'"len of masks shape" should be 2 or 3, but got {len(masks.shape)}') + masks = masks[top:bottom, left:right] + # masks = masks.permute(2, 0, 1).contiguous() + # masks = F.interpolate(masks[None], im0_shape[:2], mode='bilinear', align_corners=False)[0] + # masks = masks.permute(1, 2, 0).contiguous() + masks = cv2.resize(masks, (im0_shape[1], im0_shape[0])) + + if len(masks.shape) == 2: + masks = masks[:, :, None] + return masks + + +def mask_iou(mask1, mask2, eps=1e-7): + """ + mask1: [N, n] m1 means number of predicted objects + mask2: [M, n] m2 means number of gt objects + Note: n means image_w x image_h + + return: masks iou, [N, M] + """ + intersection = torch.matmul(mask1, mask2.t()).clamp(0) + union = (mask1.sum(1)[:, None] + mask2.sum(1)[None]) - intersection # (area1 + area2) - intersection + return intersection / (union + eps) + + +def masks_iou(mask1, mask2, eps=1e-7): + """ + mask1: [N, n] m1 means number of predicted objects + mask2: [N, n] m2 means number of gt objects + Note: n means image_w x image_h + + return: masks iou, (N, ) + """ + intersection = (mask1 * mask2).sum(1).clamp(0) # (N, ) + union = (mask1.sum(1) + mask2.sum(1))[None] - intersection # (area1 + area2) - intersection + return intersection / (union + eps) + + +def masks2segments(masks, strategy='largest'): + # Convert masks(n,160,160) into segments(n,xy) + segments = [] + for x in masks.int().cpu().numpy().astype('uint8'): + c = cv2.findContours(x, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[0] + if c: + if strategy == 'concat': # concatenate all segments + c = np.concatenate([x.reshape(-1, 2) for x in c]) + elif strategy == 'largest': # select largest segment + c = np.array(c[np.array([len(x) for x in c]).argmax()]).reshape(-1, 2) + else: + c = np.zeros((0, 2)) # no segments found + segments.append(c.astype('float32')) + return segments diff --git a/cv/3d_detection/yolov9/pytorch/utils/panoptic/loss.py b/cv/3d_detection/yolov9/pytorch/utils/panoptic/loss.py new file mode 100644 index 000000000..b45b2c27e --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/utils/panoptic/loss.py @@ -0,0 +1,186 @@ +import torch +import torch.nn as nn +import torch.nn.functional as F + +from ..general import xywh2xyxy +from ..loss import FocalLoss, smooth_BCE +from ..metrics import bbox_iou +from ..torch_utils import de_parallel +from .general import crop_mask + + +class ComputeLoss: + # Compute losses + def __init__(self, model, autobalance=False, overlap=False): + self.sort_obj_iou = False + self.overlap = overlap + device = next(model.parameters()).device # get model device + h = model.hyp # hyperparameters + self.device = device + + # Define criteria + BCEcls = nn.BCEWithLogitsLoss(pos_weight=torch.tensor([h['cls_pw']], device=device)) + BCEobj = nn.BCEWithLogitsLoss(pos_weight=torch.tensor([h['obj_pw']], device=device)) + + # Class label smoothing https://arxiv.org/pdf/1902.04103.pdf eqn 3 + self.cp, self.cn = smooth_BCE(eps=h.get('label_smoothing', 0.0)) # positive, negative BCE targets + + # Focal loss + g = h['fl_gamma'] # focal loss gamma + if g > 0: + BCEcls, BCEobj = FocalLoss(BCEcls, g), FocalLoss(BCEobj, g) + + m = de_parallel(model).model[-1] # Detect() module + self.balance = {3: [4.0, 1.0, 0.4]}.get(m.nl, [4.0, 1.0, 0.25, 0.06, 0.02]) # P3-P7 + self.ssi = list(m.stride).index(16) if autobalance else 0 # stride 16 index + self.BCEcls, self.BCEobj, self.gr, self.hyp, self.autobalance = BCEcls, BCEobj, 1.0, h, autobalance + self.na = m.na # number of anchors + self.nc = m.nc # number of classes + self.nl = m.nl # number of layers + self.nm = m.nm # number of masks + self.anchors = m.anchors + self.device = device + + def __call__(self, preds, targets, masks): # predictions, targets, model + p, proto = preds + bs, nm, mask_h, mask_w = proto.shape # batch size, number of masks, mask height, mask width + lcls = torch.zeros(1, device=self.device) + lbox = torch.zeros(1, device=self.device) + lobj = torch.zeros(1, device=self.device) + lseg = torch.zeros(1, device=self.device) + tcls, tbox, indices, anchors, tidxs, xywhn = self.build_targets(p, targets) # targets + + # Losses + for i, pi in enumerate(p): # layer index, layer predictions + b, a, gj, gi = indices[i] # image, anchor, gridy, gridx + tobj = torch.zeros(pi.shape[:4], dtype=pi.dtype, device=self.device) # target obj + + n = b.shape[0] # number of targets + if n: + pxy, pwh, _, pcls, pmask = pi[b, a, gj, gi].split((2, 2, 1, self.nc, nm), 1) # subset of predictions + + # Box regression + pxy = pxy.sigmoid() * 2 - 0.5 + pwh = (pwh.sigmoid() * 2) ** 2 * anchors[i] + pbox = torch.cat((pxy, pwh), 1) # predicted box + iou = bbox_iou(pbox, tbox[i], CIoU=True).squeeze() # iou(prediction, target) + lbox += (1.0 - iou).mean() # iou loss + + # Objectness + iou = iou.detach().clamp(0).type(tobj.dtype) + if self.sort_obj_iou: + j = iou.argsort() + b, a, gj, gi, iou = b[j], a[j], gj[j], gi[j], iou[j] + if self.gr < 1: + iou = (1.0 - self.gr) + self.gr * iou + tobj[b, a, gj, gi] = iou # iou ratio + + # Classification + if self.nc > 1: # cls loss (only if multiple classes) + t = torch.full_like(pcls, self.cn, device=self.device) # targets + t[range(n), tcls[i]] = self.cp + lcls += self.BCEcls(pcls, t) # BCE + + # Mask regression + if tuple(masks.shape[-2:]) != (mask_h, mask_w): # downsample + masks = F.interpolate(masks[None], (mask_h, mask_w), mode="nearest")[0] + marea = xywhn[i][:, 2:].prod(1) # mask width, height normalized + mxyxy = xywh2xyxy(xywhn[i] * torch.tensor([mask_w, mask_h, mask_w, mask_h], device=self.device)) + for bi in b.unique(): + j = b == bi # matching index + if self.overlap: + mask_gti = torch.where(masks[bi][None] == tidxs[i][j].view(-1, 1, 1), 1.0, 0.0) + else: + mask_gti = masks[tidxs[i]][j] + lseg += self.single_mask_loss(mask_gti, pmask[j], proto[bi], mxyxy[j], marea[j]) + + obji = self.BCEobj(pi[..., 4], tobj) + lobj += obji * self.balance[i] # obj loss + if self.autobalance: + self.balance[i] = self.balance[i] * 0.9999 + 0.0001 / obji.detach().item() + + if self.autobalance: + self.balance = [x / self.balance[self.ssi] for x in self.balance] + lbox *= self.hyp["box"] + lobj *= self.hyp["obj"] + lcls *= self.hyp["cls"] + lseg *= self.hyp["box"] / bs + + loss = lbox + lobj + lcls + lseg + return loss * bs, torch.cat((lbox, lseg, lobj, lcls)).detach() + + def single_mask_loss(self, gt_mask, pred, proto, xyxy, area): + # Mask loss for one image + pred_mask = (pred @ proto.view(self.nm, -1)).view(-1, *proto.shape[1:]) # (n,32) @ (32,80,80) -> (n,80,80) + loss = F.binary_cross_entropy_with_logits(pred_mask, gt_mask, reduction="none") + return (crop_mask(loss, xyxy).mean(dim=(1, 2)) / area).mean() + + def build_targets(self, p, targets): + # Build targets for compute_loss(), input targets(image,class,x,y,w,h) + na, nt = self.na, targets.shape[0] # number of anchors, targets + tcls, tbox, indices, anch, tidxs, xywhn = [], [], [], [], [], [] + gain = torch.ones(8, device=self.device) # normalized to gridspace gain + ai = torch.arange(na, device=self.device).float().view(na, 1).repeat(1, nt) # same as .repeat_interleave(nt) + if self.overlap: + batch = p[0].shape[0] + ti = [] + for i in range(batch): + num = (targets[:, 0] == i).sum() # find number of targets of each image + ti.append(torch.arange(num, device=self.device).float().view(1, num).repeat(na, 1) + 1) # (na, num) + ti = torch.cat(ti, 1) # (na, nt) + else: + ti = torch.arange(nt, device=self.device).float().view(1, nt).repeat(na, 1) + targets = torch.cat((targets.repeat(na, 1, 1), ai[..., None], ti[..., None]), 2) # append anchor indices + + g = 0.5 # bias + off = torch.tensor( + [ + [0, 0], + [1, 0], + [0, 1], + [-1, 0], + [0, -1], # j,k,l,m + # [1, 1], [1, -1], [-1, 1], [-1, -1], # jk,jm,lk,lm + ], + device=self.device).float() * g # offsets + + for i in range(self.nl): + anchors, shape = self.anchors[i], p[i].shape + gain[2:6] = torch.tensor(shape)[[3, 2, 3, 2]] # xyxy gain + + # Match targets to anchors + t = targets * gain # shape(3,n,7) + if nt: + # Matches + r = t[..., 4:6] / anchors[:, None] # wh ratio + j = torch.max(r, 1 / r).max(2)[0] < self.hyp['anchor_t'] # compare + # j = wh_iou(anchors, t[:, 4:6]) > model.hyp['iou_t'] # iou(3,n)=wh_iou(anchors(3,2), gwh(n,2)) + t = t[j] # filter + + # Offsets + gxy = t[:, 2:4] # grid xy + gxi = gain[[2, 3]] - gxy # inverse + j, k = ((gxy % 1 < g) & (gxy > 1)).T + l, m = ((gxi % 1 < g) & (gxi > 1)).T + j = torch.stack((torch.ones_like(j), j, k, l, m)) + t = t.repeat((5, 1, 1))[j] + offsets = (torch.zeros_like(gxy)[None] + off[:, None])[j] + else: + t = targets[0] + offsets = 0 + + # Define + bc, gxy, gwh, at = t.chunk(4, 1) # (image, class), grid xy, grid wh, anchors + (a, tidx), (b, c) = at.long().T, bc.long().T # anchors, image, class + gij = (gxy - offsets).long() + gi, gj = gij.T # grid indices + + # Append + indices.append((b, a, gj.clamp_(0, shape[2] - 1), gi.clamp_(0, shape[3] - 1))) # image, anchor, grid + tbox.append(torch.cat((gxy - gij, gwh), 1)) # box + anch.append(anchors[a]) # anchors + tcls.append(c) # class + tidxs.append(tidx) + xywhn.append(torch.cat((gxy, gwh), 1) / gain[2:6]) # xywh normalized + + return tcls, tbox, indices, anch, tidxs, xywhn diff --git a/cv/3d_detection/yolov9/pytorch/utils/panoptic/loss_tal.py b/cv/3d_detection/yolov9/pytorch/utils/panoptic/loss_tal.py new file mode 100644 index 000000000..d8594395d --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/utils/panoptic/loss_tal.py @@ -0,0 +1,285 @@ +import os + +import torch +import torch.nn as nn +import torch.nn.functional as F + +from torchvision.ops import sigmoid_focal_loss + +from utils.general import xywh2xyxy, xyxy2xywh +from utils.metrics import bbox_iou +from utils.panoptic.tal.anchor_generator import dist2bbox, make_anchors, bbox2dist +from utils.panoptic.tal.assigner import TaskAlignedAssigner +from utils.torch_utils import de_parallel +from utils.panoptic.general import crop_mask + + +def smooth_BCE(eps=0.1): # https://github.com/ultralytics/yolov3/issues/238#issuecomment-598028441 + # return positive, negative label smoothing BCE targets + return 1.0 - 0.5 * eps, 0.5 * eps + + +class VarifocalLoss(nn.Module): + # Varifocal loss by Zhang et al. https://arxiv.org/abs/2008.13367 + def __init__(self): + super().__init__() + + def forward(self, pred_score, gt_score, label, alpha=0.75, gamma=2.0): + weight = alpha * pred_score.sigmoid().pow(gamma) * (1 - label) + gt_score * label + with torch.cuda.amp.autocast(enabled=False): + loss = (F.binary_cross_entropy_with_logits(pred_score.float(), gt_score.float(), + reduction="none") * weight).sum() + return loss + + +class FocalLoss(nn.Module): + # Wraps focal loss around existing loss_fcn(), i.e. criteria = FocalLoss(nn.BCEWithLogitsLoss(), gamma=1.5) + def __init__(self, loss_fcn, gamma=1.5, alpha=0.25): + super().__init__() + self.loss_fcn = loss_fcn # must be nn.BCEWithLogitsLoss() + self.gamma = gamma + self.alpha = alpha + self.reduction = loss_fcn.reduction + self.loss_fcn.reduction = "none" # required to apply FL to each element + + def forward(self, pred, true): + loss = self.loss_fcn(pred, true) + # p_t = torch.exp(-loss) + # loss *= self.alpha * (1.000001 - p_t) ** self.gamma # non-zero power for gradient stability + + # TF implementation https://github.com/tensorflow/addons/blob/v0.7.1/tensorflow_addons/losses/focal_loss.py + pred_prob = torch.sigmoid(pred) # prob from logits + p_t = true * pred_prob + (1 - true) * (1 - pred_prob) + alpha_factor = true * self.alpha + (1 - true) * (1 - self.alpha) + modulating_factor = (1.0 - p_t) ** self.gamma + loss *= alpha_factor * modulating_factor + + if self.reduction == "mean": + return loss.mean() + elif self.reduction == "sum": + return loss.sum() + else: # 'none' + return loss + + +class BboxLoss(nn.Module): + def __init__(self, reg_max, use_dfl=False): + super().__init__() + self.reg_max = reg_max + self.use_dfl = use_dfl + + def forward(self, pred_dist, pred_bboxes, anchor_points, target_bboxes, target_scores, target_scores_sum, fg_mask): + # iou loss + bbox_mask = fg_mask.unsqueeze(-1).repeat([1, 1, 4]) # (b, h*w, 4) + pred_bboxes_pos = torch.masked_select(pred_bboxes, bbox_mask).view(-1, 4) + target_bboxes_pos = torch.masked_select(target_bboxes, bbox_mask).view(-1, 4) + bbox_weight = torch.masked_select(target_scores.sum(-1), fg_mask).unsqueeze(-1) + + iou = bbox_iou(pred_bboxes_pos, target_bboxes_pos, xywh=False, CIoU=True) + loss_iou = 1.0 - iou + + #### wiou + #iou = bbox_iou(pred_bboxes_pos, target_bboxes_pos, xywh=False, WIoU=True, scale=True) + #if type(iou) is tuple: + # if len(iou) == 2: + # loss_iou = (iou[1].detach() * (1 - iou[0])) + # iou = iou[0] + # else: + # loss_iou = (iou[0] * iou[1]) + # iou = iou[-1] + #else: + # loss_iou = (1.0 - iou) # iou loss + + loss_iou *= bbox_weight + loss_iou = loss_iou.sum() / target_scores_sum + # loss_iou = loss_iou.mean() + + # dfl loss + if self.use_dfl: + dist_mask = fg_mask.unsqueeze(-1).repeat([1, 1, (self.reg_max + 1) * 4]) + pred_dist_pos = torch.masked_select(pred_dist, dist_mask).view(-1, 4, self.reg_max + 1) + target_ltrb = bbox2dist(anchor_points, target_bboxes, self.reg_max) + target_ltrb_pos = torch.masked_select(target_ltrb, bbox_mask).view(-1, 4) + loss_dfl = self._df_loss(pred_dist_pos, target_ltrb_pos) * bbox_weight + loss_dfl = loss_dfl.sum() / target_scores_sum + else: + loss_dfl = torch.tensor(0.0).to(pred_dist.device) + + return loss_iou, loss_dfl, iou + + def _df_loss(self, pred_dist, target): + target_left = target.to(torch.long) + target_right = target_left + 1 + weight_left = target_right.to(torch.float) - target + weight_right = 1 - weight_left + loss_left = F.cross_entropy(pred_dist.view(-1, self.reg_max + 1), target_left.view(-1), reduction="none").view( + target_left.shape) * weight_left + loss_right = F.cross_entropy(pred_dist.view(-1, self.reg_max + 1), target_right.view(-1), + reduction="none").view(target_left.shape) * weight_right + return (loss_left + loss_right).mean(-1, keepdim=True) + + +class ComputeLoss: + # Compute losses + def __init__(self, model, use_dfl=True, overlap=True): + device = next(model.parameters()).device # get model device + h = model.hyp # hyperparameters + + # Define criteria + BCEcls = nn.BCEWithLogitsLoss(pos_weight=torch.tensor([h["cls_pw"]], device=device), reduction='none') + + # Class label smoothing https://arxiv.org/pdf/1902.04103.pdf eqn 3 + self.cp, self.cn = smooth_BCE(eps=h.get("label_smoothing", 0.0)) # positive, negative BCE targets + + # Focal loss + g = h["fl_gamma"] # focal loss gamma + if g > 0: + BCEcls = FocalLoss(BCEcls, g) + + m = de_parallel(model).model[-1] # Detect() module + self.balance = {3: [4.0, 1.0, 0.4]}.get(m.nl, [4.0, 1.0, 0.25, 0.06, 0.02]) # P3-P7 + self.BCEcls = BCEcls + self.hyp = h + self.stride = m.stride # model strides + self.nc = m.nc # number of classes + self.nl = m.nl # number of layers + self.no = m.no + self.nm = m.nm + self.overlap = overlap + self.reg_max = m.reg_max + self.device = device + + self.assigner = TaskAlignedAssigner(topk=int(os.getenv('YOLOM', 10)), + num_classes=self.nc, + alpha=float(os.getenv('YOLOA', 0.5)), + beta=float(os.getenv('YOLOB', 6.0))) + self.bbox_loss = BboxLoss(m.reg_max - 1, use_dfl=use_dfl).to(device) + self.proj = torch.arange(m.reg_max).float().to(device) # / 120.0 + self.use_dfl = use_dfl + + def preprocess(self, targets, batch_size, scale_tensor): + if targets.shape[0] == 0: + out = torch.zeros(batch_size, 0, 5, device=self.device) + else: + i = targets[:, 0] # image index + _, counts = i.unique(return_counts=True) + out = torch.zeros(batch_size, counts.max(), 5, device=self.device) + for j in range(batch_size): + matches = i == j + n = matches.sum() + if n: + out[j, :n] = targets[matches, 1:] + out[..., 1:5] = xywh2xyxy(out[..., 1:5].mul_(scale_tensor)) + return out + + def bbox_decode(self, anchor_points, pred_dist): + if self.use_dfl: + b, a, c = pred_dist.shape # batch, anchors, channels + pred_dist = pred_dist.view(b, a, 4, c // 4).softmax(3).matmul(self.proj.type(pred_dist.dtype)) + # pred_dist = pred_dist.view(b, a, c // 4, 4).transpose(2,3).softmax(3).matmul(self.proj.type(pred_dist.dtype)) + # pred_dist = (pred_dist.view(b, a, c // 4, 4).softmax(2) * self.proj.type(pred_dist.dtype).view(1, 1, -1, 1)).sum(2) + return dist2bbox(pred_dist, anchor_points, xywh=False) + + def __call__(self, p, targets, masks, semasks, img=None, epoch=0): + loss = torch.zeros(6, device=self.device) # box, cls, dfl + feats, pred_masks, proto, psemasks = p if len(p) == 4 else p[1] + batch_size, _, mask_h, mask_w = proto.shape + pred_distri, pred_scores = torch.cat([xi.view(feats[0].shape[0], self.no, -1) for xi in feats], 2).split( + (self.reg_max * 4, self.nc), 1) + pred_scores = pred_scores.permute(0, 2, 1).contiguous() + pred_distri = pred_distri.permute(0, 2, 1).contiguous() + pred_masks = pred_masks.permute(0, 2, 1).contiguous() + + dtype = pred_scores.dtype + batch_size, grid_size = pred_scores.shape[:2] + imgsz = torch.tensor(feats[0].shape[2:], device=self.device, dtype=dtype) * self.stride[0] # image size (h,w) + anchor_points, stride_tensor = make_anchors(feats, self.stride, 0.5) + + # targets + try: + batch_idx = targets[:, 0].view(-1, 1) + targets = self.preprocess(targets.to(self.device), batch_size, scale_tensor=imgsz[[1, 0, 1, 0]]) + gt_labels, gt_bboxes = targets.split((1, 4), 2) # cls, xyxy + mask_gt = gt_bboxes.sum(2, keepdim=True).gt_(0) + except RuntimeError as e: + raise TypeError('ERROR.') from e + + + # pboxes + pred_bboxes = self.bbox_decode(anchor_points, pred_distri) # xyxy, (b, h*w, 4) + + target_labels, target_bboxes, target_scores, fg_mask, target_gt_idx = self.assigner( + pred_scores.detach().sigmoid(), + (pred_bboxes.detach() * stride_tensor).type(gt_bboxes.dtype), + anchor_points * stride_tensor, + gt_labels, + gt_bboxes, + mask_gt) + + target_scores_sum = target_scores.sum() + + # cls loss + # loss[1] = self.varifocal_loss(pred_scores, target_scores, target_labels) / target_scores_sum # VFL way + loss[2] = self.BCEcls(pred_scores, target_scores.to(dtype)).sum() / target_scores_sum # BCE + + # bbox loss + if fg_mask.sum(): + loss[0], loss[3], _ = self.bbox_loss(pred_distri, + pred_bboxes, + anchor_points, + target_bboxes / stride_tensor, + target_scores, + target_scores_sum, + fg_mask) + + # masks loss + if tuple(masks.shape[-2:]) != (mask_h, mask_w): # downsample + masks = F.interpolate(masks[None], (mask_h, mask_w), mode='nearest')[0] + + for i in range(batch_size): + if fg_mask[i].sum(): + mask_idx = target_gt_idx[i][fg_mask[i]] + if self.overlap: + gt_mask = torch.where(masks[[i]] == (mask_idx + 1).view(-1, 1, 1), 1.0, 0.0) + else: + gt_mask = masks[batch_idx.view(-1) == i][mask_idx] + xyxyn = target_bboxes[i][fg_mask[i]] / imgsz[[1, 0, 1, 0]] + marea = xyxy2xywh(xyxyn)[:, 2:].prod(1) + mxyxy = xyxyn * torch.tensor([mask_w, mask_h, mask_w, mask_h], device=self.device) + loss[1] += self.single_mask_loss(gt_mask, pred_masks[i][fg_mask[i]], proto[i], mxyxy, + marea) # seg loss + # Semantic Segmentation + # focal loss + pt = torch.flatten(psemasks, start_dim = 2).permute(0, 2, 1) + gt = torch.flatten(semasks, start_dim = 2).permute(0, 2, 1) + + bs, _, _ = gt.shape + #torch.clamp(torch.sigmoid(logits), min=eps, max= 1 - eps) + #total_loss = (sigmoid_focal_loss(pt.float(), gt.float(), alpha = .25, gamma = 2., reduction = 'mean')) / 2. + #total_loss = (sigmoid_focal_loss(pt.clamp(-16., 16.), gt, alpha = .25, gamma = 2., reduction = 'mean')) / 2. + total_loss = (sigmoid_focal_loss(pt, gt, alpha = .25, gamma = 2., reduction = 'mean')) / 2. + loss[4] += total_loss * 20. + + # dice loss + pt = torch.flatten(psemasks.softmax(dim = 1)) + gt = torch.flatten(semasks) + + inter_mask = torch.sum(torch.mul(pt, gt)) + union_mask = torch.sum(torch.add(pt, gt)) + dice_coef = (2. * inter_mask + 1.) / (union_mask + 1.) + loss[5] += (1. - dice_coef) / 2. + + loss[0] *= 7.5 # box gain + loss[1] *= 2.5 / batch_size + loss[2] *= 0.5 # cls gain + loss[3] *= 1.5 # dfl gain + loss[4] *= 2.5 #/ batch_size + loss[5] *= 2.5 #/ batch_size + + return loss.sum() * batch_size, loss.detach() # loss(box, cls, dfl) + + def single_mask_loss(self, gt_mask, pred, proto, xyxy, area): + # Mask loss for one image + pred_mask = (pred @ proto.view(self.nm, -1)).view(-1, *proto.shape[1:]) # (n, 32) @ (32,80,80) -> (n,80,80) + loss = F.binary_cross_entropy_with_logits(pred_mask, gt_mask, reduction='none') + return (crop_mask(loss, xyxy).mean(dim=(1, 2)) / area).mean() diff --git a/cv/3d_detection/yolov9/pytorch/utils/panoptic/metrics.py b/cv/3d_detection/yolov9/pytorch/utils/panoptic/metrics.py new file mode 100644 index 000000000..dcb8bc2d6 --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/utils/panoptic/metrics.py @@ -0,0 +1,272 @@ +import numpy as np +import torch + +from ..metrics import ap_per_class + + +def fitness(x): + # Model fitness as a weighted combination of metrics + w = [0.0, 0.0, 0.1, 0.9, 0.0, 0.0, 0.1, 0.9, 0.1, 0.9] + return (x[:, :len(w)] * w).sum(1) + + +def ap_per_class_box_and_mask( + tp_m, + tp_b, + conf, + pred_cls, + target_cls, + plot=False, + save_dir=".", + names=(), +): + """ + Args: + tp_b: tp of boxes. + tp_m: tp of masks. + other arguments see `func: ap_per_class`. + """ + results_boxes = ap_per_class(tp_b, + conf, + pred_cls, + target_cls, + plot=plot, + save_dir=save_dir, + names=names, + prefix="Box")[2:] + results_masks = ap_per_class(tp_m, + conf, + pred_cls, + target_cls, + plot=plot, + save_dir=save_dir, + names=names, + prefix="Mask")[2:] + + results = { + "boxes": { + "p": results_boxes[0], + "r": results_boxes[1], + "ap": results_boxes[3], + "f1": results_boxes[2], + "ap_class": results_boxes[4]}, + "masks": { + "p": results_masks[0], + "r": results_masks[1], + "ap": results_masks[3], + "f1": results_masks[2], + "ap_class": results_masks[4]}} + return results + + +class Metric: + + def __init__(self) -> None: + self.p = [] # (nc, ) + self.r = [] # (nc, ) + self.f1 = [] # (nc, ) + self.all_ap = [] # (nc, 10) + self.ap_class_index = [] # (nc, ) + + @property + def ap50(self): + """AP@0.5 of all classes. + Return: + (nc, ) or []. + """ + return self.all_ap[:, 0] if len(self.all_ap) else [] + + @property + def ap(self): + """AP@0.5:0.95 + Return: + (nc, ) or []. + """ + return self.all_ap.mean(1) if len(self.all_ap) else [] + + @property + def mp(self): + """mean precision of all classes. + Return: + float. + """ + return self.p.mean() if len(self.p) else 0.0 + + @property + def mr(self): + """mean recall of all classes. + Return: + float. + """ + return self.r.mean() if len(self.r) else 0.0 + + @property + def map50(self): + """Mean AP@0.5 of all classes. + Return: + float. + """ + return self.all_ap[:, 0].mean() if len(self.all_ap) else 0.0 + + @property + def map(self): + """Mean AP@0.5:0.95 of all classes. + Return: + float. + """ + return self.all_ap.mean() if len(self.all_ap) else 0.0 + + def mean_results(self): + """Mean of results, return mp, mr, map50, map""" + return (self.mp, self.mr, self.map50, self.map) + + def class_result(self, i): + """class-aware result, return p[i], r[i], ap50[i], ap[i]""" + return (self.p[i], self.r[i], self.ap50[i], self.ap[i]) + + def get_maps(self, nc): + maps = np.zeros(nc) + self.map + for i, c in enumerate(self.ap_class_index): + maps[c] = self.ap[i] + return maps + + def update(self, results): + """ + Args: + results: tuple(p, r, ap, f1, ap_class) + """ + p, r, all_ap, f1, ap_class_index = results + self.p = p + self.r = r + self.all_ap = all_ap + self.f1 = f1 + self.ap_class_index = ap_class_index + + +class Metrics: + """Metric for boxes and masks.""" + + def __init__(self) -> None: + self.metric_box = Metric() + self.metric_mask = Metric() + + def update(self, results): + """ + Args: + results: Dict{'boxes': Dict{}, 'masks': Dict{}} + """ + self.metric_box.update(list(results["boxes"].values())) + self.metric_mask.update(list(results["masks"].values())) + + def mean_results(self): + return self.metric_box.mean_results() + self.metric_mask.mean_results() + + def class_result(self, i): + return self.metric_box.class_result(i) + self.metric_mask.class_result(i) + + def get_maps(self, nc): + return self.metric_box.get_maps(nc) + self.metric_mask.get_maps(nc) + + @property + def ap_class_index(self): + # boxes and masks have the same ap_class_index + return self.metric_box.ap_class_index + + +class Semantic_Metrics: + def __init__(self, nc, device): + self.nc = nc # number of classes + self.device = device + self.iou = [] + self.c_bit_counts = torch.zeros(nc, dtype = torch.long).to(device) + self.c_intersection_counts = torch.zeros(nc, dtype = torch.long).to(device) + self.c_union_counts = torch.zeros(nc, dtype = torch.long).to(device) + + def update(self, pred_masks, target_masks): + nb, nc, h, w = pred_masks.shape + device = pred_masks.device + + for b in range(nb): + onehot_mask = pred_masks[b].to(device) + # convert predict mask to one hot + semantic_mask = torch.flatten(onehot_mask, start_dim = 1).permute(1, 0) # class x h x w -> (h x w) x class + max_idx = semantic_mask.argmax(1) + output_masks = (torch.zeros(semantic_mask.shape).to(self.device)).scatter(1, max_idx.unsqueeze(1), 1.0) # one hot: (h x w) x class + output_masks = torch.reshape(output_masks.permute(1, 0), (nc, h, w)) # (h x w) x class -> class x h x w + onehot_mask = output_masks.int() + + for c in range(self.nc): + pred_mask = onehot_mask[c].to(device) + target_mask = target_masks[b, c].to(device) + + # calculate IoU + intersection = (torch.logical_and(pred_mask, target_mask).sum()).item() + union = (torch.logical_or(pred_mask, target_mask).sum()).item() + iou = 0. if (0 == union) else (intersection / union) + + # record class pixel counts, intersection counts, union counts + self.c_bit_counts[c] += target_mask.int().sum() + self.c_intersection_counts[c] += intersection + self.c_union_counts[c] += union + + self.iou.append(iou) + + def results(self): + # Mean IoU + miou = 0. if (0 == len(self.iou)) else np.sum(self.iou) / (len(self.iou) * self.nc) + + # Frequency Weighted IoU + c_iou = self.c_intersection_counts / (self.c_union_counts + 1) # add smooth + # c_bit_counts = self.c_bit_counts.astype(int) + total_c_bit_counts = self.c_bit_counts.sum() + freq_ious = torch.zeros(1, dtype = torch.long).to(self.device) if (0 == total_c_bit_counts) else (self.c_bit_counts / total_c_bit_counts) * c_iou + fwiou = (freq_ious.sum()).item() + + return (miou, fwiou) + + def reset(self): + self.iou = [] + self.c_bit_counts = torch.zeros(self.nc, dtype = torch.long).to(self.device) + self.c_intersection_counts = torch.zeros(self.nc, dtype = torch.long).to(self.device) + self.c_union_counts = torch.zeros(self.nc, dtype = torch.long).to(self.device) + + +KEYS = [ + "train/box_loss", + "train/seg_loss", # train loss + "train/cls_loss", + "train/dfl_loss", + "train/fcl_loss", + "train/dic_loss", + "metrics/precision(B)", + "metrics/recall(B)", + "metrics/mAP_0.5(B)", + "metrics/mAP_0.5:0.95(B)", # metrics + "metrics/precision(M)", + "metrics/recall(M)", + "metrics/mAP_0.5(M)", + "metrics/mAP_0.5:0.95(M)", # metrics + "metrics/MIOUS(S)", + "metrics/FWIOUS(S)", # metrics + "val/box_loss", + "val/seg_loss", # val loss + "val/cls_loss", + "val/dfl_loss", + "val/fcl_loss", + "val/dic_loss", + "x/lr0", + "x/lr1", + "x/lr2",] + +BEST_KEYS = [ + "best/epoch", + "best/precision(B)", + "best/recall(B)", + "best/mAP_0.5(B)", + "best/mAP_0.5:0.95(B)", + "best/precision(M)", + "best/recall(M)", + "best/mAP_0.5(M)", + "best/mAP_0.5:0.95(M)", + "best/MIOUS(S)", + "best/FWIOUS(S)",] diff --git a/cv/3d_detection/yolov9/pytorch/utils/panoptic/plots.py b/cv/3d_detection/yolov9/pytorch/utils/panoptic/plots.py new file mode 100644 index 000000000..55d87b795 --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/utils/panoptic/plots.py @@ -0,0 +1,164 @@ +import contextlib +import math +from pathlib import Path + +import cv2 +import matplotlib.pyplot as plt +import numpy as np +import pandas as pd +import torch +from torchvision.utils import draw_segmentation_masks, save_image + +from .. import threaded +from ..general import xywh2xyxy +from ..plots import Annotator, colors + + +@threaded +def plot_images_and_masks(images, targets, masks, semasks, paths=None, fname='images.jpg', names=None): + + try: + if images.shape[-2:] != semasks.shape[-2:]: + m = torch.nn.Upsample(scale_factor=4, mode='nearest') + semasks = m(semasks) + + for idx in range(images.shape[0]): + output_img = draw_segmentation_masks( + image = images[idx, :, :, :].cpu().to(dtype = torch.uint8), + masks = semasks[idx, :, :, :].cpu().to(dtype = torch.bool), + alpha = 1) + cv2.imwrite( + '{}_{}.jpg'.format(fname, idx), + torch.permute(output_img, (1, 2, 0)).numpy() + ) + except: + pass + + # Plot image grid with labels + if isinstance(images, torch.Tensor): + images = images.cpu().float().numpy() + if isinstance(targets, torch.Tensor): + targets = targets.cpu().numpy() + if isinstance(masks, torch.Tensor): + masks = masks.cpu().numpy().astype(int) + if isinstance(semasks, torch.Tensor): + semasks = semasks.cpu().numpy().astype(int) + + max_size = 1920 # max image size + max_subplots = 16 # max image subplots, i.e. 4x4 + bs, _, h, w = images.shape # batch size, _, height, width + bs = min(bs, max_subplots) # limit plot images + ns = np.ceil(bs ** 0.5) # number of subplots (square) + if np.max(images[0]) <= 1: + images *= 255 # de-normalise (optional) + + # Build Image + mosaic = np.full((int(ns * h), int(ns * w), 3), 255, dtype=np.uint8) # init + for i, im in enumerate(images): + if i == max_subplots: # if last batch has fewer images than we expect + break + x, y = int(w * (i // ns)), int(h * (i % ns)) # block origin + im = im.transpose(1, 2, 0) + mosaic[y:y + h, x:x + w, :] = im + + # Resize (optional) + scale = max_size / ns / max(h, w) + if scale < 1: + h = math.ceil(scale * h) + w = math.ceil(scale * w) + mosaic = cv2.resize(mosaic, tuple(int(x * ns) for x in (w, h))) + + # Annotate + fs = int((h + w) * ns * 0.01) # font size + annotator = Annotator(mosaic, line_width=round(fs / 10), font_size=fs, pil=True, example=names) + for i in range(i + 1): + x, y = int(w * (i // ns)), int(h * (i % ns)) # block origin + annotator.rectangle([x, y, x + w, y + h], None, (255, 255, 255), width=2) # borders + if paths: + annotator.text((x + 5, y + 5 + h), text=Path(paths[i]).name[:40], txt_color=(220, 220, 220)) # filenames + if len(targets) > 0: + idx = targets[:, 0] == i + ti = targets[idx] # image targets + + boxes = xywh2xyxy(ti[:, 2:6]).T + classes = ti[:, 1].astype('int') + labels = ti.shape[1] == 6 # labels if no conf column + conf = None if labels else ti[:, 6] # check for confidence presence (label vs pred) + + if boxes.shape[1]: + if boxes.max() <= 1.01: # if normalized with tolerance 0.01 + boxes[[0, 2]] *= w # scale to pixels + boxes[[1, 3]] *= h + elif scale < 1: # absolute coords need scale if image scales + boxes *= scale + boxes[[0, 2]] += x + boxes[[1, 3]] += y + for j, box in enumerate(boxes.T.tolist()): + cls = classes[j] + color = colors(cls) + cls = names[cls] if names else cls + if labels or conf[j] > 0.25: # 0.25 conf thresh + label = f'{cls}' if labels else f'{cls} {conf[j]:.1f}' + annotator.box_label(box, label, color=color) + + # Plot masks + if len(masks): + if masks.max() > 1.0: # mean that masks are overlap + image_masks = masks[[i]] # (1, 640, 640) + nl = len(ti) + index = np.arange(nl).reshape(nl, 1, 1) + 1 + image_masks = np.repeat(image_masks, nl, axis=0) + image_masks = np.where(image_masks == index, 1.0, 0.0) + else: + image_masks = masks[idx] + + im = np.asarray(annotator.im).copy() + for j, box in enumerate(boxes.T.tolist()): + if labels or conf[j] > 0.25: # 0.25 conf thresh + color = colors(classes[j]) + mh, mw = image_masks[j].shape + if mh != h or mw != w: + mask = image_masks[j].astype(np.uint8) + mask = cv2.resize(mask, (w, h)) + mask = mask.astype(bool) + else: + mask = image_masks[j].astype(bool) + with contextlib.suppress(Exception): + im[y:y + h, x:x + w, :][mask] = im[y:y + h, x:x + w, :][mask] * 0.4 + np.array(color) * 0.6 + annotator.fromarray(im) + annotator.im.save(fname) # save + + +def plot_results_with_masks(file="path/to/results.csv", dir="", best=True): + # Plot training results.csv. Usage: from utils.plots import *; plot_results('path/to/results.csv') + save_dir = Path(file).parent if file else Path(dir) + fig, ax = plt.subplots(2, 8, figsize=(18, 6), tight_layout=True) + ax = ax.ravel() + files = list(save_dir.glob("results*.csv")) + assert len(files), f"No results.csv files found in {save_dir.resolve()}, nothing to plot." + for f in files: + try: + data = pd.read_csv(f) + index = np.argmax(0.9 * data.values[:, 8] + 0.1 * data.values[:, 7] + 0.9 * data.values[:, 12] + + 0.1 * data.values[:, 11]) + s = [x.strip() for x in data.columns] + x = data.values[:, 0] + for i, j in enumerate([1, 2, 3, 4, 5, 6, 9, 10, 13, 14, 15, 16, 7, 8, 11, 12]): + y = data.values[:, j] + # y[y == 0] = np.nan # don't show zero values + ax[i].plot(x, y, marker=".", label=f.stem, linewidth=2, markersize=2) + if best: + # best + ax[i].scatter(index, y[index], color="r", label=f"best:{index}", marker="*", linewidth=3) + ax[i].set_title(s[j] + f"\n{round(y[index], 5)}") + else: + # last + ax[i].scatter(x[-1], y[-1], color="r", label="last", marker="*", linewidth=3) + ax[i].set_title(s[j] + f"\n{round(y[-1], 5)}") + # if j in [8, 9, 10]: # share train and val loss y axes + # ax[i].get_shared_y_axes().join(ax[i], ax[i - 5]) + except Exception as e: + print(f"Warning: Plotting error for {f}: {e}") + ax[1].legend() + fig.savefig(save_dir / "results.png", dpi=200) + plt.close() diff --git a/cv/3d_detection/yolov9/pytorch/utils/panoptic/tal/__init__.py b/cv/3d_detection/yolov9/pytorch/utils/panoptic/tal/__init__.py new file mode 100644 index 000000000..84952a816 --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/utils/panoptic/tal/__init__.py @@ -0,0 +1 @@ +# init \ No newline at end of file diff --git a/cv/3d_detection/yolov9/pytorch/utils/panoptic/tal/anchor_generator.py b/cv/3d_detection/yolov9/pytorch/utils/panoptic/tal/anchor_generator.py new file mode 100644 index 000000000..0de163651 --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/utils/panoptic/tal/anchor_generator.py @@ -0,0 +1,38 @@ +import torch + +from utils.general import check_version + +TORCH_1_10 = check_version(torch.__version__, '1.10.0') + + +def make_anchors(feats, strides, grid_cell_offset=0.5): + """Generate anchors from features.""" + anchor_points, stride_tensor = [], [] + assert feats is not None + dtype, device = feats[0].dtype, feats[0].device + for i, stride in enumerate(strides): + _, _, h, w = feats[i].shape + sx = torch.arange(end=w, device=device, dtype=dtype) + grid_cell_offset # shift x + sy = torch.arange(end=h, device=device, dtype=dtype) + grid_cell_offset # shift y + sy, sx = torch.meshgrid(sy, sx, indexing='ij') if TORCH_1_10 else torch.meshgrid(sy, sx) + anchor_points.append(torch.stack((sx, sy), -1).view(-1, 2)) + stride_tensor.append(torch.full((h * w, 1), stride, dtype=dtype, device=device)) + return torch.cat(anchor_points), torch.cat(stride_tensor) + + +def dist2bbox(distance, anchor_points, xywh=True, dim=-1): + """Transform distance(ltrb) to box(xywh or xyxy).""" + lt, rb = torch.split(distance, 2, dim) + x1y1 = anchor_points - lt + x2y2 = anchor_points + rb + if xywh: + c_xy = (x1y1 + x2y2) / 2 + wh = x2y2 - x1y1 + return torch.cat((c_xy, wh), dim) # xywh bbox + return torch.cat((x1y1, x2y2), dim) # xyxy bbox + + +def bbox2dist(anchor_points, bbox, reg_max): + """Transform bbox(xyxy) to dist(ltrb).""" + x1y1, x2y2 = torch.split(bbox, 2, -1) + return torch.cat((anchor_points - x1y1, x2y2 - anchor_points), -1).clamp(0, reg_max - 0.01) # dist (lt, rb) diff --git a/cv/3d_detection/yolov9/pytorch/utils/panoptic/tal/assigner.py b/cv/3d_detection/yolov9/pytorch/utils/panoptic/tal/assigner.py new file mode 100644 index 000000000..8c61f5c05 --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/utils/panoptic/tal/assigner.py @@ -0,0 +1,181 @@ +import torch +import torch.nn as nn +import torch.nn.functional as F + +from utils.metrics import bbox_iou + + +def select_candidates_in_gts(xy_centers, gt_bboxes, eps=1e-9): + """select the positive anchor center in gt + + Args: + xy_centers (Tensor): shape(h*w, 4) + gt_bboxes (Tensor): shape(b, n_boxes, 4) + Return: + (Tensor): shape(b, n_boxes, h*w) + """ + n_anchors = xy_centers.shape[0] + bs, n_boxes, _ = gt_bboxes.shape + lt, rb = gt_bboxes.view(-1, 1, 4).chunk(2, 2) # left-top, right-bottom + bbox_deltas = torch.cat((xy_centers[None] - lt, rb - xy_centers[None]), dim=2).view(bs, n_boxes, n_anchors, -1) + # return (bbox_deltas.min(3)[0] > eps).to(gt_bboxes.dtype) + return bbox_deltas.amin(3).gt_(eps) + + +def select_highest_overlaps(mask_pos, overlaps, n_max_boxes): + """if an anchor box is assigned to multiple gts, + the one with the highest iou will be selected. + + Args: + mask_pos (Tensor): shape(b, n_max_boxes, h*w) + overlaps (Tensor): shape(b, n_max_boxes, h*w) + Return: + target_gt_idx (Tensor): shape(b, h*w) + fg_mask (Tensor): shape(b, h*w) + mask_pos (Tensor): shape(b, n_max_boxes, h*w) + """ + # (b, n_max_boxes, h*w) -> (b, h*w) + fg_mask = mask_pos.sum(-2) + if fg_mask.max() > 1: # one anchor is assigned to multiple gt_bboxes + mask_multi_gts = (fg_mask.unsqueeze(1) > 1).repeat([1, n_max_boxes, 1]) # (b, n_max_boxes, h*w) + max_overlaps_idx = overlaps.argmax(1) # (b, h*w) + is_max_overlaps = F.one_hot(max_overlaps_idx, n_max_boxes) # (b, h*w, n_max_boxes) + is_max_overlaps = is_max_overlaps.permute(0, 2, 1).to(overlaps.dtype) # (b, n_max_boxes, h*w) + mask_pos = torch.where(mask_multi_gts, is_max_overlaps, mask_pos) # (b, n_max_boxes, h*w) + fg_mask = mask_pos.sum(-2) + # find each grid serve which gt(index) + target_gt_idx = mask_pos.argmax(-2) # (b, h*w) + return target_gt_idx, fg_mask, mask_pos + + +class TaskAlignedAssigner(nn.Module): + def __init__(self, topk=13, num_classes=80, alpha=1.0, beta=6.0, eps=1e-9): + super().__init__() + self.topk = topk + self.num_classes = num_classes + self.bg_idx = num_classes + self.alpha = alpha + self.beta = beta + self.eps = eps + + @torch.no_grad() + def forward(self, pd_scores, pd_bboxes, anc_points, gt_labels, gt_bboxes, mask_gt): + """This code referenced to + https://github.com/Nioolek/PPYOLOE_pytorch/blob/master/ppyoloe/assigner/tal_assigner.py + + Args: + pd_scores (Tensor): shape(bs, num_total_anchors, num_classes) + pd_bboxes (Tensor): shape(bs, num_total_anchors, 4) + anc_points (Tensor): shape(num_total_anchors, 2) + gt_labels (Tensor): shape(bs, n_max_boxes, 1) + gt_bboxes (Tensor): shape(bs, n_max_boxes, 4) + mask_gt (Tensor): shape(bs, n_max_boxes, 1) + Returns: + target_labels (Tensor): shape(bs, num_total_anchors) + target_bboxes (Tensor): shape(bs, num_total_anchors, 4) + target_scores (Tensor): shape(bs, num_total_anchors, num_classes) + fg_mask (Tensor): shape(bs, num_total_anchors) + """ + self.bs = pd_scores.size(0) + self.n_max_boxes = gt_bboxes.size(1) + + if self.n_max_boxes == 0: + device = gt_bboxes.device + return (torch.full_like(pd_scores[..., 0], self.bg_idx).to(device), + torch.zeros_like(pd_bboxes).to(device), + torch.zeros_like(pd_scores).to(device), + torch.zeros_like(pd_scores[..., 0]).to(device), + torch.zeros_like(pd_scores[..., 0]).to(device)) + + mask_pos, align_metric, overlaps = self.get_pos_mask(pd_scores, pd_bboxes, gt_labels, gt_bboxes, anc_points, + mask_gt) + + target_gt_idx, fg_mask, mask_pos = select_highest_overlaps(mask_pos, overlaps, self.n_max_boxes) + + # assigned target + target_labels, target_bboxes, target_scores = self.get_targets(gt_labels, gt_bboxes, target_gt_idx, fg_mask) + + # normalize + align_metric *= mask_pos + pos_align_metrics = align_metric.amax(axis=-1, keepdim=True) # b, max_num_obj + pos_overlaps = (overlaps * mask_pos).amax(axis=-1, keepdim=True) # b, max_num_obj + norm_align_metric = (align_metric * pos_overlaps / (pos_align_metrics + self.eps)).amax(-2).unsqueeze(-1) + target_scores = target_scores * norm_align_metric + + return target_labels, target_bboxes, target_scores, fg_mask.bool(), target_gt_idx + + def get_pos_mask(self, pd_scores, pd_bboxes, gt_labels, gt_bboxes, anc_points, mask_gt): + + # get anchor_align metric, (b, max_num_obj, h*w) + align_metric, overlaps = self.get_box_metrics(pd_scores, pd_bboxes, gt_labels, gt_bboxes) + # get in_gts mask, (b, max_num_obj, h*w) + mask_in_gts = select_candidates_in_gts(anc_points, gt_bboxes) + # get topk_metric mask, (b, max_num_obj, h*w) + mask_topk = self.select_topk_candidates(align_metric * mask_in_gts, + topk_mask=mask_gt.repeat([1, 1, self.topk]).bool()) + # merge all mask to a final mask, (b, max_num_obj, h*w) + mask_pos = mask_topk * mask_in_gts * mask_gt + + return mask_pos, align_metric, overlaps + + def get_box_metrics(self, pd_scores, pd_bboxes, gt_labels, gt_bboxes): + + gt_labels = gt_labels.to(torch.long) # b, max_num_obj, 1 + ind = torch.zeros([2, self.bs, self.n_max_boxes], dtype=torch.long) # 2, b, max_num_obj + ind[0] = torch.arange(end=self.bs).view(-1, 1).repeat(1, self.n_max_boxes) # b, max_num_obj + ind[1] = gt_labels.squeeze(-1) # b, max_num_obj + # get the scores of each grid for each gt cls + bbox_scores = pd_scores[ind[0], :, ind[1]] # b, max_num_obj, h*w + + overlaps = bbox_iou(gt_bboxes.unsqueeze(2), pd_bboxes.unsqueeze(1), xywh=False, CIoU=True).squeeze(3).clamp(0) + #overlaps = bbox_iou(gt_bboxes.unsqueeze(2), pd_bboxes.unsqueeze(1), xywh=False, WIoU=True, scale=True)[-1].squeeze(3).clamp(0) + align_metric = bbox_scores.pow(self.alpha) * overlaps.pow(self.beta) + return align_metric, overlaps + + def select_topk_candidates(self, metrics, largest=True, topk_mask=None): + """ + Args: + metrics: (b, max_num_obj, h*w). + topk_mask: (b, max_num_obj, topk) or None + """ + + num_anchors = metrics.shape[-1] # h*w + # (b, max_num_obj, topk) + topk_metrics, topk_idxs = torch.topk(metrics, self.topk, dim=-1, largest=largest) + if topk_mask is None: + topk_mask = (topk_metrics.max(-1, keepdim=True) > self.eps).tile([1, 1, self.topk]) + # (b, max_num_obj, topk) + topk_idxs = torch.where(topk_mask, topk_idxs, 0) + # (b, max_num_obj, topk, h*w) -> (b, max_num_obj, h*w) + is_in_topk = F.one_hot(topk_idxs, num_anchors).sum(-2) + # filter invalid bboxes + # assigned topk should be unique, this is for dealing with empty labels + # since empty labels will generate index `0` through `F.one_hot` + # NOTE: but what if the topk_idxs include `0`? + is_in_topk = torch.where(is_in_topk > 1, 0, is_in_topk) + return is_in_topk.to(metrics.dtype) + + def get_targets(self, gt_labels, gt_bboxes, target_gt_idx, fg_mask): + """ + Args: + gt_labels: (b, max_num_obj, 1) + gt_bboxes: (b, max_num_obj, 4) + target_gt_idx: (b, h*w) + fg_mask: (b, h*w) + """ + + # assigned target labels, (b, 1) + batch_ind = torch.arange(end=self.bs, dtype=torch.int64, device=gt_labels.device)[..., None] + target_gt_idx = target_gt_idx + batch_ind * self.n_max_boxes # (b, h*w) + target_labels = gt_labels.long().flatten()[target_gt_idx] # (b, h*w) + + # assigned target boxes, (b, max_num_obj, 4) -> (b, h*w) + target_bboxes = gt_bboxes.view(-1, 4)[target_gt_idx] + + # assigned target scores + target_labels.clamp(0) + target_scores = F.one_hot(target_labels, self.num_classes) # (b, h*w, 80) + fg_scores_mask = fg_mask[:, :, None].repeat(1, 1, self.num_classes) # (b, h*w, 80) + target_scores = torch.where(fg_scores_mask > 0, target_scores, 0) + + return target_labels, target_bboxes, target_scores diff --git a/cv/3d_detection/yolov9/pytorch/utils/plots.py b/cv/3d_detection/yolov9/pytorch/utils/plots.py new file mode 100644 index 000000000..fa49dc19d --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/utils/plots.py @@ -0,0 +1,570 @@ +import contextlib +import math +import os +from copy import copy +from pathlib import Path +from urllib.error import URLError + +import cv2 +import matplotlib +import matplotlib.pyplot as plt +import numpy as np +import pandas as pd +import seaborn as sn +import torch +from PIL import Image, ImageDraw, ImageFont + +from utils import TryExcept, threaded +from utils.general import (CONFIG_DIR, FONT, LOGGER, check_font, check_requirements, clip_boxes, increment_path, + is_ascii, xywh2xyxy, xyxy2xywh) +from utils.metrics import fitness +from utils.segment.general import scale_image + +# Settings +RANK = int(os.getenv('RANK', -1)) +matplotlib.rc('font', **{'size': 11}) +matplotlib.use('Agg') # for writing to files only + + +class Colors: + # Ultralytics color palette https://ultralytics.com/ + def __init__(self): + # hex = matplotlib.colors.TABLEAU_COLORS.values() + hexs = ('FF3838', 'FF9D97', 'FF701F', 'FFB21D', 'CFD231', '48F90A', '92CC17', '3DDB86', '1A9334', '00D4BB', + '2C99A8', '00C2FF', '344593', '6473FF', '0018EC', '8438FF', '520085', 'CB38FF', 'FF95C8', 'FF37C7') + self.palette = [self.hex2rgb(f'#{c}') for c in hexs] + self.n = len(self.palette) + + def __call__(self, i, bgr=False): + c = self.palette[int(i) % self.n] + return (c[2], c[1], c[0]) if bgr else c + + @staticmethod + def hex2rgb(h): # rgb order (PIL) + return tuple(int(h[1 + i:1 + i + 2], 16) for i in (0, 2, 4)) + + +colors = Colors() # create instance for 'from utils.plots import colors' + + +def check_pil_font(font=FONT, size=10): + # Return a PIL TrueType Font, downloading to CONFIG_DIR if necessary + font = Path(font) + font = font if font.exists() else (CONFIG_DIR / font.name) + try: + return ImageFont.truetype(str(font) if font.exists() else font.name, size) + except Exception: # download if missing + try: + check_font(font) + return ImageFont.truetype(str(font), size) + except TypeError: + check_requirements('Pillow>=8.4.0') # known issue https://github.com/ultralytics/yolov5/issues/5374 + except URLError: # not online + return ImageFont.load_default() + + +class Annotator: + # YOLOv5 Annotator for train/val mosaics and jpgs and detect/hub inference annotations + def __init__(self, im, line_width=None, font_size=None, font='Arial.ttf', pil=False, example='abc'): + assert im.data.contiguous, 'Image not contiguous. Apply np.ascontiguousarray(im) to Annotator() input images.' + non_ascii = not is_ascii(example) # non-latin labels, i.e. asian, arabic, cyrillic + self.pil = pil or non_ascii + if self.pil: # use PIL + self.im = im if isinstance(im, Image.Image) else Image.fromarray(im) + self.draw = ImageDraw.Draw(self.im) + self.font = check_pil_font(font='Arial.Unicode.ttf' if non_ascii else font, + size=font_size or max(round(sum(self.im.size) / 2 * 0.035), 12)) + else: # use cv2 + self.im = im + self.lw = line_width or max(round(sum(im.shape) / 2 * 0.003), 2) # line width + + def box_label(self, box, label='', color=(128, 128, 128), txt_color=(255, 255, 255)): + # Add one xyxy box to image with label + if self.pil or not is_ascii(label): + self.draw.rectangle(box, width=self.lw, outline=color) # box + if label: + w, h = self.font.getsize(label) # text width, height + outside = box[1] - h >= 0 # label fits outside box + self.draw.rectangle( + (box[0], box[1] - h if outside else box[1], box[0] + w + 1, + box[1] + 1 if outside else box[1] + h + 1), + fill=color, + ) + # self.draw.text((box[0], box[1]), label, fill=txt_color, font=self.font, anchor='ls') # for PIL>8.0 + self.draw.text((box[0], box[1] - h if outside else box[1]), label, fill=txt_color, font=self.font) + else: # cv2 + p1, p2 = (int(box[0]), int(box[1])), (int(box[2]), int(box[3])) + cv2.rectangle(self.im, p1, p2, color, thickness=self.lw, lineType=cv2.LINE_AA) + if label: + tf = max(self.lw - 1, 1) # font thickness + w, h = cv2.getTextSize(label, 0, fontScale=self.lw / 3, thickness=tf)[0] # text width, height + outside = p1[1] - h >= 3 + p2 = p1[0] + w, p1[1] - h - 3 if outside else p1[1] + h + 3 + cv2.rectangle(self.im, p1, p2, color, -1, cv2.LINE_AA) # filled + cv2.putText(self.im, + label, (p1[0], p1[1] - 2 if outside else p1[1] + h + 2), + 0, + self.lw / 3, + txt_color, + thickness=tf, + lineType=cv2.LINE_AA) + + def masks(self, masks, colors, im_gpu=None, alpha=0.5): + """Plot masks at once. + Args: + masks (tensor): predicted masks on cuda, shape: [n, h, w] + colors (List[List[Int]]): colors for predicted masks, [[r, g, b] * n] + im_gpu (tensor): img is in cuda, shape: [3, h, w], range: [0, 1] + alpha (float): mask transparency: 0.0 fully transparent, 1.0 opaque + """ + if self.pil: + # convert to numpy first + self.im = np.asarray(self.im).copy() + if im_gpu is None: + # Add multiple masks of shape(h,w,n) with colors list([r,g,b], [r,g,b], ...) + if len(masks) == 0: + return + if isinstance(masks, torch.Tensor): + masks = torch.as_tensor(masks, dtype=torch.uint8) + masks = masks.permute(1, 2, 0).contiguous() + masks = masks.cpu().numpy() + # masks = np.ascontiguousarray(masks.transpose(1, 2, 0)) + masks = scale_image(masks.shape[:2], masks, self.im.shape) + masks = np.asarray(masks, dtype=np.float32) + colors = np.asarray(colors, dtype=np.float32) # shape(n,3) + s = masks.sum(2, keepdims=True).clip(0, 1) # add all masks together + masks = (masks @ colors).clip(0, 255) # (h,w,n) @ (n,3) = (h,w,3) + self.im[:] = masks * alpha + self.im * (1 - s * alpha) + else: + if len(masks) == 0: + self.im[:] = im_gpu.permute(1, 2, 0).contiguous().cpu().numpy() * 255 + colors = torch.tensor(colors, device=im_gpu.device, dtype=torch.float32) / 255.0 + colors = colors[:, None, None] # shape(n,1,1,3) + masks = masks.unsqueeze(3) # shape(n,h,w,1) + masks_color = masks * (colors * alpha) # shape(n,h,w,3) + + inv_alph_masks = (1 - masks * alpha).cumprod(0) # shape(n,h,w,1) + mcs = (masks_color * inv_alph_masks).sum(0) * 2 # mask color summand shape(n,h,w,3) + + im_gpu = im_gpu.flip(dims=[0]) # flip channel + im_gpu = im_gpu.permute(1, 2, 0).contiguous() # shape(h,w,3) + im_gpu = im_gpu * inv_alph_masks[-1] + mcs + im_mask = (im_gpu * 255).byte().cpu().numpy() + self.im[:] = scale_image(im_gpu.shape, im_mask, self.im.shape) + if self.pil: + # convert im back to PIL and update draw + self.fromarray(self.im) + + def rectangle(self, xy, fill=None, outline=None, width=1): + # Add rectangle to image (PIL-only) + self.draw.rectangle(xy, fill, outline, width) + + def text(self, xy, text, txt_color=(255, 255, 255), anchor='top'): + # Add text to image (PIL-only) + if anchor == 'bottom': # start y from font bottom + w, h = self.font.getsize(text) # text width, height + xy[1] += 1 - h + self.draw.text(xy, text, fill=txt_color, font=self.font) + + def fromarray(self, im): + # Update self.im from a numpy array + self.im = im if isinstance(im, Image.Image) else Image.fromarray(im) + self.draw = ImageDraw.Draw(self.im) + + def result(self): + # Return annotated image as array + return np.asarray(self.im) + + +def feature_visualization(x, module_type, stage, n=32, save_dir=Path('runs/detect/exp')): + """ + x: Features to be visualized + module_type: Module type + stage: Module stage within model + n: Maximum number of feature maps to plot + save_dir: Directory to save results + """ + if 'Detect' not in module_type: + batch, channels, height, width = x.shape # batch, channels, height, width + if height > 1 and width > 1: + f = save_dir / f"stage{stage}_{module_type.split('.')[-1]}_features.png" # filename + + blocks = torch.chunk(x[0].cpu(), channels, dim=0) # select batch index 0, block by channels + n = min(n, channels) # number of plots + fig, ax = plt.subplots(math.ceil(n / 8), 8, tight_layout=True) # 8 rows x n/8 cols + ax = ax.ravel() + plt.subplots_adjust(wspace=0.05, hspace=0.05) + for i in range(n): + ax[i].imshow(blocks[i].squeeze()) # cmap='gray' + ax[i].axis('off') + + LOGGER.info(f'Saving {f}... ({n}/{channels})') + plt.savefig(f, dpi=300, bbox_inches='tight') + plt.close() + np.save(str(f.with_suffix('.npy')), x[0].cpu().numpy()) # npy save + + +def hist2d(x, y, n=100): + # 2d histogram used in labels.png and evolve.png + xedges, yedges = np.linspace(x.min(), x.max(), n), np.linspace(y.min(), y.max(), n) + hist, xedges, yedges = np.histogram2d(x, y, (xedges, yedges)) + xidx = np.clip(np.digitize(x, xedges) - 1, 0, hist.shape[0] - 1) + yidx = np.clip(np.digitize(y, yedges) - 1, 0, hist.shape[1] - 1) + return np.log(hist[xidx, yidx]) + + +def butter_lowpass_filtfilt(data, cutoff=1500, fs=50000, order=5): + from scipy.signal import butter, filtfilt + + # https://stackoverflow.com/questions/28536191/how-to-filter-smooth-with-scipy-numpy + def butter_lowpass(cutoff, fs, order): + nyq = 0.5 * fs + normal_cutoff = cutoff / nyq + return butter(order, normal_cutoff, btype='low', analog=False) + + b, a = butter_lowpass(cutoff, fs, order=order) + return filtfilt(b, a, data) # forward-backward filter + + +def output_to_target(output, max_det=300): + # Convert model output to target format [batch_id, class_id, x, y, w, h, conf] for plotting + targets = [] + for i, o in enumerate(output): + box, conf, cls = o[:max_det, :6].cpu().split((4, 1, 1), 1) + j = torch.full((conf.shape[0], 1), i) + targets.append(torch.cat((j, cls, xyxy2xywh(box), conf), 1)) + return torch.cat(targets, 0).numpy() + + +@threaded +def plot_images(images, targets, paths=None, fname='images.jpg', names=None): + # Plot image grid with labels + if isinstance(images, torch.Tensor): + images = images.cpu().float().numpy() + if isinstance(targets, torch.Tensor): + targets = targets.cpu().numpy() + + max_size = 1920 # max image size + max_subplots = 16 # max image subplots, i.e. 4x4 + bs, _, h, w = images.shape # batch size, _, height, width + bs = min(bs, max_subplots) # limit plot images + ns = np.ceil(bs ** 0.5) # number of subplots (square) + if np.max(images[0]) <= 1: + images *= 255 # de-normalise (optional) + + # Build Image + mosaic = np.full((int(ns * h), int(ns * w), 3), 255, dtype=np.uint8) # init + for i, im in enumerate(images): + if i == max_subplots: # if last batch has fewer images than we expect + break + x, y = int(w * (i // ns)), int(h * (i % ns)) # block origin + im = im.transpose(1, 2, 0) + mosaic[y:y + h, x:x + w, :] = im + + # Resize (optional) + scale = max_size / ns / max(h, w) + if scale < 1: + h = math.ceil(scale * h) + w = math.ceil(scale * w) + mosaic = cv2.resize(mosaic, tuple(int(x * ns) for x in (w, h))) + + # Annotate + fs = int((h + w) * ns * 0.01) # font size + annotator = Annotator(mosaic, line_width=round(fs / 10), font_size=fs, pil=True, example=names) + for i in range(i + 1): + x, y = int(w * (i // ns)), int(h * (i % ns)) # block origin + annotator.rectangle([x, y, x + w, y + h], None, (255, 255, 255), width=2) # borders + if paths: + annotator.text((x + 5, y + 5), text=Path(paths[i]).name[:40], txt_color=(220, 220, 220)) # filenames + if len(targets) > 0: + ti = targets[targets[:, 0] == i] # image targets + boxes = xywh2xyxy(ti[:, 2:6]).T + classes = ti[:, 1].astype('int') + labels = ti.shape[1] == 6 # labels if no conf column + conf = None if labels else ti[:, 6] # check for confidence presence (label vs pred) + + if boxes.shape[1]: + if boxes.max() <= 1.01: # if normalized with tolerance 0.01 + boxes[[0, 2]] *= w # scale to pixels + boxes[[1, 3]] *= h + elif scale < 1: # absolute coords need scale if image scales + boxes *= scale + boxes[[0, 2]] += x + boxes[[1, 3]] += y + for j, box in enumerate(boxes.T.tolist()): + cls = classes[j] + color = colors(cls) + cls = names[cls] if names else cls + if labels or conf[j] > 0.25: # 0.25 conf thresh + label = f'{cls}' if labels else f'{cls} {conf[j]:.1f}' + annotator.box_label(box, label, color=color) + annotator.im.save(fname) # save + + +def plot_lr_scheduler(optimizer, scheduler, epochs=300, save_dir=''): + # Plot LR simulating training for full epochs + optimizer, scheduler = copy(optimizer), copy(scheduler) # do not modify originals + y = [] + for _ in range(epochs): + scheduler.step() + y.append(optimizer.param_groups[0]['lr']) + plt.plot(y, '.-', label='LR') + plt.xlabel('epoch') + plt.ylabel('LR') + plt.grid() + plt.xlim(0, epochs) + plt.ylim(0) + plt.savefig(Path(save_dir) / 'LR.png', dpi=200) + plt.close() + + +def plot_val_txt(): # from utils.plots import *; plot_val() + # Plot val.txt histograms + x = np.loadtxt('val.txt', dtype=np.float32) + box = xyxy2xywh(x[:, :4]) + cx, cy = box[:, 0], box[:, 1] + + fig, ax = plt.subplots(1, 1, figsize=(6, 6), tight_layout=True) + ax.hist2d(cx, cy, bins=600, cmax=10, cmin=0) + ax.set_aspect('equal') + plt.savefig('hist2d.png', dpi=300) + + fig, ax = plt.subplots(1, 2, figsize=(12, 6), tight_layout=True) + ax[0].hist(cx, bins=600) + ax[1].hist(cy, bins=600) + plt.savefig('hist1d.png', dpi=200) + + +def plot_targets_txt(): # from utils.plots import *; plot_targets_txt() + # Plot targets.txt histograms + x = np.loadtxt('targets.txt', dtype=np.float32).T + s = ['x targets', 'y targets', 'width targets', 'height targets'] + fig, ax = plt.subplots(2, 2, figsize=(8, 8), tight_layout=True) + ax = ax.ravel() + for i in range(4): + ax[i].hist(x[i], bins=100, label=f'{x[i].mean():.3g} +/- {x[i].std():.3g}') + ax[i].legend() + ax[i].set_title(s[i]) + plt.savefig('targets.jpg', dpi=200) + + +def plot_val_study(file='', dir='', x=None): # from utils.plots import *; plot_val_study() + # Plot file=study.txt generated by val.py (or plot all study*.txt in dir) + save_dir = Path(file).parent if file else Path(dir) + plot2 = False # plot additional results + if plot2: + ax = plt.subplots(2, 4, figsize=(10, 6), tight_layout=True)[1].ravel() + + fig2, ax2 = plt.subplots(1, 1, figsize=(8, 4), tight_layout=True) + # for f in [save_dir / f'study_coco_{x}.txt' for x in ['yolov5n6', 'yolov5s6', 'yolov5m6', 'yolov5l6', 'yolov5x6']]: + for f in sorted(save_dir.glob('study*.txt')): + y = np.loadtxt(f, dtype=np.float32, usecols=[0, 1, 2, 3, 7, 8, 9], ndmin=2).T + x = np.arange(y.shape[1]) if x is None else np.array(x) + if plot2: + s = ['P', 'R', 'mAP@.5', 'mAP@.5:.95', 't_preprocess (ms/img)', 't_inference (ms/img)', 't_NMS (ms/img)'] + for i in range(7): + ax[i].plot(x, y[i], '.-', linewidth=2, markersize=8) + ax[i].set_title(s[i]) + + j = y[3].argmax() + 1 + ax2.plot(y[5, 1:j], + y[3, 1:j] * 1E2, + '.-', + linewidth=2, + markersize=8, + label=f.stem.replace('study_coco_', '').replace('yolo', 'YOLO')) + + ax2.plot(1E3 / np.array([209, 140, 97, 58, 35, 18]), [34.6, 40.5, 43.0, 47.5, 49.7, 51.5], + 'k.-', + linewidth=2, + markersize=8, + alpha=.25, + label='EfficientDet') + + ax2.grid(alpha=0.2) + ax2.set_yticks(np.arange(20, 60, 5)) + ax2.set_xlim(0, 57) + ax2.set_ylim(25, 55) + ax2.set_xlabel('GPU Speed (ms/img)') + ax2.set_ylabel('COCO AP val') + ax2.legend(loc='lower right') + f = save_dir / 'study.png' + print(f'Saving {f}...') + plt.savefig(f, dpi=300) + + +@TryExcept() # known issue https://github.com/ultralytics/yolov5/issues/5395 +def plot_labels(labels, names=(), save_dir=Path('')): + # plot dataset labels + LOGGER.info(f"Plotting labels to {save_dir / 'labels.jpg'}... ") + c, b = labels[:, 0], labels[:, 1:].transpose() # classes, boxes + nc = int(c.max() + 1) # number of classes + x = pd.DataFrame(b.transpose(), columns=['x', 'y', 'width', 'height']) + + # seaborn correlogram + sn.pairplot(x, corner=True, diag_kind='auto', kind='hist', diag_kws=dict(bins=50), plot_kws=dict(pmax=0.9)) + plt.savefig(save_dir / 'labels_correlogram.jpg', dpi=200) + plt.close() + + # matplotlib labels + matplotlib.use('svg') # faster + ax = plt.subplots(2, 2, figsize=(8, 8), tight_layout=True)[1].ravel() + y = ax[0].hist(c, bins=np.linspace(0, nc, nc + 1) - 0.5, rwidth=0.8) + with contextlib.suppress(Exception): # color histogram bars by class + [y[2].patches[i].set_color([x / 255 for x in colors(i)]) for i in range(nc)] # known issue #3195 + ax[0].set_ylabel('instances') + if 0 < len(names) < 30: + ax[0].set_xticks(range(len(names))) + ax[0].set_xticklabels(list(names.values()), rotation=90, fontsize=10) + else: + ax[0].set_xlabel('classes') + sn.histplot(x, x='x', y='y', ax=ax[2], bins=50, pmax=0.9) + sn.histplot(x, x='width', y='height', ax=ax[3], bins=50, pmax=0.9) + + # rectangles + labels[:, 1:3] = 0.5 # center + labels[:, 1:] = xywh2xyxy(labels[:, 1:]) * 2000 + img = Image.fromarray(np.ones((2000, 2000, 3), dtype=np.uint8) * 255) + for cls, *box in labels[:1000]: + ImageDraw.Draw(img).rectangle(box, width=1, outline=colors(cls)) # plot + ax[1].imshow(img) + ax[1].axis('off') + + for a in [0, 1, 2, 3]: + for s in ['top', 'right', 'left', 'bottom']: + ax[a].spines[s].set_visible(False) + + plt.savefig(save_dir / 'labels.jpg', dpi=200) + matplotlib.use('Agg') + plt.close() + + +def imshow_cls(im, labels=None, pred=None, names=None, nmax=25, verbose=False, f=Path('images.jpg')): + # Show classification image grid with labels (optional) and predictions (optional) + from utils.augmentations import denormalize + + names = names or [f'class{i}' for i in range(1000)] + blocks = torch.chunk(denormalize(im.clone()).cpu().float(), len(im), + dim=0) # select batch index 0, block by channels + n = min(len(blocks), nmax) # number of plots + m = min(8, round(n ** 0.5)) # 8 x 8 default + fig, ax = plt.subplots(math.ceil(n / m), m) # 8 rows x n/8 cols + ax = ax.ravel() if m > 1 else [ax] + # plt.subplots_adjust(wspace=0.05, hspace=0.05) + for i in range(n): + ax[i].imshow(blocks[i].squeeze().permute((1, 2, 0)).numpy().clip(0.0, 1.0)) + ax[i].axis('off') + if labels is not None: + s = names[labels[i]] + (f'—{names[pred[i]]}' if pred is not None else '') + ax[i].set_title(s, fontsize=8, verticalalignment='top') + plt.savefig(f, dpi=300, bbox_inches='tight') + plt.close() + if verbose: + LOGGER.info(f"Saving {f}") + if labels is not None: + LOGGER.info('True: ' + ' '.join(f'{names[i]:3s}' for i in labels[:nmax])) + if pred is not None: + LOGGER.info('Predicted:' + ' '.join(f'{names[i]:3s}' for i in pred[:nmax])) + return f + + +def plot_evolve(evolve_csv='path/to/evolve.csv'): # from utils.plots import *; plot_evolve() + # Plot evolve.csv hyp evolution results + evolve_csv = Path(evolve_csv) + data = pd.read_csv(evolve_csv) + keys = [x.strip() for x in data.columns] + x = data.values + f = fitness(x) + j = np.argmax(f) # max fitness index + plt.figure(figsize=(10, 12), tight_layout=True) + matplotlib.rc('font', **{'size': 8}) + print(f'Best results from row {j} of {evolve_csv}:') + for i, k in enumerate(keys[7:]): + v = x[:, 7 + i] + mu = v[j] # best single result + plt.subplot(6, 5, i + 1) + plt.scatter(v, f, c=hist2d(v, f, 20), cmap='viridis', alpha=.8, edgecolors='none') + plt.plot(mu, f.max(), 'k+', markersize=15) + plt.title(f'{k} = {mu:.3g}', fontdict={'size': 9}) # limit to 40 characters + if i % 5 != 0: + plt.yticks([]) + print(f'{k:>15}: {mu:.3g}') + f = evolve_csv.with_suffix('.png') # filename + plt.savefig(f, dpi=200) + plt.close() + print(f'Saved {f}') + + +def plot_results(file='path/to/results.csv', dir=''): + # Plot training results.csv. Usage: from utils.plots import *; plot_results('path/to/results.csv') + save_dir = Path(file).parent if file else Path(dir) + fig, ax = plt.subplots(2, 5, figsize=(12, 6), tight_layout=True) + ax = ax.ravel() + files = list(save_dir.glob('results*.csv')) + assert len(files), f'No results.csv files found in {save_dir.resolve()}, nothing to plot.' + for f in files: + try: + data = pd.read_csv(f) + s = [x.strip() for x in data.columns] + x = data.values[:, 0] + for i, j in enumerate([1, 2, 3, 4, 5, 8, 9, 10, 6, 7]): + y = data.values[:, j].astype('float') + # y[y == 0] = np.nan # don't show zero values + ax[i].plot(x, y, marker='.', label=f.stem, linewidth=2, markersize=8) + ax[i].set_title(s[j], fontsize=12) + # if j in [8, 9, 10]: # share train and val loss y axes + # ax[i].get_shared_y_axes().join(ax[i], ax[i - 5]) + except Exception as e: + LOGGER.info(f'Warning: Plotting error for {f}: {e}') + ax[1].legend() + fig.savefig(save_dir / 'results.png', dpi=200) + plt.close() + + +def profile_idetection(start=0, stop=0, labels=(), save_dir=''): + # Plot iDetection '*.txt' per-image logs. from utils.plots import *; profile_idetection() + ax = plt.subplots(2, 4, figsize=(12, 6), tight_layout=True)[1].ravel() + s = ['Images', 'Free Storage (GB)', 'RAM Usage (GB)', 'Battery', 'dt_raw (ms)', 'dt_smooth (ms)', 'real-world FPS'] + files = list(Path(save_dir).glob('frames*.txt')) + for fi, f in enumerate(files): + try: + results = np.loadtxt(f, ndmin=2).T[:, 90:-30] # clip first and last rows + n = results.shape[1] # number of rows + x = np.arange(start, min(stop, n) if stop else n) + results = results[:, x] + t = (results[0] - results[0].min()) # set t0=0s + results[0] = x + for i, a in enumerate(ax): + if i < len(results): + label = labels[fi] if len(labels) else f.stem.replace('frames_', '') + a.plot(t, results[i], marker='.', label=label, linewidth=1, markersize=5) + a.set_title(s[i]) + a.set_xlabel('time (s)') + # if fi == len(files) - 1: + # a.set_ylim(bottom=0) + for side in ['top', 'right']: + a.spines[side].set_visible(False) + else: + a.remove() + except Exception as e: + print(f'Warning: Plotting error for {f}; {e}') + ax[1].legend() + plt.savefig(Path(save_dir) / 'idetection_profile.png', dpi=200) + + +def save_one_box(xyxy, im, file=Path('im.jpg'), gain=1.02, pad=10, square=False, BGR=False, save=True): + # Save image crop as {file} with crop size multiple {gain} and {pad} pixels. Save and/or return crop + xyxy = torch.tensor(xyxy).view(-1, 4) + b = xyxy2xywh(xyxy) # boxes + if square: + b[:, 2:] = b[:, 2:].max(1)[0].unsqueeze(1) # attempt rectangle to square + b[:, 2:] = b[:, 2:] * gain + pad # box wh * gain + pad + xyxy = xywh2xyxy(b).long() + clip_boxes(xyxy, im.shape) + crop = im[int(xyxy[0, 1]):int(xyxy[0, 3]), int(xyxy[0, 0]):int(xyxy[0, 2]), ::(1 if BGR else -1)] + if save: + file.parent.mkdir(parents=True, exist_ok=True) # make directory + f = str(increment_path(file).with_suffix('.jpg')) + # cv2.imwrite(f, crop) # save BGR, https://github.com/ultralytics/yolov5/issues/7007 chroma subsampling issue + Image.fromarray(crop[..., ::-1]).save(f, quality=95, subsampling=0) # save RGB + return crop diff --git a/cv/3d_detection/yolov9/pytorch/utils/segment/__init__.py b/cv/3d_detection/yolov9/pytorch/utils/segment/__init__.py new file mode 100644 index 000000000..84952a816 --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/utils/segment/__init__.py @@ -0,0 +1 @@ +# init \ No newline at end of file diff --git a/cv/3d_detection/yolov9/pytorch/utils/segment/augmentations.py b/cv/3d_detection/yolov9/pytorch/utils/segment/augmentations.py new file mode 100644 index 000000000..34b5bf75f --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/utils/segment/augmentations.py @@ -0,0 +1,99 @@ +import math +import random + +import cv2 +import numpy as np + +from ..augmentations import box_candidates +from ..general import resample_segments, segment2box + + +def mixup(im, labels, segments, im2, labels2, segments2): + # Applies MixUp augmentation https://arxiv.org/pdf/1710.09412.pdf + r = np.random.beta(32.0, 32.0) # mixup ratio, alpha=beta=32.0 + im = (im * r + im2 * (1 - r)).astype(np.uint8) + labels = np.concatenate((labels, labels2), 0) + segments = np.concatenate((segments, segments2), 0) + return im, labels, segments + + +def random_perspective(im, + targets=(), + segments=(), + degrees=10, + translate=.1, + scale=.1, + shear=10, + perspective=0.0, + border=(0, 0)): + # torchvision.transforms.RandomAffine(degrees=(-10, 10), translate=(.1, .1), scale=(.9, 1.1), shear=(-10, 10)) + # targets = [cls, xyxy] + + height = im.shape[0] + border[0] * 2 # shape(h,w,c) + width = im.shape[1] + border[1] * 2 + + # Center + C = np.eye(3) + C[0, 2] = -im.shape[1] / 2 # x translation (pixels) + C[1, 2] = -im.shape[0] / 2 # y translation (pixels) + + # Perspective + P = np.eye(3) + P[2, 0] = random.uniform(-perspective, perspective) # x perspective (about y) + P[2, 1] = random.uniform(-perspective, perspective) # y perspective (about x) + + # Rotation and Scale + R = np.eye(3) + a = random.uniform(-degrees, degrees) + # a += random.choice([-180, -90, 0, 90]) # add 90deg rotations to small rotations + s = random.uniform(1 - scale, 1 + scale) + # s = 2 ** random.uniform(-scale, scale) + R[:2] = cv2.getRotationMatrix2D(angle=a, center=(0, 0), scale=s) + + # Shear + S = np.eye(3) + S[0, 1] = math.tan(random.uniform(-shear, shear) * math.pi / 180) # x shear (deg) + S[1, 0] = math.tan(random.uniform(-shear, shear) * math.pi / 180) # y shear (deg) + + # Translation + T = np.eye(3) + T[0, 2] = (random.uniform(0.5 - translate, 0.5 + translate) * width) # x translation (pixels) + T[1, 2] = (random.uniform(0.5 - translate, 0.5 + translate) * height) # y translation (pixels) + + # Combined rotation matrix + M = T @ S @ R @ P @ C # order of operations (right to left) is IMPORTANT + if (border[0] != 0) or (border[1] != 0) or (M != np.eye(3)).any(): # image changed + if perspective: + im = cv2.warpPerspective(im, M, dsize=(width, height), borderValue=(114, 114, 114)) + else: # affine + im = cv2.warpAffine(im, M[:2], dsize=(width, height), borderValue=(114, 114, 114)) + + # Visualize + # import matplotlib.pyplot as plt + # ax = plt.subplots(1, 2, figsize=(12, 6))[1].ravel() + # ax[0].imshow(im[:, :, ::-1]) # base + # ax[1].imshow(im2[:, :, ::-1]) # warped + + # Transform label coordinates + n = len(targets) + new_segments = [] + if n: + new = np.zeros((n, 4)) + segments = resample_segments(segments) # upsample + for i, segment in enumerate(segments): + xy = np.ones((len(segment), 3)) + xy[:, :2] = segment + xy = xy @ M.T # transform + xy = (xy[:, :2] / xy[:, 2:3] if perspective else xy[:, :2]) # perspective rescale or affine + + # clip + new[i] = segment2box(xy, width, height) + new_segments.append(xy) + + # filter candidates + i = box_candidates(box1=targets[:, 1:5].T * s, box2=new.T, area_thr=0.01) + targets = targets[i] + targets[:, 1:5] = new[i] + new_segments = np.array(new_segments)[i] + + return im, targets, new_segments diff --git a/cv/3d_detection/yolov9/pytorch/utils/segment/dataloaders.py b/cv/3d_detection/yolov9/pytorch/utils/segment/dataloaders.py new file mode 100644 index 000000000..335570a63 --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/utils/segment/dataloaders.py @@ -0,0 +1,328 @@ +import os +import random + +import cv2 +import numpy as np +import torch +from torch.utils.data import DataLoader, distributed + +from ..augmentations import augment_hsv, copy_paste, letterbox +from ..dataloaders import InfiniteDataLoader, LoadImagesAndLabels, seed_worker +from ..general import LOGGER, xyn2xy, xywhn2xyxy, xyxy2xywhn +from ..torch_utils import torch_distributed_zero_first +from .augmentations import mixup, random_perspective + +RANK = int(os.getenv('RANK', -1)) + + +def create_dataloader(path, + imgsz, + batch_size, + stride, + single_cls=False, + hyp=None, + augment=False, + cache=False, + pad=0.0, + rect=False, + rank=-1, + workers=8, + image_weights=False, + close_mosaic=False, + quad=False, + prefix='', + shuffle=False, + mask_downsample_ratio=1, + overlap_mask=False): + if rect and shuffle: + LOGGER.warning('WARNING ⚠️ --rect is incompatible with DataLoader shuffle, setting shuffle=False') + shuffle = False + with torch_distributed_zero_first(rank): # init dataset *.cache only once if DDP + dataset = LoadImagesAndLabelsAndMasks( + path, + imgsz, + batch_size, + augment=augment, # augmentation + hyp=hyp, # hyperparameters + rect=rect, # rectangular batches + cache_images=cache, + single_cls=single_cls, + stride=int(stride), + pad=pad, + image_weights=image_weights, + prefix=prefix, + downsample_ratio=mask_downsample_ratio, + overlap=overlap_mask) + + batch_size = min(batch_size, len(dataset)) + nd = torch.cuda.device_count() # number of CUDA devices + nw = min([os.cpu_count() // max(nd, 1), batch_size if batch_size > 1 else 0, workers]) # number of workers + sampler = None if rank == -1 else distributed.DistributedSampler(dataset, shuffle=shuffle) + #loader = DataLoader if image_weights else InfiniteDataLoader # only DataLoader allows for attribute updates + loader = DataLoader if image_weights or close_mosaic else InfiniteDataLoader + generator = torch.Generator() + generator.manual_seed(6148914691236517205 + RANK) + return loader( + dataset, + batch_size=batch_size, + shuffle=shuffle and sampler is None, + num_workers=nw, + sampler=sampler, + pin_memory=True, + collate_fn=LoadImagesAndLabelsAndMasks.collate_fn4 if quad else LoadImagesAndLabelsAndMasks.collate_fn, + worker_init_fn=seed_worker, + generator=generator, + ), dataset + + +class LoadImagesAndLabelsAndMasks(LoadImagesAndLabels): # for training/testing + + def __init__( + self, + path, + img_size=640, + batch_size=16, + augment=False, + hyp=None, + rect=False, + image_weights=False, + cache_images=False, + single_cls=False, + stride=32, + pad=0, + min_items=0, + prefix="", + downsample_ratio=1, + overlap=False, + ): + super().__init__(path, img_size, batch_size, augment, hyp, rect, image_weights, cache_images, single_cls, + stride, pad, min_items, prefix) + self.downsample_ratio = downsample_ratio + self.overlap = overlap + + def __getitem__(self, index): + index = self.indices[index] # linear, shuffled, or image_weights + + hyp = self.hyp + mosaic = self.mosaic and random.random() < hyp['mosaic'] + masks = [] + if mosaic: + # Load mosaic + img, labels, segments = self.load_mosaic(index) + shapes = None + + # MixUp augmentation + if random.random() < hyp["mixup"]: + img, labels, segments = mixup(img, labels, segments, *self.load_mosaic(random.randint(0, self.n - 1))) + + else: + # Load image + img, (h0, w0), (h, w) = self.load_image(index) + + # Letterbox + shape = self.batch_shapes[self.batch[index]] if self.rect else self.img_size # final letterboxed shape + img, ratio, pad = letterbox(img, shape, auto=False, scaleup=self.augment) + shapes = (h0, w0), ((h / h0, w / w0), pad) # for COCO mAP rescaling + + labels = self.labels[index].copy() + # [array, array, ....], array.shape=(num_points, 2), xyxyxyxy + segments = self.segments[index].copy() + if len(segments): + for i_s in range(len(segments)): + segments[i_s] = xyn2xy( + segments[i_s], + ratio[0] * w, + ratio[1] * h, + padw=pad[0], + padh=pad[1], + ) + if labels.size: # normalized xywh to pixel xyxy format + labels[:, 1:] = xywhn2xyxy(labels[:, 1:], ratio[0] * w, ratio[1] * h, padw=pad[0], padh=pad[1]) + + if self.augment: + img, labels, segments = random_perspective(img, + labels, + segments=segments, + degrees=hyp["degrees"], + translate=hyp["translate"], + scale=hyp["scale"], + shear=hyp["shear"], + perspective=hyp["perspective"]) + + nl = len(labels) # number of labels + if nl: + labels[:, 1:5] = xyxy2xywhn(labels[:, 1:5], w=img.shape[1], h=img.shape[0], clip=True, eps=1e-3) + if self.overlap: + masks, sorted_idx = polygons2masks_overlap(img.shape[:2], + segments, + downsample_ratio=self.downsample_ratio) + masks = masks[None] # (640, 640) -> (1, 640, 640) + labels = labels[sorted_idx] + else: + masks = polygons2masks(img.shape[:2], segments, color=1, downsample_ratio=self.downsample_ratio) + + masks = (torch.from_numpy(masks) if len(masks) else torch.zeros(1 if self.overlap else nl, img.shape[0] // + self.downsample_ratio, img.shape[1] // + self.downsample_ratio)) + # TODO: albumentations support + if self.augment: + # Albumentations + # there are some augmentation that won't change boxes and masks, + # so just be it for now. + img, labels = self.albumentations(img, labels) + nl = len(labels) # update after albumentations + + # HSV color-space + augment_hsv(img, hgain=hyp["hsv_h"], sgain=hyp["hsv_s"], vgain=hyp["hsv_v"]) + + # Flip up-down + if random.random() < hyp["flipud"]: + img = np.flipud(img) + if nl: + labels[:, 2] = 1 - labels[:, 2] + masks = torch.flip(masks, dims=[1]) + + # Flip left-right + if random.random() < hyp["fliplr"]: + img = np.fliplr(img) + if nl: + labels[:, 1] = 1 - labels[:, 1] + masks = torch.flip(masks, dims=[2]) + + # Cutouts # labels = cutout(img, labels, p=0.5) + + labels_out = torch.zeros((nl, 6)) + if nl: + labels_out[:, 1:] = torch.from_numpy(labels) + + # Convert + img = img.transpose((2, 0, 1))[::-1] # HWC to CHW, BGR to RGB + img = np.ascontiguousarray(img) + + return (torch.from_numpy(img), labels_out, self.im_files[index], shapes, masks) + + def load_mosaic(self, index): + # YOLOv5 4-mosaic loader. Loads 1 image + 3 random images into a 4-image mosaic + labels4, segments4 = [], [] + s = self.img_size + yc, xc = (int(random.uniform(-x, 2 * s + x)) for x in self.mosaic_border) # mosaic center x, y + + # 3 additional image indices + indices = [index] + random.choices(self.indices, k=3) # 3 additional image indices + for i, index in enumerate(indices): + # Load image + img, _, (h, w) = self.load_image(index) + + # place img in img4 + if i == 0: # top left + img4 = np.full((s * 2, s * 2, img.shape[2]), 114, dtype=np.uint8) # base image with 4 tiles + x1a, y1a, x2a, y2a = max(xc - w, 0), max(yc - h, 0), xc, yc # xmin, ymin, xmax, ymax (large image) + x1b, y1b, x2b, y2b = w - (x2a - x1a), h - (y2a - y1a), w, h # xmin, ymin, xmax, ymax (small image) + elif i == 1: # top right + x1a, y1a, x2a, y2a = xc, max(yc - h, 0), min(xc + w, s * 2), yc + x1b, y1b, x2b, y2b = 0, h - (y2a - y1a), min(w, x2a - x1a), h + elif i == 2: # bottom left + x1a, y1a, x2a, y2a = max(xc - w, 0), yc, xc, min(s * 2, yc + h) + x1b, y1b, x2b, y2b = w - (x2a - x1a), 0, w, min(y2a - y1a, h) + elif i == 3: # bottom right + x1a, y1a, x2a, y2a = xc, yc, min(xc + w, s * 2), min(s * 2, yc + h) + x1b, y1b, x2b, y2b = 0, 0, min(w, x2a - x1a), min(y2a - y1a, h) + + img4[y1a:y2a, x1a:x2a] = img[y1b:y2b, x1b:x2b] # img4[ymin:ymax, xmin:xmax] + padw = x1a - x1b + padh = y1a - y1b + + labels, segments = self.labels[index].copy(), self.segments[index].copy() + + if labels.size: + labels[:, 1:] = xywhn2xyxy(labels[:, 1:], w, h, padw, padh) # normalized xywh to pixel xyxy format + segments = [xyn2xy(x, w, h, padw, padh) for x in segments] + labels4.append(labels) + segments4.extend(segments) + + # Concat/clip labels + labels4 = np.concatenate(labels4, 0) + for x in (labels4[:, 1:], *segments4): + np.clip(x, 0, 2 * s, out=x) # clip when using random_perspective() + # img4, labels4 = replicate(img4, labels4) # replicate + + # Augment + img4, labels4, segments4 = copy_paste(img4, labels4, segments4, p=self.hyp["copy_paste"]) + img4, labels4, segments4 = random_perspective(img4, + labels4, + segments4, + degrees=self.hyp["degrees"], + translate=self.hyp["translate"], + scale=self.hyp["scale"], + shear=self.hyp["shear"], + perspective=self.hyp["perspective"], + border=self.mosaic_border) # border to remove + return img4, labels4, segments4 + + @staticmethod + def collate_fn(batch): + img, label, path, shapes, masks = zip(*batch) # transposed + batched_masks = torch.cat(masks, 0) + for i, l in enumerate(label): + l[:, 0] = i # add target image index for build_targets() + return torch.stack(img, 0), torch.cat(label, 0), path, shapes, batched_masks + + +def polygon2mask(img_size, polygons, color=1, downsample_ratio=1): + """ + Args: + img_size (tuple): The image size. + polygons (np.ndarray): [N, M], N is the number of polygons, + M is the number of points(Be divided by 2). + """ + mask = np.zeros(img_size, dtype=np.uint8) + polygons = np.asarray(polygons) + polygons = polygons.astype(np.int32) + shape = polygons.shape + polygons = polygons.reshape(shape[0], -1, 2) + cv2.fillPoly(mask, polygons, color=color) + nh, nw = (img_size[0] // downsample_ratio, img_size[1] // downsample_ratio) + # NOTE: fillPoly firstly then resize is trying the keep the same way + # of loss calculation when mask-ratio=1. + mask = cv2.resize(mask, (nw, nh)) + return mask + + +def polygons2masks(img_size, polygons, color, downsample_ratio=1): + """ + Args: + img_size (tuple): The image size. + polygons (list[np.ndarray]): each polygon is [N, M], + N is the number of polygons, + M is the number of points(Be divided by 2). + """ + masks = [] + for si in range(len(polygons)): + mask = polygon2mask(img_size, [polygons[si].reshape(-1)], color, downsample_ratio) + masks.append(mask) + return np.array(masks) + + +def polygons2masks_overlap(img_size, segments, downsample_ratio=1): + """Return a (640, 640) overlap mask.""" + masks = np.zeros((img_size[0] // downsample_ratio, img_size[1] // downsample_ratio), + dtype=np.int32 if len(segments) > 255 else np.uint8) + areas = [] + ms = [] + for si in range(len(segments)): + mask = polygon2mask( + img_size, + [segments[si].reshape(-1)], + downsample_ratio=downsample_ratio, + color=1, + ) + ms.append(mask) + areas.append(mask.sum()) + areas = np.asarray(areas) + index = np.argsort(-areas) + ms = np.array(ms)[index] + for i in range(len(segments)): + mask = ms[i] * (i + 1) + masks = masks + mask + masks = np.clip(masks, a_min=0, a_max=i + 1) + return masks, index diff --git a/cv/3d_detection/yolov9/pytorch/utils/segment/general.py b/cv/3d_detection/yolov9/pytorch/utils/segment/general.py new file mode 100644 index 000000000..b526333dc --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/utils/segment/general.py @@ -0,0 +1,137 @@ +import cv2 +import numpy as np +import torch +import torch.nn.functional as F + + +def crop_mask(masks, boxes): + """ + "Crop" predicted masks by zeroing out everything not in the predicted bbox. + Vectorized by Chong (thanks Chong). + + Args: + - masks should be a size [h, w, n] tensor of masks + - boxes should be a size [n, 4] tensor of bbox coords in relative point form + """ + + n, h, w = masks.shape + x1, y1, x2, y2 = torch.chunk(boxes[:, :, None], 4, 1) # x1 shape(1,1,n) + r = torch.arange(w, device=masks.device, dtype=x1.dtype)[None, None, :] # rows shape(1,w,1) + c = torch.arange(h, device=masks.device, dtype=x1.dtype)[None, :, None] # cols shape(h,1,1) + + return masks * ((r >= x1) * (r < x2) * (c >= y1) * (c < y2)) + + +def process_mask_upsample(protos, masks_in, bboxes, shape): + """ + Crop after upsample. + proto_out: [mask_dim, mask_h, mask_w] + out_masks: [n, mask_dim], n is number of masks after nms + bboxes: [n, 4], n is number of masks after nms + shape:input_image_size, (h, w) + + return: h, w, n + """ + + c, mh, mw = protos.shape # CHW + masks = (masks_in @ protos.float().view(c, -1)).sigmoid().view(-1, mh, mw) + masks = F.interpolate(masks[None], shape, mode='bilinear', align_corners=False)[0] # CHW + masks = crop_mask(masks, bboxes) # CHW + return masks.gt_(0.5) + + +def process_mask(protos, masks_in, bboxes, shape, upsample=False): + """ + Crop before upsample. + proto_out: [mask_dim, mask_h, mask_w] + out_masks: [n, mask_dim], n is number of masks after nms + bboxes: [n, 4], n is number of masks after nms + shape:input_image_size, (h, w) + + return: h, w, n + """ + + c, mh, mw = protos.shape # CHW + ih, iw = shape + masks = (masks_in @ protos.float().view(c, -1)).sigmoid().view(-1, mh, mw) # CHW + + downsampled_bboxes = bboxes.clone() + downsampled_bboxes[:, 0] *= mw / iw + downsampled_bboxes[:, 2] *= mw / iw + downsampled_bboxes[:, 3] *= mh / ih + downsampled_bboxes[:, 1] *= mh / ih + + masks = crop_mask(masks, downsampled_bboxes) # CHW + if upsample: + masks = F.interpolate(masks[None], shape, mode='bilinear', align_corners=False)[0] # CHW + return masks.gt_(0.5) + + +def scale_image(im1_shape, masks, im0_shape, ratio_pad=None): + """ + img1_shape: model input shape, [h, w] + img0_shape: origin pic shape, [h, w, 3] + masks: [h, w, num] + """ + # Rescale coordinates (xyxy) from im1_shape to im0_shape + if ratio_pad is None: # calculate from im0_shape + gain = min(im1_shape[0] / im0_shape[0], im1_shape[1] / im0_shape[1]) # gain = old / new + pad = (im1_shape[1] - im0_shape[1] * gain) / 2, (im1_shape[0] - im0_shape[0] * gain) / 2 # wh padding + else: + pad = ratio_pad[1] + top, left = int(pad[1]), int(pad[0]) # y, x + bottom, right = int(im1_shape[0] - pad[1]), int(im1_shape[1] - pad[0]) + + if len(masks.shape) < 2: + raise ValueError(f'"len of masks shape" should be 2 or 3, but got {len(masks.shape)}') + masks = masks[top:bottom, left:right] + # masks = masks.permute(2, 0, 1).contiguous() + # masks = F.interpolate(masks[None], im0_shape[:2], mode='bilinear', align_corners=False)[0] + # masks = masks.permute(1, 2, 0).contiguous() + masks = cv2.resize(masks, (im0_shape[1], im0_shape[0])) + + if len(masks.shape) == 2: + masks = masks[:, :, None] + return masks + + +def mask_iou(mask1, mask2, eps=1e-7): + """ + mask1: [N, n] m1 means number of predicted objects + mask2: [M, n] m2 means number of gt objects + Note: n means image_w x image_h + + return: masks iou, [N, M] + """ + intersection = torch.matmul(mask1, mask2.t()).clamp(0) + union = (mask1.sum(1)[:, None] + mask2.sum(1)[None]) - intersection # (area1 + area2) - intersection + return intersection / (union + eps) + + +def masks_iou(mask1, mask2, eps=1e-7): + """ + mask1: [N, n] m1 means number of predicted objects + mask2: [N, n] m2 means number of gt objects + Note: n means image_w x image_h + + return: masks iou, (N, ) + """ + intersection = (mask1 * mask2).sum(1).clamp(0) # (N, ) + union = (mask1.sum(1) + mask2.sum(1))[None] - intersection # (area1 + area2) - intersection + return intersection / (union + eps) + + +def masks2segments(masks, strategy='largest'): + # Convert masks(n,160,160) into segments(n,xy) + segments = [] + for x in masks.int().cpu().numpy().astype('uint8'): + c = cv2.findContours(x, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[0] + if c: + if strategy == 'concat': # concatenate all segments + c = np.concatenate([x.reshape(-1, 2) for x in c]) + elif strategy == 'largest': # select largest segment + c = np.array(c[np.array([len(x) for x in c]).argmax()]).reshape(-1, 2) + else: + c = np.zeros((0, 2)) # no segments found + segments.append(c.astype('float32')) + return segments diff --git a/cv/3d_detection/yolov9/pytorch/utils/segment/loss.py b/cv/3d_detection/yolov9/pytorch/utils/segment/loss.py new file mode 100644 index 000000000..b45b2c27e --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/utils/segment/loss.py @@ -0,0 +1,186 @@ +import torch +import torch.nn as nn +import torch.nn.functional as F + +from ..general import xywh2xyxy +from ..loss import FocalLoss, smooth_BCE +from ..metrics import bbox_iou +from ..torch_utils import de_parallel +from .general import crop_mask + + +class ComputeLoss: + # Compute losses + def __init__(self, model, autobalance=False, overlap=False): + self.sort_obj_iou = False + self.overlap = overlap + device = next(model.parameters()).device # get model device + h = model.hyp # hyperparameters + self.device = device + + # Define criteria + BCEcls = nn.BCEWithLogitsLoss(pos_weight=torch.tensor([h['cls_pw']], device=device)) + BCEobj = nn.BCEWithLogitsLoss(pos_weight=torch.tensor([h['obj_pw']], device=device)) + + # Class label smoothing https://arxiv.org/pdf/1902.04103.pdf eqn 3 + self.cp, self.cn = smooth_BCE(eps=h.get('label_smoothing', 0.0)) # positive, negative BCE targets + + # Focal loss + g = h['fl_gamma'] # focal loss gamma + if g > 0: + BCEcls, BCEobj = FocalLoss(BCEcls, g), FocalLoss(BCEobj, g) + + m = de_parallel(model).model[-1] # Detect() module + self.balance = {3: [4.0, 1.0, 0.4]}.get(m.nl, [4.0, 1.0, 0.25, 0.06, 0.02]) # P3-P7 + self.ssi = list(m.stride).index(16) if autobalance else 0 # stride 16 index + self.BCEcls, self.BCEobj, self.gr, self.hyp, self.autobalance = BCEcls, BCEobj, 1.0, h, autobalance + self.na = m.na # number of anchors + self.nc = m.nc # number of classes + self.nl = m.nl # number of layers + self.nm = m.nm # number of masks + self.anchors = m.anchors + self.device = device + + def __call__(self, preds, targets, masks): # predictions, targets, model + p, proto = preds + bs, nm, mask_h, mask_w = proto.shape # batch size, number of masks, mask height, mask width + lcls = torch.zeros(1, device=self.device) + lbox = torch.zeros(1, device=self.device) + lobj = torch.zeros(1, device=self.device) + lseg = torch.zeros(1, device=self.device) + tcls, tbox, indices, anchors, tidxs, xywhn = self.build_targets(p, targets) # targets + + # Losses + for i, pi in enumerate(p): # layer index, layer predictions + b, a, gj, gi = indices[i] # image, anchor, gridy, gridx + tobj = torch.zeros(pi.shape[:4], dtype=pi.dtype, device=self.device) # target obj + + n = b.shape[0] # number of targets + if n: + pxy, pwh, _, pcls, pmask = pi[b, a, gj, gi].split((2, 2, 1, self.nc, nm), 1) # subset of predictions + + # Box regression + pxy = pxy.sigmoid() * 2 - 0.5 + pwh = (pwh.sigmoid() * 2) ** 2 * anchors[i] + pbox = torch.cat((pxy, pwh), 1) # predicted box + iou = bbox_iou(pbox, tbox[i], CIoU=True).squeeze() # iou(prediction, target) + lbox += (1.0 - iou).mean() # iou loss + + # Objectness + iou = iou.detach().clamp(0).type(tobj.dtype) + if self.sort_obj_iou: + j = iou.argsort() + b, a, gj, gi, iou = b[j], a[j], gj[j], gi[j], iou[j] + if self.gr < 1: + iou = (1.0 - self.gr) + self.gr * iou + tobj[b, a, gj, gi] = iou # iou ratio + + # Classification + if self.nc > 1: # cls loss (only if multiple classes) + t = torch.full_like(pcls, self.cn, device=self.device) # targets + t[range(n), tcls[i]] = self.cp + lcls += self.BCEcls(pcls, t) # BCE + + # Mask regression + if tuple(masks.shape[-2:]) != (mask_h, mask_w): # downsample + masks = F.interpolate(masks[None], (mask_h, mask_w), mode="nearest")[0] + marea = xywhn[i][:, 2:].prod(1) # mask width, height normalized + mxyxy = xywh2xyxy(xywhn[i] * torch.tensor([mask_w, mask_h, mask_w, mask_h], device=self.device)) + for bi in b.unique(): + j = b == bi # matching index + if self.overlap: + mask_gti = torch.where(masks[bi][None] == tidxs[i][j].view(-1, 1, 1), 1.0, 0.0) + else: + mask_gti = masks[tidxs[i]][j] + lseg += self.single_mask_loss(mask_gti, pmask[j], proto[bi], mxyxy[j], marea[j]) + + obji = self.BCEobj(pi[..., 4], tobj) + lobj += obji * self.balance[i] # obj loss + if self.autobalance: + self.balance[i] = self.balance[i] * 0.9999 + 0.0001 / obji.detach().item() + + if self.autobalance: + self.balance = [x / self.balance[self.ssi] for x in self.balance] + lbox *= self.hyp["box"] + lobj *= self.hyp["obj"] + lcls *= self.hyp["cls"] + lseg *= self.hyp["box"] / bs + + loss = lbox + lobj + lcls + lseg + return loss * bs, torch.cat((lbox, lseg, lobj, lcls)).detach() + + def single_mask_loss(self, gt_mask, pred, proto, xyxy, area): + # Mask loss for one image + pred_mask = (pred @ proto.view(self.nm, -1)).view(-1, *proto.shape[1:]) # (n,32) @ (32,80,80) -> (n,80,80) + loss = F.binary_cross_entropy_with_logits(pred_mask, gt_mask, reduction="none") + return (crop_mask(loss, xyxy).mean(dim=(1, 2)) / area).mean() + + def build_targets(self, p, targets): + # Build targets for compute_loss(), input targets(image,class,x,y,w,h) + na, nt = self.na, targets.shape[0] # number of anchors, targets + tcls, tbox, indices, anch, tidxs, xywhn = [], [], [], [], [], [] + gain = torch.ones(8, device=self.device) # normalized to gridspace gain + ai = torch.arange(na, device=self.device).float().view(na, 1).repeat(1, nt) # same as .repeat_interleave(nt) + if self.overlap: + batch = p[0].shape[0] + ti = [] + for i in range(batch): + num = (targets[:, 0] == i).sum() # find number of targets of each image + ti.append(torch.arange(num, device=self.device).float().view(1, num).repeat(na, 1) + 1) # (na, num) + ti = torch.cat(ti, 1) # (na, nt) + else: + ti = torch.arange(nt, device=self.device).float().view(1, nt).repeat(na, 1) + targets = torch.cat((targets.repeat(na, 1, 1), ai[..., None], ti[..., None]), 2) # append anchor indices + + g = 0.5 # bias + off = torch.tensor( + [ + [0, 0], + [1, 0], + [0, 1], + [-1, 0], + [0, -1], # j,k,l,m + # [1, 1], [1, -1], [-1, 1], [-1, -1], # jk,jm,lk,lm + ], + device=self.device).float() * g # offsets + + for i in range(self.nl): + anchors, shape = self.anchors[i], p[i].shape + gain[2:6] = torch.tensor(shape)[[3, 2, 3, 2]] # xyxy gain + + # Match targets to anchors + t = targets * gain # shape(3,n,7) + if nt: + # Matches + r = t[..., 4:6] / anchors[:, None] # wh ratio + j = torch.max(r, 1 / r).max(2)[0] < self.hyp['anchor_t'] # compare + # j = wh_iou(anchors, t[:, 4:6]) > model.hyp['iou_t'] # iou(3,n)=wh_iou(anchors(3,2), gwh(n,2)) + t = t[j] # filter + + # Offsets + gxy = t[:, 2:4] # grid xy + gxi = gain[[2, 3]] - gxy # inverse + j, k = ((gxy % 1 < g) & (gxy > 1)).T + l, m = ((gxi % 1 < g) & (gxi > 1)).T + j = torch.stack((torch.ones_like(j), j, k, l, m)) + t = t.repeat((5, 1, 1))[j] + offsets = (torch.zeros_like(gxy)[None] + off[:, None])[j] + else: + t = targets[0] + offsets = 0 + + # Define + bc, gxy, gwh, at = t.chunk(4, 1) # (image, class), grid xy, grid wh, anchors + (a, tidx), (b, c) = at.long().T, bc.long().T # anchors, image, class + gij = (gxy - offsets).long() + gi, gj = gij.T # grid indices + + # Append + indices.append((b, a, gj.clamp_(0, shape[2] - 1), gi.clamp_(0, shape[3] - 1))) # image, anchor, grid + tbox.append(torch.cat((gxy - gij, gwh), 1)) # box + anch.append(anchors[a]) # anchors + tcls.append(c) # class + tidxs.append(tidx) + xywhn.append(torch.cat((gxy, gwh), 1) / gain[2:6]) # xywh normalized + + return tcls, tbox, indices, anch, tidxs, xywhn diff --git a/cv/3d_detection/yolov9/pytorch/utils/segment/loss_tal.py b/cv/3d_detection/yolov9/pytorch/utils/segment/loss_tal.py new file mode 100644 index 000000000..3f90b27ef --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/utils/segment/loss_tal.py @@ -0,0 +1,261 @@ +import os + +import torch +import torch.nn as nn +import torch.nn.functional as F + +from torchvision.ops import sigmoid_focal_loss + +from utils.general import xywh2xyxy, xyxy2xywh +from utils.metrics import bbox_iou +from utils.segment.tal.anchor_generator import dist2bbox, make_anchors, bbox2dist +from utils.segment.tal.assigner import TaskAlignedAssigner +from utils.torch_utils import de_parallel +from utils.segment.general import crop_mask + + +def smooth_BCE(eps=0.1): # https://github.com/ultralytics/yolov3/issues/238#issuecomment-598028441 + # return positive, negative label smoothing BCE targets + return 1.0 - 0.5 * eps, 0.5 * eps + + +class VarifocalLoss(nn.Module): + # Varifocal loss by Zhang et al. https://arxiv.org/abs/2008.13367 + def __init__(self): + super().__init__() + + def forward(self, pred_score, gt_score, label, alpha=0.75, gamma=2.0): + weight = alpha * pred_score.sigmoid().pow(gamma) * (1 - label) + gt_score * label + with torch.cuda.amp.autocast(enabled=False): + loss = (F.binary_cross_entropy_with_logits(pred_score.float(), gt_score.float(), + reduction="none") * weight).sum() + return loss + + +class FocalLoss(nn.Module): + # Wraps focal loss around existing loss_fcn(), i.e. criteria = FocalLoss(nn.BCEWithLogitsLoss(), gamma=1.5) + def __init__(self, loss_fcn, gamma=1.5, alpha=0.25): + super().__init__() + self.loss_fcn = loss_fcn # must be nn.BCEWithLogitsLoss() + self.gamma = gamma + self.alpha = alpha + self.reduction = loss_fcn.reduction + self.loss_fcn.reduction = "none" # required to apply FL to each element + + def forward(self, pred, true): + loss = self.loss_fcn(pred, true) + # p_t = torch.exp(-loss) + # loss *= self.alpha * (1.000001 - p_t) ** self.gamma # non-zero power for gradient stability + + # TF implementation https://github.com/tensorflow/addons/blob/v0.7.1/tensorflow_addons/losses/focal_loss.py + pred_prob = torch.sigmoid(pred) # prob from logits + p_t = true * pred_prob + (1 - true) * (1 - pred_prob) + alpha_factor = true * self.alpha + (1 - true) * (1 - self.alpha) + modulating_factor = (1.0 - p_t) ** self.gamma + loss *= alpha_factor * modulating_factor + + if self.reduction == "mean": + return loss.mean() + elif self.reduction == "sum": + return loss.sum() + else: # 'none' + return loss + + +class BboxLoss(nn.Module): + def __init__(self, reg_max, use_dfl=False): + super().__init__() + self.reg_max = reg_max + self.use_dfl = use_dfl + + def forward(self, pred_dist, pred_bboxes, anchor_points, target_bboxes, target_scores, target_scores_sum, fg_mask): + # iou loss + bbox_mask = fg_mask.unsqueeze(-1).repeat([1, 1, 4]) # (b, h*w, 4) + pred_bboxes_pos = torch.masked_select(pred_bboxes, bbox_mask).view(-1, 4) + target_bboxes_pos = torch.masked_select(target_bboxes, bbox_mask).view(-1, 4) + bbox_weight = torch.masked_select(target_scores.sum(-1), fg_mask).unsqueeze(-1) + + iou = bbox_iou(pred_bboxes_pos, target_bboxes_pos, xywh=False, CIoU=True) + loss_iou = 1.0 - iou + + loss_iou *= bbox_weight + loss_iou = loss_iou.sum() / target_scores_sum + + # dfl loss + if self.use_dfl: + dist_mask = fg_mask.unsqueeze(-1).repeat([1, 1, (self.reg_max + 1) * 4]) + pred_dist_pos = torch.masked_select(pred_dist, dist_mask).view(-1, 4, self.reg_max + 1) + target_ltrb = bbox2dist(anchor_points, target_bboxes, self.reg_max) + target_ltrb_pos = torch.masked_select(target_ltrb, bbox_mask).view(-1, 4) + loss_dfl = self._df_loss(pred_dist_pos, target_ltrb_pos) * bbox_weight + loss_dfl = loss_dfl.sum() / target_scores_sum + else: + loss_dfl = torch.tensor(0.0).to(pred_dist.device) + + return loss_iou, loss_dfl, iou + + def _df_loss(self, pred_dist, target): + target_left = target.to(torch.long) + target_right = target_left + 1 + weight_left = target_right.to(torch.float) - target + weight_right = 1 - weight_left + loss_left = F.cross_entropy(pred_dist.view(-1, self.reg_max + 1), target_left.view(-1), reduction="none").view( + target_left.shape) * weight_left + loss_right = F.cross_entropy(pred_dist.view(-1, self.reg_max + 1), target_right.view(-1), + reduction="none").view(target_left.shape) * weight_right + return (loss_left + loss_right).mean(-1, keepdim=True) + + +class ComputeLoss: + # Compute losses + def __init__(self, model, use_dfl=True, overlap=True): + device = next(model.parameters()).device # get model device + h = model.hyp # hyperparameters + + # Define criteria + BCEcls = nn.BCEWithLogitsLoss(pos_weight=torch.tensor([h["cls_pw"]], device=device), reduction='none') + + # Class label smoothing https://arxiv.org/pdf/1902.04103.pdf eqn 3 + self.cp, self.cn = smooth_BCE(eps=h.get("label_smoothing", 0.0)) # positive, negative BCE targets + + # Focal loss + g = h["fl_gamma"] # focal loss gamma + if g > 0: + BCEcls = FocalLoss(BCEcls, g) + + m = de_parallel(model).model[-1] # Detect() module + self.balance = {3: [4.0, 1.0, 0.4]}.get(m.nl, [4.0, 1.0, 0.25, 0.06, 0.02]) # P3-P7 + self.BCEcls = BCEcls + self.hyp = h + self.stride = m.stride # model strides + self.nc = m.nc # number of classes + self.nl = m.nl # number of layers + self.no = m.no + self.nm = m.nm + self.overlap = overlap + self.reg_max = m.reg_max + self.device = device + + self.assigner = TaskAlignedAssigner(topk=int(os.getenv('YOLOM', 10)), + num_classes=self.nc, + alpha=float(os.getenv('YOLOA', 0.5)), + beta=float(os.getenv('YOLOB', 6.0))) + self.bbox_loss = BboxLoss(m.reg_max - 1, use_dfl=use_dfl).to(device) + self.proj = torch.arange(m.reg_max).float().to(device) # / 120.0 + self.use_dfl = use_dfl + + def preprocess(self, targets, batch_size, scale_tensor): + if targets.shape[0] == 0: + out = torch.zeros(batch_size, 0, 5, device=self.device) + else: + i = targets[:, 0] # image index + _, counts = i.unique(return_counts=True) + out = torch.zeros(batch_size, counts.max(), 5, device=self.device) + for j in range(batch_size): + matches = i == j + n = matches.sum() + if n: + out[j, :n] = targets[matches, 1:] + out[..., 1:5] = xywh2xyxy(out[..., 1:5].mul_(scale_tensor)) + return out + + def bbox_decode(self, anchor_points, pred_dist): + if self.use_dfl: + b, a, c = pred_dist.shape # batch, anchors, channels + pred_dist = pred_dist.view(b, a, 4, c // 4).softmax(3).matmul(self.proj.type(pred_dist.dtype)) + # pred_dist = pred_dist.view(b, a, c // 4, 4).transpose(2,3).softmax(3).matmul(self.proj.type(pred_dist.dtype)) + # pred_dist = (pred_dist.view(b, a, c // 4, 4).softmax(2) * self.proj.type(pred_dist.dtype).view(1, 1, -1, 1)).sum(2) + return dist2bbox(pred_dist, anchor_points, xywh=False) + + def __call__(self, p, targets, masks, img=None, epoch=0): + loss = torch.zeros(4, device=self.device) # box, cls, dfl + feats, pred_masks, proto = p if len(p) == 3 else p[1] + batch_size, _, mask_h, mask_w = proto.shape + pred_distri, pred_scores = torch.cat([xi.view(feats[0].shape[0], self.no, -1) for xi in feats], 2).split( + (self.reg_max * 4, self.nc), 1) + pred_scores = pred_scores.permute(0, 2, 1).contiguous() + pred_distri = pred_distri.permute(0, 2, 1).contiguous() + pred_masks = pred_masks.permute(0, 2, 1).contiguous() + + dtype = pred_scores.dtype + batch_size, grid_size = pred_scores.shape[:2] + imgsz = torch.tensor(feats[0].shape[2:], device=self.device, dtype=dtype) * self.stride[0] # image size (h,w) + anchor_points, stride_tensor = make_anchors(feats, self.stride, 0.5) + + # targets + try: + batch_idx = targets[:, 0].view(-1, 1) + targets = self.preprocess(targets.to(self.device), batch_size, scale_tensor=imgsz[[1, 0, 1, 0]]) + gt_labels, gt_bboxes = targets.split((1, 4), 2) # cls, xyxy + mask_gt = gt_bboxes.sum(2, keepdim=True).gt_(0) + except RuntimeError as e: + raise TypeError('ERROR.') from e + + + # pboxes + pred_bboxes = self.bbox_decode(anchor_points, pred_distri) # xyxy, (b, h*w, 4) + + target_labels, target_bboxes, target_scores, fg_mask, target_gt_idx = self.assigner( + pred_scores.detach().sigmoid(), + (pred_bboxes.detach() * stride_tensor).type(gt_bboxes.dtype), + anchor_points * stride_tensor, + gt_labels, + gt_bboxes, + mask_gt) + + target_scores_sum = target_scores.sum() + + # cls loss + # loss[1] = self.varifocal_loss(pred_scores, target_scores, target_labels) / target_scores_sum # VFL way + loss[2] = self.BCEcls(pred_scores, target_scores.to(dtype)).sum() / target_scores_sum # BCE + + # bbox loss + if fg_mask.sum(): + loss[0], loss[3], _ = self.bbox_loss(pred_distri, + pred_bboxes, + anchor_points, + target_bboxes / stride_tensor, + target_scores, + target_scores_sum, + fg_mask) + + # masks loss + if tuple(masks.shape[-2:]) != (mask_h, mask_w): # downsample + masks = F.interpolate(masks[None], (mask_h, mask_w), mode='nearest')[0] + + for i in range(batch_size): + if fg_mask[i].sum(): + mask_idx = target_gt_idx[i][fg_mask[i]] + if self.overlap: + gt_mask = torch.where(masks[[i]] == (mask_idx + 1).view(-1, 1, 1), 1.0, 0.0) + else: + gt_mask = masks[batch_idx.view(-1) == i][mask_idx] + xyxyn = target_bboxes[i][fg_mask[i]] / imgsz[[1, 0, 1, 0]] + marea = xyxy2xywh(xyxyn)[:, 2:].prod(1) + mxyxy = xyxyn * torch.tensor([mask_w, mask_h, mask_w, mask_h], device=self.device) + loss[1] += self.single_mask_loss(gt_mask, pred_masks[i][fg_mask[i]], proto[i], mxyxy, + marea) # seg loss + + loss[0] *= 7.5 # box gain + loss[1] *= 2.5 / batch_size + loss[2] *= 0.5 # cls gain + loss[3] *= 1.5 # dfl gain + + return loss.sum() * batch_size, loss.detach() # loss(box, cls, dfl) + + def single_mask_loss(self, gt_mask, pred, proto, xyxy, area): + # Mask loss for one image + pred_mask = (pred @ proto.view(self.nm, -1)).view(-1, *proto.shape[1:]) # (n, 32) @ (32,80,80) -> (n,80,80) + loss = F.binary_cross_entropy_with_logits(pred_mask, gt_mask, reduction='none') + #loss = sigmoid_focal_loss(pred_mask, gt_mask, alpha = .25, gamma = 2., reduction = 'none') + + return (crop_mask(loss, xyxy).mean(dim=(1, 2)) / area).mean() + + #p_m = torch.flatten(pred_mask.sigmoid()) + #p_m = torch.flatten(pred_mask.softmax(dim = 1)) + #g_m = torch.flatten(gt_mask) + #i_m = torch.sum(torch.mul(p_m, g_m)) + #u_m = torch.sum(torch.add(p_m, g_m)) + #d_c = (2. * i_m + 1.) / (u_m + 1.) + #d_l = (1. - d_c) + #return d_l diff --git a/cv/3d_detection/yolov9/pytorch/utils/segment/loss_tal_dual.py b/cv/3d_detection/yolov9/pytorch/utils/segment/loss_tal_dual.py new file mode 100644 index 000000000..87bb8ebfb --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/utils/segment/loss_tal_dual.py @@ -0,0 +1,727 @@ +import os + +import torch +import torch.nn as nn +import torch.nn.functional as F + +from torchvision.ops import sigmoid_focal_loss + +from utils.general import xywh2xyxy, xyxy2xywh +from utils.metrics import bbox_iou +from utils.segment.tal.anchor_generator import dist2bbox, make_anchors, bbox2dist +from utils.segment.tal.assigner import TaskAlignedAssigner +from utils.torch_utils import de_parallel +from utils.segment.general import crop_mask + + +def smooth_BCE(eps=0.1): # https://github.com/ultralytics/yolov3/issues/238#issuecomment-598028441 + # return positive, negative label smoothing BCE targets + return 1.0 - 0.5 * eps, 0.5 * eps + + +class VarifocalLoss(nn.Module): + # Varifocal loss by Zhang et al. https://arxiv.org/abs/2008.13367 + def __init__(self): + super().__init__() + + def forward(self, pred_score, gt_score, label, alpha=0.75, gamma=2.0): + weight = alpha * pred_score.sigmoid().pow(gamma) * (1 - label) + gt_score * label + with torch.cuda.amp.autocast(enabled=False): + loss = (F.binary_cross_entropy_with_logits(pred_score.float(), gt_score.float(), + reduction="none") * weight).sum() + return loss + + +class FocalLoss(nn.Module): + # Wraps focal loss around existing loss_fcn(), i.e. criteria = FocalLoss(nn.BCEWithLogitsLoss(), gamma=1.5) + def __init__(self, loss_fcn, gamma=1.5, alpha=0.25): + super().__init__() + self.loss_fcn = loss_fcn # must be nn.BCEWithLogitsLoss() + self.gamma = gamma + self.alpha = alpha + self.reduction = loss_fcn.reduction + self.loss_fcn.reduction = "none" # required to apply FL to each element + + def forward(self, pred, true): + loss = self.loss_fcn(pred, true) + # p_t = torch.exp(-loss) + # loss *= self.alpha * (1.000001 - p_t) ** self.gamma # non-zero power for gradient stability + + # TF implementation https://github.com/tensorflow/addons/blob/v0.7.1/tensorflow_addons/losses/focal_loss.py + pred_prob = torch.sigmoid(pred) # prob from logits + p_t = true * pred_prob + (1 - true) * (1 - pred_prob) + alpha_factor = true * self.alpha + (1 - true) * (1 - self.alpha) + modulating_factor = (1.0 - p_t) ** self.gamma + loss *= alpha_factor * modulating_factor + + if self.reduction == "mean": + return loss.mean() + elif self.reduction == "sum": + return loss.sum() + else: # 'none' + return loss + + +class BboxLoss(nn.Module): + def __init__(self, reg_max, use_dfl=False): + super().__init__() + self.reg_max = reg_max + self.use_dfl = use_dfl + + def forward(self, pred_dist, pred_bboxes, anchor_points, target_bboxes, target_scores, target_scores_sum, fg_mask): + # iou loss + bbox_mask = fg_mask.unsqueeze(-1).repeat([1, 1, 4]) # (b, h*w, 4) + pred_bboxes_pos = torch.masked_select(pred_bboxes, bbox_mask).view(-1, 4) + target_bboxes_pos = torch.masked_select(target_bboxes, bbox_mask).view(-1, 4) + bbox_weight = torch.masked_select(target_scores.sum(-1), fg_mask).unsqueeze(-1) + + iou = bbox_iou(pred_bboxes_pos, target_bboxes_pos, xywh=False, CIoU=True) + loss_iou = 1.0 - iou + + loss_iou *= bbox_weight + loss_iou = loss_iou.sum() / target_scores_sum + + # dfl loss + if self.use_dfl: + dist_mask = fg_mask.unsqueeze(-1).repeat([1, 1, (self.reg_max + 1) * 4]) + pred_dist_pos = torch.masked_select(pred_dist, dist_mask).view(-1, 4, self.reg_max + 1) + target_ltrb = bbox2dist(anchor_points, target_bboxes, self.reg_max) + target_ltrb_pos = torch.masked_select(target_ltrb, bbox_mask).view(-1, 4) + loss_dfl = self._df_loss(pred_dist_pos, target_ltrb_pos) * bbox_weight + loss_dfl = loss_dfl.sum() / target_scores_sum + else: + loss_dfl = torch.tensor(0.0).to(pred_dist.device) + + return loss_iou, loss_dfl, iou + + def _df_loss(self, pred_dist, target): + target_left = target.to(torch.long) + target_right = target_left + 1 + weight_left = target_right.to(torch.float) - target + weight_right = 1 - weight_left + loss_left = F.cross_entropy(pred_dist.view(-1, self.reg_max + 1), target_left.view(-1), reduction="none").view( + target_left.shape) * weight_left + loss_right = F.cross_entropy(pred_dist.view(-1, self.reg_max + 1), target_right.view(-1), + reduction="none").view(target_left.shape) * weight_right + return (loss_left + loss_right).mean(-1, keepdim=True) + + +class ComputeLoss: + # Compute losses + def __init__(self, model, use_dfl=True, overlap=True): + device = next(model.parameters()).device # get model device + h = model.hyp # hyperparameters + + # Define criteria + BCEcls = nn.BCEWithLogitsLoss(pos_weight=torch.tensor([h["cls_pw"]], device=device), reduction='none') + + # Class label smoothing https://arxiv.org/pdf/1902.04103.pdf eqn 3 + self.cp, self.cn = smooth_BCE(eps=h.get("label_smoothing", 0.0)) # positive, negative BCE targets + + # Focal loss + g = h["fl_gamma"] # focal loss gamma + if g > 0: + BCEcls = FocalLoss(BCEcls, g) + + m = de_parallel(model).model[-1] # Detect() module + self.balance = {3: [4.0, 1.0, 0.4]}.get(m.nl, [4.0, 1.0, 0.25, 0.06, 0.02]) # P3-P7 + self.BCEcls = BCEcls + self.hyp = h + self.stride = m.stride # model strides + self.nc = m.nc # number of classes + self.nl = m.nl # number of layers + self.no = m.no + self.nm = m.nm + self.overlap = overlap + self.reg_max = m.reg_max + self.device = device + + self.assigner = TaskAlignedAssigner(topk=int(os.getenv('YOLOM', 10)), + num_classes=self.nc, + alpha=float(os.getenv('YOLOA', 0.5)), + beta=float(os.getenv('YOLOB', 6.0))) + self.assigner2 = TaskAlignedAssigner(topk=int(os.getenv('YOLOM', 10)), + num_classes=self.nc, + alpha=float(os.getenv('YOLOA', 0.5)), + beta=float(os.getenv('YOLOB', 6.0))) + self.bbox_loss = BboxLoss(m.reg_max - 1, use_dfl=use_dfl).to(device) + self.bbox_loss2 = BboxLoss(m.reg_max - 1, use_dfl=use_dfl).to(device) + self.proj = torch.arange(m.reg_max).float().to(device) # / 120.0 + self.use_dfl = use_dfl + + def preprocess(self, targets, batch_size, scale_tensor): + if targets.shape[0] == 0: + out = torch.zeros(batch_size, 0, 5, device=self.device) + else: + i = targets[:, 0] # image index + _, counts = i.unique(return_counts=True) + out = torch.zeros(batch_size, counts.max(), 5, device=self.device) + for j in range(batch_size): + matches = i == j + n = matches.sum() + if n: + out[j, :n] = targets[matches, 1:] + out[..., 1:5] = xywh2xyxy(out[..., 1:5].mul_(scale_tensor)) + return out + + def bbox_decode(self, anchor_points, pred_dist): + if self.use_dfl: + b, a, c = pred_dist.shape # batch, anchors, channels + pred_dist = pred_dist.view(b, a, 4, c // 4).softmax(3).matmul(self.proj.type(pred_dist.dtype)) + # pred_dist = pred_dist.view(b, a, c // 4, 4).transpose(2,3).softmax(3).matmul(self.proj.type(pred_dist.dtype)) + # pred_dist = (pred_dist.view(b, a, c // 4, 4).softmax(2) * self.proj.type(pred_dist.dtype).view(1, 1, -1, 1)).sum(2) + return dist2bbox(pred_dist, anchor_points, xywh=False) + + def __call__(self, p, targets, masks, img=None, epoch=0): + loss = torch.zeros(4, device=self.device) # box, cls, dfl + + feats_, pred_masks_, proto_ = p if len(p) == 3 else p[1] + + feats, pred_masks, proto = feats_[0], pred_masks_[0], proto_[0] + feats2, pred_masks2, proto2 = feats_[1], pred_masks_[1], proto_[1] + + batch_size, _, mask_h, mask_w = proto.shape + + pred_distri, pred_scores = torch.cat([xi.view(feats[0].shape[0], self.no, -1) for xi in feats], 2).split( + (self.reg_max * 4, self.nc), 1) + pred_scores = pred_scores.permute(0, 2, 1).contiguous() + pred_distri = pred_distri.permute(0, 2, 1).contiguous() + pred_masks = pred_masks.permute(0, 2, 1).contiguous() + + pred_distri2, pred_scores2 = torch.cat([xi.view(feats[0].shape[0], self.no, -1) for xi in feats2], 2).split( + (self.reg_max * 4, self.nc), 1) + pred_scores2 = pred_scores2.permute(0, 2, 1).contiguous() + pred_distri2 = pred_distri2.permute(0, 2, 1).contiguous() + pred_masks2 = pred_masks2.permute(0, 2, 1).contiguous() + + dtype = pred_scores.dtype + batch_size, grid_size = pred_scores.shape[:2] + imgsz = torch.tensor(feats[0].shape[2:], device=self.device, dtype=dtype) * self.stride[0] # image size (h,w) + anchor_points, stride_tensor = make_anchors(feats, self.stride, 0.5) + + # targets + try: + batch_idx = targets[:, 0].view(-1, 1) + targets = self.preprocess(targets.to(self.device), batch_size, scale_tensor=imgsz[[1, 0, 1, 0]]) + gt_labels, gt_bboxes = targets.split((1, 4), 2) # cls, xyxy + mask_gt = gt_bboxes.sum(2, keepdim=True).gt_(0) + except RuntimeError as e: + raise TypeError('ERROR.') from e + + + # pboxes + pred_bboxes = self.bbox_decode(anchor_points, pred_distri) # xyxy, (b, h*w, 4) + + pred_bboxes2 = self.bbox_decode(anchor_points, pred_distri2) # xyxy, (b, h*w, 4) + + target_labels, target_bboxes, target_scores, fg_mask, target_gt_idx = self.assigner( + pred_scores.detach().sigmoid(), + (pred_bboxes.detach() * stride_tensor).type(gt_bboxes.dtype), + anchor_points * stride_tensor, + gt_labels, + gt_bboxes, + mask_gt) + + target_labels2, target_bboxes2, target_scores2, fg_mask2, target_gt_idx2 = self.assigner2( + pred_scores2.detach().sigmoid(), + (pred_bboxes2.detach() * stride_tensor).type(gt_bboxes.dtype), + anchor_points * stride_tensor, + gt_labels, + gt_bboxes, + mask_gt) + + target_scores_sum = target_scores.sum() + + target_scores_sum2 = target_scores2.sum() + + # cls loss + # loss[1] = self.varifocal_loss(pred_scores, target_scores, target_labels) / target_scores_sum # VFL way + loss[2] = self.BCEcls(pred_scores, target_scores.to(dtype)).sum() / target_scores_sum # BCE + loss[2] *= 0.25 + loss[2] += self.BCEcls(pred_scores2, target_scores2.to(dtype)).sum() / target_scores_sum2 # BCE + + # bbox loss + if fg_mask.sum(): + loss[0], loss[3], _ = self.bbox_loss(pred_distri, + pred_bboxes, + anchor_points, + target_bboxes / stride_tensor, + target_scores, + target_scores_sum, + fg_mask) + + # masks loss + if tuple(masks.shape[-2:]) != (mask_h, mask_w): # downsample + masks = F.interpolate(masks[None], (mask_h, mask_w), mode='nearest')[0] + + for i in range(batch_size): + if fg_mask[i].sum(): + mask_idx = target_gt_idx[i][fg_mask[i]] + if self.overlap: + gt_mask = torch.where(masks[[i]] == (mask_idx + 1).view(-1, 1, 1), 1.0, 0.0) + else: + gt_mask = masks[batch_idx.view(-1) == i][mask_idx] + xyxyn = target_bboxes[i][fg_mask[i]] / imgsz[[1, 0, 1, 0]] + marea = xyxy2xywh(xyxyn)[:, 2:].prod(1) + mxyxy = xyxyn * torch.tensor([mask_w, mask_h, mask_w, mask_h], device=self.device) + loss[1] += self.single_mask_loss(gt_mask, pred_masks[i][fg_mask[i]], proto[i], mxyxy, + marea) # seg loss + + loss[0] *= 0.25 + loss[3] *= 0.25 + loss[1] *= 0.25 + + # bbox loss + if fg_mask2.sum(): + loss0_, loss3_, _ = self.bbox_loss2(pred_distri2, + pred_bboxes2, + anchor_points, + target_bboxes2 / stride_tensor, + target_scores2, + target_scores_sum2, + fg_mask2) + + # masks loss + if tuple(masks.shape[-2:]) != (mask_h, mask_w): # downsample + masks = F.interpolate(masks[None], (mask_h, mask_w), mode='nearest')[0] + + for i in range(batch_size): + if fg_mask2[i].sum(): + mask_idx = target_gt_idx2[i][fg_mask2[i]] + if self.overlap: + gt_mask = torch.where(masks[[i]] == (mask_idx + 1).view(-1, 1, 1), 1.0, 0.0) + else: + gt_mask = masks[batch_idx.view(-1) == i][mask_idx] + xyxyn = target_bboxes2[i][fg_mask2[i]] / imgsz[[1, 0, 1, 0]] + marea = xyxy2xywh(xyxyn)[:, 2:].prod(1) + mxyxy = xyxyn * torch.tensor([mask_w, mask_h, mask_w, mask_h], device=self.device) + loss[1] += self.single_mask_loss(gt_mask, pred_masks2[i][fg_mask2[i]], proto2[i], mxyxy, + marea) # seg loss + + loss[0] += loss0_ + loss[3] += loss3_ + + loss[0] *= 7.5 # box gain + loss[1] *= 2.5 / batch_size + loss[2] *= 0.5 # cls gain + loss[3] *= 1.5 # dfl gain + + return loss.sum() * batch_size, loss.detach() # loss(box, cls, dfl) + + def single_mask_loss(self, gt_mask, pred, proto, xyxy, area): + # Mask loss for one image + pred_mask = (pred @ proto.view(self.nm, -1)).view(-1, *proto.shape[1:]) # (n, 32) @ (32,80,80) -> (n,80,80) + loss = F.binary_cross_entropy_with_logits(pred_mask, gt_mask, reduction='none') + #loss = sigmoid_focal_loss(pred_mask, gt_mask, alpha = .25, gamma = 2., reduction = 'none') + + #p_m = torch.flatten(pred_mask.softmax(dim = 1)) + #g_m = torch.flatten(gt_mask) + #i_m = torch.sum(torch.mul(p_m, g_m)) + #u_m = torch.sum(torch.add(p_m, g_m)) + #dice_coef = (2. * i_m + 1.) / (u_m + 1.) + #dice_loss = (1. - dice_coef) + return (crop_mask(loss, xyxy).mean(dim=(1, 2)) / area).mean() + + +class ComputeLossLH: + # Compute losses + def __init__(self, model, use_dfl=True, overlap=True): + device = next(model.parameters()).device # get model device + h = model.hyp # hyperparameters + + # Define criteria + BCEcls = nn.BCEWithLogitsLoss(pos_weight=torch.tensor([h["cls_pw"]], device=device), reduction='none') + + # Class label smoothing https://arxiv.org/pdf/1902.04103.pdf eqn 3 + self.cp, self.cn = smooth_BCE(eps=h.get("label_smoothing", 0.0)) # positive, negative BCE targets + + # Focal loss + g = h["fl_gamma"] # focal loss gamma + if g > 0: + BCEcls = FocalLoss(BCEcls, g) + + m = de_parallel(model).model[-1] # Detect() module + self.balance = {3: [4.0, 1.0, 0.4]}.get(m.nl, [4.0, 1.0, 0.25, 0.06, 0.02]) # P3-P7 + self.BCEcls = BCEcls + self.hyp = h + self.stride = m.stride # model strides + self.nc = m.nc # number of classes + self.nl = m.nl # number of layers + self.no = m.no + self.nm = m.nm + self.overlap = overlap + self.reg_max = m.reg_max + self.device = device + + self.assigner = TaskAlignedAssigner(topk=int(os.getenv('YOLOM', 10)), + num_classes=self.nc, + alpha=float(os.getenv('YOLOA', 0.5)), + beta=float(os.getenv('YOLOB', 6.0))) + self.bbox_loss = BboxLoss(m.reg_max - 1, use_dfl=use_dfl).to(device) + self.proj = torch.arange(m.reg_max).float().to(device) # / 120.0 + self.use_dfl = use_dfl + + def preprocess(self, targets, batch_size, scale_tensor): + if targets.shape[0] == 0: + out = torch.zeros(batch_size, 0, 5, device=self.device) + else: + i = targets[:, 0] # image index + _, counts = i.unique(return_counts=True) + out = torch.zeros(batch_size, counts.max(), 5, device=self.device) + for j in range(batch_size): + matches = i == j + n = matches.sum() + if n: + out[j, :n] = targets[matches, 1:] + out[..., 1:5] = xywh2xyxy(out[..., 1:5].mul_(scale_tensor)) + return out + + def bbox_decode(self, anchor_points, pred_dist): + if self.use_dfl: + b, a, c = pred_dist.shape # batch, anchors, channels + pred_dist = pred_dist.view(b, a, 4, c // 4).softmax(3).matmul(self.proj.type(pred_dist.dtype)) + # pred_dist = pred_dist.view(b, a, c // 4, 4).transpose(2,3).softmax(3).matmul(self.proj.type(pred_dist.dtype)) + # pred_dist = (pred_dist.view(b, a, c // 4, 4).softmax(2) * self.proj.type(pred_dist.dtype).view(1, 1, -1, 1)).sum(2) + return dist2bbox(pred_dist, anchor_points, xywh=False) + + def __call__(self, p, targets, masks, img=None, epoch=0): + loss = torch.zeros(4, device=self.device) # box, cls, dfl + + feats_, pred_masks_, proto_ = p if len(p) == 3 else p[1] + + feats, pred_masks, proto = feats_[0], pred_masks_[0], proto_[0] + feats2, pred_masks2, proto2 = feats_[1], pred_masks_[1], proto_[1] + + batch_size, _, mask_h, mask_w = proto.shape + + pred_distri, pred_scores = torch.cat([xi.view(feats[0].shape[0], self.no, -1) for xi in feats], 2).split( + (self.reg_max * 4, self.nc), 1) + pred_scores = pred_scores.permute(0, 2, 1).contiguous() + pred_distri = pred_distri.permute(0, 2, 1).contiguous() + pred_masks = pred_masks.permute(0, 2, 1).contiguous() + + pred_distri2, pred_scores2 = torch.cat([xi.view(feats[0].shape[0], self.no, -1) for xi in feats2], 2).split( + (self.reg_max * 4, self.nc), 1) + pred_scores2 = pred_scores2.permute(0, 2, 1).contiguous() + pred_distri2 = pred_distri2.permute(0, 2, 1).contiguous() + pred_masks2 = pred_masks2.permute(0, 2, 1).contiguous() + + dtype = pred_scores.dtype + batch_size, grid_size = pred_scores.shape[:2] + imgsz = torch.tensor(feats[0].shape[2:], device=self.device, dtype=dtype) * self.stride[0] # image size (h,w) + anchor_points, stride_tensor = make_anchors(feats, self.stride, 0.5) + + # targets + try: + batch_idx = targets[:, 0].view(-1, 1) + targets = self.preprocess(targets.to(self.device), batch_size, scale_tensor=imgsz[[1, 0, 1, 0]]) + gt_labels, gt_bboxes = targets.split((1, 4), 2) # cls, xyxy + mask_gt = gt_bboxes.sum(2, keepdim=True).gt_(0) + except RuntimeError as e: + raise TypeError('ERROR.') from e + + + # pboxes + pred_bboxes = self.bbox_decode(anchor_points, pred_distri) # xyxy, (b, h*w, 4) + + pred_bboxes2 = self.bbox_decode(anchor_points, pred_distri2) # xyxy, (b, h*w, 4) + + target_labels, target_bboxes, target_scores, fg_mask, target_gt_idx = self.assigner( + pred_scores2.detach().sigmoid(), + (pred_bboxes2.detach() * stride_tensor).type(gt_bboxes.dtype), + anchor_points * stride_tensor, + gt_labels, + gt_bboxes, + mask_gt) + + target_scores_sum = target_scores.sum() + + # cls loss + # loss[1] = self.varifocal_loss(pred_scores, target_scores, target_labels) / target_scores_sum # VFL way + loss[2] = self.BCEcls(pred_scores, target_scores.to(dtype)).sum() / target_scores_sum # BCE + loss[2] *= 0.25 + loss[2] += self.BCEcls(pred_scores2, target_scores.to(dtype)).sum() / target_scores_sum # BCE + + # bbox loss + if fg_mask.sum(): + loss[0], loss[3], _ = self.bbox_loss(pred_distri, + pred_bboxes, + anchor_points, + target_bboxes / stride_tensor, + target_scores, + target_scores_sum, + fg_mask) + + # masks loss + if tuple(masks.shape[-2:]) != (mask_h, mask_w): # downsample + masks = F.interpolate(masks[None], (mask_h, mask_w), mode='nearest')[0] + + for i in range(batch_size): + if fg_mask[i].sum(): + mask_idx = target_gt_idx[i][fg_mask[i]] + if self.overlap: + gt_mask = torch.where(masks[[i]] == (mask_idx + 1).view(-1, 1, 1), 1.0, 0.0) + else: + gt_mask = masks[batch_idx.view(-1) == i][mask_idx] + xyxyn = target_bboxes[i][fg_mask[i]] / imgsz[[1, 0, 1, 0]] + marea = xyxy2xywh(xyxyn)[:, 2:].prod(1) + mxyxy = xyxyn * torch.tensor([mask_w, mask_h, mask_w, mask_h], device=self.device) + loss[1] += self.single_mask_loss(gt_mask, pred_masks[i][fg_mask[i]], proto[i], mxyxy, + marea) # seg loss + + loss[0] *= 0.25 + loss[3] *= 0.25 + loss[1] *= 0.25 + + # bbox loss + if fg_mask.sum(): + loss0_, loss3_, _ = self.bbox_loss(pred_distri2, + pred_bboxes2, + anchor_points, + target_bboxes / stride_tensor, + target_scores, + target_scores_sum, + fg_mask) + + # masks loss + if tuple(masks.shape[-2:]) != (mask_h, mask_w): # downsample + masks = F.interpolate(masks[None], (mask_h, mask_w), mode='nearest')[0] + + for i in range(batch_size): + if fg_mask[i].sum(): + mask_idx = target_gt_idx[i][fg_mask[i]] + if self.overlap: + gt_mask = torch.where(masks[[i]] == (mask_idx + 1).view(-1, 1, 1), 1.0, 0.0) + else: + gt_mask = masks[batch_idx.view(-1) == i][mask_idx] + xyxyn = target_bboxes[i][fg_mask[i]] / imgsz[[1, 0, 1, 0]] + marea = xyxy2xywh(xyxyn)[:, 2:].prod(1) + mxyxy = xyxyn * torch.tensor([mask_w, mask_h, mask_w, mask_h], device=self.device) + loss[1] += self.single_mask_loss(gt_mask, pred_masks2[i][fg_mask[i]], proto2[i], mxyxy, + marea) # seg loss + + loss[0] += loss0_ + loss[3] += loss3_ + + loss[0] *= 7.5 # box gain + loss[1] *= 2.5 / batch_size + loss[2] *= 0.5 # cls gain + loss[3] *= 1.5 # dfl gain + + return loss.sum() * batch_size, loss.detach() # loss(box, cls, dfl) + + def single_mask_loss(self, gt_mask, pred, proto, xyxy, area): + # Mask loss for one image + pred_mask = (pred @ proto.view(self.nm, -1)).view(-1, *proto.shape[1:]) # (n, 32) @ (32,80,80) -> (n,80,80) + loss = F.binary_cross_entropy_with_logits(pred_mask, gt_mask, reduction='none') + #loss = sigmoid_focal_loss(pred_mask, gt_mask, alpha = .25, gamma = 2., reduction = 'none') + + #p_m = torch.flatten(pred_mask.softmax(dim = 1)) + #g_m = torch.flatten(gt_mask) + #i_m = torch.sum(torch.mul(p_m, g_m)) + #u_m = torch.sum(torch.add(p_m, g_m)) + #dice_coef = (2. * i_m + 1.) / (u_m + 1.) + #dice_loss = (1. - dice_coef) + return (crop_mask(loss, xyxy).mean(dim=(1, 2)) / area).mean() + + +class ComputeLossLH0: + # Compute losses + def __init__(self, model, use_dfl=True, overlap=True): + device = next(model.parameters()).device # get model device + h = model.hyp # hyperparameters + + # Define criteria + BCEcls = nn.BCEWithLogitsLoss(pos_weight=torch.tensor([h["cls_pw"]], device=device), reduction='none') + + # Class label smoothing https://arxiv.org/pdf/1902.04103.pdf eqn 3 + self.cp, self.cn = smooth_BCE(eps=h.get("label_smoothing", 0.0)) # positive, negative BCE targets + + # Focal loss + g = h["fl_gamma"] # focal loss gamma + if g > 0: + BCEcls = FocalLoss(BCEcls, g) + + m = de_parallel(model).model[-1] # Detect() module + self.balance = {3: [4.0, 1.0, 0.4]}.get(m.nl, [4.0, 1.0, 0.25, 0.06, 0.02]) # P3-P7 + self.BCEcls = BCEcls + self.hyp = h + self.stride = m.stride # model strides + self.nc = m.nc # number of classes + self.nl = m.nl # number of layers + self.no = m.no + self.nm = m.nm + self.overlap = overlap + self.reg_max = m.reg_max + self.device = device + + self.assigner = TaskAlignedAssigner(topk=int(os.getenv('YOLOM', 10)), + num_classes=self.nc, + alpha=float(os.getenv('YOLOA', 0.5)), + beta=float(os.getenv('YOLOB', 6.0))) + self.bbox_loss = BboxLoss(m.reg_max - 1, use_dfl=use_dfl).to(device) + self.proj = torch.arange(m.reg_max).float().to(device) # / 120.0 + self.use_dfl = use_dfl + + def preprocess(self, targets, batch_size, scale_tensor): + if targets.shape[0] == 0: + out = torch.zeros(batch_size, 0, 5, device=self.device) + else: + i = targets[:, 0] # image index + _, counts = i.unique(return_counts=True) + out = torch.zeros(batch_size, counts.max(), 5, device=self.device) + for j in range(batch_size): + matches = i == j + n = matches.sum() + if n: + out[j, :n] = targets[matches, 1:] + out[..., 1:5] = xywh2xyxy(out[..., 1:5].mul_(scale_tensor)) + return out + + def bbox_decode(self, anchor_points, pred_dist): + if self.use_dfl: + b, a, c = pred_dist.shape # batch, anchors, channels + pred_dist = pred_dist.view(b, a, 4, c // 4).softmax(3).matmul(self.proj.type(pred_dist.dtype)) + # pred_dist = pred_dist.view(b, a, c // 4, 4).transpose(2,3).softmax(3).matmul(self.proj.type(pred_dist.dtype)) + # pred_dist = (pred_dist.view(b, a, c // 4, 4).softmax(2) * self.proj.type(pred_dist.dtype).view(1, 1, -1, 1)).sum(2) + return dist2bbox(pred_dist, anchor_points, xywh=False) + + def __call__(self, p, targets, masks, img=None, epoch=0): + loss = torch.zeros(4, device=self.device) # box, cls, dfl + + feats_, pred_masks_, proto_ = p if len(p) == 3 else p[1] + + feats, pred_masks, proto = feats_[0], pred_masks_[0], proto_[0] + feats2, pred_masks2, proto2 = feats_[1], pred_masks_[1], proto_[1] + + batch_size, _, mask_h, mask_w = proto.shape + + pred_distri, pred_scores = torch.cat([xi.view(feats[0].shape[0], self.no, -1) for xi in feats], 2).split( + (self.reg_max * 4, self.nc), 1) + pred_scores = pred_scores.permute(0, 2, 1).contiguous() + pred_distri = pred_distri.permute(0, 2, 1).contiguous() + pred_masks = pred_masks.permute(0, 2, 1).contiguous() + + pred_distri2, pred_scores2 = torch.cat([xi.view(feats[0].shape[0], self.no, -1) for xi in feats2], 2).split( + (self.reg_max * 4, self.nc), 1) + pred_scores2 = pred_scores2.permute(0, 2, 1).contiguous() + pred_distri2 = pred_distri2.permute(0, 2, 1).contiguous() + pred_masks2 = pred_masks2.permute(0, 2, 1).contiguous() + + dtype = pred_scores.dtype + batch_size, grid_size = pred_scores.shape[:2] + imgsz = torch.tensor(feats[0].shape[2:], device=self.device, dtype=dtype) * self.stride[0] # image size (h,w) + anchor_points, stride_tensor = make_anchors(feats, self.stride, 0.5) + + # targets + try: + batch_idx = targets[:, 0].view(-1, 1) + targets = self.preprocess(targets.to(self.device), batch_size, scale_tensor=imgsz[[1, 0, 1, 0]]) + gt_labels, gt_bboxes = targets.split((1, 4), 2) # cls, xyxy + mask_gt = gt_bboxes.sum(2, keepdim=True).gt_(0) + except RuntimeError as e: + raise TypeError('ERROR.') from e + + + # pboxes + pred_bboxes = self.bbox_decode(anchor_points, pred_distri) # xyxy, (b, h*w, 4) + + pred_bboxes2 = self.bbox_decode(anchor_points, pred_distri2) # xyxy, (b, h*w, 4) + + target_labels, target_bboxes, target_scores, fg_mask, target_gt_idx = self.assigner( + pred_scores2.detach().sigmoid(), + (pred_bboxes2.detach() * stride_tensor).type(gt_bboxes.dtype), + anchor_points * stride_tensor, + gt_labels, + gt_bboxes, + mask_gt) + + target_scores_sum = target_scores.sum() + + # cls loss + # loss[1] = self.varifocal_loss(pred_scores, target_scores, target_labels) / target_scores_sum # VFL way + loss[2] = self.BCEcls(pred_scores, target_scores.to(dtype)).sum() / target_scores_sum # BCE + loss[2] *= 0.25 + loss[2] += self.BCEcls(pred_scores2, target_scores.to(dtype)).sum() / target_scores_sum # BCE + + # bbox loss + if fg_mask.sum(): + loss[0], loss[3], _ = self.bbox_loss(pred_distri, + pred_bboxes, + anchor_points, + target_bboxes / stride_tensor, + target_scores, + target_scores_sum, + fg_mask) + + # masks loss + if tuple(masks.shape[-2:]) != (mask_h, mask_w): # downsample + masks = F.interpolate(masks[None], (mask_h, mask_w), mode='nearest')[0] + + for i in range(batch_size): + if fg_mask[i].sum(): + mask_idx = target_gt_idx[i][fg_mask[i]] + if self.overlap: + gt_mask = torch.where(masks[[i]] == (mask_idx + 1).view(-1, 1, 1), 1.0, 0.0) + else: + gt_mask = masks[batch_idx.view(-1) == i][mask_idx] + xyxyn = target_bboxes[i][fg_mask[i]] / imgsz[[1, 0, 1, 0]] + marea = xyxy2xywh(xyxyn)[:, 2:].prod(1) + mxyxy = xyxyn * torch.tensor([mask_w, mask_h, mask_w, mask_h], device=self.device) + loss[1] += self.single_mask_loss(gt_mask, pred_masks[i][fg_mask[i]], proto[i], mxyxy, + marea) # seg loss + + loss[0] *= 0.25 + loss[3] *= 0.25 + loss[1] *= 0.25 + + # bbox loss + if fg_mask.sum(): + loss0_, loss3_, _ = self.bbox_loss(pred_distri2, + pred_bboxes2, + anchor_points, + target_bboxes / stride_tensor, + target_scores, + target_scores_sum, + fg_mask) + + # masks loss + if tuple(masks.shape[-2:]) != (mask_h, mask_w): # downsample + masks = F.interpolate(masks[None], (mask_h, mask_w), mode='nearest')[0] + + for i in range(batch_size): + if fg_mask[i].sum(): + mask_idx = target_gt_idx[i][fg_mask[i]] + if self.overlap: + gt_mask = torch.where(masks[[i]] == (mask_idx + 1).view(-1, 1, 1), 1.0, 0.0) + else: + gt_mask = masks[batch_idx.view(-1) == i][mask_idx] + xyxyn = target_bboxes[i][fg_mask[i]] / imgsz[[1, 0, 1, 0]] + marea = xyxy2xywh(xyxyn)[:, 2:].prod(1) + mxyxy = xyxyn * torch.tensor([mask_w, mask_h, mask_w, mask_h], device=self.device) + loss[1] += 0. * self.single_mask_loss(gt_mask, pred_masks2[i][fg_mask[i]], proto2[i], mxyxy, + marea) # seg loss + + loss[0] += loss0_ + loss[3] += loss3_ + + loss[0] *= 7.5 # box gain + loss[1] *= 2.5 / batch_size + loss[2] *= 0.5 # cls gain + loss[3] *= 1.5 # dfl gain + + return loss.sum() * batch_size, loss.detach() # loss(box, cls, dfl) + + def single_mask_loss(self, gt_mask, pred, proto, xyxy, area): + # Mask loss for one image + pred_mask = (pred @ proto.view(self.nm, -1)).view(-1, *proto.shape[1:]) # (n, 32) @ (32,80,80) -> (n,80,80) + loss = F.binary_cross_entropy_with_logits(pred_mask, gt_mask, reduction='none') + #loss = sigmoid_focal_loss(pred_mask, gt_mask, alpha = .25, gamma = 2., reduction = 'none') + + #p_m = torch.flatten(pred_mask.softmax(dim = 1)) + #g_m = torch.flatten(gt_mask) + #i_m = torch.sum(torch.mul(p_m, g_m)) + #u_m = torch.sum(torch.add(p_m, g_m)) + #dice_coef = (2. * i_m + 1.) / (u_m + 1.) + #dice_loss = (1. - dice_coef) + return (crop_mask(loss, xyxy).mean(dim=(1, 2)) / area).mean() diff --git a/cv/3d_detection/yolov9/pytorch/utils/segment/metrics.py b/cv/3d_detection/yolov9/pytorch/utils/segment/metrics.py new file mode 100644 index 000000000..e6e5a0ad3 --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/utils/segment/metrics.py @@ -0,0 +1,205 @@ +import numpy as np + +from ..metrics import ap_per_class + + +def fitness(x): + # Model fitness as a weighted combination of metrics + w = [0.0, 0.0, 0.1, 0.9, 0.0, 0.0, 0.1, 0.9] + return (x[:, :8] * w).sum(1) + + +def ap_per_class_box_and_mask( + tp_m, + tp_b, + conf, + pred_cls, + target_cls, + plot=False, + save_dir=".", + names=(), +): + """ + Args: + tp_b: tp of boxes. + tp_m: tp of masks. + other arguments see `func: ap_per_class`. + """ + results_boxes = ap_per_class(tp_b, + conf, + pred_cls, + target_cls, + plot=plot, + save_dir=save_dir, + names=names, + prefix="Box")[2:] + results_masks = ap_per_class(tp_m, + conf, + pred_cls, + target_cls, + plot=plot, + save_dir=save_dir, + names=names, + prefix="Mask")[2:] + + results = { + "boxes": { + "p": results_boxes[0], + "r": results_boxes[1], + "ap": results_boxes[3], + "f1": results_boxes[2], + "ap_class": results_boxes[4]}, + "masks": { + "p": results_masks[0], + "r": results_masks[1], + "ap": results_masks[3], + "f1": results_masks[2], + "ap_class": results_masks[4]}} + return results + + +class Metric: + + def __init__(self) -> None: + self.p = [] # (nc, ) + self.r = [] # (nc, ) + self.f1 = [] # (nc, ) + self.all_ap = [] # (nc, 10) + self.ap_class_index = [] # (nc, ) + + @property + def ap50(self): + """AP@0.5 of all classes. + Return: + (nc, ) or []. + """ + return self.all_ap[:, 0] if len(self.all_ap) else [] + + @property + def ap(self): + """AP@0.5:0.95 + Return: + (nc, ) or []. + """ + return self.all_ap.mean(1) if len(self.all_ap) else [] + + @property + def mp(self): + """mean precision of all classes. + Return: + float. + """ + return self.p.mean() if len(self.p) else 0.0 + + @property + def mr(self): + """mean recall of all classes. + Return: + float. + """ + return self.r.mean() if len(self.r) else 0.0 + + @property + def map50(self): + """Mean AP@0.5 of all classes. + Return: + float. + """ + return self.all_ap[:, 0].mean() if len(self.all_ap) else 0.0 + + @property + def map(self): + """Mean AP@0.5:0.95 of all classes. + Return: + float. + """ + return self.all_ap.mean() if len(self.all_ap) else 0.0 + + def mean_results(self): + """Mean of results, return mp, mr, map50, map""" + return (self.mp, self.mr, self.map50, self.map) + + def class_result(self, i): + """class-aware result, return p[i], r[i], ap50[i], ap[i]""" + return (self.p[i], self.r[i], self.ap50[i], self.ap[i]) + + def get_maps(self, nc): + maps = np.zeros(nc) + self.map + for i, c in enumerate(self.ap_class_index): + maps[c] = self.ap[i] + return maps + + def update(self, results): + """ + Args: + results: tuple(p, r, ap, f1, ap_class) + """ + p, r, all_ap, f1, ap_class_index = results + self.p = p + self.r = r + self.all_ap = all_ap + self.f1 = f1 + self.ap_class_index = ap_class_index + + +class Metrics: + """Metric for boxes and masks.""" + + def __init__(self) -> None: + self.metric_box = Metric() + self.metric_mask = Metric() + + def update(self, results): + """ + Args: + results: Dict{'boxes': Dict{}, 'masks': Dict{}} + """ + self.metric_box.update(list(results["boxes"].values())) + self.metric_mask.update(list(results["masks"].values())) + + def mean_results(self): + return self.metric_box.mean_results() + self.metric_mask.mean_results() + + def class_result(self, i): + return self.metric_box.class_result(i) + self.metric_mask.class_result(i) + + def get_maps(self, nc): + return self.metric_box.get_maps(nc) + self.metric_mask.get_maps(nc) + + @property + def ap_class_index(self): + # boxes and masks have the same ap_class_index + return self.metric_box.ap_class_index + + +KEYS = [ + "train/box_loss", + "train/seg_loss", # train loss + "train/obj_loss", + "train/cls_loss", + "metrics/precision(B)", + "metrics/recall(B)", + "metrics/mAP_0.5(B)", + "metrics/mAP_0.5:0.95(B)", # metrics + "metrics/precision(M)", + "metrics/recall(M)", + "metrics/mAP_0.5(M)", + "metrics/mAP_0.5:0.95(M)", # metrics + "val/box_loss", + "val/seg_loss", # val loss + "val/obj_loss", + "val/cls_loss", + "x/lr0", + "x/lr1", + "x/lr2",] + +BEST_KEYS = [ + "best/epoch", + "best/precision(B)", + "best/recall(B)", + "best/mAP_0.5(B)", + "best/mAP_0.5:0.95(B)", + "best/precision(M)", + "best/recall(M)", + "best/mAP_0.5(M)", + "best/mAP_0.5:0.95(M)",] diff --git a/cv/3d_detection/yolov9/pytorch/utils/segment/plots.py b/cv/3d_detection/yolov9/pytorch/utils/segment/plots.py new file mode 100644 index 000000000..9b90900b3 --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/utils/segment/plots.py @@ -0,0 +1,143 @@ +import contextlib +import math +from pathlib import Path + +import cv2 +import matplotlib.pyplot as plt +import numpy as np +import pandas as pd +import torch + +from .. import threaded +from ..general import xywh2xyxy +from ..plots import Annotator, colors + + +@threaded +def plot_images_and_masks(images, targets, masks, paths=None, fname='images.jpg', names=None): + # Plot image grid with labels + if isinstance(images, torch.Tensor): + images = images.cpu().float().numpy() + if isinstance(targets, torch.Tensor): + targets = targets.cpu().numpy() + if isinstance(masks, torch.Tensor): + masks = masks.cpu().numpy().astype(int) + + max_size = 1920 # max image size + max_subplots = 16 # max image subplots, i.e. 4x4 + bs, _, h, w = images.shape # batch size, _, height, width + bs = min(bs, max_subplots) # limit plot images + ns = np.ceil(bs ** 0.5) # number of subplots (square) + if np.max(images[0]) <= 1: + images *= 255 # de-normalise (optional) + + # Build Image + mosaic = np.full((int(ns * h), int(ns * w), 3), 255, dtype=np.uint8) # init + for i, im in enumerate(images): + if i == max_subplots: # if last batch has fewer images than we expect + break + x, y = int(w * (i // ns)), int(h * (i % ns)) # block origin + im = im.transpose(1, 2, 0) + mosaic[y:y + h, x:x + w, :] = im + + # Resize (optional) + scale = max_size / ns / max(h, w) + if scale < 1: + h = math.ceil(scale * h) + w = math.ceil(scale * w) + mosaic = cv2.resize(mosaic, tuple(int(x * ns) for x in (w, h))) + + # Annotate + fs = int((h + w) * ns * 0.01) # font size + annotator = Annotator(mosaic, line_width=round(fs / 10), font_size=fs, pil=True, example=names) + for i in range(i + 1): + x, y = int(w * (i // ns)), int(h * (i % ns)) # block origin + annotator.rectangle([x, y, x + w, y + h], None, (255, 255, 255), width=2) # borders + if paths: + annotator.text((x + 5, y + 5 + h), text=Path(paths[i]).name[:40], txt_color=(220, 220, 220)) # filenames + if len(targets) > 0: + idx = targets[:, 0] == i + ti = targets[idx] # image targets + + boxes = xywh2xyxy(ti[:, 2:6]).T + classes = ti[:, 1].astype('int') + labels = ti.shape[1] == 6 # labels if no conf column + conf = None if labels else ti[:, 6] # check for confidence presence (label vs pred) + + if boxes.shape[1]: + if boxes.max() <= 1.01: # if normalized with tolerance 0.01 + boxes[[0, 2]] *= w # scale to pixels + boxes[[1, 3]] *= h + elif scale < 1: # absolute coords need scale if image scales + boxes *= scale + boxes[[0, 2]] += x + boxes[[1, 3]] += y + for j, box in enumerate(boxes.T.tolist()): + cls = classes[j] + color = colors(cls) + cls = names[cls] if names else cls + if labels or conf[j] > 0.25: # 0.25 conf thresh + label = f'{cls}' if labels else f'{cls} {conf[j]:.1f}' + annotator.box_label(box, label, color=color) + + # Plot masks + if len(masks): + if masks.max() > 1.0: # mean that masks are overlap + image_masks = masks[[i]] # (1, 640, 640) + nl = len(ti) + index = np.arange(nl).reshape(nl, 1, 1) + 1 + image_masks = np.repeat(image_masks, nl, axis=0) + image_masks = np.where(image_masks == index, 1.0, 0.0) + else: + image_masks = masks[idx] + + im = np.asarray(annotator.im).copy() + for j, box in enumerate(boxes.T.tolist()): + if labels or conf[j] > 0.25: # 0.25 conf thresh + color = colors(classes[j]) + mh, mw = image_masks[j].shape + if mh != h or mw != w: + mask = image_masks[j].astype(np.uint8) + mask = cv2.resize(mask, (w, h)) + mask = mask.astype(bool) + else: + mask = image_masks[j].astype(bool) + with contextlib.suppress(Exception): + im[y:y + h, x:x + w, :][mask] = im[y:y + h, x:x + w, :][mask] * 0.4 + np.array(color) * 0.6 + annotator.fromarray(im) + annotator.im.save(fname) # save + + +def plot_results_with_masks(file="path/to/results.csv", dir="", best=True): + # Plot training results.csv. Usage: from utils.plots import *; plot_results('path/to/results.csv') + save_dir = Path(file).parent if file else Path(dir) + fig, ax = plt.subplots(2, 8, figsize=(18, 6), tight_layout=True) + ax = ax.ravel() + files = list(save_dir.glob("results*.csv")) + assert len(files), f"No results.csv files found in {save_dir.resolve()}, nothing to plot." + for f in files: + try: + data = pd.read_csv(f) + index = np.argmax(0.9 * data.values[:, 8] + 0.1 * data.values[:, 7] + 0.9 * data.values[:, 12] + + 0.1 * data.values[:, 11]) + s = [x.strip() for x in data.columns] + x = data.values[:, 0] + for i, j in enumerate([1, 2, 3, 4, 5, 6, 9, 10, 13, 14, 15, 16, 7, 8, 11, 12]): + y = data.values[:, j] + # y[y == 0] = np.nan # don't show zero values + ax[i].plot(x, y, marker=".", label=f.stem, linewidth=2, markersize=2) + if best: + # best + ax[i].scatter(index, y[index], color="r", label=f"best:{index}", marker="*", linewidth=3) + ax[i].set_title(s[j] + f"\n{round(y[index], 5)}") + else: + # last + ax[i].scatter(x[-1], y[-1], color="r", label="last", marker="*", linewidth=3) + ax[i].set_title(s[j] + f"\n{round(y[-1], 5)}") + # if j in [8, 9, 10]: # share train and val loss y axes + # ax[i].get_shared_y_axes().join(ax[i], ax[i - 5]) + except Exception as e: + print(f"Warning: Plotting error for {f}: {e}") + ax[1].legend() + fig.savefig(save_dir / "results.png", dpi=200) + plt.close() diff --git a/cv/3d_detection/yolov9/pytorch/utils/segment/tal/__init__.py b/cv/3d_detection/yolov9/pytorch/utils/segment/tal/__init__.py new file mode 100644 index 000000000..84952a816 --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/utils/segment/tal/__init__.py @@ -0,0 +1 @@ +# init \ No newline at end of file diff --git a/cv/3d_detection/yolov9/pytorch/utils/segment/tal/anchor_generator.py b/cv/3d_detection/yolov9/pytorch/utils/segment/tal/anchor_generator.py new file mode 100644 index 000000000..0de163651 --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/utils/segment/tal/anchor_generator.py @@ -0,0 +1,38 @@ +import torch + +from utils.general import check_version + +TORCH_1_10 = check_version(torch.__version__, '1.10.0') + + +def make_anchors(feats, strides, grid_cell_offset=0.5): + """Generate anchors from features.""" + anchor_points, stride_tensor = [], [] + assert feats is not None + dtype, device = feats[0].dtype, feats[0].device + for i, stride in enumerate(strides): + _, _, h, w = feats[i].shape + sx = torch.arange(end=w, device=device, dtype=dtype) + grid_cell_offset # shift x + sy = torch.arange(end=h, device=device, dtype=dtype) + grid_cell_offset # shift y + sy, sx = torch.meshgrid(sy, sx, indexing='ij') if TORCH_1_10 else torch.meshgrid(sy, sx) + anchor_points.append(torch.stack((sx, sy), -1).view(-1, 2)) + stride_tensor.append(torch.full((h * w, 1), stride, dtype=dtype, device=device)) + return torch.cat(anchor_points), torch.cat(stride_tensor) + + +def dist2bbox(distance, anchor_points, xywh=True, dim=-1): + """Transform distance(ltrb) to box(xywh or xyxy).""" + lt, rb = torch.split(distance, 2, dim) + x1y1 = anchor_points - lt + x2y2 = anchor_points + rb + if xywh: + c_xy = (x1y1 + x2y2) / 2 + wh = x2y2 - x1y1 + return torch.cat((c_xy, wh), dim) # xywh bbox + return torch.cat((x1y1, x2y2), dim) # xyxy bbox + + +def bbox2dist(anchor_points, bbox, reg_max): + """Transform bbox(xyxy) to dist(ltrb).""" + x1y1, x2y2 = torch.split(bbox, 2, -1) + return torch.cat((anchor_points - x1y1, x2y2 - anchor_points), -1).clamp(0, reg_max - 0.01) # dist (lt, rb) diff --git a/cv/3d_detection/yolov9/pytorch/utils/segment/tal/assigner.py b/cv/3d_detection/yolov9/pytorch/utils/segment/tal/assigner.py new file mode 100644 index 000000000..598b3575f --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/utils/segment/tal/assigner.py @@ -0,0 +1,180 @@ +import torch +import torch.nn as nn +import torch.nn.functional as F + +from utils.metrics import bbox_iou + + +def select_candidates_in_gts(xy_centers, gt_bboxes, eps=1e-9): + """select the positive anchor center in gt + + Args: + xy_centers (Tensor): shape(h*w, 4) + gt_bboxes (Tensor): shape(b, n_boxes, 4) + Return: + (Tensor): shape(b, n_boxes, h*w) + """ + n_anchors = xy_centers.shape[0] + bs, n_boxes, _ = gt_bboxes.shape + lt, rb = gt_bboxes.view(-1, 1, 4).chunk(2, 2) # left-top, right-bottom + bbox_deltas = torch.cat((xy_centers[None] - lt, rb - xy_centers[None]), dim=2).view(bs, n_boxes, n_anchors, -1) + # return (bbox_deltas.min(3)[0] > eps).to(gt_bboxes.dtype) + return bbox_deltas.amin(3).gt_(eps) + + +def select_highest_overlaps(mask_pos, overlaps, n_max_boxes): + """if an anchor box is assigned to multiple gts, + the one with the highest iou will be selected. + + Args: + mask_pos (Tensor): shape(b, n_max_boxes, h*w) + overlaps (Tensor): shape(b, n_max_boxes, h*w) + Return: + target_gt_idx (Tensor): shape(b, h*w) + fg_mask (Tensor): shape(b, h*w) + mask_pos (Tensor): shape(b, n_max_boxes, h*w) + """ + # (b, n_max_boxes, h*w) -> (b, h*w) + fg_mask = mask_pos.sum(-2) + if fg_mask.max() > 1: # one anchor is assigned to multiple gt_bboxes + mask_multi_gts = (fg_mask.unsqueeze(1) > 1).repeat([1, n_max_boxes, 1]) # (b, n_max_boxes, h*w) + max_overlaps_idx = overlaps.argmax(1) # (b, h*w) + is_max_overlaps = F.one_hot(max_overlaps_idx, n_max_boxes) # (b, h*w, n_max_boxes) + is_max_overlaps = is_max_overlaps.permute(0, 2, 1).to(overlaps.dtype) # (b, n_max_boxes, h*w) + mask_pos = torch.where(mask_multi_gts, is_max_overlaps, mask_pos) # (b, n_max_boxes, h*w) + fg_mask = mask_pos.sum(-2) + # find each grid serve which gt(index) + target_gt_idx = mask_pos.argmax(-2) # (b, h*w) + return target_gt_idx, fg_mask, mask_pos + + +class TaskAlignedAssigner(nn.Module): + def __init__(self, topk=13, num_classes=80, alpha=1.0, beta=6.0, eps=1e-9): + super().__init__() + self.topk = topk + self.num_classes = num_classes + self.bg_idx = num_classes + self.alpha = alpha + self.beta = beta + self.eps = eps + + @torch.no_grad() + def forward(self, pd_scores, pd_bboxes, anc_points, gt_labels, gt_bboxes, mask_gt): + """This code referenced to + https://github.com/Nioolek/PPYOLOE_pytorch/blob/master/ppyoloe/assigner/tal_assigner.py + + Args: + pd_scores (Tensor): shape(bs, num_total_anchors, num_classes) + pd_bboxes (Tensor): shape(bs, num_total_anchors, 4) + anc_points (Tensor): shape(num_total_anchors, 2) + gt_labels (Tensor): shape(bs, n_max_boxes, 1) + gt_bboxes (Tensor): shape(bs, n_max_boxes, 4) + mask_gt (Tensor): shape(bs, n_max_boxes, 1) + Returns: + target_labels (Tensor): shape(bs, num_total_anchors) + target_bboxes (Tensor): shape(bs, num_total_anchors, 4) + target_scores (Tensor): shape(bs, num_total_anchors, num_classes) + fg_mask (Tensor): shape(bs, num_total_anchors) + """ + self.bs = pd_scores.size(0) + self.n_max_boxes = gt_bboxes.size(1) + + if self.n_max_boxes == 0: + device = gt_bboxes.device + return (torch.full_like(pd_scores[..., 0], self.bg_idx).to(device), + torch.zeros_like(pd_bboxes).to(device), + torch.zeros_like(pd_scores).to(device), + torch.zeros_like(pd_scores[..., 0]).to(device), + torch.zeros_like(pd_scores[..., 0]).to(device)) + + mask_pos, align_metric, overlaps = self.get_pos_mask(pd_scores, pd_bboxes, gt_labels, gt_bboxes, anc_points, + mask_gt) + + target_gt_idx, fg_mask, mask_pos = select_highest_overlaps(mask_pos, overlaps, self.n_max_boxes) + + # assigned target + target_labels, target_bboxes, target_scores = self.get_targets(gt_labels, gt_bboxes, target_gt_idx, fg_mask) + + # normalize + align_metric *= mask_pos + pos_align_metrics = align_metric.amax(axis=-1, keepdim=True) # b, max_num_obj + pos_overlaps = (overlaps * mask_pos).amax(axis=-1, keepdim=True) # b, max_num_obj + norm_align_metric = (align_metric * pos_overlaps / (pos_align_metrics + self.eps)).amax(-2).unsqueeze(-1) + target_scores = target_scores * norm_align_metric + + return target_labels, target_bboxes, target_scores, fg_mask.bool(), target_gt_idx + + def get_pos_mask(self, pd_scores, pd_bboxes, gt_labels, gt_bboxes, anc_points, mask_gt): + + # get anchor_align metric, (b, max_num_obj, h*w) + align_metric, overlaps = self.get_box_metrics(pd_scores, pd_bboxes, gt_labels, gt_bboxes) + # get in_gts mask, (b, max_num_obj, h*w) + mask_in_gts = select_candidates_in_gts(anc_points, gt_bboxes) + # get topk_metric mask, (b, max_num_obj, h*w) + mask_topk = self.select_topk_candidates(align_metric * mask_in_gts, + topk_mask=mask_gt.repeat([1, 1, self.topk]).bool()) + # merge all mask to a final mask, (b, max_num_obj, h*w) + mask_pos = mask_topk * mask_in_gts * mask_gt + + return mask_pos, align_metric, overlaps + + def get_box_metrics(self, pd_scores, pd_bboxes, gt_labels, gt_bboxes): + + gt_labels = gt_labels.to(torch.long) # b, max_num_obj, 1 + ind = torch.zeros([2, self.bs, self.n_max_boxes], dtype=torch.long) # 2, b, max_num_obj + ind[0] = torch.arange(end=self.bs).view(-1, 1).repeat(1, self.n_max_boxes) # b, max_num_obj + ind[1] = gt_labels.squeeze(-1) # b, max_num_obj + # get the scores of each grid for each gt cls + bbox_scores = pd_scores[ind[0], :, ind[1]] # b, max_num_obj, h*w + + overlaps = bbox_iou(gt_bboxes.unsqueeze(2), pd_bboxes.unsqueeze(1), xywh=False, CIoU=True).squeeze(3).clamp(0) + align_metric = bbox_scores.pow(self.alpha) * (overlaps).pow(self.beta) + return align_metric, overlaps + + def select_topk_candidates(self, metrics, largest=True, topk_mask=None): + """ + Args: + metrics: (b, max_num_obj, h*w). + topk_mask: (b, max_num_obj, topk) or None + """ + + num_anchors = metrics.shape[-1] # h*w + # (b, max_num_obj, topk) + topk_metrics, topk_idxs = torch.topk(metrics, self.topk, dim=-1, largest=largest) + if topk_mask is None: + topk_mask = (topk_metrics.max(-1, keepdim=True) > self.eps).tile([1, 1, self.topk]) + # (b, max_num_obj, topk) + topk_idxs = torch.where(topk_mask, topk_idxs, 0) + # (b, max_num_obj, topk, h*w) -> (b, max_num_obj, h*w) + is_in_topk = F.one_hot(topk_idxs, num_anchors).sum(-2) + # filter invalid bboxes + # assigned topk should be unique, this is for dealing with empty labels + # since empty labels will generate index `0` through `F.one_hot` + # NOTE: but what if the topk_idxs include `0`? + is_in_topk = torch.where(is_in_topk > 1, 0, is_in_topk) + return is_in_topk.to(metrics.dtype) + + def get_targets(self, gt_labels, gt_bboxes, target_gt_idx, fg_mask): + """ + Args: + gt_labels: (b, max_num_obj, 1) + gt_bboxes: (b, max_num_obj, 4) + target_gt_idx: (b, h*w) + fg_mask: (b, h*w) + """ + + # assigned target labels, (b, 1) + batch_ind = torch.arange(end=self.bs, dtype=torch.int64, device=gt_labels.device)[..., None] + target_gt_idx = target_gt_idx + batch_ind * self.n_max_boxes # (b, h*w) + target_labels = gt_labels.long().flatten()[target_gt_idx] # (b, h*w) + + # assigned target boxes, (b, max_num_obj, 4) -> (b, h*w) + target_bboxes = gt_bboxes.view(-1, 4)[target_gt_idx] + + # assigned target scores + target_labels.clamp(0) + target_scores = F.one_hot(target_labels, self.num_classes) # (b, h*w, 80) + fg_scores_mask = fg_mask[:, :, None].repeat(1, 1, self.num_classes) # (b, h*w, 80) + target_scores = torch.where(fg_scores_mask > 0, target_scores, 0) + + return target_labels, target_bboxes, target_scores diff --git a/cv/3d_detection/yolov9/pytorch/utils/tal/__init__.py b/cv/3d_detection/yolov9/pytorch/utils/tal/__init__.py new file mode 100644 index 000000000..84952a816 --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/utils/tal/__init__.py @@ -0,0 +1 @@ +# init \ No newline at end of file diff --git a/cv/3d_detection/yolov9/pytorch/utils/tal/anchor_generator.py b/cv/3d_detection/yolov9/pytorch/utils/tal/anchor_generator.py new file mode 100644 index 000000000..0de163651 --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/utils/tal/anchor_generator.py @@ -0,0 +1,38 @@ +import torch + +from utils.general import check_version + +TORCH_1_10 = check_version(torch.__version__, '1.10.0') + + +def make_anchors(feats, strides, grid_cell_offset=0.5): + """Generate anchors from features.""" + anchor_points, stride_tensor = [], [] + assert feats is not None + dtype, device = feats[0].dtype, feats[0].device + for i, stride in enumerate(strides): + _, _, h, w = feats[i].shape + sx = torch.arange(end=w, device=device, dtype=dtype) + grid_cell_offset # shift x + sy = torch.arange(end=h, device=device, dtype=dtype) + grid_cell_offset # shift y + sy, sx = torch.meshgrid(sy, sx, indexing='ij') if TORCH_1_10 else torch.meshgrid(sy, sx) + anchor_points.append(torch.stack((sx, sy), -1).view(-1, 2)) + stride_tensor.append(torch.full((h * w, 1), stride, dtype=dtype, device=device)) + return torch.cat(anchor_points), torch.cat(stride_tensor) + + +def dist2bbox(distance, anchor_points, xywh=True, dim=-1): + """Transform distance(ltrb) to box(xywh or xyxy).""" + lt, rb = torch.split(distance, 2, dim) + x1y1 = anchor_points - lt + x2y2 = anchor_points + rb + if xywh: + c_xy = (x1y1 + x2y2) / 2 + wh = x2y2 - x1y1 + return torch.cat((c_xy, wh), dim) # xywh bbox + return torch.cat((x1y1, x2y2), dim) # xyxy bbox + + +def bbox2dist(anchor_points, bbox, reg_max): + """Transform bbox(xyxy) to dist(ltrb).""" + x1y1, x2y2 = torch.split(bbox, 2, -1) + return torch.cat((anchor_points - x1y1, x2y2 - anchor_points), -1).clamp(0, reg_max - 0.01) # dist (lt, rb) diff --git a/cv/3d_detection/yolov9/pytorch/utils/tal/assigner.py b/cv/3d_detection/yolov9/pytorch/utils/tal/assigner.py new file mode 100644 index 000000000..ac4bdb8c8 --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/utils/tal/assigner.py @@ -0,0 +1,179 @@ +import torch +import torch.nn as nn +import torch.nn.functional as F + +from utils.metrics import bbox_iou + + +def select_candidates_in_gts(xy_centers, gt_bboxes, eps=1e-9): + """select the positive anchor center in gt + + Args: + xy_centers (Tensor): shape(h*w, 4) + gt_bboxes (Tensor): shape(b, n_boxes, 4) + Return: + (Tensor): shape(b, n_boxes, h*w) + """ + n_anchors = xy_centers.shape[0] + bs, n_boxes, _ = gt_bboxes.shape + lt, rb = gt_bboxes.view(-1, 1, 4).chunk(2, 2) # left-top, right-bottom + bbox_deltas = torch.cat((xy_centers[None] - lt, rb - xy_centers[None]), dim=2).view(bs, n_boxes, n_anchors, -1) + # return (bbox_deltas.min(3)[0] > eps).to(gt_bboxes.dtype) + return bbox_deltas.amin(3).gt_(eps) + + +def select_highest_overlaps(mask_pos, overlaps, n_max_boxes): + """if an anchor box is assigned to multiple gts, + the one with the highest iou will be selected. + + Args: + mask_pos (Tensor): shape(b, n_max_boxes, h*w) + overlaps (Tensor): shape(b, n_max_boxes, h*w) + Return: + target_gt_idx (Tensor): shape(b, h*w) + fg_mask (Tensor): shape(b, h*w) + mask_pos (Tensor): shape(b, n_max_boxes, h*w) + """ + # (b, n_max_boxes, h*w) -> (b, h*w) + fg_mask = mask_pos.sum(-2) + if fg_mask.max() > 1: # one anchor is assigned to multiple gt_bboxes + mask_multi_gts = (fg_mask.unsqueeze(1) > 1).repeat([1, n_max_boxes, 1]) # (b, n_max_boxes, h*w) + max_overlaps_idx = overlaps.argmax(1) # (b, h*w) + is_max_overlaps = F.one_hot(max_overlaps_idx, n_max_boxes) # (b, h*w, n_max_boxes) + is_max_overlaps = is_max_overlaps.permute(0, 2, 1).to(overlaps.dtype) # (b, n_max_boxes, h*w) + mask_pos = torch.where(mask_multi_gts, is_max_overlaps, mask_pos) # (b, n_max_boxes, h*w) + fg_mask = mask_pos.sum(-2) + # find each grid serve which gt(index) + target_gt_idx = mask_pos.argmax(-2) # (b, h*w) + return target_gt_idx, fg_mask, mask_pos + + +class TaskAlignedAssigner(nn.Module): + def __init__(self, topk=13, num_classes=80, alpha=1.0, beta=6.0, eps=1e-9): + super().__init__() + self.topk = topk + self.num_classes = num_classes + self.bg_idx = num_classes + self.alpha = alpha + self.beta = beta + self.eps = eps + + @torch.no_grad() + def forward(self, pd_scores, pd_bboxes, anc_points, gt_labels, gt_bboxes, mask_gt): + """This code referenced to + https://github.com/Nioolek/PPYOLOE_pytorch/blob/master/ppyoloe/assigner/tal_assigner.py + + Args: + pd_scores (Tensor): shape(bs, num_total_anchors, num_classes) + pd_bboxes (Tensor): shape(bs, num_total_anchors, 4) + anc_points (Tensor): shape(num_total_anchors, 2) + gt_labels (Tensor): shape(bs, n_max_boxes, 1) + gt_bboxes (Tensor): shape(bs, n_max_boxes, 4) + mask_gt (Tensor): shape(bs, n_max_boxes, 1) + Returns: + target_labels (Tensor): shape(bs, num_total_anchors) + target_bboxes (Tensor): shape(bs, num_total_anchors, 4) + target_scores (Tensor): shape(bs, num_total_anchors, num_classes) + fg_mask (Tensor): shape(bs, num_total_anchors) + """ + self.bs = pd_scores.size(0) + self.n_max_boxes = gt_bboxes.size(1) + + if self.n_max_boxes == 0: + device = gt_bboxes.device + return (torch.full_like(pd_scores[..., 0], self.bg_idx).to(device), + torch.zeros_like(pd_bboxes).to(device), + torch.zeros_like(pd_scores).to(device), + torch.zeros_like(pd_scores[..., 0]).to(device)) + + mask_pos, align_metric, overlaps = self.get_pos_mask(pd_scores, pd_bboxes, gt_labels, gt_bboxes, anc_points, + mask_gt) + + target_gt_idx, fg_mask, mask_pos = select_highest_overlaps(mask_pos, overlaps, self.n_max_boxes) + + # assigned target + target_labels, target_bboxes, target_scores = self.get_targets(gt_labels, gt_bboxes, target_gt_idx, fg_mask) + + # normalize + align_metric *= mask_pos + pos_align_metrics = align_metric.amax(axis=-1, keepdim=True) # b, max_num_obj + pos_overlaps = (overlaps * mask_pos).amax(axis=-1, keepdim=True) # b, max_num_obj + norm_align_metric = (align_metric * pos_overlaps / (pos_align_metrics + self.eps)).amax(-2).unsqueeze(-1) + target_scores = target_scores * norm_align_metric + + return target_labels, target_bboxes, target_scores, fg_mask.bool() + + def get_pos_mask(self, pd_scores, pd_bboxes, gt_labels, gt_bboxes, anc_points, mask_gt): + + # get anchor_align metric, (b, max_num_obj, h*w) + align_metric, overlaps = self.get_box_metrics(pd_scores, pd_bboxes, gt_labels, gt_bboxes) + # get in_gts mask, (b, max_num_obj, h*w) + mask_in_gts = select_candidates_in_gts(anc_points, gt_bboxes) + # get topk_metric mask, (b, max_num_obj, h*w) + mask_topk = self.select_topk_candidates(align_metric * mask_in_gts, + topk_mask=mask_gt.repeat([1, 1, self.topk]).bool()) + # merge all mask to a final mask, (b, max_num_obj, h*w) + mask_pos = mask_topk * mask_in_gts * mask_gt + + return mask_pos, align_metric, overlaps + + def get_box_metrics(self, pd_scores, pd_bboxes, gt_labels, gt_bboxes): + + gt_labels = gt_labels.to(torch.long) # b, max_num_obj, 1 + ind = torch.zeros([2, self.bs, self.n_max_boxes], dtype=torch.long) # 2, b, max_num_obj + ind[0] = torch.arange(end=self.bs).view(-1, 1).repeat(1, self.n_max_boxes) # b, max_num_obj + ind[1] = gt_labels.squeeze(-1) # b, max_num_obj + # get the scores of each grid for each gt cls + bbox_scores = pd_scores[ind[0], :, ind[1]] # b, max_num_obj, h*w + + overlaps = bbox_iou(gt_bboxes.unsqueeze(2), pd_bboxes.unsqueeze(1), xywh=False, CIoU=True).squeeze(3).clamp(0) + align_metric = bbox_scores.pow(self.alpha) * overlaps.pow(self.beta) + return align_metric, overlaps + + def select_topk_candidates(self, metrics, largest=True, topk_mask=None): + """ + Args: + metrics: (b, max_num_obj, h*w). + topk_mask: (b, max_num_obj, topk) or None + """ + + num_anchors = metrics.shape[-1] # h*w + # (b, max_num_obj, topk) + topk_metrics, topk_idxs = torch.topk(metrics, self.topk, dim=-1, largest=largest) + if topk_mask is None: + topk_mask = (topk_metrics.max(-1, keepdim=True) > self.eps).tile([1, 1, self.topk]) + # (b, max_num_obj, topk) + topk_idxs = torch.where(topk_mask, topk_idxs, 0) + # (b, max_num_obj, topk, h*w) -> (b, max_num_obj, h*w) + is_in_topk = F.one_hot(topk_idxs, num_anchors).sum(-2) + # filter invalid bboxes + # assigned topk should be unique, this is for dealing with empty labels + # since empty labels will generate index `0` through `F.one_hot` + # NOTE: but what if the topk_idxs include `0`? + is_in_topk = torch.where(is_in_topk > 1, 0, is_in_topk) + return is_in_topk.to(metrics.dtype) + + def get_targets(self, gt_labels, gt_bboxes, target_gt_idx, fg_mask): + """ + Args: + gt_labels: (b, max_num_obj, 1) + gt_bboxes: (b, max_num_obj, 4) + target_gt_idx: (b, h*w) + fg_mask: (b, h*w) + """ + + # assigned target labels, (b, 1) + batch_ind = torch.arange(end=self.bs, dtype=torch.int64, device=gt_labels.device)[..., None] + target_gt_idx = target_gt_idx + batch_ind * self.n_max_boxes # (b, h*w) + target_labels = gt_labels.long().flatten()[target_gt_idx] # (b, h*w) + + # assigned target boxes, (b, max_num_obj, 4) -> (b, h*w) + target_bboxes = gt_bboxes.view(-1, 4)[target_gt_idx] + + # assigned target scores + target_labels.clamp(0) + target_scores = F.one_hot(target_labels, self.num_classes) # (b, h*w, 80) + fg_scores_mask = fg_mask[:, :, None].repeat(1, 1, self.num_classes) # (b, h*w, 80) + target_scores = torch.where(fg_scores_mask > 0, target_scores, 0) + + return target_labels, target_bboxes, target_scores diff --git a/cv/3d_detection/yolov9/pytorch/utils/torch_utils.py b/cv/3d_detection/yolov9/pytorch/utils/torch_utils.py new file mode 100644 index 000000000..3f1ce2d25 --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/utils/torch_utils.py @@ -0,0 +1,529 @@ +import math +import os +import platform +import subprocess +import time +import warnings +from contextlib import contextmanager +from copy import deepcopy +from pathlib import Path + +import torch +import torch.distributed as dist +import torch.nn as nn +import torch.nn.functional as F +from torch.nn.parallel import DistributedDataParallel as DDP + +from utils.general import LOGGER, check_version, colorstr, file_date, git_describe +from utils.lion import Lion + +LOCAL_RANK = int(os.getenv('LOCAL_RANK', -1)) # https://pytorch.org/docs/stable/elastic/run.html +RANK = int(os.getenv('RANK', -1)) +WORLD_SIZE = int(os.getenv('WORLD_SIZE', 1)) + +try: + import thop # for FLOPs computation +except ImportError: + thop = None + +# Suppress PyTorch warnings +warnings.filterwarnings('ignore', message='User provided device_type of \'cuda\', but CUDA is not available. Disabling') +warnings.filterwarnings('ignore', category=UserWarning) + + +def smart_inference_mode(torch_1_9=check_version(torch.__version__, '1.9.0')): + # Applies torch.inference_mode() decorator if torch>=1.9.0 else torch.no_grad() decorator + def decorate(fn): + return (torch.inference_mode if torch_1_9 else torch.no_grad)()(fn) + + return decorate + + +def smartCrossEntropyLoss(label_smoothing=0.0): + # Returns nn.CrossEntropyLoss with label smoothing enabled for torch>=1.10.0 + if check_version(torch.__version__, '1.10.0'): + return nn.CrossEntropyLoss(label_smoothing=label_smoothing) + if label_smoothing > 0: + LOGGER.warning(f'WARNING ⚠️ label smoothing {label_smoothing} requires torch>=1.10.0') + return nn.CrossEntropyLoss() + + +def smart_DDP(model): + # Model DDP creation with checks + assert not check_version(torch.__version__, '1.12.0', pinned=True), \ + 'torch==1.12.0 torchvision==0.13.0 DDP training is not supported due to a known issue. ' \ + 'Please upgrade or downgrade torch to use DDP. See https://github.com/ultralytics/yolov5/issues/8395' + if check_version(torch.__version__, '1.11.0'): + return DDP(model, device_ids=[LOCAL_RANK], output_device=LOCAL_RANK, static_graph=True) + else: + return DDP(model, device_ids=[LOCAL_RANK], output_device=LOCAL_RANK) + + +def reshape_classifier_output(model, n=1000): + # Update a TorchVision classification model to class count 'n' if required + from models.common import Classify + name, m = list((model.model if hasattr(model, 'model') else model).named_children())[-1] # last module + if isinstance(m, Classify): # YOLOv5 Classify() head + if m.linear.out_features != n: + m.linear = nn.Linear(m.linear.in_features, n) + elif isinstance(m, nn.Linear): # ResNet, EfficientNet + if m.out_features != n: + setattr(model, name, nn.Linear(m.in_features, n)) + elif isinstance(m, nn.Sequential): + types = [type(x) for x in m] + if nn.Linear in types: + i = types.index(nn.Linear) # nn.Linear index + if m[i].out_features != n: + m[i] = nn.Linear(m[i].in_features, n) + elif nn.Conv2d in types: + i = types.index(nn.Conv2d) # nn.Conv2d index + if m[i].out_channels != n: + m[i] = nn.Conv2d(m[i].in_channels, n, m[i].kernel_size, m[i].stride, bias=m[i].bias is not None) + + +@contextmanager +def torch_distributed_zero_first(local_rank: int): + # Decorator to make all processes in distributed training wait for each local_master to do something + if local_rank not in [-1, 0]: + dist.barrier(device_ids=[local_rank]) + yield + if local_rank == 0: + dist.barrier(device_ids=[0]) + + +def device_count(): + # Returns number of CUDA devices available. Safe version of torch.cuda.device_count(). Supports Linux and Windows + assert platform.system() in ('Linux', 'Windows'), 'device_count() only supported on Linux or Windows' + try: + cmd = 'nvidia-smi -L | wc -l' if platform.system() == 'Linux' else 'nvidia-smi -L | find /c /v ""' # Windows + return int(subprocess.run(cmd, shell=True, capture_output=True, check=True).stdout.decode().split()[-1]) + except Exception: + return 0 + + +def select_device(device='', batch_size=0, newline=True): + # device = None or 'cpu' or 0 or '0' or '0,1,2,3' + s = f'YOLO 🚀 {git_describe() or file_date()} Python-{platform.python_version()} torch-{torch.__version__} ' + device = str(device).strip().lower().replace('cuda:', '').replace('none', '') # to string, 'cuda:0' to '0' + cpu = device == 'cpu' + mps = device == 'mps' # Apple Metal Performance Shaders (MPS) + if cpu or mps: + os.environ['CUDA_VISIBLE_DEVICES'] = '-1' # force torch.cuda.is_available() = False + elif device: # non-cpu device requested + os.environ['CUDA_VISIBLE_DEVICES'] = device # set environment variable - must be before assert is_available() + assert torch.cuda.is_available() and torch.cuda.device_count() >= len(device.replace(',', '')), \ + f"Invalid CUDA '--device {device}' requested, use '--device cpu' or pass valid CUDA device(s)" + + if not cpu and not mps and torch.cuda.is_available(): # prefer GPU if available + devices = device.split(',') if device else '0' # range(torch.cuda.device_count()) # i.e. 0,1,6,7 + n = len(devices) # device count + if n > 1 and batch_size > 0: # check batch_size is divisible by device_count + assert batch_size % n == 0, f'batch-size {batch_size} not multiple of GPU count {n}' + space = ' ' * (len(s) + 1) + for i, d in enumerate(devices): + p = torch.cuda.get_device_properties(i) + s += f"{'' if i == 0 else space}CUDA:{d} ({p.name}, {p.total_memory / (1 << 20):.0f}MiB)\n" # bytes to MB + arg = 'cuda:0' + elif mps and getattr(torch, 'has_mps', False) and torch.backends.mps.is_available(): # prefer MPS if available + s += 'MPS\n' + arg = 'mps' + else: # revert to CPU + s += 'CPU\n' + arg = 'cpu' + + if not newline: + s = s.rstrip() + LOGGER.info(s) + return torch.device(arg) + + +def time_sync(): + # PyTorch-accurate time + if torch.cuda.is_available(): + torch.cuda.synchronize() + return time.time() + + +def profile(input, ops, n=10, device=None): + """ YOLOv5 speed/memory/FLOPs profiler + Usage: + input = torch.randn(16, 3, 640, 640) + m1 = lambda x: x * torch.sigmoid(x) + m2 = nn.SiLU() + profile(input, [m1, m2], n=100) # profile over 100 iterations + """ + results = [] + if not isinstance(device, torch.device): + device = select_device(device) + print(f"{'Params':>12s}{'GFLOPs':>12s}{'GPU_mem (GB)':>14s}{'forward (ms)':>14s}{'backward (ms)':>14s}" + f"{'input':>24s}{'output':>24s}") + + for x in input if isinstance(input, list) else [input]: + x = x.to(device) + x.requires_grad = True + for m in ops if isinstance(ops, list) else [ops]: + m = m.to(device) if hasattr(m, 'to') else m # device + m = m.half() if hasattr(m, 'half') and isinstance(x, torch.Tensor) and x.dtype is torch.float16 else m + tf, tb, t = 0, 0, [0, 0, 0] # dt forward, backward + try: + flops = thop.profile(m, inputs=(x,), verbose=False)[0] / 1E9 * 2 # GFLOPs + except Exception: + flops = 0 + + try: + for _ in range(n): + t[0] = time_sync() + y = m(x) + t[1] = time_sync() + try: + _ = (sum(yi.sum() for yi in y) if isinstance(y, list) else y).sum().backward() + t[2] = time_sync() + except Exception: # no backward method + # print(e) # for debug + t[2] = float('nan') + tf += (t[1] - t[0]) * 1000 / n # ms per op forward + tb += (t[2] - t[1]) * 1000 / n # ms per op backward + mem = torch.cuda.memory_reserved() / 1E9 if torch.cuda.is_available() else 0 # (GB) + s_in, s_out = (tuple(x.shape) if isinstance(x, torch.Tensor) else 'list' for x in (x, y)) # shapes + p = sum(x.numel() for x in m.parameters()) if isinstance(m, nn.Module) else 0 # parameters + print(f'{p:12}{flops:12.4g}{mem:>14.3f}{tf:14.4g}{tb:14.4g}{str(s_in):>24s}{str(s_out):>24s}') + results.append([p, flops, mem, tf, tb, s_in, s_out]) + except Exception as e: + print(e) + results.append(None) + torch.cuda.empty_cache() + return results + + +def is_parallel(model): + # Returns True if model is of type DP or DDP + return type(model) in (nn.parallel.DataParallel, nn.parallel.DistributedDataParallel) + + +def de_parallel(model): + # De-parallelize a model: returns single-GPU model if model is of type DP or DDP + return model.module if is_parallel(model) else model + + +def initialize_weights(model): + for m in model.modules(): + t = type(m) + if t is nn.Conv2d: + pass # nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu') + elif t is nn.BatchNorm2d: + m.eps = 1e-3 + m.momentum = 0.03 + elif t in [nn.Hardswish, nn.LeakyReLU, nn.ReLU, nn.ReLU6, nn.SiLU]: + m.inplace = True + + +def find_modules(model, mclass=nn.Conv2d): + # Finds layer indices matching module class 'mclass' + return [i for i, m in enumerate(model.module_list) if isinstance(m, mclass)] + + +def sparsity(model): + # Return global model sparsity + a, b = 0, 0 + for p in model.parameters(): + a += p.numel() + b += (p == 0).sum() + return b / a + + +def prune(model, amount=0.3): + # Prune model to requested global sparsity + import torch.nn.utils.prune as prune + for name, m in model.named_modules(): + if isinstance(m, nn.Conv2d): + prune.l1_unstructured(m, name='weight', amount=amount) # prune + prune.remove(m, 'weight') # make permanent + LOGGER.info(f'Model pruned to {sparsity(model):.3g} global sparsity') + + +def fuse_conv_and_bn(conv, bn): + # Fuse Conv2d() and BatchNorm2d() layers https://tehnokv.com/posts/fusing-batchnorm-and-conv/ + fusedconv = nn.Conv2d(conv.in_channels, + conv.out_channels, + kernel_size=conv.kernel_size, + stride=conv.stride, + padding=conv.padding, + dilation=conv.dilation, + groups=conv.groups, + bias=True).requires_grad_(False).to(conv.weight.device) + + # Prepare filters + w_conv = conv.weight.clone().view(conv.out_channels, -1) + w_bn = torch.diag(bn.weight.div(torch.sqrt(bn.eps + bn.running_var))) + fusedconv.weight.copy_(torch.mm(w_bn, w_conv).view(fusedconv.weight.shape)) + + # Prepare spatial bias + b_conv = torch.zeros(conv.weight.size(0), device=conv.weight.device) if conv.bias is None else conv.bias + b_bn = bn.bias - bn.weight.mul(bn.running_mean).div(torch.sqrt(bn.running_var + bn.eps)) + fusedconv.bias.copy_(torch.mm(w_bn, b_conv.reshape(-1, 1)).reshape(-1) + b_bn) + + return fusedconv + + +def model_info(model, verbose=False, imgsz=640): + # Model information. img_size may be int or list, i.e. img_size=640 or img_size=[640, 320] + n_p = sum(x.numel() for x in model.parameters()) # number parameters + n_g = sum(x.numel() for x in model.parameters() if x.requires_grad) # number gradients + if verbose: + print(f"{'layer':>5} {'name':>40} {'gradient':>9} {'parameters':>12} {'shape':>20} {'mu':>10} {'sigma':>10}") + for i, (name, p) in enumerate(model.named_parameters()): + name = name.replace('module_list.', '') + print('%5g %40s %9s %12g %20s %10.3g %10.3g' % + (i, name, p.requires_grad, p.numel(), list(p.shape), p.mean(), p.std())) + + try: # FLOPs + p = next(model.parameters()) + stride = max(int(model.stride.max()), 32) if hasattr(model, 'stride') else 32 # max stride + im = torch.empty((1, p.shape[1], stride, stride), device=p.device) # input image in BCHW format + flops = thop.profile(deepcopy(model), inputs=(im,), verbose=False)[0] / 1E9 * 2 # stride GFLOPs + imgsz = imgsz if isinstance(imgsz, list) else [imgsz, imgsz] # expand if int/float + fs = f', {flops * imgsz[0] / stride * imgsz[1] / stride:.1f} GFLOPs' # 640x640 GFLOPs + except Exception: + fs = '' + + name = Path(model.yaml_file).stem.replace('yolov5', 'YOLOv5') if hasattr(model, 'yaml_file') else 'Model' + LOGGER.info(f"{name} summary: {len(list(model.modules()))} layers, {n_p} parameters, {n_g} gradients{fs}") + + +def scale_img(img, ratio=1.0, same_shape=False, gs=32): # img(16,3,256,416) + # Scales img(bs,3,y,x) by ratio constrained to gs-multiple + if ratio == 1.0: + return img + h, w = img.shape[2:] + s = (int(h * ratio), int(w * ratio)) # new size + img = F.interpolate(img, size=s, mode='bilinear', align_corners=False) # resize + if not same_shape: # pad/crop img + h, w = (math.ceil(x * ratio / gs) * gs for x in (h, w)) + return F.pad(img, [0, w - s[1], 0, h - s[0]], value=0.447) # value = imagenet mean + + +def copy_attr(a, b, include=(), exclude=()): + # Copy attributes from b to a, options to only include [...] and to exclude [...] + for k, v in b.__dict__.items(): + if (len(include) and k not in include) or k.startswith('_') or k in exclude: + continue + else: + setattr(a, k, v) + + +def smart_optimizer(model, name='Adam', lr=0.001, momentum=0.9, decay=1e-5): + # YOLOv5 3-param group optimizer: 0) weights with decay, 1) weights no decay, 2) biases no decay + g = [], [], [] # optimizer parameter groups + bn = tuple(v for k, v in nn.__dict__.items() if 'Norm' in k) # normalization layers, i.e. BatchNorm2d() + #for v in model.modules(): + # for p_name, p in v.named_parameters(recurse=0): + # if p_name == 'bias': # bias (no decay) + # g[2].append(p) + # elif p_name == 'weight' and isinstance(v, bn): # weight (no decay) + # g[1].append(p) + # else: + # g[0].append(p) # weight (with decay) + + for v in model.modules(): + if hasattr(v, 'bias') and isinstance(v.bias, nn.Parameter): # bias (no decay) + g[2].append(v.bias) + if isinstance(v, bn): # weight (no decay) + g[1].append(v.weight) + elif hasattr(v, 'weight') and isinstance(v.weight, nn.Parameter): # weight (with decay) + g[0].append(v.weight) + + if hasattr(v, 'im'): + if hasattr(v.im, 'implicit'): + g[1].append(v.im.implicit) + else: + for iv in v.im: + g[1].append(iv.implicit) + if hasattr(v, 'ia'): + if hasattr(v.ia, 'implicit'): + g[1].append(v.ia.implicit) + else: + for iv in v.ia: + g[1].append(iv.implicit) + + if hasattr(v, 'im2'): + if hasattr(v.im2, 'implicit'): + g[1].append(v.im2.implicit) + else: + for iv in v.im2: + g[1].append(iv.implicit) + if hasattr(v, 'ia2'): + if hasattr(v.ia2, 'implicit'): + g[1].append(v.ia2.implicit) + else: + for iv in v.ia2: + g[1].append(iv.implicit) + + if hasattr(v, 'im3'): + if hasattr(v.im3, 'implicit'): + g[1].append(v.im3.implicit) + else: + for iv in v.im3: + g[1].append(iv.implicit) + if hasattr(v, 'ia3'): + if hasattr(v.ia3, 'implicit'): + g[1].append(v.ia3.implicit) + else: + for iv in v.ia3: + g[1].append(iv.implicit) + + if hasattr(v, 'im4'): + if hasattr(v.im4, 'implicit'): + g[1].append(v.im4.implicit) + else: + for iv in v.im4: + g[1].append(iv.implicit) + if hasattr(v, 'ia4'): + if hasattr(v.ia4, 'implicit'): + g[1].append(v.ia4.implicit) + else: + for iv in v.ia4: + g[1].append(iv.implicit) + + if hasattr(v, 'im5'): + if hasattr(v.im5, 'implicit'): + g[1].append(v.im5.implicit) + else: + for iv in v.im5: + g[1].append(iv.implicit) + if hasattr(v, 'ia5'): + if hasattr(v.ia5, 'implicit'): + g[1].append(v.ia5.implicit) + else: + for iv in v.ia5: + g[1].append(iv.implicit) + + if hasattr(v, 'im6'): + if hasattr(v.im6, 'implicit'): + g[1].append(v.im6.implicit) + else: + for iv in v.im6: + g[1].append(iv.implicit) + if hasattr(v, 'ia6'): + if hasattr(v.ia6, 'implicit'): + g[1].append(v.ia6.implicit) + else: + for iv in v.ia6: + g[1].append(iv.implicit) + + if hasattr(v, 'im7'): + if hasattr(v.im7, 'implicit'): + g[1].append(v.im7.implicit) + else: + for iv in v.im7: + g[1].append(iv.implicit) + if hasattr(v, 'ia7'): + if hasattr(v.ia7, 'implicit'): + g[1].append(v.ia7.implicit) + else: + for iv in v.ia7: + g[1].append(iv.implicit) + + if name == 'Adam': + optimizer = torch.optim.Adam(g[2], lr=lr, betas=(momentum, 0.999)) # adjust beta1 to momentum + elif name == 'AdamW': + optimizer = torch.optim.AdamW(g[2], lr=lr, betas=(momentum, 0.999), weight_decay=0.0, amsgrad=True) + elif name == 'RMSProp': + optimizer = torch.optim.RMSprop(g[2], lr=lr, momentum=momentum) + elif name == 'SGD': + optimizer = torch.optim.SGD(g[2], lr=lr, momentum=momentum, nesterov=True) + elif name == 'LION': + optimizer = Lion(g[2], lr=lr, betas=(momentum, 0.99), weight_decay=0.0) + else: + raise NotImplementedError(f'Optimizer {name} not implemented.') + + optimizer.add_param_group({'params': g[0], 'weight_decay': decay}) # add g0 with weight_decay + optimizer.add_param_group({'params': g[1], 'weight_decay': 0.0}) # add g1 (BatchNorm2d weights) + LOGGER.info(f"{colorstr('optimizer:')} {type(optimizer).__name__}(lr={lr}) with parameter groups " + f"{len(g[1])} weight(decay=0.0), {len(g[0])} weight(decay={decay}), {len(g[2])} bias") + return optimizer + + +def smart_hub_load(repo='ultralytics/yolov5', model='yolov5s', **kwargs): + # YOLOv5 torch.hub.load() wrapper with smart error/issue handling + if check_version(torch.__version__, '1.9.1'): + kwargs['skip_validation'] = True # validation causes GitHub API rate limit errors + if check_version(torch.__version__, '1.12.0'): + kwargs['trust_repo'] = True # argument required starting in torch 0.12 + try: + return torch.hub.load(repo, model, **kwargs) + except Exception: + return torch.hub.load(repo, model, force_reload=True, **kwargs) + + +def smart_resume(ckpt, optimizer, ema=None, weights='yolov5s.pt', epochs=300, resume=True): + # Resume training from a partially trained checkpoint + best_fitness = 0.0 + start_epoch = ckpt['epoch'] + 1 + if ckpt['optimizer'] is not None: + optimizer.load_state_dict(ckpt['optimizer']) # optimizer + best_fitness = ckpt['best_fitness'] + if ema and ckpt.get('ema'): + ema.ema.load_state_dict(ckpt['ema'].float().state_dict()) # EMA + ema.updates = ckpt['updates'] + if resume: + assert start_epoch > 0, f'{weights} training to {epochs} epochs is finished, nothing to resume.\n' \ + f"Start a new training without --resume, i.e. 'python train.py --weights {weights}'" + LOGGER.info(f'Resuming training from {weights} from epoch {start_epoch} to {epochs} total epochs') + if epochs < start_epoch: + LOGGER.info(f"{weights} has been trained for {ckpt['epoch']} epochs. Fine-tuning for {epochs} more epochs.") + epochs += ckpt['epoch'] # finetune additional epochs + return best_fitness, start_epoch, epochs + + +class EarlyStopping: + # YOLOv5 simple early stopper + def __init__(self, patience=30): + self.best_fitness = 0.0 # i.e. mAP + self.best_epoch = 0 + self.patience = patience or float('inf') # epochs to wait after fitness stops improving to stop + self.possible_stop = False # possible stop may occur next epoch + + def __call__(self, epoch, fitness): + if fitness >= self.best_fitness: # >= 0 to allow for early zero-fitness stage of training + self.best_epoch = epoch + self.best_fitness = fitness + delta = epoch - self.best_epoch # epochs without improvement + self.possible_stop = delta >= (self.patience - 1) # possible stop may occur next epoch + stop = delta >= self.patience # stop training if patience exceeded + if stop: + LOGGER.info(f'Stopping training early as no improvement observed in last {self.patience} epochs. ' + f'Best results observed at epoch {self.best_epoch}, best model saved as best.pt.\n' + f'To update EarlyStopping(patience={self.patience}) pass a new patience value, ' + f'i.e. `python train.py --patience 300` or use `--patience 0` to disable EarlyStopping.') + return stop + + +class ModelEMA: + """ Updated Exponential Moving Average (EMA) from https://github.com/rwightman/pytorch-image-models + Keeps a moving average of everything in the model state_dict (parameters and buffers) + For EMA details see https://www.tensorflow.org/api_docs/python/tf/train/ExponentialMovingAverage + """ + + def __init__(self, model, decay=0.9999, tau=2000, updates=0): + # Create EMA + self.ema = deepcopy(de_parallel(model)).eval() # FP32 EMA + self.updates = updates # number of EMA updates + self.decay = lambda x: decay * (1 - math.exp(-x / tau)) # decay exponential ramp (to help early epochs) + for p in self.ema.parameters(): + p.requires_grad_(False) + + def update(self, model): + # Update EMA parameters + self.updates += 1 + d = self.decay(self.updates) + + msd = de_parallel(model).state_dict() # model state_dict + for k, v in self.ema.state_dict().items(): + if v.dtype.is_floating_point: # true for FP16 and FP32 + v *= d + v += (1 - d) * msd[k].detach() + # assert v.dtype == msd[k].dtype == torch.float32, f'{k}: EMA {v.dtype} and model {msd[k].dtype} must be FP32' + + def update_attr(self, model, include=(), exclude=('process_group', 'reducer')): + # Update EMA attributes + copy_attr(self.ema, model, include, exclude) diff --git a/cv/3d_detection/yolov9/pytorch/utils/triton.py b/cv/3d_detection/yolov9/pytorch/utils/triton.py new file mode 100644 index 000000000..bf09797cf --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/utils/triton.py @@ -0,0 +1,81 @@ +import typing +from urllib.parse import urlparse + +import torch + + +class TritonRemoteModel: + """ A wrapper over a model served by the Triton Inference Server. It can + be configured to communicate over GRPC or HTTP. It accepts Torch Tensors + as input and returns them as outputs. + """ + + def __init__(self, url: str): + """ + Keyword arguments: + url: Fully qualified address of the Triton server - for e.g. grpc://localhost:8000 + """ + + parsed_url = urlparse(url) + if parsed_url.scheme == "grpc": + from tritonclient.grpc import InferenceServerClient, InferInput + + self.client = InferenceServerClient(parsed_url.netloc) # Triton GRPC client + model_repository = self.client.get_model_repository_index() + self.model_name = model_repository.models[0].name + self.metadata = self.client.get_model_metadata(self.model_name, as_json=True) + + def create_input_placeholders() -> typing.List[InferInput]: + return [ + InferInput(i['name'], [int(s) for s in i["shape"]], i['datatype']) for i in self.metadata['inputs']] + + else: + from tritonclient.http import InferenceServerClient, InferInput + + self.client = InferenceServerClient(parsed_url.netloc) # Triton HTTP client + model_repository = self.client.get_model_repository_index() + self.model_name = model_repository[0]['name'] + self.metadata = self.client.get_model_metadata(self.model_name) + + def create_input_placeholders() -> typing.List[InferInput]: + return [ + InferInput(i['name'], [int(s) for s in i["shape"]], i['datatype']) for i in self.metadata['inputs']] + + self._create_input_placeholders_fn = create_input_placeholders + + @property + def runtime(self): + """Returns the model runtime""" + return self.metadata.get("backend", self.metadata.get("platform")) + + def __call__(self, *args, **kwargs) -> typing.Union[torch.Tensor, typing.Tuple[torch.Tensor, ...]]: + """ Invokes the model. Parameters can be provided via args or kwargs. + args, if provided, are assumed to match the order of inputs of the model. + kwargs are matched with the model input names. + """ + inputs = self._create_inputs(*args, **kwargs) + response = self.client.infer(model_name=self.model_name, inputs=inputs) + result = [] + for output in self.metadata['outputs']: + tensor = torch.as_tensor(response.as_numpy(output['name'])) + result.append(tensor) + return result[0] if len(result) == 1 else result + + def _create_inputs(self, *args, **kwargs): + args_len, kwargs_len = len(args), len(kwargs) + if not args_len and not kwargs_len: + raise RuntimeError("No inputs provided.") + if args_len and kwargs_len: + raise RuntimeError("Cannot specify args and kwargs at the same time") + + placeholders = self._create_input_placeholders_fn() + if args_len: + if args_len != len(placeholders): + raise RuntimeError(f"Expected {len(placeholders)} inputs, got {args_len}.") + for input, value in zip(placeholders, args): + input.set_data_from_numpy(value.cpu().numpy()) + else: + for input in placeholders: + value = kwargs[input.name] + input.set_data_from_numpy(value.cpu().numpy()) + return placeholders diff --git a/cv/3d_detection/yolov9/pytorch/val.py b/cv/3d_detection/yolov9/pytorch/val.py new file mode 100644 index 000000000..496b941f9 --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/val.py @@ -0,0 +1,389 @@ +import argparse +import json +import os +import sys +from pathlib import Path + +import numpy as np +import torch +from tqdm import tqdm + +FILE = Path(__file__).resolve() +ROOT = FILE.parents[0] # YOLO root directory +if str(ROOT) not in sys.path: + sys.path.append(str(ROOT)) # add ROOT to PATH +ROOT = Path(os.path.relpath(ROOT, Path.cwd())) # relative + +from models.common import DetectMultiBackend +from utils.callbacks import Callbacks +from utils.dataloaders import create_dataloader +from utils.general import (LOGGER, TQDM_BAR_FORMAT, Profile, check_dataset, check_img_size, check_requirements, + check_yaml, coco80_to_coco91_class, colorstr, increment_path, non_max_suppression, + print_args, scale_boxes, xywh2xyxy, xyxy2xywh) +from utils.metrics import ConfusionMatrix, ap_per_class, box_iou +from utils.plots import output_to_target, plot_images, plot_val_study +from utils.torch_utils import select_device, smart_inference_mode + + +def save_one_txt(predn, save_conf, shape, file): + # Save one txt result + gn = torch.tensor(shape)[[1, 0, 1, 0]] # normalization gain whwh + for *xyxy, conf, cls in predn.tolist(): + xywh = (xyxy2xywh(torch.tensor(xyxy).view(1, 4)) / gn).view(-1).tolist() # normalized xywh + line = (cls, *xywh, conf) if save_conf else (cls, *xywh) # label format + with open(file, 'a') as f: + f.write(('%g ' * len(line)).rstrip() % line + '\n') + + +def save_one_json(predn, jdict, path, class_map): + # Save one JSON result {"image_id": 42, "category_id": 18, "bbox": [258.15, 41.29, 348.26, 243.78], "score": 0.236} + image_id = int(path.stem) if path.stem.isnumeric() else path.stem + box = xyxy2xywh(predn[:, :4]) # xywh + box[:, :2] -= box[:, 2:] / 2 # xy center to top-left corner + for p, b in zip(predn.tolist(), box.tolist()): + jdict.append({ + 'image_id': image_id, + 'category_id': class_map[int(p[5])], + 'bbox': [round(x, 3) for x in b], + 'score': round(p[4], 5)}) + + +def process_batch(detections, labels, iouv): + """ + Return correct prediction matrix + Arguments: + detections (array[N, 6]), x1, y1, x2, y2, conf, class + labels (array[M, 5]), class, x1, y1, x2, y2 + Returns: + correct (array[N, 10]), for 10 IoU levels + """ + correct = np.zeros((detections.shape[0], iouv.shape[0])).astype(bool) + iou = box_iou(labels[:, 1:], detections[:, :4]) + correct_class = labels[:, 0:1] == detections[:, 5] + for i in range(len(iouv)): + x = torch.where((iou >= iouv[i]) & correct_class) # IoU > threshold and classes match + if x[0].shape[0]: + matches = torch.cat((torch.stack(x, 1), iou[x[0], x[1]][:, None]), 1).cpu().numpy() # [label, detect, iou] + if x[0].shape[0] > 1: + matches = matches[matches[:, 2].argsort()[::-1]] + matches = matches[np.unique(matches[:, 1], return_index=True)[1]] + # matches = matches[matches[:, 2].argsort()[::-1]] + matches = matches[np.unique(matches[:, 0], return_index=True)[1]] + correct[matches[:, 1].astype(int), i] = True + return torch.tensor(correct, dtype=torch.bool, device=iouv.device) + + +@smart_inference_mode() +def run( + data, + weights=None, # model.pt path(s) + batch_size=32, # batch size + imgsz=640, # inference size (pixels) + conf_thres=0.001, # confidence threshold + iou_thres=0.7, # NMS IoU threshold + max_det=300, # maximum detections per image + task='val', # train, val, test, speed or study + device='', # cuda device, i.e. 0 or 0,1,2,3 or cpu + workers=8, # max dataloader workers (per RANK in DDP mode) + single_cls=False, # treat as single-class dataset + augment=False, # augmented inference + verbose=False, # verbose output + save_txt=False, # save results to *.txt + save_hybrid=False, # save label+prediction hybrid results to *.txt + save_conf=False, # save confidences in --save-txt labels + save_json=False, # save a COCO-JSON results file + project=ROOT / 'runs/val', # save to project/name + name='exp', # save to project/name + exist_ok=False, # existing project/name ok, do not increment + half=True, # use FP16 half-precision inference + dnn=False, # use OpenCV DNN for ONNX inference + min_items=0, # Experimental + model=None, + dataloader=None, + save_dir=Path(''), + plots=True, + callbacks=Callbacks(), + compute_loss=None, +): + # Initialize/load model and set device + training = model is not None + if training: # called by train.py + device, pt, jit, engine = next(model.parameters()).device, True, False, False # get model device, PyTorch model + half &= device.type != 'cpu' # half precision only supported on CUDA + model.half() if half else model.float() + else: # called directly + device = select_device(device, batch_size=batch_size) + + # Directories + save_dir = increment_path(Path(project) / name, exist_ok=exist_ok) # increment run + (save_dir / 'labels' if save_txt else save_dir).mkdir(parents=True, exist_ok=True) # make dir + + # Load model + model = DetectMultiBackend(weights, device=device, dnn=dnn, data=data, fp16=half) + stride, pt, jit, engine = model.stride, model.pt, model.jit, model.engine + imgsz = check_img_size(imgsz, s=stride) # check image size + half = model.fp16 # FP16 supported on limited backends with CUDA + if engine: + batch_size = model.batch_size + else: + device = model.device + if not (pt or jit): + batch_size = 1 # export.py models default to batch-size 1 + LOGGER.info(f'Forcing --batch-size 1 square inference (1,3,{imgsz},{imgsz}) for non-PyTorch models') + + # Data + data = check_dataset(data) # check + + # Configure + model.eval() + cuda = device.type != 'cpu' + #is_coco = isinstance(data.get('val'), str) and data['val'].endswith(f'coco{os.sep}val2017.txt') # COCO dataset + is_coco = isinstance(data.get('val'), str) and data['val'].endswith(f'val2017.txt') # COCO dataset + nc = 1 if single_cls else int(data['nc']) # number of classes + iouv = torch.linspace(0.5, 0.95, 10, device=device) # iou vector for mAP@0.5:0.95 + niou = iouv.numel() + + # Dataloader + if not training: + if pt and not single_cls: # check --weights are trained on --data + ncm = model.model.nc + assert ncm == nc, f'{weights} ({ncm} classes) trained on different --data than what you passed ({nc} ' \ + f'classes). Pass correct combination of --weights and --data that are trained together.' + model.warmup(imgsz=(1 if pt else batch_size, 3, imgsz, imgsz)) # warmup + pad, rect = (0.0, False) if task == 'speed' else (0.5, pt) # square inference for benchmarks + task = task if task in ('train', 'val', 'test') else 'val' # path to train/val/test images + dataloader = create_dataloader(data[task], + imgsz, + batch_size, + stride, + single_cls, + pad=pad, + rect=rect, + workers=workers, + min_items=opt.min_items, + prefix=colorstr(f'{task}: '))[0] + + seen = 0 + confusion_matrix = ConfusionMatrix(nc=nc) + names = model.names if hasattr(model, 'names') else model.module.names # get class names + if isinstance(names, (list, tuple)): # old format + names = dict(enumerate(names)) + class_map = coco80_to_coco91_class() if is_coco else list(range(1000)) + s = ('%22s' + '%11s' * 6) % ('Class', 'Images', 'Instances', 'P', 'R', 'mAP50', 'mAP50-95') + tp, fp, p, r, f1, mp, mr, map50, ap50, map = 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 + dt = Profile(), Profile(), Profile() # profiling times + loss = torch.zeros(3, device=device) + jdict, stats, ap, ap_class = [], [], [], [] + callbacks.run('on_val_start') + pbar = tqdm(dataloader, desc=s, bar_format=TQDM_BAR_FORMAT) # progress bar + for batch_i, (im, targets, paths, shapes) in enumerate(pbar): + callbacks.run('on_val_batch_start') + with dt[0]: + if cuda: + im = im.to(device, non_blocking=True) + targets = targets.to(device) + im = im.half() if half else im.float() # uint8 to fp16/32 + im /= 255 # 0 - 255 to 0.0 - 1.0 + nb, _, height, width = im.shape # batch size, channels, height, width + + # Inference + with dt[1]: + preds, train_out = model(im) if compute_loss else (model(im, augment=augment), None) + + # Loss + if compute_loss: + loss += compute_loss(train_out, targets)[1] # box, obj, cls + + # NMS + targets[:, 2:] *= torch.tensor((width, height, width, height), device=device) # to pixels + lb = [targets[targets[:, 0] == i, 1:] for i in range(nb)] if save_hybrid else [] # for autolabelling + with dt[2]: + preds = non_max_suppression(preds, + conf_thres, + iou_thres, + labels=lb, + multi_label=True, + agnostic=single_cls, + max_det=max_det) + + # Metrics + for si, pred in enumerate(preds): + labels = targets[targets[:, 0] == si, 1:] + nl, npr = labels.shape[0], pred.shape[0] # number of labels, predictions + path, shape = Path(paths[si]), shapes[si][0] + correct = torch.zeros(npr, niou, dtype=torch.bool, device=device) # init + seen += 1 + + if npr == 0: + if nl: + stats.append((correct, *torch.zeros((2, 0), device=device), labels[:, 0])) + if plots: + confusion_matrix.process_batch(detections=None, labels=labels[:, 0]) + continue + + # Predictions + if single_cls: + pred[:, 5] = 0 + predn = pred.clone() + scale_boxes(im[si].shape[1:], predn[:, :4], shape, shapes[si][1]) # native-space pred + + # Evaluate + if nl: + tbox = xywh2xyxy(labels[:, 1:5]) # target boxes + scale_boxes(im[si].shape[1:], tbox, shape, shapes[si][1]) # native-space labels + labelsn = torch.cat((labels[:, 0:1], tbox), 1) # native-space labels + correct = process_batch(predn, labelsn, iouv) + if plots: + confusion_matrix.process_batch(predn, labelsn) + stats.append((correct, pred[:, 4], pred[:, 5], labels[:, 0])) # (correct, conf, pcls, tcls) + + # Save/log + if save_txt: + save_one_txt(predn, save_conf, shape, file=save_dir / 'labels' / f'{path.stem}.txt') + if save_json: + save_one_json(predn, jdict, path, class_map) # append to COCO-JSON dictionary + callbacks.run('on_val_image_end', pred, predn, path, names, im[si]) + + # Plot images + if plots and batch_i < 3: + plot_images(im, targets, paths, save_dir / f'val_batch{batch_i}_labels.jpg', names) # labels + plot_images(im, output_to_target(preds), paths, save_dir / f'val_batch{batch_i}_pred.jpg', names) # pred + + callbacks.run('on_val_batch_end', batch_i, im, targets, paths, shapes, preds) + + # Compute metrics + stats = [torch.cat(x, 0).cpu().numpy() for x in zip(*stats)] # to numpy + if len(stats) and stats[0].any(): + tp, fp, p, r, f1, ap, ap_class = ap_per_class(*stats, plot=plots, save_dir=save_dir, names=names) + ap50, ap = ap[:, 0], ap.mean(1) # AP@0.5, AP@0.5:0.95 + mp, mr, map50, map = p.mean(), r.mean(), ap50.mean(), ap.mean() + nt = np.bincount(stats[3].astype(int), minlength=nc) # number of targets per class + + # Print results + pf = '%22s' + '%11i' * 2 + '%11.3g' * 4 # print format + LOGGER.info(pf % ('all', seen, nt.sum(), mp, mr, map50, map)) + if nt.sum() == 0: + LOGGER.warning(f'WARNING ⚠️ no labels found in {task} set, can not compute metrics without labels') + + # Print results per class + if (verbose or (nc < 50 and not training)) and nc > 1 and len(stats): + for i, c in enumerate(ap_class): + LOGGER.info(pf % (names[c], seen, nt[c], p[i], r[i], ap50[i], ap[i])) + + # Print speeds + t = tuple(x.t / seen * 1E3 for x in dt) # speeds per image + if not training: + shape = (batch_size, 3, imgsz, imgsz) + LOGGER.info(f'Speed: %.1fms pre-process, %.1fms inference, %.1fms NMS per image at shape {shape}' % t) + + # Plots + if plots: + confusion_matrix.plot(save_dir=save_dir, names=list(names.values())) + callbacks.run('on_val_end', nt, tp, fp, p, r, f1, ap, ap50, ap_class, confusion_matrix) + + # Save JSON + if save_json and len(jdict): + w = Path(weights[0] if isinstance(weights, list) else weights).stem if weights is not None else '' # weights + anno_json = str(Path(data.get('path', '../coco')) / 'annotations/instances_val2017.json') # annotations json + pred_json = str(save_dir / f"{w}_predictions.json") # predictions json + LOGGER.info(f'\nEvaluating pycocotools mAP... saving {pred_json}...') + with open(pred_json, 'w') as f: + json.dump(jdict, f) + + try: # https://github.com/cocodataset/cocoapi/blob/master/PythonAPI/pycocoEvalDemo.ipynb + check_requirements('pycocotools') + from pycocotools.coco import COCO + from pycocotools.cocoeval import COCOeval + + anno = COCO(anno_json) # init annotations api + pred = anno.loadRes(pred_json) # init predictions api + eval = COCOeval(anno, pred, 'bbox') + if is_coco: + eval.params.imgIds = [int(Path(x).stem) for x in dataloader.dataset.im_files] # image IDs to evaluate + eval.evaluate() + eval.accumulate() + eval.summarize() + map, map50 = eval.stats[:2] # update results (mAP@0.5:0.95, mAP@0.5) + except Exception as e: + LOGGER.info(f'pycocotools unable to run: {e}') + + # Return results + model.float() # for training + if not training: + s = f"\n{len(list(save_dir.glob('labels/*.txt')))} labels saved to {save_dir / 'labels'}" if save_txt else '' + LOGGER.info(f"Results saved to {colorstr('bold', save_dir)}{s}") + maps = np.zeros(nc) + map + for i, c in enumerate(ap_class): + maps[c] = ap[i] + return (mp, mr, map50, map, *(loss.cpu() / len(dataloader)).tolist()), maps, t + + +def parse_opt(): + parser = argparse.ArgumentParser() + parser.add_argument('--data', type=str, default=ROOT / 'data/coco.yaml', help='dataset.yaml path') + parser.add_argument('--weights', nargs='+', type=str, default=ROOT / 'yolo.pt', help='model path(s)') + parser.add_argument('--batch-size', type=int, default=32, help='batch size') + parser.add_argument('--imgsz', '--img', '--img-size', type=int, default=640, help='inference size (pixels)') + parser.add_argument('--conf-thres', type=float, default=0.001, help='confidence threshold') + parser.add_argument('--iou-thres', type=float, default=0.7, help='NMS IoU threshold') + parser.add_argument('--max-det', type=int, default=300, help='maximum detections per image') + parser.add_argument('--task', default='val', help='train, val, test, speed or study') + parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu') + parser.add_argument('--workers', type=int, default=8, help='max dataloader workers (per RANK in DDP mode)') + parser.add_argument('--single-cls', action='store_true', help='treat as single-class dataset') + parser.add_argument('--augment', action='store_true', help='augmented inference') + parser.add_argument('--verbose', action='store_true', help='report mAP by class') + parser.add_argument('--save-txt', action='store_true', help='save results to *.txt') + parser.add_argument('--save-hybrid', action='store_true', help='save label+prediction hybrid results to *.txt') + parser.add_argument('--save-conf', action='store_true', help='save confidences in --save-txt labels') + parser.add_argument('--save-json', action='store_true', help='save a COCO-JSON results file') + parser.add_argument('--project', default=ROOT / 'runs/val', help='save to project/name') + parser.add_argument('--name', default='exp', help='save to project/name') + parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment') + parser.add_argument('--half', action='store_true', help='use FP16 half-precision inference') + parser.add_argument('--dnn', action='store_true', help='use OpenCV DNN for ONNX inference') + parser.add_argument('--min-items', type=int, default=0, help='Experimental') + opt = parser.parse_args() + opt.data = check_yaml(opt.data) # check YAML + opt.save_json |= opt.data.endswith('coco.yaml') + opt.save_txt |= opt.save_hybrid + print_args(vars(opt)) + return opt + + +def main(opt): + #check_requirements(exclude=('tensorboard', 'thop')) + + if opt.task in ('train', 'val', 'test'): # run normally + if opt.conf_thres > 0.001: # https://github.com/ultralytics/yolov5/issues/1466 + LOGGER.info(f'WARNING ⚠️ confidence threshold {opt.conf_thres} > 0.001 produces invalid results') + if opt.save_hybrid: + LOGGER.info('WARNING ⚠️ --save-hybrid will return high mAP from hybrid labels, not from predictions alone') + run(**vars(opt)) + + else: + weights = opt.weights if isinstance(opt.weights, list) else [opt.weights] + opt.half = torch.cuda.is_available() and opt.device != 'cpu' # FP16 for fastest results + if opt.task == 'speed': # speed benchmarks + # python val.py --task speed --data coco.yaml --batch 1 --weights yolo.pt... + opt.conf_thres, opt.iou_thres, opt.save_json = 0.25, 0.45, False + for opt.weights in weights: + run(**vars(opt), plots=False) + + elif opt.task == 'study': # speed vs mAP benchmarks + # python val.py --task study --data coco.yaml --iou 0.7 --weights yolo.pt... + for opt.weights in weights: + f = f'study_{Path(opt.data).stem}_{Path(opt.weights).stem}.txt' # filename to save to + x, y = list(range(256, 1536 + 128, 128)), [] # x axis (image sizes), y axis + for opt.imgsz in x: # img-size + LOGGER.info(f'\nRunning {f} --imgsz {opt.imgsz}...') + r, _, t = run(**vars(opt), plots=False) + y.append(r + t) # results and times + np.savetxt(f, y, fmt='%10.4g') # save + os.system('zip -r study.zip study_*.txt') + plot_val_study(x=x) # plot + + +if __name__ == "__main__": + opt = parse_opt() + main(opt) diff --git a/cv/3d_detection/yolov9/pytorch/val_dual.py b/cv/3d_detection/yolov9/pytorch/val_dual.py new file mode 100644 index 000000000..4f0af05bf --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/val_dual.py @@ -0,0 +1,393 @@ +import argparse +import json +import os +import sys +from pathlib import Path + +import numpy as np +import torch +from tqdm import tqdm + +FILE = Path(__file__).resolve() +ROOT = FILE.parents[0] # YOLO root directory +if str(ROOT) not in sys.path: + sys.path.append(str(ROOT)) # add ROOT to PATH +ROOT = Path(os.path.relpath(ROOT, Path.cwd())) # relative + +from models.common import DetectMultiBackend +from utils.callbacks import Callbacks +from utils.dataloaders import create_dataloader +from utils.general import (LOGGER, TQDM_BAR_FORMAT, Profile, check_dataset, check_img_size, check_requirements, + check_yaml, coco80_to_coco91_class, colorstr, increment_path, non_max_suppression, + print_args, scale_boxes, xywh2xyxy, xyxy2xywh) +from utils.metrics import ConfusionMatrix, ap_per_class, box_iou +from utils.plots import output_to_target, plot_images, plot_val_study +from utils.torch_utils import select_device, smart_inference_mode + + +def save_one_txt(predn, save_conf, shape, file): + # Save one txt result + gn = torch.tensor(shape)[[1, 0, 1, 0]] # normalization gain whwh + for *xyxy, conf, cls in predn.tolist(): + xywh = (xyxy2xywh(torch.tensor(xyxy).view(1, 4)) / gn).view(-1).tolist() # normalized xywh + line = (cls, *xywh, conf) if save_conf else (cls, *xywh) # label format + with open(file, 'a') as f: + f.write(('%g ' * len(line)).rstrip() % line + '\n') + + +def save_one_json(predn, jdict, path, class_map): + # Save one JSON result {"image_id": 42, "category_id": 18, "bbox": [258.15, 41.29, 348.26, 243.78], "score": 0.236} + image_id = int(path.stem) if path.stem.isnumeric() else path.stem + box = xyxy2xywh(predn[:, :4]) # xywh + box[:, :2] -= box[:, 2:] / 2 # xy center to top-left corner + for p, b in zip(predn.tolist(), box.tolist()): + jdict.append({ + 'image_id': image_id, + 'category_id': class_map[int(p[5])], + 'bbox': [round(x, 3) for x in b], + 'score': round(p[4], 5)}) + + +def process_batch(detections, labels, iouv): + """ + Return correct prediction matrix + Arguments: + detections (array[N, 6]), x1, y1, x2, y2, conf, class + labels (array[M, 5]), class, x1, y1, x2, y2 + Returns: + correct (array[N, 10]), for 10 IoU levels + """ + correct = np.zeros((detections.shape[0], iouv.shape[0])).astype(bool) + iou = box_iou(labels[:, 1:], detections[:, :4]) + correct_class = labels[:, 0:1] == detections[:, 5] + for i in range(len(iouv)): + x = torch.where((iou >= iouv[i]) & correct_class) # IoU > threshold and classes match + if x[0].shape[0]: + matches = torch.cat((torch.stack(x, 1), iou[x[0], x[1]][:, None]), 1).cpu().numpy() # [label, detect, iou] + if x[0].shape[0] > 1: + matches = matches[matches[:, 2].argsort()[::-1]] + matches = matches[np.unique(matches[:, 1], return_index=True)[1]] + # matches = matches[matches[:, 2].argsort()[::-1]] + matches = matches[np.unique(matches[:, 0], return_index=True)[1]] + correct[matches[:, 1].astype(int), i] = True + return torch.tensor(correct, dtype=torch.bool, device=iouv.device) + + +@smart_inference_mode() +def run( + data, + weights=None, # model.pt path(s) + batch_size=32, # batch size + imgsz=640, # inference size (pixels) + conf_thres=0.001, # confidence threshold + iou_thres=0.7, # NMS IoU threshold + max_det=300, # maximum detections per image + task='val', # train, val, test, speed or study + device='', # cuda device, i.e. 0 or 0,1,2,3 or cpu + workers=8, # max dataloader workers (per RANK in DDP mode) + single_cls=False, # treat as single-class dataset + augment=False, # augmented inference + verbose=False, # verbose output + save_txt=False, # save results to *.txt + save_hybrid=False, # save label+prediction hybrid results to *.txt + save_conf=False, # save confidences in --save-txt labels + save_json=False, # save a COCO-JSON results file + project=ROOT / 'runs/val', # save to project/name + name='exp', # save to project/name + exist_ok=False, # existing project/name ok, do not increment + half=True, # use FP16 half-precision inference + dnn=False, # use OpenCV DNN for ONNX inference + min_items=0, # Experimental + model=None, + dataloader=None, + save_dir=Path(''), + plots=True, + callbacks=Callbacks(), + compute_loss=None, +): + # Initialize/load model and set device + training = model is not None + if training: # called by train.py + device, pt, jit, engine = next(model.parameters()).device, True, False, False # get model device, PyTorch model + half &= device.type != 'cpu' # half precision only supported on CUDA + model.half() if half else model.float() + else: # called directly + device = select_device(device, batch_size=batch_size) + + # Directories + save_dir = increment_path(Path(project) / name, exist_ok=exist_ok) # increment run + (save_dir / 'labels' if save_txt else save_dir).mkdir(parents=True, exist_ok=True) # make dir + + # Load model + model = DetectMultiBackend(weights, device=device, dnn=dnn, data=data, fp16=half) + stride, pt, jit, engine = model.stride, model.pt, model.jit, model.engine + imgsz = check_img_size(imgsz, s=stride) # check image size + half = model.fp16 # FP16 supported on limited backends with CUDA + if engine: + batch_size = model.batch_size + else: + device = model.device + if not (pt or jit): + batch_size = 1 # export.py models default to batch-size 1 + LOGGER.info(f'Forcing --batch-size 1 square inference (1,3,{imgsz},{imgsz}) for non-PyTorch models') + + # Data + data = check_dataset(data) # check + + # Configure + model.eval() + cuda = device.type != 'cpu' + #is_coco = isinstance(data.get('val'), str) and data['val'].endswith(f'coco{os.sep}val2017.txt') # COCO dataset + is_coco = isinstance(data.get('val'), str) and data['val'].endswith(f'val2017.txt') # COCO dataset + nc = 1 if single_cls else int(data['nc']) # number of classes + iouv = torch.linspace(0.5, 0.95, 10, device=device) # iou vector for mAP@0.5:0.95 + niou = iouv.numel() + + # Dataloader + if not training: + if pt and not single_cls: # check --weights are trained on --data + ncm = model.model.nc + assert ncm == nc, f'{weights} ({ncm} classes) trained on different --data than what you passed ({nc} ' \ + f'classes). Pass correct combination of --weights and --data that are trained together.' + model.warmup(imgsz=(1 if pt else batch_size, 3, imgsz, imgsz)) # warmup + pad, rect = (0.0, False) if task == 'speed' else (0.5, pt) # square inference for benchmarks + task = task if task in ('train', 'val', 'test') else 'val' # path to train/val/test images + dataloader = create_dataloader(data[task], + imgsz, + batch_size, + stride, + single_cls, + pad=pad, + rect=rect, + workers=workers, + min_items=opt.min_items, + prefix=colorstr(f'{task}: '))[0] + + seen = 0 + confusion_matrix = ConfusionMatrix(nc=nc) + names = model.names if hasattr(model, 'names') else model.module.names # get class names + if isinstance(names, (list, tuple)): # old format + names = dict(enumerate(names)) + class_map = coco80_to_coco91_class() if is_coco else list(range(1000)) + s = ('%22s' + '%11s' * 6) % ('Class', 'Images', 'Instances', 'P', 'R', 'mAP50', 'mAP50-95') + tp, fp, p, r, f1, mp, mr, map50, ap50, map = 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 + dt = Profile(), Profile(), Profile() # profiling times + loss = torch.zeros(3, device=device) + jdict, stats, ap, ap_class = [], [], [], [] + callbacks.run('on_val_start') + pbar = tqdm(dataloader, desc=s, bar_format=TQDM_BAR_FORMAT) # progress bar + for batch_i, (im, targets, paths, shapes) in enumerate(pbar): + callbacks.run('on_val_batch_start') + with dt[0]: + if cuda: + im = im.to(device, non_blocking=True) + targets = targets.to(device) + im = im.half() if half else im.float() # uint8 to fp16/32 + im /= 255 # 0 - 255 to 0.0 - 1.0 + nb, _, height, width = im.shape # batch size, channels, height, width + + # Inference + with dt[1]: + preds, train_out = model(im) if compute_loss else (model(im, augment=augment), None) + + # Loss + if compute_loss: + preds = preds[1] + #train_out = train_out[1] + #loss += compute_loss(train_out, targets)[1] # box, obj, cls + else: + preds = preds[0][1] + + # NMS + targets[:, 2:] *= torch.tensor((width, height, width, height), device=device) # to pixels + lb = [targets[targets[:, 0] == i, 1:] for i in range(nb)] if save_hybrid else [] # for autolabelling + with dt[2]: + preds = non_max_suppression(preds, + conf_thres, + iou_thres, + labels=lb, + multi_label=True, + agnostic=single_cls, + max_det=max_det) + + # Metrics + for si, pred in enumerate(preds): + labels = targets[targets[:, 0] == si, 1:] + nl, npr = labels.shape[0], pred.shape[0] # number of labels, predictions + path, shape = Path(paths[si]), shapes[si][0] + correct = torch.zeros(npr, niou, dtype=torch.bool, device=device) # init + seen += 1 + + if npr == 0: + if nl: + stats.append((correct, *torch.zeros((2, 0), device=device), labels[:, 0])) + if plots: + confusion_matrix.process_batch(detections=None, labels=labels[:, 0]) + continue + + # Predictions + if single_cls: + pred[:, 5] = 0 + predn = pred.clone() + scale_boxes(im[si].shape[1:], predn[:, :4], shape, shapes[si][1]) # native-space pred + + # Evaluate + if nl: + tbox = xywh2xyxy(labels[:, 1:5]) # target boxes + scale_boxes(im[si].shape[1:], tbox, shape, shapes[si][1]) # native-space labels + labelsn = torch.cat((labels[:, 0:1], tbox), 1) # native-space labels + correct = process_batch(predn, labelsn, iouv) + if plots: + confusion_matrix.process_batch(predn, labelsn) + stats.append((correct, pred[:, 4], pred[:, 5], labels[:, 0])) # (correct, conf, pcls, tcls) + + # Save/log + if save_txt: + save_one_txt(predn, save_conf, shape, file=save_dir / 'labels' / f'{path.stem}.txt') + if save_json: + save_one_json(predn, jdict, path, class_map) # append to COCO-JSON dictionary + callbacks.run('on_val_image_end', pred, predn, path, names, im[si]) + + # Plot images + if plots and batch_i < 3: + plot_images(im, targets, paths, save_dir / f'val_batch{batch_i}_labels.jpg', names) # labels + plot_images(im, output_to_target(preds), paths, save_dir / f'val_batch{batch_i}_pred.jpg', names) # pred + + callbacks.run('on_val_batch_end', batch_i, im, targets, paths, shapes, preds) + + # Compute metrics + stats = [torch.cat(x, 0).cpu().numpy() for x in zip(*stats)] # to numpy + if len(stats) and stats[0].any(): + tp, fp, p, r, f1, ap, ap_class = ap_per_class(*stats, plot=plots, save_dir=save_dir, names=names) + ap50, ap = ap[:, 0], ap.mean(1) # AP@0.5, AP@0.5:0.95 + mp, mr, map50, map = p.mean(), r.mean(), ap50.mean(), ap.mean() + nt = np.bincount(stats[3].astype(int), minlength=nc) # number of targets per class + + # Print results + pf = '%22s' + '%11i' * 2 + '%11.3g' * 4 # print format + LOGGER.info(pf % ('all', seen, nt.sum(), mp, mr, map50, map)) + if nt.sum() == 0: + LOGGER.warning(f'WARNING ⚠️ no labels found in {task} set, can not compute metrics without labels') + + # Print results per class + if (verbose or (nc < 50 and not training)) and nc > 1 and len(stats): + for i, c in enumerate(ap_class): + LOGGER.info(pf % (names[c], seen, nt[c], p[i], r[i], ap50[i], ap[i])) + + # Print speeds + t = tuple(x.t / seen * 1E3 for x in dt) # speeds per image + if not training: + shape = (batch_size, 3, imgsz, imgsz) + LOGGER.info(f'Speed: %.1fms pre-process, %.1fms inference, %.1fms NMS per image at shape {shape}' % t) + + # Plots + if plots: + confusion_matrix.plot(save_dir=save_dir, names=list(names.values())) + callbacks.run('on_val_end', nt, tp, fp, p, r, f1, ap, ap50, ap_class, confusion_matrix) + + # Save JSON + if save_json and len(jdict): + w = Path(weights[0] if isinstance(weights, list) else weights).stem if weights is not None else '' # weights + anno_json = str(Path(data.get('path', '../coco')) / 'annotations/instances_val2017.json') # annotations json + pred_json = str(save_dir / f"{w}_predictions.json") # predictions json + LOGGER.info(f'\nEvaluating pycocotools mAP... saving {pred_json}...') + with open(pred_json, 'w') as f: + json.dump(jdict, f) + + try: # https://github.com/cocodataset/cocoapi/blob/master/PythonAPI/pycocoEvalDemo.ipynb + check_requirements('pycocotools') + from pycocotools.coco import COCO + from pycocotools.cocoeval import COCOeval + + anno = COCO(anno_json) # init annotations api + pred = anno.loadRes(pred_json) # init predictions api + eval = COCOeval(anno, pred, 'bbox') + if is_coco: + eval.params.imgIds = [int(Path(x).stem) for x in dataloader.dataset.im_files] # image IDs to evaluate + eval.evaluate() + eval.accumulate() + eval.summarize() + map, map50 = eval.stats[:2] # update results (mAP@0.5:0.95, mAP@0.5) + except Exception as e: + LOGGER.info(f'pycocotools unable to run: {e}') + + # Return results + model.float() # for training + if not training: + s = f"\n{len(list(save_dir.glob('labels/*.txt')))} labels saved to {save_dir / 'labels'}" if save_txt else '' + LOGGER.info(f"Results saved to {colorstr('bold', save_dir)}{s}") + maps = np.zeros(nc) + map + for i, c in enumerate(ap_class): + maps[c] = ap[i] + return (mp, mr, map50, map, *(loss.cpu() / len(dataloader)).tolist()), maps, t + + +def parse_opt(): + parser = argparse.ArgumentParser() + parser.add_argument('--data', type=str, default=ROOT / 'data/coco.yaml', help='dataset.yaml path') + parser.add_argument('--weights', nargs='+', type=str, default=ROOT / 'yolo.pt', help='model path(s)') + parser.add_argument('--batch-size', type=int, default=32, help='batch size') + parser.add_argument('--imgsz', '--img', '--img-size', type=int, default=640, help='inference size (pixels)') + parser.add_argument('--conf-thres', type=float, default=0.001, help='confidence threshold') + parser.add_argument('--iou-thres', type=float, default=0.7, help='NMS IoU threshold') + parser.add_argument('--max-det', type=int, default=300, help='maximum detections per image') + parser.add_argument('--task', default='val', help='train, val, test, speed or study') + parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu') + parser.add_argument('--workers', type=int, default=8, help='max dataloader workers (per RANK in DDP mode)') + parser.add_argument('--single-cls', action='store_true', help='treat as single-class dataset') + parser.add_argument('--augment', action='store_true', help='augmented inference') + parser.add_argument('--verbose', action='store_true', help='report mAP by class') + parser.add_argument('--save-txt', action='store_true', help='save results to *.txt') + parser.add_argument('--save-hybrid', action='store_true', help='save label+prediction hybrid results to *.txt') + parser.add_argument('--save-conf', action='store_true', help='save confidences in --save-txt labels') + parser.add_argument('--save-json', action='store_true', help='save a COCO-JSON results file') + parser.add_argument('--project', default=ROOT / 'runs/val', help='save to project/name') + parser.add_argument('--name', default='exp', help='save to project/name') + parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment') + parser.add_argument('--half', action='store_true', help='use FP16 half-precision inference') + parser.add_argument('--dnn', action='store_true', help='use OpenCV DNN for ONNX inference') + parser.add_argument('--min-items', type=int, default=0, help='Experimental') + opt = parser.parse_args() + opt.data = check_yaml(opt.data) # check YAML + opt.save_json |= opt.data.endswith('coco.yaml') + opt.save_txt |= opt.save_hybrid + print_args(vars(opt)) + return opt + + +def main(opt): + #check_requirements(exclude=('tensorboard', 'thop')) + + if opt.task in ('train', 'val', 'test'): # run normally + if opt.conf_thres > 0.001: # https://github.com/ultralytics/yolov5/issues/1466 + LOGGER.info(f'WARNING ⚠️ confidence threshold {opt.conf_thres} > 0.001 produces invalid results') + if opt.save_hybrid: + LOGGER.info('WARNING ⚠️ --save-hybrid will return high mAP from hybrid labels, not from predictions alone') + run(**vars(opt)) + + else: + weights = opt.weights if isinstance(opt.weights, list) else [opt.weights] + opt.half = torch.cuda.is_available() and opt.device != 'cpu' # FP16 for fastest results + if opt.task == 'speed': # speed benchmarks + # python val.py --task speed --data coco.yaml --batch 1 --weights yolo.pt... + opt.conf_thres, opt.iou_thres, opt.save_json = 0.25, 0.45, False + for opt.weights in weights: + run(**vars(opt), plots=False) + + elif opt.task == 'study': # speed vs mAP benchmarks + # python val.py --task study --data coco.yaml --iou 0.7 --weights yolo.pt... + for opt.weights in weights: + f = f'study_{Path(opt.data).stem}_{Path(opt.weights).stem}.txt' # filename to save to + x, y = list(range(256, 1536 + 128, 128)), [] # x axis (image sizes), y axis + for opt.imgsz in x: # img-size + LOGGER.info(f'\nRunning {f} --imgsz {opt.imgsz}...') + r, _, t = run(**vars(opt), plots=False) + y.append(r + t) # results and times + np.savetxt(f, y, fmt='%10.4g') # save + os.system('zip -r study.zip study_*.txt') + plot_val_study(x=x) # plot + + +if __name__ == "__main__": + opt = parse_opt() + main(opt) diff --git a/cv/3d_detection/yolov9/pytorch/val_triple.py b/cv/3d_detection/yolov9/pytorch/val_triple.py new file mode 100644 index 000000000..e8997a34b --- /dev/null +++ b/cv/3d_detection/yolov9/pytorch/val_triple.py @@ -0,0 +1,391 @@ +import argparse +import json +import os +import sys +from pathlib import Path + +import numpy as np +import torch +from tqdm import tqdm + +FILE = Path(__file__).resolve() +ROOT = FILE.parents[0] # YOLO root directory +if str(ROOT) not in sys.path: + sys.path.append(str(ROOT)) # add ROOT to PATH +ROOT = Path(os.path.relpath(ROOT, Path.cwd())) # relative + +from models.common import DetectMultiBackend +from utils.callbacks import Callbacks +from utils.dataloaders import create_dataloader +from utils.general import (LOGGER, TQDM_BAR_FORMAT, Profile, check_dataset, check_img_size, check_requirements, + check_yaml, coco80_to_coco91_class, colorstr, increment_path, non_max_suppression, + print_args, scale_boxes, xywh2xyxy, xyxy2xywh) +from utils.metrics import ConfusionMatrix, ap_per_class, box_iou +from utils.plots import output_to_target, plot_images, plot_val_study +from utils.torch_utils import select_device, smart_inference_mode + + +def save_one_txt(predn, save_conf, shape, file): + # Save one txt result + gn = torch.tensor(shape)[[1, 0, 1, 0]] # normalization gain whwh + for *xyxy, conf, cls in predn.tolist(): + xywh = (xyxy2xywh(torch.tensor(xyxy).view(1, 4)) / gn).view(-1).tolist() # normalized xywh + line = (cls, *xywh, conf) if save_conf else (cls, *xywh) # label format + with open(file, 'a') as f: + f.write(('%g ' * len(line)).rstrip() % line + '\n') + + +def save_one_json(predn, jdict, path, class_map): + # Save one JSON result {"image_id": 42, "category_id": 18, "bbox": [258.15, 41.29, 348.26, 243.78], "score": 0.236} + image_id = int(path.stem) if path.stem.isnumeric() else path.stem + box = xyxy2xywh(predn[:, :4]) # xywh + box[:, :2] -= box[:, 2:] / 2 # xy center to top-left corner + for p, b in zip(predn.tolist(), box.tolist()): + jdict.append({ + 'image_id': image_id, + 'category_id': class_map[int(p[5])], + 'bbox': [round(x, 3) for x in b], + 'score': round(p[4], 5)}) + + +def process_batch(detections, labels, iouv): + """ + Return correct prediction matrix + Arguments: + detections (array[N, 6]), x1, y1, x2, y2, conf, class + labels (array[M, 5]), class, x1, y1, x2, y2 + Returns: + correct (array[N, 10]), for 10 IoU levels + """ + correct = np.zeros((detections.shape[0], iouv.shape[0])).astype(bool) + iou = box_iou(labels[:, 1:], detections[:, :4]) + correct_class = labels[:, 0:1] == detections[:, 5] + for i in range(len(iouv)): + x = torch.where((iou >= iouv[i]) & correct_class) # IoU > threshold and classes match + if x[0].shape[0]: + matches = torch.cat((torch.stack(x, 1), iou[x[0], x[1]][:, None]), 1).cpu().numpy() # [label, detect, iou] + if x[0].shape[0] > 1: + matches = matches[matches[:, 2].argsort()[::-1]] + matches = matches[np.unique(matches[:, 1], return_index=True)[1]] + # matches = matches[matches[:, 2].argsort()[::-1]] + matches = matches[np.unique(matches[:, 0], return_index=True)[1]] + correct[matches[:, 1].astype(int), i] = True + return torch.tensor(correct, dtype=torch.bool, device=iouv.device) + + +@smart_inference_mode() +def run( + data, + weights=None, # model.pt path(s) + batch_size=32, # batch size + imgsz=640, # inference size (pixels) + conf_thres=0.001, # confidence threshold + iou_thres=0.7, # NMS IoU threshold + max_det=300, # maximum detections per image + task='val', # train, val, test, speed or study + device='', # cuda device, i.e. 0 or 0,1,2,3 or cpu + workers=8, # max dataloader workers (per RANK in DDP mode) + single_cls=False, # treat as single-class dataset + augment=False, # augmented inference + verbose=False, # verbose output + save_txt=False, # save results to *.txt + save_hybrid=False, # save label+prediction hybrid results to *.txt + save_conf=False, # save confidences in --save-txt labels + save_json=False, # save a COCO-JSON results file + project=ROOT / 'runs/val', # save to project/name + name='exp', # save to project/name + exist_ok=False, # existing project/name ok, do not increment + half=True, # use FP16 half-precision inference + dnn=False, # use OpenCV DNN for ONNX inference + min_items=0, # Experimental + model=None, + dataloader=None, + save_dir=Path(''), + plots=True, + callbacks=Callbacks(), + compute_loss=None, +): + # Initialize/load model and set device + training = model is not None + if training: # called by train.py + device, pt, jit, engine = next(model.parameters()).device, True, False, False # get model device, PyTorch model + half &= device.type != 'cpu' # half precision only supported on CUDA + model.half() if half else model.float() + else: # called directly + device = select_device(device, batch_size=batch_size) + + # Directories + save_dir = increment_path(Path(project) / name, exist_ok=exist_ok) # increment run + (save_dir / 'labels' if save_txt else save_dir).mkdir(parents=True, exist_ok=True) # make dir + + # Load model + model = DetectMultiBackend(weights, device=device, dnn=dnn, data=data, fp16=half) + stride, pt, jit, engine = model.stride, model.pt, model.jit, model.engine + imgsz = check_img_size(imgsz, s=stride) # check image size + half = model.fp16 # FP16 supported on limited backends with CUDA + if engine: + batch_size = model.batch_size + else: + device = model.device + if not (pt or jit): + batch_size = 1 # export.py models default to batch-size 1 + LOGGER.info(f'Forcing --batch-size 1 square inference (1,3,{imgsz},{imgsz}) for non-PyTorch models') + + # Data + data = check_dataset(data) # check + + # Configure + model.eval() + cuda = device.type != 'cpu' + #is_coco = isinstance(data.get('val'), str) and data['val'].endswith(f'coco{os.sep}val2017.txt') # COCO dataset + is_coco = isinstance(data.get('val'), str) and data['val'].endswith(f'val2017.txt') # COCO dataset + nc = 1 if single_cls else int(data['nc']) # number of classes + iouv = torch.linspace(0.5, 0.95, 10, device=device) # iou vector for mAP@0.5:0.95 + niou = iouv.numel() + + # Dataloader + if not training: + if pt and not single_cls: # check --weights are trained on --data + ncm = model.model.nc + assert ncm == nc, f'{weights} ({ncm} classes) trained on different --data than what you passed ({nc} ' \ + f'classes). Pass correct combination of --weights and --data that are trained together.' + model.warmup(imgsz=(1 if pt else batch_size, 3, imgsz, imgsz)) # warmup + pad, rect = (0.0, False) if task == 'speed' else (0.5, pt) # square inference for benchmarks + task = task if task in ('train', 'val', 'test') else 'val' # path to train/val/test images + dataloader = create_dataloader(data[task], + imgsz, + batch_size, + stride, + single_cls, + pad=pad, + rect=rect, + workers=workers, + min_items=opt.min_items, + prefix=colorstr(f'{task}: '))[0] + + seen = 0 + confusion_matrix = ConfusionMatrix(nc=nc) + names = model.names if hasattr(model, 'names') else model.module.names # get class names + if isinstance(names, (list, tuple)): # old format + names = dict(enumerate(names)) + class_map = coco80_to_coco91_class() if is_coco else list(range(1000)) + s = ('%22s' + '%11s' * 6) % ('Class', 'Images', 'Instances', 'P', 'R', 'mAP50', 'mAP50-95') + tp, fp, p, r, f1, mp, mr, map50, ap50, map = 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 + dt = Profile(), Profile(), Profile() # profiling times + loss = torch.zeros(3, device=device) + jdict, stats, ap, ap_class = [], [], [], [] + callbacks.run('on_val_start') + pbar = tqdm(dataloader, desc=s, bar_format=TQDM_BAR_FORMAT) # progress bar + for batch_i, (im, targets, paths, shapes) in enumerate(pbar): + callbacks.run('on_val_batch_start') + with dt[0]: + if cuda: + im = im.to(device, non_blocking=True) + targets = targets.to(device) + im = im.half() if half else im.float() # uint8 to fp16/32 + im /= 255 # 0 - 255 to 0.0 - 1.0 + nb, _, height, width = im.shape # batch size, channels, height, width + + # Inference + with dt[1]: + preds, train_out = model(im) if compute_loss else (model(im, augment=augment), None) + preds = preds[2] + train_out = train_out[2] + + # Loss + #if compute_loss: + # loss += compute_loss(train_out, targets)[2] # box, obj, cls + + # NMS + targets[:, 2:] *= torch.tensor((width, height, width, height), device=device) # to pixels + lb = [targets[targets[:, 0] == i, 1:] for i in range(nb)] if save_hybrid else [] # for autolabelling + with dt[2]: + preds = non_max_suppression(preds, + conf_thres, + iou_thres, + labels=lb, + multi_label=True, + agnostic=single_cls, + max_det=max_det) + + # Metrics + for si, pred in enumerate(preds): + labels = targets[targets[:, 0] == si, 1:] + nl, npr = labels.shape[0], pred.shape[0] # number of labels, predictions + path, shape = Path(paths[si]), shapes[si][0] + correct = torch.zeros(npr, niou, dtype=torch.bool, device=device) # init + seen += 1 + + if npr == 0: + if nl: + stats.append((correct, *torch.zeros((2, 0), device=device), labels[:, 0])) + if plots: + confusion_matrix.process_batch(detections=None, labels=labels[:, 0]) + continue + + # Predictions + if single_cls: + pred[:, 5] = 0 + predn = pred.clone() + scale_boxes(im[si].shape[1:], predn[:, :4], shape, shapes[si][1]) # native-space pred + + # Evaluate + if nl: + tbox = xywh2xyxy(labels[:, 1:5]) # target boxes + scale_boxes(im[si].shape[1:], tbox, shape, shapes[si][1]) # native-space labels + labelsn = torch.cat((labels[:, 0:1], tbox), 1) # native-space labels + correct = process_batch(predn, labelsn, iouv) + if plots: + confusion_matrix.process_batch(predn, labelsn) + stats.append((correct, pred[:, 4], pred[:, 5], labels[:, 0])) # (correct, conf, pcls, tcls) + + # Save/log + if save_txt: + save_one_txt(predn, save_conf, shape, file=save_dir / 'labels' / f'{path.stem}.txt') + if save_json: + save_one_json(predn, jdict, path, class_map) # append to COCO-JSON dictionary + callbacks.run('on_val_image_end', pred, predn, path, names, im[si]) + + # Plot images + if plots and batch_i < 3: + plot_images(im, targets, paths, save_dir / f'val_batch{batch_i}_labels.jpg', names) # labels + plot_images(im, output_to_target(preds), paths, save_dir / f'val_batch{batch_i}_pred.jpg', names) # pred + + callbacks.run('on_val_batch_end', batch_i, im, targets, paths, shapes, preds) + + # Compute metrics + stats = [torch.cat(x, 0).cpu().numpy() for x in zip(*stats)] # to numpy + if len(stats) and stats[0].any(): + tp, fp, p, r, f1, ap, ap_class = ap_per_class(*stats, plot=plots, save_dir=save_dir, names=names) + ap50, ap = ap[:, 0], ap.mean(1) # AP@0.5, AP@0.5:0.95 + mp, mr, map50, map = p.mean(), r.mean(), ap50.mean(), ap.mean() + nt = np.bincount(stats[3].astype(int), minlength=nc) # number of targets per class + + # Print results + pf = '%22s' + '%11i' * 2 + '%11.3g' * 4 # print format + LOGGER.info(pf % ('all', seen, nt.sum(), mp, mr, map50, map)) + if nt.sum() == 0: + LOGGER.warning(f'WARNING ⚠️ no labels found in {task} set, can not compute metrics without labels') + + # Print results per class + if (verbose or (nc < 50 and not training)) and nc > 1 and len(stats): + for i, c in enumerate(ap_class): + LOGGER.info(pf % (names[c], seen, nt[c], p[i], r[i], ap50[i], ap[i])) + + # Print speeds + t = tuple(x.t / seen * 1E3 for x in dt) # speeds per image + if not training: + shape = (batch_size, 3, imgsz, imgsz) + LOGGER.info(f'Speed: %.1fms pre-process, %.1fms inference, %.1fms NMS per image at shape {shape}' % t) + + # Plots + if plots: + confusion_matrix.plot(save_dir=save_dir, names=list(names.values())) + callbacks.run('on_val_end', nt, tp, fp, p, r, f1, ap, ap50, ap_class, confusion_matrix) + + # Save JSON + if save_json and len(jdict): + w = Path(weights[0] if isinstance(weights, list) else weights).stem if weights is not None else '' # weights + anno_json = str(Path(data.get('path', '../coco')) / 'annotations/instances_val2017.json') # annotations json + pred_json = str(save_dir / f"{w}_predictions.json") # predictions json + LOGGER.info(f'\nEvaluating pycocotools mAP... saving {pred_json}...') + with open(pred_json, 'w') as f: + json.dump(jdict, f) + + try: # https://github.com/cocodataset/cocoapi/blob/master/PythonAPI/pycocoEvalDemo.ipynb + check_requirements('pycocotools') + from pycocotools.coco import COCO + from pycocotools.cocoeval import COCOeval + + anno = COCO(anno_json) # init annotations api + pred = anno.loadRes(pred_json) # init predictions api + eval = COCOeval(anno, pred, 'bbox') + if is_coco: + eval.params.imgIds = [int(Path(x).stem) for x in dataloader.dataset.im_files] # image IDs to evaluate + eval.evaluate() + eval.accumulate() + eval.summarize() + map, map50 = eval.stats[:2] # update results (mAP@0.5:0.95, mAP@0.5) + except Exception as e: + LOGGER.info(f'pycocotools unable to run: {e}') + + # Return results + model.float() # for training + if not training: + s = f"\n{len(list(save_dir.glob('labels/*.txt')))} labels saved to {save_dir / 'labels'}" if save_txt else '' + LOGGER.info(f"Results saved to {colorstr('bold', save_dir)}{s}") + maps = np.zeros(nc) + map + for i, c in enumerate(ap_class): + maps[c] = ap[i] + return (mp, mr, map50, map, *(loss.cpu() / len(dataloader)).tolist()), maps, t + + +def parse_opt(): + parser = argparse.ArgumentParser() + parser.add_argument('--data', type=str, default=ROOT / 'data/coco.yaml', help='dataset.yaml path') + parser.add_argument('--weights', nargs='+', type=str, default=ROOT / 'yolo.pt', help='model path(s)') + parser.add_argument('--batch-size', type=int, default=32, help='batch size') + parser.add_argument('--imgsz', '--img', '--img-size', type=int, default=640, help='inference size (pixels)') + parser.add_argument('--conf-thres', type=float, default=0.001, help='confidence threshold') + parser.add_argument('--iou-thres', type=float, default=0.7, help='NMS IoU threshold') + parser.add_argument('--max-det', type=int, default=300, help='maximum detections per image') + parser.add_argument('--task', default='val', help='train, val, test, speed or study') + parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu') + parser.add_argument('--workers', type=int, default=8, help='max dataloader workers (per RANK in DDP mode)') + parser.add_argument('--single-cls', action='store_true', help='treat as single-class dataset') + parser.add_argument('--augment', action='store_true', help='augmented inference') + parser.add_argument('--verbose', action='store_true', help='report mAP by class') + parser.add_argument('--save-txt', action='store_true', help='save results to *.txt') + parser.add_argument('--save-hybrid', action='store_true', help='save label+prediction hybrid results to *.txt') + parser.add_argument('--save-conf', action='store_true', help='save confidences in --save-txt labels') + parser.add_argument('--save-json', action='store_true', help='save a COCO-JSON results file') + parser.add_argument('--project', default=ROOT / 'runs/val', help='save to project/name') + parser.add_argument('--name', default='exp', help='save to project/name') + parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment') + parser.add_argument('--half', action='store_true', help='use FP16 half-precision inference') + parser.add_argument('--dnn', action='store_true', help='use OpenCV DNN for ONNX inference') + parser.add_argument('--min-items', type=int, default=0, help='Experimental') + opt = parser.parse_args() + opt.data = check_yaml(opt.data) # check YAML + opt.save_json |= opt.data.endswith('coco.yaml') + opt.save_txt |= opt.save_hybrid + print_args(vars(opt)) + return opt + + +def main(opt): + #check_requirements(exclude=('tensorboard', 'thop')) + + if opt.task in ('train', 'val', 'test'): # run normally + if opt.conf_thres > 0.001: # https://github.com/ultralytics/yolov5/issues/1466 + LOGGER.info(f'WARNING ⚠️ confidence threshold {opt.conf_thres} > 0.001 produces invalid results') + if opt.save_hybrid: + LOGGER.info('WARNING ⚠️ --save-hybrid will return high mAP from hybrid labels, not from predictions alone') + run(**vars(opt)) + + else: + weights = opt.weights if isinstance(opt.weights, list) else [opt.weights] + opt.half = torch.cuda.is_available() and opt.device != 'cpu' # FP16 for fastest results + if opt.task == 'speed': # speed benchmarks + # python val.py --task speed --data coco.yaml --batch 1 --weights yolo.pt... + opt.conf_thres, opt.iou_thres, opt.save_json = 0.25, 0.45, False + for opt.weights in weights: + run(**vars(opt), plots=False) + + elif opt.task == 'study': # speed vs mAP benchmarks + # python val.py --task study --data coco.yaml --iou 0.7 --weights yolo.pt... + for opt.weights in weights: + f = f'study_{Path(opt.data).stem}_{Path(opt.weights).stem}.txt' # filename to save to + x, y = list(range(256, 1536 + 128, 128)), [] # x axis (image sizes), y axis + for opt.imgsz in x: # img-size + LOGGER.info(f'\nRunning {f} --imgsz {opt.imgsz}...') + r, _, t = run(**vars(opt), plots=False) + y.append(r + t) # results and times + np.savetxt(f, y, fmt='%10.4g') # save + os.system('zip -r study.zip study_*.txt') + plot_val_study(x=x) # plot + + +if __name__ == "__main__": + opt = parse_opt() + main(opt) -- Gitee