diff --git a/421_Gold-YOLO-Head/LICENSE b/421_Gold-YOLO-Head/LICENSE
new file mode 100644
index 0000000000..3ab9d83ecc
--- /dev/null
+++ b/421_Gold-YOLO-Head/LICENSE
@@ -0,0 +1,673 @@
+ 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
\ No newline at end of file
diff --git a/421_Gold-YOLO-Head/README.md b/421_Gold-YOLO-Head/README.md
new file mode 100644
index 0000000000..0e30879d1d
--- /dev/null
+++ b/421_Gold-YOLO-Head/README.md
@@ -0,0 +1 @@
+# Note
diff --git a/421_Gold-YOLO-Head/demo/demo_goldyolo_onnx.py b/421_Gold-YOLO-Head/demo/demo_goldyolo_onnx.py
new file mode 100644
index 0000000000..acbc057a48
--- /dev/null
+++ b/421_Gold-YOLO-Head/demo/demo_goldyolo_onnx.py
@@ -0,0 +1,350 @@
+#!/usr/bin/env python
+
+import copy
+import cv2
+import time
+import numpy as np
+import onnxruntime
+from argparse import ArgumentParser
+from typing import Tuple, Optional, List
+
+
+class GoldYOLOONNX(object):
+ def __init__(
+ self,
+ model_path: Optional[str] = 'gold_yolo_n_hand_post_0333_0.4040_1x3x480x640.onnx',
+ class_score_th: Optional[float] = 0.35,
+ providers: Optional[List] = [
+ # (
+ # 'TensorrtExecutionProvider', {
+ # 'trt_engine_cache_enable': True,
+ # 'trt_engine_cache_path': '.',
+ # 'trt_fp16_enable': True,
+ # }
+ # ),
+ 'CUDAExecutionProvider',
+ 'CPUExecutionProvider',
+ ],
+ ):
+ """GoldYOLOONNX
+
+ Parameters
+ ----------
+ model_path: Optional[str]
+ ONNX file path for GoldYOLO
+
+ class_score_th: Optional[float]
+ Score threshold. Default: 0.35
+
+ providers: Optional[List]
+ Name of onnx execution providers
+ Default:
+ [
+ (
+ 'TensorrtExecutionProvider', {
+ 'trt_engine_cache_enable': True,
+ 'trt_engine_cache_path': '.',
+ 'trt_fp16_enable': True,
+ }
+ ),
+ 'CUDAExecutionProvider',
+ 'CPUExecutionProvider',
+ ]
+ """
+ # Threshold
+ self.class_score_th = class_score_th
+
+ # Model loading
+ session_option = onnxruntime.SessionOptions()
+ session_option.log_severity_level = 3
+ self.onnx_session = onnxruntime.InferenceSession(
+ model_path,
+ sess_options=session_option,
+ providers=providers,
+ )
+ self.providers = self.onnx_session.get_providers()
+
+ self.input_shapes = [
+ input.shape for input in self.onnx_session.get_inputs()
+ ]
+ self.input_names = [
+ input.name for input in self.onnx_session.get_inputs()
+ ]
+ self.output_names = [
+ output.name for output in self.onnx_session.get_outputs()
+ ]
+
+
+ def __call__(
+ self,
+ image: np.ndarray,
+ ) -> Tuple[np.ndarray, np.ndarray]:
+ """YOLOv7ONNX
+
+ Parameters
+ ----------
+ image: np.ndarray
+ Entire image
+
+ Returns
+ -------
+ boxes: np.ndarray
+ Predicted boxes: [N, y1, x1, y2, x2]
+
+ scores: np.ndarray
+ Predicted box scores: [N, score]
+ """
+ temp_image = copy.deepcopy(image)
+
+ # PreProcess
+ resized_image = self.__preprocess(
+ temp_image,
+ )
+
+ # Inference
+ inferece_image = np.asarray([resized_image], dtype=np.float32)
+ boxes = self.onnx_session.run(
+ self.output_names,
+ {input_name: inferece_image for input_name in self.input_names},
+ )[0]
+
+ # PostProcess
+ result_boxes, result_scores = \
+ self.__postprocess(
+ image=temp_image,
+ boxes=boxes,
+ )
+
+ return result_boxes, result_scores
+
+
+ def __preprocess(
+ self,
+ image: np.ndarray,
+ swap: Optional[Tuple[int,int,int]] = (2, 0, 1),
+ ) -> np.ndarray:
+ """__preprocess
+
+ Parameters
+ ----------
+ image: np.ndarray
+ Entire image
+
+ swap: tuple
+ HWC to CHW: (2,0,1)
+ CHW to HWC: (1,2,0)
+ HWC to HWC: (0,1,2)
+ CHW to CHW: (0,1,2)
+
+ Returns
+ -------
+ resized_image: np.ndarray
+ Resized and normalized image.
+ """
+ # Normalization + BGR->RGB
+ resized_image = cv2.resize(
+ image,
+ (
+ int(self.input_shapes[0][3]),
+ int(self.input_shapes[0][2]),
+ )
+ )
+ resized_image = np.divide(resized_image, 255.0)
+ resized_image = resized_image[..., ::-1]
+ resized_image = resized_image.transpose(swap)
+ resized_image = np.ascontiguousarray(
+ resized_image,
+ dtype=np.float32,
+ )
+ return resized_image
+
+
+ def __postprocess(
+ self,
+ image: np.ndarray,
+ boxes: np.ndarray,
+ ) -> Tuple[np.ndarray, np.ndarray]:
+ """__postprocess
+
+ Parameters
+ ----------
+ image: np.ndarray
+ Entire image.
+
+ boxes: np.ndarray
+ float32[N, 7]
+
+ Returns
+ -------
+ result_boxes: np.ndarray
+ Predicted boxes: [N, y1, x1, y2, x2]
+
+ result_scores: np.ndarray
+ Predicted box confs: [N, score]
+ """
+ image_height = image.shape[0]
+ image_width = image.shape[1]
+
+ """
+ Detector is
+ N -> Number of boxes detected
+ batchno -> always 0: BatchNo.0
+
+ batchno_classid_y1x1y2x2_score: float32[N,7]
+ """
+ result_boxes = []
+ result_scores = []
+ if len(boxes) > 0:
+ scores = boxes[:, 6:7]
+ keep_idxs = scores[:, 0] > self.class_score_th
+ scores_keep = scores[keep_idxs, :]
+ boxes_keep = boxes[keep_idxs, :]
+
+ if len(boxes_keep) > 0:
+ for box, score in zip(boxes_keep, scores_keep):
+ x_min = int(max(box[2], 0) * image_width / self.input_shapes[0][3])
+ y_min = int(max(box[3], 0) * image_height / self.input_shapes[0][2])
+ x_max = int(min(box[4], self.input_shapes[0][3]) * image_width / self.input_shapes[0][3])
+ y_max = int(min(box[5], self.input_shapes[0][2]) * image_height / self.input_shapes[0][2])
+
+ result_boxes.append(
+ [x_min, y_min, x_max, y_max]
+ )
+ result_scores.append(
+ score
+ )
+
+ return np.asarray(result_boxes), np.asarray(result_scores)
+
+
+def is_parsable_to_int(s):
+ try:
+ int(s)
+ return True
+ except ValueError:
+ return False
+
+
+def main():
+ parser = ArgumentParser()
+ parser.add_argument(
+ '-m',
+ '--model',
+ type=str,
+ default='gold_yolo_n_hand_post_0333_0.4040_1x3x480x640.onnx',
+ )
+ parser.add_argument(
+ '-v',
+ '--video',
+ type=str,
+ default="0",
+ )
+ args = parser.parse_args()
+
+ model = GoldYOLOONNX(
+ model_path=args.model,
+ )
+
+ cap = cv2.VideoCapture(
+ int(args.video) if is_parsable_to_int(args.video) else args.video
+ )
+ cap_fps = cap.get(cv2.CAP_PROP_FPS)
+ w = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
+ h = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
+ fourcc = cv2.VideoWriter_fourcc('m', 'p', '4', 'v')
+ video_writer = cv2.VideoWriter(
+ filename='output.mp4',
+ fourcc=fourcc,
+ fps=cap_fps,
+ frameSize=(w, h),
+ )
+
+ while cap.isOpened():
+ res, image = cap.read()
+ if not res:
+ break
+
+ debug_image = copy.deepcopy(image)
+
+ start_time = time.time()
+ boxes, scores = model(debug_image)
+ elapsed_time = time.time() - start_time
+ fps = 1 / elapsed_time
+ cv2.putText(
+ debug_image,
+ f'{fps:.1f} FPS (inferece + post-process)',
+ (10, 30),
+ cv2.FONT_HERSHEY_SIMPLEX,
+ 0.7,
+ (255, 255, 255),
+ 2,
+ cv2.LINE_AA,
+ )
+ cv2.putText(
+ debug_image,
+ f'{fps:.1f} FPS (inferece + post-process)',
+ (10, 30),
+ cv2.FONT_HERSHEY_SIMPLEX,
+ 0.7,
+ (0, 0, 255),
+ 1,
+ cv2.LINE_AA,
+ )
+
+ for box, score in zip(boxes, scores):
+ cv2.rectangle(
+ debug_image,
+ (box[0], box[1]),
+ (box[2], box[3]),
+ (255,255,255),
+ 2,
+ )
+ cv2.rectangle(
+ debug_image,
+ (box[0], box[1]),
+ (box[2], box[3]),
+ (0,0,255),
+ 1,
+ )
+ cv2.putText(
+ debug_image,
+ f'{score[0]:.2f}',
+ (
+ box[0],
+ box[1]-10 if box[1]-10 > 0 else 10
+ ),
+ cv2.FONT_HERSHEY_SIMPLEX,
+ 0.7,
+ (255, 255, 255),
+ 2,
+ cv2.LINE_AA,
+ )
+ cv2.putText(
+ debug_image,
+ f'{score[0]:.2f}',
+ (
+ box[0],
+ box[1]-10 if box[1]-10 > 0 else 10
+ ),
+ cv2.FONT_HERSHEY_SIMPLEX,
+ 0.7,
+ (0, 0, 255),
+ 1,
+ cv2.LINE_AA,
+ )
+
+ key = cv2.waitKey(1)
+ if key == 27: # ESC
+ break
+
+ cv2.imshow("test", debug_image)
+ video_writer.write(debug_image)
+
+ if video_writer:
+ video_writer.release()
+
+ if cap:
+ cap.release()
+
+if __name__ == "__main__":
+ main()
diff --git a/421_Gold-YOLO-Head/demo/demo_goldyolo_onnx_image.py b/421_Gold-YOLO-Head/demo/demo_goldyolo_onnx_image.py
new file mode 100644
index 0000000000..7536d66fba
--- /dev/null
+++ b/421_Gold-YOLO-Head/demo/demo_goldyolo_onnx_image.py
@@ -0,0 +1,314 @@
+#!/usr/bin/env python
+
+import os
+import copy
+import cv2
+from tqdm import tqdm
+import glob
+import numpy as np
+import onnxruntime
+from argparse import ArgumentParser
+from typing import Tuple, Optional, List
+
+
+class GoldYOLOONNX(object):
+ def __init__(
+ self,
+ model_path: Optional[str] = 'gold_yolo_n_hand_post_0333_0.4040_1x3x480x640.onnx',
+ class_score_th: Optional[float] = 0.35,
+ providers: Optional[List] = [
+ (
+ 'TensorrtExecutionProvider', {
+ 'trt_engine_cache_enable': True,
+ 'trt_engine_cache_path': '.',
+ 'trt_fp16_enable': True,
+ }
+ ),
+ 'CUDAExecutionProvider',
+ 'CPUExecutionProvider',
+ ],
+ ):
+ """GoldYOLOONNX
+
+ Parameters
+ ----------
+ model_path: Optional[str]
+ ONNX file path for GoldYOLO
+
+ class_score_th: Optional[float]
+ Score threshold. Default: 0.35
+
+ providers: Optional[List]
+ Name of onnx execution providers
+ Default:
+ [
+ (
+ 'TensorrtExecutionProvider', {
+ 'trt_engine_cache_enable': True,
+ 'trt_engine_cache_path': '.',
+ 'trt_fp16_enable': True,
+ }
+ ),
+ 'CUDAExecutionProvider',
+ 'CPUExecutionProvider',
+ ]
+ """
+ # Threshold
+ self.class_score_th = class_score_th
+
+ # Model loading
+ session_option = onnxruntime.SessionOptions()
+ session_option.log_severity_level = 3
+ self.onnx_session = onnxruntime.InferenceSession(
+ model_path,
+ sess_options=session_option,
+ providers=providers,
+ )
+ self.providers = self.onnx_session.get_providers()
+
+ self.input_shapes = [
+ input.shape for input in self.onnx_session.get_inputs()
+ ]
+ self.input_names = [
+ input.name for input in self.onnx_session.get_inputs()
+ ]
+ self.output_names = [
+ output.name for output in self.onnx_session.get_outputs()
+ ]
+
+
+ def __call__(
+ self,
+ image: np.ndarray,
+ ) -> Tuple[np.ndarray, np.ndarray]:
+ """YOLOv7ONNX
+
+ Parameters
+ ----------
+ image: np.ndarray
+ Entire image
+
+ Returns
+ -------
+ boxes: np.ndarray
+ Predicted boxes: [N, y1, x1, y2, x2]
+
+ scores: np.ndarray
+ Predicted box scores: [N, score]
+ """
+ temp_image = copy.deepcopy(image)
+
+ # PreProcess
+ resized_image = self.__preprocess(
+ temp_image,
+ )
+
+ # Inference
+ inferece_image = np.asarray([resized_image], dtype=np.float32)
+ boxes = self.onnx_session.run(
+ self.output_names,
+ {input_name: inferece_image for input_name in self.input_names},
+ )[0]
+
+ # PostProcess
+ result_boxes, result_scores = \
+ self.__postprocess(
+ image=temp_image,
+ boxes=boxes,
+ )
+
+ return result_boxes, result_scores
+
+
+ def __preprocess(
+ self,
+ image: np.ndarray,
+ swap: Optional[Tuple[int,int,int]] = (2, 0, 1),
+ ) -> np.ndarray:
+ """__preprocess
+
+ Parameters
+ ----------
+ image: np.ndarray
+ Entire image
+
+ swap: tuple
+ HWC to CHW: (2,0,1)
+ CHW to HWC: (1,2,0)
+ HWC to HWC: (0,1,2)
+ CHW to CHW: (0,1,2)
+
+ Returns
+ -------
+ resized_image: np.ndarray
+ Resized and normalized image.
+ """
+ # Normalization + BGR->RGB
+ resized_image = cv2.resize(
+ image,
+ (
+ int(self.input_shapes[0][3]),
+ int(self.input_shapes[0][2]),
+ )
+ )
+ resized_image = np.divide(resized_image, 255.0)
+ resized_image = resized_image[..., ::-1]
+ resized_image = resized_image.transpose(swap)
+ resized_image = np.ascontiguousarray(
+ resized_image,
+ dtype=np.float32,
+ )
+ return resized_image
+
+
+ def __postprocess(
+ self,
+ image: np.ndarray,
+ boxes: np.ndarray,
+ ) -> Tuple[np.ndarray, np.ndarray]:
+ """__postprocess
+
+ Parameters
+ ----------
+ image: np.ndarray
+ Entire image.
+
+ boxes: np.ndarray
+ float32[N, 7]
+
+ Returns
+ -------
+ result_boxes: np.ndarray
+ Predicted boxes: [N, y1, x1, y2, x2]
+
+ result_scores: np.ndarray
+ Predicted box confs: [N, score]
+ """
+ image_height = image.shape[0]
+ image_width = image.shape[1]
+
+ """
+ Detector is
+ N -> Number of boxes detected
+ batchno -> always 0: BatchNo.0
+
+ batchno_classid_y1x1y2x2_score: float32[N,7]
+ """
+ result_boxes = []
+ result_scores = []
+ if len(boxes) > 0:
+ scores = boxes[:, 6:7]
+ keep_idxs = scores[:, 0] > self.class_score_th
+ scores_keep = scores[keep_idxs, :]
+ boxes_keep = boxes[keep_idxs, :]
+
+ if len(boxes_keep) > 0:
+ for box, score in zip(boxes_keep, scores_keep):
+ x_min = int(max(box[2], 0) * image_width / self.input_shapes[0][3])
+ y_min = int(max(box[3], 0) * image_height / self.input_shapes[0][2])
+ x_max = int(min(box[4], self.input_shapes[0][3]) * image_width / self.input_shapes[0][3])
+ y_max = int(min(box[5], self.input_shapes[0][2]) * image_height / self.input_shapes[0][2])
+
+ result_boxes.append(
+ [x_min, y_min, x_max, y_max]
+ )
+ result_scores.append(
+ score
+ )
+
+ return np.asarray(result_boxes), np.asarray(result_scores)
+
+
+def is_parsable_to_int(s):
+ try:
+ int(s)
+ return True
+ except ValueError:
+ return False
+
+
+def main():
+ parser = ArgumentParser()
+ parser.add_argument(
+ '-m',
+ '--model',
+ type=str,
+ default='gold_yolo_n_hand_post_0333_0.4040_1x3x480x640.onnx',
+ )
+ parser.add_argument(
+ '-i',
+ '--images_path',
+ type=str,
+ default="./00_COCO-Hand-S_base",
+ )
+ parser.add_argument(
+ '-o',
+ '--output_path',
+ type=str,
+ default="./output",
+ )
+ args = parser.parse_args()
+
+ model = GoldYOLOONNX(
+ model_path=args.model,
+ )
+
+ files = sorted(glob.glob(f"{args.images_path}/*.jpg"))
+ os.makedirs(args.output_path, exist_ok=True)
+
+ for file in tqdm(files, dynamic_ncols=True):
+ image = cv2.imread(file)
+ debug_image = copy.deepcopy(image)
+ boxes, scores = model(debug_image)
+
+ for box, score in zip(boxes, scores):
+ cv2.rectangle(
+ debug_image,
+ (box[0], box[1]),
+ (box[2], box[3]),
+ (255,255,255),
+ 2,
+ )
+ cv2.rectangle(
+ debug_image,
+ (box[0], box[1]),
+ (box[2], box[3]),
+ (0,0,255),
+ 1,
+ )
+ cv2.putText(
+ debug_image,
+ f'{score[0]:.2f}',
+ (
+ box[0],
+ box[1]-10 if box[1]-10 > 0 else 10
+ ),
+ cv2.FONT_HERSHEY_SIMPLEX,
+ 0.7,
+ (255, 255, 255),
+ 2,
+ cv2.LINE_AA,
+ )
+ cv2.putText(
+ debug_image,
+ f'{score[0]:.2f}',
+ (
+ box[0],
+ box[1]-10 if box[1]-10 > 0 else 10
+ ),
+ cv2.FONT_HERSHEY_SIMPLEX,
+ 0.7,
+ (0, 0, 255),
+ 1,
+ cv2.LINE_AA,
+ )
+ cv2.imwrite(f'{args.output_path}/{os.path.basename(file)}', debug_image)
+
+ key = cv2.waitKey(1)
+ if key == 27: # ESC
+ break
+
+ cv2.imshow("test", debug_image)
+
+if __name__ == "__main__":
+ main()
diff --git a/421_Gold-YOLO-Head/download_l.sh b/421_Gold-YOLO-Head/download_l.sh
new file mode 100755
index 0000000000..1e35406ad5
--- /dev/null
+++ b/421_Gold-YOLO-Head/download_l.sh
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+curl "https://s3.ap-northeast-2.wasabisys.com/pinto-model-zoo/421_Gold-YOLO-Head/resources_l.tar.gz" -o resources.tar.gz
+tar -zxvf resources.tar.gz
+rm resources.tar.gz
+
+echo Download finished.
diff --git a/421_Gold-YOLO-Head/download_m.sh b/421_Gold-YOLO-Head/download_m.sh
new file mode 100755
index 0000000000..295616a910
--- /dev/null
+++ b/421_Gold-YOLO-Head/download_m.sh
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+curl "https://s3.ap-northeast-2.wasabisys.com/pinto-model-zoo/421_Gold-YOLO-Head/resources_m.tar.gz" -o resources.tar.gz
+tar -zxvf resources.tar.gz
+rm resources.tar.gz
+
+echo Download finished.
diff --git a/421_Gold-YOLO-Head/download_n.sh b/421_Gold-YOLO-Head/download_n.sh
new file mode 100755
index 0000000000..591c68db08
--- /dev/null
+++ b/421_Gold-YOLO-Head/download_n.sh
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+curl "https://s3.ap-northeast-2.wasabisys.com/pinto-model-zoo/421_Gold-YOLO-Head/resources_n.tar.gz" -o resources.tar.gz
+tar -zxvf resources.tar.gz
+rm resources.tar.gz
+
+echo Download finished.
diff --git a/421_Gold-YOLO-Head/download_s.sh b/421_Gold-YOLO-Head/download_s.sh
new file mode 100755
index 0000000000..e8d6c5c473
--- /dev/null
+++ b/421_Gold-YOLO-Head/download_s.sh
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+curl "https://s3.ap-northeast-2.wasabisys.com/pinto-model-zoo/421_Gold-YOLO-Head/resources_s.tar.gz" -o resources.tar.gz
+tar -zxvf resources.tar.gz
+rm resources.tar.gz
+
+echo Download finished.
diff --git a/421_Gold-YOLO-Head/post_process_gen_tools/README.md b/421_Gold-YOLO-Head/post_process_gen_tools/README.md
new file mode 100644
index 0000000000..6cf00fd90a
--- /dev/null
+++ b/421_Gold-YOLO-Head/post_process_gen_tools/README.md
@@ -0,0 +1,209 @@
+# Note
+- INPUTS
+ - `predictions`: `float32 [batches, boxes, 5 + classes]`
+
+ * 5 = [center_x, center_y, width, height, score]
+- OUTPUTS
+ - `batchno_classid_x1y1x2y2_score`: `float32 [final_boxes_count, 7]`
+
+ * NMS boxes
+ * final_boxes_count (N) ≠ batches
+ * 7 = [batch_no, classid, x1, y1, x2, y2, score]
+
+![image](https://github.com/PINTO0309/PINTO_model_zoo/assets/33194443/9d4fecdf-c90e-4e0a-99a5-9c3e61a4cf41)
+
+# How to generate post-processing ONNX
+Simply change the following parameters and run all shells.
+
+https://github.com/PINTO0309/PINTO_model_zoo/blob/main/420_Gold-YOLO-Hand/post_process_gen_tools/convert_script.sh
+```bash
+OPSET=11
+BATCHES=1
+BOXES=5040
+CLASSES=1
+```
+
+```bash
+sudo chmod +x ./convert_script.sh
+./convert_script.sh
+```
+
+# How to change NMS parameters
+![image](https://user-images.githubusercontent.com/33194443/178084918-af33bfcc-425f-496e-87fb-1331ef7b2b6e.png)
+
+https://github.com/PINTO0309/simple-onnx-processing-tools
+
+Run the script below to directly rewrite the parameters of the ONNX file.
+```bash
+### Number of output boxes for Gold-YOLO
+BOXES=5040
+
+### max_output_boxes_per_class
+sam4onnx \
+--op_name main01_nonmaxsuppression11 \
+--input_onnx_file_path 30_nms_gold_yolo_m_hand_${BOXES}.onnx \
+--output_onnx_file_path 30_nms_gold_yolo_m_hand_${BOXES}.onnx \
+--input_constants main01_max_output_boxes_per_class int64 [10]
+
+### iou_threshold
+sam4onnx \
+--op_name main01_nonmaxsuppression11 \
+--input_onnx_file_path 30_nms_gold_yolo_m_hand_${BOXES}.onnx \
+--output_onnx_file_path 30_nms_gold_yolo_m_hand_${BOXES}.onnx \
+--input_constants main01_iou_threshold float32 [0.05]
+
+### score_threshold
+sam4onnx \
+--op_name main01_nonmaxsuppression11 \
+--input_onnx_file_path 30_nms_gold_yolo_m_hand_${BOXES}.onnx \
+--output_onnx_file_path 30_nms_gold_yolo_m_hand_${BOXES}.onnx \
+--input_constants main01_score_threshold float32 [0.25]
+```
+
+# How to merge post-processing into a Gold-YOLO model
+Simply execute the following command.
+
+https://github.com/PINTO0309/simple-onnx-processing-tools
+
+```bash
+################################################### Gold-YOLO + Post-Process
+MODEL=gold_yolo
+BOXES=5040
+H=256
+W=320
+
+snc4onnx \
+--input_onnx_file_paths ${MODEL}_${H}x${W}.onnx 30_nms_gold_yolo_m_hand_${BOXES}.onnx \
+--srcop_destop output predictions \
+--output_onnx_file_path ${MODEL}_post_${H}x${W}.onnx
+onnxsim ${MODEL}_post_${H}x${W}.onnx ${MODEL}_post_${H}x${W}.onnx
+onnxsim ${MODEL}_post_${H}x${W}.onnx ${MODEL}_post_${H}x${W}.onnx
+
+################################################### 1 Batch
+
+MODEL=gold_yolo
+
+BOXES=5040
+H=256
+W=320
+snc4onnx \
+--input_onnx_file_paths ${MODEL}_${H}x${W}.onnx 30_nms_gold_yolo_m_hand_${BOXES}.onnx \
+--srcop_destop output predictions \
+--output_onnx_file_path ${MODEL}_post_${H}x${W}.onnx
+onnxsim ${MODEL}_post_${H}x${W}.onnx ${MODEL}_post_${H}x${W}.onnx
+onnxsim ${MODEL}_post_${H}x${W}.onnx ${MODEL}_post_${H}x${W}.onnx
+
+BOXES=7560
+H=256
+W=480
+snc4onnx \
+--input_onnx_file_paths ${MODEL}_${H}x${W}.onnx 30_nms_gold_yolo_m_hand_${BOXES}.onnx \
+--srcop_destop output predictions \
+--output_onnx_file_path ${MODEL}_post_${H}x${W}.onnx
+onnxsim ${MODEL}_post_${H}x${W}.onnx ${MODEL}_post_${H}x${W}.onnx
+onnxsim ${MODEL}_post_${H}x${W}.onnx ${MODEL}_post_${H}x${W}.onnx
+
+BOXES=10080
+H=256
+W=640
+snc4onnx \
+--input_onnx_file_paths ${MODEL}_${H}x${W}.onnx 30_nms_gold_yolo_m_hand_${BOXES}.onnx \
+--srcop_destop output predictions \
+--output_onnx_file_path ${MODEL}_post_${H}x${W}.onnx
+onnxsim ${MODEL}_post_${H}x${W}.onnx ${MODEL}_post_${H}x${W}.onnx
+onnxsim ${MODEL}_post_${H}x${W}.onnx ${MODEL}_post_${H}x${W}.onnx
+
+BOXES=15120
+H=384
+W=640
+snc4onnx \
+--input_onnx_file_paths ${MODEL}_${H}x${W}.onnx 30_nms_gold_yolo_m_hand_${BOXES}.onnx \
+--srcop_destop output predictions \
+--output_onnx_file_path ${MODEL}_post_${H}x${W}.onnx
+onnxsim ${MODEL}_post_${H}x${W}.onnx ${MODEL}_post_${H}x${W}.onnx
+onnxsim ${MODEL}_post_${H}x${W}.onnx ${MODEL}_post_${H}x${W}.onnx
+
+BOXES=18900
+H=480
+W=640
+snc4onnx \
+--input_onnx_file_paths ${MODEL}_${H}x${W}.onnx 30_nms_gold_yolo_m_hand_${BOXES}.onnx \
+--srcop_destop output predictions \
+--output_onnx_file_path ${MODEL}_post_${H}x${W}.onnx
+onnxsim ${MODEL}_post_${H}x${W}.onnx ${MODEL}_post_${H}x${W}.onnx
+onnxsim ${MODEL}_post_${H}x${W}.onnx ${MODEL}_post_${H}x${W}.onnx
+
+BOXES=57960
+H=736
+W=1280
+snc4onnx \
+--input_onnx_file_paths ${MODEL}_${H}x${W}.onnx 30_nms_gold_yolo_m_hand_${BOXES}.onnx \
+--srcop_destop output predictions \
+--output_onnx_file_path ${MODEL}_post_${H}x${W}.onnx
+onnxsim ${MODEL}_post_${H}x${W}.onnx ${MODEL}_post_${H}x${W}.onnx
+onnxsim ${MODEL}_post_${H}x${W}.onnx ${MODEL}_post_${H}x${W}.onnx
+
+################################################### N Batch
+
+MODEL=gold_yolo
+
+BOXES=5040
+H=256
+W=320
+snc4onnx \
+--input_onnx_file_paths ${MODEL}_Nx3x${H}x${W}.onnx 31_nms_gold_yolo_m_hand_N_${BOXES}.onnx \
+--srcop_destop output predictions \
+--output_onnx_file_path ${MODEL}_post_Nx3x${H}x${W}.onnx
+onnxsim ${MODEL}_post_Nx3x${H}x${W}.onnx ${MODEL}_post_Nx3x${H}x${W}.onnx
+onnxsim ${MODEL}_post_Nx3x${H}x${W}.onnx ${MODEL}_post_Nx3x${H}x${W}.onnx
+
+BOXES=7560
+H=256
+W=480
+snc4onnx \
+--input_onnx_file_paths ${MODEL}_Nx3x${H}x${W}.onnx 31_nms_gold_yolo_m_hand_N_${BOXES}.onnx \
+--srcop_destop output predictions \
+--output_onnx_file_path ${MODEL}_post_Nx3x${H}x${W}.onnx
+onnxsim ${MODEL}_post_Nx3x${H}x${W}.onnx ${MODEL}_post_Nx3x${H}x${W}.onnx
+onnxsim ${MODEL}_post_Nx3x${H}x${W}.onnx ${MODEL}_post_Nx3x${H}x${W}.onnx
+
+BOXES=10080
+H=256
+W=640
+snc4onnx \
+--input_onnx_file_paths ${MODEL}_Nx3x${H}x${W}.onnx 31_nms_gold_yolo_m_hand_N_${BOXES}.onnx \
+--srcop_destop output predictions \
+--output_onnx_file_path ${MODEL}_post_Nx3x${H}x${W}.onnx
+onnxsim ${MODEL}_post_Nx3x${H}x${W}.onnx ${MODEL}_post_Nx3x${H}x${W}.onnx
+onnxsim ${MODEL}_post_Nx3x${H}x${W}.onnx ${MODEL}_post_Nx3x${H}x${W}.onnx
+
+BOXES=15120
+H=384
+W=640
+snc4onnx \
+--input_onnx_file_paths ${MODEL}_Nx3x${H}x${W}.onnx 31_nms_gold_yolo_m_hand_N_${BOXES}.onnx \
+--srcop_destop output predictions \
+--output_onnx_file_path ${MODEL}_post_Nx3x${H}x${W}.onnx
+onnxsim ${MODEL}_post_Nx3x${H}x${W}.onnx ${MODEL}_post_Nx3x${H}x${W}.onnx
+onnxsim ${MODEL}_post_Nx3x${H}x${W}.onnx ${MODEL}_post_Nx3x${H}x${W}.onnx
+
+BOXES=18900
+H=480
+W=640
+snc4onnx \
+--input_onnx_file_paths ${MODEL}_Nx3x${H}x${W}.onnx 31_nms_gold_yolo_m_hand_N_${BOXES}.onnx \
+--srcop_destop output predictions \
+--output_onnx_file_path ${MODEL}_post_Nx3x${H}x${W}.onnx
+onnxsim ${MODEL}_post_Nx3x${H}x${W}.onnx ${MODEL}_post_Nx3x${H}x${W}.onnx
+onnxsim ${MODEL}_post_Nx3x${H}x${W}.onnx ${MODEL}_post_Nx3x${H}x${W}.onnx
+
+BOXES=57960
+H=736
+W=1280
+snc4onnx \
+--input_onnx_file_paths ${MODEL}_Nx3x${H}x${W}.onnx 31_nms_gold_yolo_m_hand_N_${BOXES}.onnx \
+--srcop_destop output predictions \
+--output_onnx_file_path ${MODEL}_post_Nx3x${H}x${W}.onnx
+onnxsim ${MODEL}_post_Nx3x${H}x${W}.onnx ${MODEL}_post_Nx3x${H}x${W}.onnx
+onnxsim ${MODEL}_post_Nx3x${H}x${W}.onnx ${MODEL}_post_Nx3x${H}x${W}.onnx
+```
diff --git a/421_Gold-YOLO-Head/post_process_gen_tools/boxes_listup.py b/421_Gold-YOLO-Head/post_process_gen_tools/boxes_listup.py
new file mode 100644
index 0000000000..4d6be5b33f
--- /dev/null
+++ b/421_Gold-YOLO-Head/post_process_gen_tools/boxes_listup.py
@@ -0,0 +1,54 @@
+import onnxruntime as ort
+from collections import OrderedDict
+
+MODELS = OrderedDict(
+ {
+ "01": "gold_yolo_n_hand_0423_0.2295_1x3x192x320.onnx",
+ "02": "gold_yolo_n_hand_0423_0.2295_1x3x192x416.onnx",
+ "03": "gold_yolo_n_hand_0423_0.2295_1x3x192x640.onnx",
+ "04": "gold_yolo_n_hand_0423_0.2295_1x3x192x800.onnx",
+ "05": "gold_yolo_n_hand_0423_0.2295_1x3x256x320.onnx",
+ "06": "gold_yolo_n_hand_0423_0.2295_1x3x256x416.onnx",
+ "07": "gold_yolo_n_hand_0423_0.2295_1x3x256x640.onnx",
+ "08": "gold_yolo_n_hand_0423_0.2295_1x3x256x800.onnx",
+ "09": "gold_yolo_n_hand_0423_0.2295_1x3x256x960.onnx",
+ "10": "gold_yolo_n_hand_0423_0.2295_1x3x288x1280.onnx",
+ "11": "gold_yolo_n_hand_0423_0.2295_1x3x288x480.onnx",
+ "12": "gold_yolo_n_hand_0423_0.2295_1x3x288x640.onnx",
+ "13": "gold_yolo_n_hand_0423_0.2295_1x3x288x800.onnx",
+ "14": "gold_yolo_n_hand_0423_0.2295_1x3x288x960.onnx",
+ "15": "gold_yolo_n_hand_0423_0.2295_1x3x320x320.onnx",
+ "16": "gold_yolo_n_hand_0423_0.2295_1x3x384x1280.onnx",
+ "17": "gold_yolo_n_hand_0423_0.2295_1x3x384x480.onnx",
+ "18": "gold_yolo_n_hand_0423_0.2295_1x3x384x640.onnx",
+ "19": "gold_yolo_n_hand_0423_0.2295_1x3x384x800.onnx",
+ "20": "gold_yolo_n_hand_0423_0.2295_1x3x384x960.onnx",
+ "21": "gold_yolo_n_hand_0423_0.2295_1x3x416x416.onnx",
+ "22": "gold_yolo_n_hand_0423_0.2295_1x3x480x1280.onnx",
+ "23": "gold_yolo_n_hand_0423_0.2295_1x3x480x640.onnx",
+ "24": "gold_yolo_n_hand_0423_0.2295_1x3x480x800.onnx",
+ "25": "gold_yolo_n_hand_0423_0.2295_1x3x480x960.onnx",
+ "26": "gold_yolo_n_hand_0423_0.2295_1x3x512x512.onnx",
+ "27": "gold_yolo_n_hand_0423_0.2295_1x3x512x640.onnx",
+ "28": "gold_yolo_n_hand_0423_0.2295_1x3x512x896.onnx",
+ "29": "gold_yolo_n_hand_0423_0.2295_1x3x544x1280.onnx",
+ "30": "gold_yolo_n_hand_0423_0.2295_1x3x544x800.onnx",
+ "31": "gold_yolo_n_hand_0423_0.2295_1x3x544x960.onnx",
+ "32": "gold_yolo_n_hand_0423_0.2295_1x3x640x640.onnx",
+ "33": "gold_yolo_n_hand_0423_0.2295_1x3x736x1280.onnx",
+ }
+)
+
+box_sizes = []
+for k, v in MODELS.items():
+ onnx_session = ort.InferenceSession(
+ path_or_bytes=v,
+ providers=['CPUExecutionProvider'],
+ )
+ box_sizes.append([onnx_session.get_inputs()[0].shape[2], onnx_session.get_inputs()[0].shape[3], onnx_session.get_outputs()[0].shape[1]])
+
+print(f'MODELS count: {len(MODELS)}')
+print(f'BOX_SIZE count: {len(box_sizes)}')
+
+for box_size in box_sizes:
+ print(f'"{box_size[0]} {box_size[1]} {box_size[2]}"')
\ No newline at end of file
diff --git a/421_Gold-YOLO-Head/post_process_gen_tools/convert_script.sh b/421_Gold-YOLO-Head/post_process_gen_tools/convert_script.sh
new file mode 100755
index 0000000000..17d43dd17e
--- /dev/null
+++ b/421_Gold-YOLO-Head/post_process_gen_tools/convert_script.sh
@@ -0,0 +1,484 @@
+# pip install -U pip \
+# && pip install onnxsim==0.4.33 \
+# && pip install -U simple-onnx-processing-tools \
+# && pip install -U onnx \
+# && python3 -m pip install -U onnx_graphsurgeon --index-url https://pypi.ngc.nvidia.com
+
+MODEL_NAME=gold_yolo_n_hand
+SUFFIX="0333_0.4040_1x3x"
+OPSET=11
+BATCHES=1
+CLASSES=1
+
+RESOLUTIONS=(
+ "192 320 1260"
+ "192 416 1638"
+ "192 640 2520"
+ "192 800 3150"
+ "256 320 1680"
+ "256 416 2184"
+ "256 640 3360"
+ "256 800 4200"
+ "256 960 5040"
+ "288 1280 7560"
+ "288 480 2835"
+ "288 640 3780"
+ "288 800 4725"
+ "288 960 5670"
+ "320 320 2100"
+ "384 1280 10080"
+ "384 480 3780"
+ "384 640 5040"
+ "384 800 6300"
+ "384 960 7560"
+ "416 416 3549"
+ "480 1280 12600"
+ "480 640 6300"
+ "480 800 7875"
+ "480 960 9450"
+ "512 512 5376"
+ "512 640 6720"
+ "512 896 9408"
+ "544 1280 14280"
+ "544 800 8925"
+ "544 960 10710"
+ "640 640 8400"
+ "736 1280 19320"
+)
+
+for((i=0; i<${#RESOLUTIONS[@]}; i++))
+do
+ RESOLUTION=(`echo ${RESOLUTIONS[i]}`)
+ H=${RESOLUTION[0]}
+ W=${RESOLUTION[1]}
+ BOXES=${RESOLUTION[2]}
+
+ ################################################### Boxes + Scores
+ python make_boxes_scores.py -o ${OPSET} -b ${BATCHES} -x ${BOXES} -c ${CLASSES}
+ python make_cxcywh_y1x1y2x2.py -o ${OPSET} -b ${BATCHES} -x ${BOXES}
+
+ sor4onnx \
+ --input_onnx_file_path 01_boxes_scores_${BOXES}.onnx \
+ --old_new "/Constant" "boxes_scores_Constant" \
+ --mode full \
+ --search_mode prefix_match \
+ --output_onnx_file_path 01_boxes_scores_${BOXES}.onnx
+
+ sor4onnx \
+ --input_onnx_file_path 02_cxcywh_y1x1y2x2_${BOXES}.onnx \
+ --old_new "/Constant" "cxcywh_y1x1y2x2_Constant" \
+ --mode full \
+ --search_mode prefix_match \
+ --output_onnx_file_path 02_cxcywh_y1x1y2x2_${BOXES}.onnx
+
+ sor4onnx \
+ --input_onnx_file_path 02_cxcywh_y1x1y2x2_${BOXES}.onnx \
+ --old_new "/Slice" "cxcywh_y1x1y2x2_Slice" \
+ --mode full \
+ --search_mode prefix_match \
+ --output_onnx_file_path 02_cxcywh_y1x1y2x2_${BOXES}.onnx
+
+ snc4onnx \
+ --input_onnx_file_paths 01_boxes_scores_${BOXES}.onnx 02_cxcywh_y1x1y2x2_${BOXES}.onnx \
+ --srcop_destop boxes_cxcywh cxcywh \
+ --output_onnx_file_path 03_boxes_y1x1y2x2_scores_${BOXES}.onnx
+
+
+ ################################################### NonMaxSuppression
+ sog4onnx \
+ --op_type Constant \
+ --opset ${OPSET} \
+ --op_name max_output_boxes_per_class_const \
+ --output_variables max_output_boxes_per_class int64 [1] \
+ --attributes value int64 [20] \
+ --output_onnx_file_path 04_Constant_max_output_boxes_per_class.onnx
+
+ # N: iou_threshold_const=0.40, score_threshold_const=0.25
+ # M: iou_threshold_const=0.40, score_threshold_const=0.25
+
+ sog4onnx \
+ --op_type Constant \
+ --opset ${OPSET} \
+ --op_name iou_threshold_const \
+ --output_variables iou_threshold float32 [1] \
+ --attributes value float32 [0.40] \
+ --output_onnx_file_path 05_Constant_iou_threshold.onnx
+
+ sog4onnx \
+ --op_type Constant \
+ --opset ${OPSET} \
+ --op_name score_threshold_const \
+ --output_variables score_threshold float32 [1] \
+ --attributes value float32 [0.25] \
+ --output_onnx_file_path 06_Constant_score_threshold.onnx
+
+
+ OP=NonMaxSuppression
+ LOWEROP=${OP,,}
+ sog4onnx \
+ --op_type ${OP} \
+ --opset ${OPSET} \
+ --op_name ${LOWEROP}${OPSET} \
+ --input_variables boxes_var float32 [${BATCHES},${BOXES},4] \
+ --input_variables scores_var float32 [${BATCHES},${CLASSES},${BOXES}] \
+ --input_variables max_output_boxes_per_class_var int64 [1] \
+ --input_variables iou_threshold_var float32 [1] \
+ --input_variables score_threshold_var float32 [1] \
+ --output_variables selected_indices int64 [\'N\',3] \
+ --attributes center_point_box int64 0 \
+ --output_onnx_file_path 07_${OP}${OPSET}.onnx
+
+
+ snc4onnx \
+ --input_onnx_file_paths 04_Constant_max_output_boxes_per_class.onnx 07_${OP}${OPSET}.onnx \
+ --srcop_destop max_output_boxes_per_class max_output_boxes_per_class_var \
+ --output_onnx_file_path 07_${OP}${OPSET}.onnx
+
+ snc4onnx \
+ --input_onnx_file_paths 05_Constant_iou_threshold.onnx 07_${OP}${OPSET}.onnx \
+ --srcop_destop iou_threshold iou_threshold_var \
+ --output_onnx_file_path 07_${OP}${OPSET}.onnx
+
+ snc4onnx \
+ --input_onnx_file_paths 06_Constant_score_threshold.onnx 07_${OP}${OPSET}.onnx \
+ --srcop_destop score_threshold score_threshold_var \
+ --output_onnx_file_path 07_${OP}${OPSET}.onnx
+
+ soc4onnx \
+ --input_onnx_file_path 07_${OP}${OPSET}.onnx \
+ --output_onnx_file_path 07_${OP}${OPSET}.onnx \
+ --opset ${OPSET}
+
+
+ ################################################### Boxes + Scores + NonMaxSuppression
+ snc4onnx \
+ --input_onnx_file_paths 03_boxes_y1x1y2x2_scores_${BOXES}.onnx 07_${OP}${OPSET}.onnx \
+ --srcop_destop scores scores_var y1x1y2x2 boxes_var \
+ --output_onnx_file_path 08_nms_${MODEL_NAME}_${BOXES}.onnx
+
+
+ ################################################### Myriad workaround Mul
+ OP=Mul
+ LOWEROP=${OP,,}
+ OPSET=${OPSET}
+ sog4onnx \
+ --op_type ${OP} \
+ --opset ${OPSET} \
+ --op_name ${LOWEROP}${OPSET} \
+ --input_variables workaround_mul_a int64 [\'N\',3] \
+ --input_variables workaround_mul_b int64 [1] \
+ --output_variables workaround_mul_out int64 [\'N\',3] \
+ --output_onnx_file_path 09_${OP}${OPSET}_workaround.onnx
+
+ ############ Myriad workaround Constant
+ sog4onnx \
+ --op_type Constant \
+ --opset ${OPSET} \
+ --op_name workaround_mul_const_op \
+ --output_variables workaround_mul_const int64 [1] \
+ --attributes value int64 [1] \
+ --output_onnx_file_path 10_Constant_workaround_mul.onnx
+
+ ############ Myriad workaround Mul + Myriad workaround Constant
+ snc4onnx \
+ --input_onnx_file_paths 10_Constant_workaround_mul.onnx 09_${OP}${OPSET}_workaround.onnx \
+ --srcop_destop workaround_mul_const workaround_mul_b \
+ --output_onnx_file_path 09_${OP}${OPSET}_workaround.onnx
+
+
+
+ ################################################### NonMaxSuppression + Myriad workaround Mul
+ snc4onnx \
+ --input_onnx_file_paths 08_nms_${MODEL_NAME}_${BOXES}.onnx 09_${OP}${OPSET}_workaround.onnx \
+ --srcop_destop selected_indices workaround_mul_a \
+ --output_onnx_file_path 11_nms_${MODEL_NAME}_${BOXES}.onnx \
+ --disable_onnxsim
+
+ ################################################### N batch NMS
+ sbi4onnx \
+ --input_onnx_file_path 11_nms_${MODEL_NAME}_${BOXES}.onnx \
+ --output_onnx_file_path 12_nms_${MODEL_NAME}_${BOXES}_batch.onnx \
+ --initialization_character_string batch
+
+ sio4onnx \
+ --input_onnx_file_path 12_nms_${MODEL_NAME}_${BOXES}_batch.onnx \
+ --output_onnx_file_path 12_nms_${MODEL_NAME}_${BOXES}_batch.onnx \
+ --input_names "predictions" \
+ --input_shapes "batch" ${BOXES} $((CLASSES+5)) \
+ --output_names "x1y1x2y2" \
+ --output_names "workaround_mul_out" \
+ --output_shapes "batch" ${BOXES} 4 \
+ --output_shapes "N" 3
+
+
+
+
+ ################################################### Score GatherND
+ python make_score_gather_nd.py -b ${BATCHES} -x ${BOXES} -c ${CLASSES}
+
+ python -m tf2onnx.convert \
+ --opset ${OPSET} \
+ --tflite saved_model_postprocess/nms_score_gather_nd.tflite \
+ --output 13_nms_score_gather_nd.onnx
+
+ sor4onnx \
+ --input_onnx_file_path 13_nms_score_gather_nd.onnx \
+ --old_new ":0" "" \
+ --mode full \
+ --search_mode partial_match \
+ --output_onnx_file_path 13_nms_score_gather_nd.onnx
+
+ sor4onnx \
+ --input_onnx_file_path 13_nms_score_gather_nd.onnx \
+ --old_new "serving_default_input_1" "gn_scores" \
+ --output_onnx_file_path 13_nms_score_gather_nd.onnx \
+ --mode inputs
+
+ sor4onnx \
+ --input_onnx_file_path 13_nms_score_gather_nd.onnx \
+ --old_new "serving_default_input_2" "gn_selected_indices" \
+ --output_onnx_file_path 13_nms_score_gather_nd.onnx \
+ --mode inputs
+
+ sor4onnx \
+ --input_onnx_file_path 13_nms_score_gather_nd.onnx \
+ --old_new "PartitionedCall" "final_scores" \
+ --output_onnx_file_path 13_nms_score_gather_nd.onnx \
+ --mode outputs
+
+ python make_input_output_shape_update.py \
+ --input_onnx_file_path 13_nms_score_gather_nd.onnx \
+ --output_onnx_file_path 13_nms_score_gather_nd.onnx \
+ --input_names gn_scores \
+ --input_names gn_selected_indices \
+ --input_shapes ${BATCHES} ${CLASSES} ${BOXES} \
+ --input_shapes N 3 \
+ --output_names final_scores \
+ --output_shapes N 1
+
+ onnxsim 13_nms_score_gather_nd.onnx 13_nms_score_gather_nd.onnx
+ onnxsim 13_nms_score_gather_nd.onnx 13_nms_score_gather_nd.onnx
+
+ sio4onnx \
+ --input_onnx_file_path 13_nms_score_gather_nd.onnx \
+ --output_onnx_file_path 14_nms_score_gather_nd_batch.onnx \
+ --input_names "gn_scores" \
+ --input_names "gn_selected_indices" \
+ --input_shapes "batch" ${CLASSES} ${BOXES} \
+ --input_shapes "N" 3 \
+ --output_names "final_scores" \
+ --output_shapes "N" 1
+
+
+ ################################################### NonMaxSuppression + Score GatherND
+ snc4onnx \
+ --input_onnx_file_paths 11_nms_${MODEL_NAME}_${BOXES}.onnx 13_nms_score_gather_nd.onnx \
+ --srcop_destop scores gn_scores workaround_mul_out gn_selected_indices \
+ --output_onnx_file_path 15_nms_${MODEL_NAME}_${BOXES}_nd.onnx
+
+ onnxsim 15_nms_${MODEL_NAME}_${BOXES}_nd.onnx 15_nms_${MODEL_NAME}_${BOXES}_nd.onnx
+ onnxsim 15_nms_${MODEL_NAME}_${BOXES}_nd.onnx 15_nms_${MODEL_NAME}_${BOXES}_nd.onnx
+
+
+ snc4onnx \
+ --input_onnx_file_paths 12_nms_${MODEL_NAME}_${BOXES}_batch.onnx 14_nms_score_gather_nd_batch.onnx \
+ --srcop_destop scores gn_scores workaround_mul_out gn_selected_indices \
+ --output_onnx_file_path 16_nms_${MODEL_NAME}_${BOXES}_nd_batch.onnx
+
+ onnxsim 16_nms_${MODEL_NAME}_${BOXES}_nd_batch.onnx 16_nms_${MODEL_NAME}_${BOXES}_nd_batch.onnx
+ onnxsim 16_nms_${MODEL_NAME}_${BOXES}_nd_batch.onnx 16_nms_${MODEL_NAME}_${BOXES}_nd_batch.onnx
+
+
+
+
+
+
+
+ ################################################### Final Batch Nums
+ python make_final_batch_nums_final_class_nums_final_box_nums.py
+
+
+ ################################################### Boxes GatherND
+ python make_box_gather_nd.py
+
+ python -m tf2onnx.convert \
+ --opset ${OPSET} \
+ --tflite saved_model_postprocess/nms_box_gather_nd.tflite \
+ --output 18_nms_box_gather_nd.onnx
+
+ sor4onnx \
+ --input_onnx_file_path 18_nms_box_gather_nd.onnx \
+ --old_new ":0" "" \
+ --mode full \
+ --search_mode partial_match \
+ --output_onnx_file_path 18_nms_box_gather_nd.onnx
+
+ sor4onnx \
+ --input_onnx_file_path 18_nms_box_gather_nd.onnx \
+ --old_new "serving_default_input_1" "gn_boxes" \
+ --output_onnx_file_path 18_nms_box_gather_nd.onnx \
+ --mode inputs
+
+ sor4onnx \
+ --input_onnx_file_path 18_nms_box_gather_nd.onnx \
+ --old_new "serving_default_input_2" "gn_box_selected_indices" \
+ --output_onnx_file_path 18_nms_box_gather_nd.onnx \
+ --mode inputs
+
+ sor4onnx \
+ --input_onnx_file_path 18_nms_box_gather_nd.onnx \
+ --old_new "PartitionedCall" "final_boxes" \
+ --output_onnx_file_path 18_nms_box_gather_nd.onnx \
+ --mode outputs
+
+ python make_input_output_shape_update.py \
+ --input_onnx_file_path 18_nms_box_gather_nd.onnx \
+ --output_onnx_file_path 18_nms_box_gather_nd.onnx \
+ --input_names gn_boxes \
+ --input_names gn_box_selected_indices \
+ --input_shapes ${BATCHES} ${BOXES} 4 \
+ --input_shapes N 2 \
+ --output_names final_boxes \
+ --output_shapes N 4
+
+ onnxsim 18_nms_box_gather_nd.onnx 18_nms_box_gather_nd.onnx
+ onnxsim 18_nms_box_gather_nd.onnx 18_nms_box_gather_nd.onnx
+
+ sio4onnx \
+ --input_onnx_file_path 18_nms_box_gather_nd.onnx \
+ --output_onnx_file_path 19_nms_box_gather_nd_batch.onnx \
+ --input_names "gn_boxes" \
+ --input_names "gn_box_selected_indices" \
+ --input_shapes "batch" ${BOXES} 4 \
+ --input_shapes "N" 2 \
+ --output_names "final_boxes" \
+ --output_shapes "N" 4
+
+
+ ################################################### nms_${MODEL_NAME}_xxx_nd + nms_final_batch_nums_final_class_nums_final_box_nums
+ snc4onnx \
+ --input_onnx_file_paths 15_nms_${MODEL_NAME}_${BOXES}_nd.onnx 17_nms_final_batch_nums_final_class_nums_final_box_nums.onnx \
+ --srcop_destop selected_indices bc_input \
+ --op_prefixes_after_merging main01 sub01 \
+ --output_onnx_file_path 20_nms_${MODEL_NAME}_${BOXES}_split.onnx
+
+ snc4onnx \
+ --input_onnx_file_paths 16_nms_${MODEL_NAME}_${BOXES}_nd_batch.onnx 17_nms_final_batch_nums_final_class_nums_final_box_nums.onnx \
+ --srcop_destop workaround_mul_out bc_input \
+ --op_prefixes_after_merging main01 sub01 \
+ --output_onnx_file_path 21_nms_${MODEL_NAME}_${BOXES}_split_batch.onnx
+
+
+
+ ################################################### nms_${MODEL_NAME}_${BOXES}_split + nms_box_gather_nd
+ snc4onnx \
+ --input_onnx_file_paths 20_nms_${MODEL_NAME}_${BOXES}_split.onnx 18_nms_box_gather_nd.onnx \
+ --srcop_destop x1y1x2y2 gn_boxes final_box_nums gn_box_selected_indices \
+ --output_onnx_file_path 22_nms_${MODEL_NAME}_${BOXES}_merged.onnx
+
+ onnxsim 22_nms_${MODEL_NAME}_${BOXES}_merged.onnx 22_nms_${MODEL_NAME}_${BOXES}_merged.onnx
+ onnxsim 22_nms_${MODEL_NAME}_${BOXES}_merged.onnx 22_nms_${MODEL_NAME}_${BOXES}_merged.onnx
+
+
+ snc4onnx \
+ --input_onnx_file_paths 21_nms_${MODEL_NAME}_${BOXES}_split_batch.onnx 19_nms_box_gather_nd_batch.onnx \
+ --srcop_destop x1y1x2y2 gn_boxes final_box_nums gn_box_selected_indices \
+ --output_onnx_file_path 23_nms_${MODEL_NAME}_${BOXES}_merged_batch.onnx
+
+ onnxsim 23_nms_${MODEL_NAME}_${BOXES}_merged_batch.onnx 23_nms_${MODEL_NAME}_${BOXES}_merged_batch.onnx
+ onnxsim 23_nms_${MODEL_NAME}_${BOXES}_merged_batch.onnx 23_nms_${MODEL_NAME}_${BOXES}_merged_batch.onnx
+
+
+
+
+
+ ################################################### nms output op name Cleaning
+ sor4onnx \
+ --input_onnx_file_path 22_nms_${MODEL_NAME}_${BOXES}_merged.onnx \
+ --old_new "main01_final_scores" "final_scores" \
+ --output_onnx_file_path 22_nms_${MODEL_NAME}_${BOXES}_merged.onnx \
+ --mode outputs
+
+ sor4onnx \
+ --input_onnx_file_path 22_nms_${MODEL_NAME}_${BOXES}_merged.onnx \
+ --old_new "sub01_final_batch_nums" "final_batch_nums" \
+ --output_onnx_file_path 22_nms_${MODEL_NAME}_${BOXES}_merged.onnx \
+ --mode outputs
+
+ sor4onnx \
+ --input_onnx_file_path 22_nms_${MODEL_NAME}_${BOXES}_merged.onnx \
+ --old_new "sub01_final_class_nums" "final_class_nums" \
+ --output_onnx_file_path 22_nms_${MODEL_NAME}_${BOXES}_merged.onnx \
+ --mode outputs
+
+
+ sor4onnx \
+ --input_onnx_file_path 23_nms_${MODEL_NAME}_${BOXES}_merged_batch.onnx \
+ --old_new "main01_final_scores" "final_scores" \
+ --output_onnx_file_path 23_nms_${MODEL_NAME}_${BOXES}_merged_batch.onnx \
+ --mode outputs
+
+ sor4onnx \
+ --input_onnx_file_path 23_nms_${MODEL_NAME}_${BOXES}_merged_batch.onnx \
+ --old_new "sub01_final_batch_nums" "final_batch_nums" \
+ --output_onnx_file_path 23_nms_${MODEL_NAME}_${BOXES}_merged_batch.onnx \
+ --mode outputs
+
+ sor4onnx \
+ --input_onnx_file_path 23_nms_${MODEL_NAME}_${BOXES}_merged_batch.onnx \
+ --old_new "sub01_final_class_nums" "final_class_nums" \
+ --output_onnx_file_path 23_nms_${MODEL_NAME}_${BOXES}_merged_batch.onnx \
+ --mode outputs
+
+
+
+
+
+
+
+ ################################################### nms output merge
+ python make_nms_outputs_merge.py
+
+ onnxsim 24_nms_batchno_classid_x1y1x2y2_score_cat.onnx 24_nms_batchno_classid_x1y1x2y2_score_cat.onnx
+
+
+ ################################################### merge
+ snc4onnx \
+ --input_onnx_file_paths 22_nms_${MODEL_NAME}_${BOXES}_merged.onnx 24_nms_batchno_classid_x1y1x2y2_score_cat.onnx \
+ --srcop_destop final_batch_nums cat_batch final_class_nums cat_classid final_boxes cat_x1y1x2y2 final_scores cat_score \
+ --output_onnx_file_path 30_nms_${MODEL_NAME}_${BOXES}.onnx
+
+ sor4onnx \
+ --input_onnx_file_path 30_nms_${MODEL_NAME}_${BOXES}.onnx \
+ --old_new "final_scores" "score" \
+ --output_onnx_file_path 30_nms_${MODEL_NAME}_${BOXES}.onnx \
+ --mode outputs
+
+
+
+ ################################################### merge
+ snc4onnx \
+ --input_onnx_file_paths 23_nms_${MODEL_NAME}_${BOXES}_merged_batch.onnx 24_nms_batchno_classid_x1y1x2y2_score_cat.onnx \
+ --srcop_destop final_batch_nums cat_batch final_class_nums cat_classid final_boxes cat_x1y1x2y2 final_scores cat_score \
+ --output_onnx_file_path 31_nms_${MODEL_NAME}_N_${BOXES}.onnx
+
+ sor4onnx \
+ --input_onnx_file_path 31_nms_${MODEL_NAME}_N_${BOXES}.onnx \
+ --old_new "final_scores" "score" \
+ --output_onnx_file_path 31_nms_${MODEL_NAME}_N_${BOXES}.onnx \
+ --mode outputs
+
+ # ################################################### Cleaning
+ rm 0*.onnx
+ rm 1*.onnx
+ rm 2*.onnx
+
+
+ ################################################### ${MODEL_NAME} + Post-Process
+ snc4onnx \
+ --input_onnx_file_paths ${MODEL_NAME}_${SUFFIX}${H}x${W}.onnx 30_nms_${MODEL_NAME}_${BOXES}.onnx \
+ --srcop_destop output predictions \
+ --output_onnx_file_path ${MODEL_NAME}_post_${SUFFIX}${H}x${W}.onnx
+ onnxsim ${MODEL_NAME}_post_${SUFFIX}${H}x${W}.onnx ${MODEL_NAME}_post_${SUFFIX}${H}x${W}.onnx
+ onnxsim ${MODEL_NAME}_post_${SUFFIX}${H}x${W}.onnx ${MODEL_NAME}_post_${SUFFIX}${H}x${W}.onnx
+done
diff --git a/421_Gold-YOLO-Head/post_process_gen_tools/demo_goldyolo_onnx.py b/421_Gold-YOLO-Head/post_process_gen_tools/demo_goldyolo_onnx.py
new file mode 100644
index 0000000000..901db733c2
--- /dev/null
+++ b/421_Gold-YOLO-Head/post_process_gen_tools/demo_goldyolo_onnx.py
@@ -0,0 +1,340 @@
+#!/usr/bin/env python
+
+import copy
+import cv2
+import time
+import numpy as np
+import onnxruntime
+from argparse import ArgumentParser
+from typing import Tuple, Optional, List
+
+
+class GoldYOLOONNX(object):
+ def __init__(
+ self,
+ model_path: Optional[str] = 'gold_yolo_m_hand_post_0465_0.2501_1x3x480x640.onnx',
+ class_score_th: Optional[float] = 0.40,
+ providers: Optional[List] = [
+ (
+ 'TensorrtExecutionProvider', {
+ 'trt_engine_cache_enable': True,
+ 'trt_engine_cache_path': '.',
+ 'trt_fp16_enable': True,
+ }
+ ),
+ 'CUDAExecutionProvider',
+ 'CPUExecutionProvider',
+ ],
+ ):
+ """YOLOv7ONNX
+
+ Parameters
+ ----------
+ model_path: Optional[str]
+ ONNX file path for YOLOv7
+
+ class_score_th: Optional[float]
+ Score threshold. Default: 0.25
+
+ providers: Optional[List]
+ Name of onnx execution providers
+ Default:
+ [
+ (
+ 'TensorrtExecutionProvider', {
+ 'trt_engine_cache_enable': True,
+ 'trt_engine_cache_path': '.',
+ 'trt_fp16_enable': True,
+ }
+ ),
+ 'CUDAExecutionProvider',
+ 'CPUExecutionProvider',
+ ]
+ """
+ # Threshold
+ self.class_score_th = class_score_th
+
+ # Model loading
+ session_option = onnxruntime.SessionOptions()
+ session_option.log_severity_level = 3
+ self.onnx_session = onnxruntime.InferenceSession(
+ model_path,
+ sess_options=session_option,
+ providers=providers,
+ )
+ self.providers = self.onnx_session.get_providers()
+
+ self.input_shapes = [
+ input.shape for input in self.onnx_session.get_inputs()
+ ]
+ self.input_names = [
+ input.name for input in self.onnx_session.get_inputs()
+ ]
+ self.output_names = [
+ output.name for output in self.onnx_session.get_outputs()
+ ]
+
+
+ def __call__(
+ self,
+ image: np.ndarray,
+ ) -> Tuple[np.ndarray, np.ndarray]:
+ """YOLOv7ONNX
+
+ Parameters
+ ----------
+ image: np.ndarray
+ Entire image
+
+ Returns
+ -------
+ boxes: np.ndarray
+ Predicted boxes: [N, y1, x1, y2, x2]
+
+ scores: np.ndarray
+ Predicted box scores: [N, score]
+ """
+ temp_image = copy.deepcopy(image)
+
+ # PreProcess
+ resized_image = self.__preprocess(
+ temp_image,
+ )
+
+ # Inference
+ inferece_image = np.asarray([resized_image], dtype=np.float32)
+ boxes = self.onnx_session.run(
+ self.output_names,
+ {input_name: inferece_image for input_name in self.input_names},
+ )[0]
+
+ # PostProcess
+ result_boxes, result_scores = \
+ self.__postprocess(
+ image=temp_image,
+ boxes=boxes,
+ )
+
+ return result_boxes, result_scores
+
+
+ def __preprocess(
+ self,
+ image: np.ndarray,
+ swap: Optional[Tuple[int,int,int]] = (2, 0, 1),
+ ) -> np.ndarray:
+ """__preprocess
+
+ Parameters
+ ----------
+ image: np.ndarray
+ Entire image
+
+ swap: tuple
+ HWC to CHW: (2,0,1)
+ CHW to HWC: (1,2,0)
+ HWC to HWC: (0,1,2)
+ CHW to CHW: (0,1,2)
+
+ Returns
+ -------
+ resized_image: np.ndarray
+ Resized and normalized image.
+ """
+ # Normalization + BGR->RGB
+ resized_image = cv2.resize(
+ image,
+ (
+ int(self.input_shapes[0][3]),
+ int(self.input_shapes[0][2]),
+ )
+ )
+ resized_image = np.divide(resized_image, 255.0)
+ resized_image = resized_image[..., ::-1]
+ resized_image = resized_image.transpose(swap)
+ resized_image = np.ascontiguousarray(
+ resized_image,
+ dtype=np.float32,
+ )
+ return resized_image
+
+
+ def __postprocess(
+ self,
+ image: np.ndarray,
+ boxes: np.ndarray,
+ ) -> Tuple[np.ndarray, np.ndarray]:
+ """__postprocess
+
+ Parameters
+ ----------
+ image: np.ndarray
+ Entire image.
+
+ boxes: np.ndarray
+ float32[N, 7]
+
+ Returns
+ -------
+ result_boxes: np.ndarray
+ Predicted boxes: [N, y1, x1, y2, x2]
+
+ result_scores: np.ndarray
+ Predicted box confs: [N, score]
+ """
+ image_height = image.shape[0]
+ image_width = image.shape[1]
+
+ """
+ Detector is
+ N -> Number of boxes detected
+ batchno -> always 0: BatchNo.0
+
+ batchno_classid_y1x1y2x2_score: float32[N,7]
+ """
+ result_boxes = []
+ result_scores = []
+ if len(boxes) > 0:
+ scores = boxes[:, 6:7]
+ keep_idxs = scores[:, 0] > self.class_score_th
+ scores_keep = scores[keep_idxs, :]
+ boxes_keep = boxes[keep_idxs, :]
+
+ if len(boxes_keep) > 0:
+ for box, score in zip(boxes_keep, scores_keep):
+ x_min = max(int(box[2]), 0)
+ y_min = max(int(box[3]), 0)
+ x_max = min(int(box[4]), image_width)
+ y_max = min(int(box[5]), image_height)
+
+ result_boxes.append(
+ [x_min, y_min, x_max, y_max]
+ )
+ result_scores.append(
+ score
+ )
+
+ return np.asarray(result_boxes), np.asarray(result_scores)
+
+
+def main():
+ parser = ArgumentParser()
+ parser.add_argument(
+ '-m',
+ '--model',
+ type=str,
+ default='gold_yolo_m_hand_post_0465_0.2501_1x3x480x640.onnx',
+ )
+ parser.add_argument(
+ '-v',
+ '--video',
+ type=int,
+ default=0,
+ )
+ args = parser.parse_args()
+
+ model = GoldYOLOONNX(
+ model_path=args.model,
+ )
+
+ cap = cv2.VideoCapture(args.video)
+ cap_fps = cap.get(cv2.CAP_PROP_FPS)
+ w = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
+ h = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
+ fourcc = cv2.VideoWriter_fourcc('m', 'p', '4', 'v')
+ video_writer = cv2.VideoWriter(
+ filename='output.mp4',
+ fourcc=fourcc,
+ fps=cap_fps,
+ frameSize=(w, h),
+ )
+
+ while cap.isOpened():
+ res, image = cap.read()
+ if not res:
+ break
+
+ debug_image = copy.deepcopy(image)
+
+ start_time = time.time()
+ boxes, scores = model(debug_image)
+ elapsed_time = time.time() - start_time
+ fps = 1 / elapsed_time
+ cv2.putText(
+ debug_image,
+ f'{fps:.1f} FPS (inferece + post-process)',
+ (10, 30),
+ cv2.FONT_HERSHEY_SIMPLEX,
+ 0.7,
+ (255, 255, 255),
+ 2,
+ cv2.LINE_AA,
+ )
+ cv2.putText(
+ debug_image,
+ f'{fps:.1f} FPS (inferece + post-process)',
+ (10, 30),
+ cv2.FONT_HERSHEY_SIMPLEX,
+ 0.7,
+ (0, 0, 255),
+ 1,
+ cv2.LINE_AA,
+ )
+
+ for box, score in zip(boxes, scores):
+ cv2.rectangle(
+ debug_image,
+ (box[0], box[1]),
+ (box[2], box[3]),
+ (255,255,255),
+ 2,
+ )
+ cv2.rectangle(
+ debug_image,
+ (box[0], box[1]),
+ (box[2], box[3]),
+ (0,0,255),
+ 1,
+ )
+ cv2.putText(
+ debug_image,
+ f'{score[0]:.2f}',
+ (
+ box[0],
+ box[1]-10 if box[1]-10 > 0 else 10
+ ),
+ cv2.FONT_HERSHEY_SIMPLEX,
+ 0.7,
+ (255, 255, 255),
+ 2,
+ cv2.LINE_AA,
+ )
+ cv2.putText(
+ debug_image,
+ f'{score[0]:.2f}',
+ (
+ box[0],
+ box[1]-10 if box[1]-10 > 0 else 10
+ ),
+ cv2.FONT_HERSHEY_SIMPLEX,
+ 0.7,
+ (0, 0, 255),
+ 1,
+ cv2.LINE_AA,
+ )
+
+ key = cv2.waitKey(1)
+ if key == 27: # ESC
+ break
+
+ cv2.imshow("test", debug_image)
+ video_writer.write(debug_image)
+
+ if video_writer:
+ video_writer.release()
+
+ if cap:
+ cap.release()
+
+if __name__ == "__main__":
+ main()
diff --git a/421_Gold-YOLO-Head/post_process_gen_tools/make_batch_initialize.py b/421_Gold-YOLO-Head/post_process_gen_tools/make_batch_initialize.py
new file mode 100644
index 0000000000..50c6ddc6d8
--- /dev/null
+++ b/421_Gold-YOLO-Head/post_process_gen_tools/make_batch_initialize.py
@@ -0,0 +1,209 @@
+#! /usr/bin/env python
+
+import sys
+import onnx
+import onnx_graphsurgeon as gs
+from typing import Optional
+import struct
+from argparse import ArgumentParser
+from onnxsim import simplify
+
+class Color:
+ BLACK = '\033[30m'
+ RED = '\033[31m'
+ GREEN = '\033[32m'
+ YELLOW = '\033[33m'
+ BLUE = '\033[34m'
+ MAGENTA = '\033[35m'
+ CYAN = '\033[36m'
+ WHITE = '\033[37m'
+ COLOR_DEFAULT = '\033[39m'
+ BOLD = '\033[1m'
+ UNDERLINE = '\033[4m'
+ INVISIBLE = '\033[08m'
+ REVERCE = '\033[07m'
+ BG_BLACK = '\033[40m'
+ BG_RED = '\033[41m'
+ BG_GREEN = '\033[42m'
+ BG_YELLOW = '\033[43m'
+ BG_BLUE = '\033[44m'
+ BG_MAGENTA = '\033[45m'
+ BG_CYAN = '\033[46m'
+ BG_WHITE = '\033[47m'
+ BG_DEFAULT = '\033[49m'
+ RESET = '\033[0m'
+
+
+TARGET_INPUTS = [
+ 'predictions',
+]
+
+TARGET_VALUE_INFO = [
+ 'main01_boxes_cxcywh',
+ 'main01_onnx::Mul_15',
+ 'main01_onnx::Mul_10',
+
+ 'main01_onnx::Div_28',
+ 'main01_onnx::Add_30',
+ 'main01_onnx::Add_26',
+ 'main01_onnx::Unsqueeze_31',
+ 'main01_onnx::Concat_32',
+
+ 'main01_onnx::Div_20',
+ 'main01_onnx::Add_22',
+ 'main01_onnx::Add_18',
+ 'main01_onnx::Unsqueeze_23',
+ 'main01_onnx::Concat_24',
+
+ 'main01_onnx::Div_12',
+ 'main01_onnx::Sub_14',
+ 'main01_onnx::Sub_10',
+ 'main01_onnx::Unsqueeze_15',
+ 'main01_onnx::Concat_16',
+
+ 'main01_onnx::Div_4',
+ 'main01_onnx::Sub_6',
+ 'main01_onnx::Sub_2',
+ 'main01_onnx::Unsqueeze_7',
+ 'main01_onnx::Concat_8',
+
+ 'main01_y1x1y2x2',
+ 'main01_onnx::Transpose_16',
+ 'main01_scores',
+]
+
+def initialize(
+ input_onnx_file_path: Optional[str] = '',
+ onnx_graph: Optional[onnx.ModelProto] = None,
+ output_onnx_file_path: Optional[str] = '',
+ initialization_character_string: Optional[str] = 'batch',
+ non_verbose: Optional[bool] = False,
+) -> onnx.ModelProto:
+ """
+ Parameters
+ ----------
+ input_onnx_file_path: Optional[str]
+ Input onnx file path.\n\
+ Either input_onnx_file_path or onnx_graph must be specified.\n\
+ Default: ''
+ onnx_graph: Optional[onnx.ModelProto]
+ onnx.ModelProto.\n\
+ Either input_onnx_file_path or onnx_graph must be specified.\n\
+ onnx_graph If specified, ignore input_onnx_file_path and process onnx_graph.
+ output_onnx_file_path: Optional[str]
+ Output onnx file path. If not specified, no ONNX file is output.\n\
+ Default: ''
+ initialization_character_string: Optional[str]
+ String to initialize batch size. "-1" or "N" or "xxx", etc...\n
+ Default: 'batch'
+ non_verbose: Optional[bool]
+ Do not show all information logs. Only error logs are displayed.\n\
+ Default: False
+ Returns
+ -------
+ changed_graph: onnx.ModelProto
+ Changed onnx ModelProto.
+ """
+
+ # Unspecified check for input_onnx_file_path and onnx_graph
+ if not input_onnx_file_path and not onnx_graph:
+ print(
+ f'{Color.RED}ERROR:{Color.RESET} '+
+ f'One of input_onnx_file_path or onnx_graph must be specified.'
+ )
+ sys.exit(1)
+
+ if not initialization_character_string:
+ print(
+ f'{Color.RED}ERROR:{Color.RESET} '+
+ f'The initialization_character_string cannot be empty.'
+ )
+ sys.exit(1)
+
+ # Loading Graphs
+ # onnx_graph If specified, onnx_graph is processed first
+ if not onnx_graph:
+ onnx_graph = onnx.load(input_onnx_file_path)
+ try:
+ onnx_graph, _ = simplify(onnx_graph)
+ except:
+ pass
+ graph = gs.import_onnx(onnx_graph)
+ graph.cleanup().toposort()
+ target_model = gs.export_onnx(graph)
+ target_graph = target_model.graph
+
+ for node in target_graph.input:
+ if node.name in TARGET_INPUTS:
+ if len(node.type.tensor_type.shape.dim)>0:
+ node.type.tensor_type.shape.dim[0].dim_param = initialization_character_string
+
+ target_value_info = [value_info for value_info in target_graph.value_info if value_info.name in TARGET_VALUE_INFO]
+ for tensor in target_value_info:
+ if len(tensor.type.tensor_type.shape.dim)>0:
+ tensor.type.tensor_type.shape.dim[0].dim_param = initialization_character_string
+
+
+ # infer_shapes
+ target_model = onnx.shape_inference.infer_shapes(target_model)
+
+ # Save
+ if output_onnx_file_path:
+ onnx.save(target_model, output_onnx_file_path)
+
+ if not non_verbose:
+ print(f'{Color.GREEN}INFO:{Color.RESET} Finish!')
+
+ # Return
+ return target_model
+
+
+def main():
+ parser = ArgumentParser()
+ parser.add_argument(
+ '--input_onnx_file_path',
+ type=str,
+ required=True,
+ help='Input onnx file path.'
+ )
+ parser.add_argument(
+ '--output_onnx_file_path',
+ type=str,
+ required=True,
+ help='Output onnx file path.'
+ )
+ parser.add_argument(
+ '--initialization_character_string',
+ type=str,
+ default='batch',
+ help=\
+ 'String to initialize batch size. "-1" or "N" or "xxx", etc... \n'+
+ 'Default: \'batch\''
+ )
+ parser.add_argument(
+ '--non_verbose',
+ action='store_true',
+ help='Do not show all information logs. Only error logs are displayed.'
+ )
+ args = parser.parse_args()
+
+ input_onnx_file_path = args.input_onnx_file_path
+ output_onnx_file_path = args.output_onnx_file_path
+ initialization_character_string = args.initialization_character_string
+ non_verbose = args.non_verbose
+
+ # Load
+ onnx_graph = onnx.load(input_onnx_file_path)
+
+ # Batchsize change
+ changed_graph = initialize(
+ input_onnx_file_path=None,
+ onnx_graph=onnx_graph,
+ output_onnx_file_path=output_onnx_file_path,
+ initialization_character_string=initialization_character_string,
+ non_verbose=non_verbose,
+ )
+
+
+if __name__ == '__main__':
+ main()
\ No newline at end of file
diff --git a/421_Gold-YOLO-Head/post_process_gen_tools/make_box_gather_nd.py b/421_Gold-YOLO-Head/post_process_gen_tools/make_box_gather_nd.py
new file mode 100644
index 0000000000..7fd64f78c0
--- /dev/null
+++ b/421_Gold-YOLO-Head/post_process_gen_tools/make_box_gather_nd.py
@@ -0,0 +1,62 @@
+import os
+os.environ['CUDA_VISIBLE_DEVICES'] = '-1'
+import tensorflow as tf
+import numpy as np
+np.random.seed(0)
+from argparse import ArgumentParser
+
+
+if __name__ == "__main__":
+ parser = ArgumentParser()
+ parser.add_argument(
+ '-b',
+ '--batches',
+ type=int,
+ default=1,
+ help='batch size'
+ )
+ parser.add_argument(
+ '-x',
+ '--boxes',
+ type=int,
+ default=5040,
+ help='boxes'
+ )
+ args = parser.parse_args()
+ BATCHES = args.batches
+ BOXES = args.boxes
+
+ # Create a model
+ boxes = tf.keras.layers.Input(
+ shape=[
+ BOXES,
+ 4,
+ ],
+ batch_size=BATCHES,
+ dtype=tf.float32,
+ )
+
+ selected_indices = tf.keras.layers.Input(
+ shape=[
+ 2,
+ ],
+ dtype=tf.int64,
+ )
+
+ gathered_boxes = tf.gather_nd(
+ boxes,
+ selected_indices,
+ batch_dims=0,
+ )
+
+ model = tf.keras.models.Model(inputs=[boxes, selected_indices], outputs=[gathered_boxes])
+ model.summary()
+ output_path = 'saved_model_postprocess'
+ tf.saved_model.save(model, output_path)
+ converter = tf.lite.TFLiteConverter.from_keras_model(model)
+ converter.target_spec.supported_ops = [
+ tf.lite.OpsSet.TFLITE_BUILTINS,
+ tf.lite.OpsSet.SELECT_TF_OPS
+ ]
+ tflite_model = converter.convert()
+ open(f"{output_path}/nms_box_gather_nd.tflite", "wb").write(tflite_model)
\ No newline at end of file
diff --git a/421_Gold-YOLO-Head/post_process_gen_tools/make_boxes_scores.py b/421_Gold-YOLO-Head/post_process_gen_tools/make_boxes_scores.py
new file mode 100644
index 0000000000..054cfa5ab2
--- /dev/null
+++ b/421_Gold-YOLO-Head/post_process_gen_tools/make_boxes_scores.py
@@ -0,0 +1,97 @@
+#! /usr/bin/env python
+
+import torch
+import torch.nn as nn
+import onnx
+from onnxsim import simplify
+from argparse import ArgumentParser
+
+"""
+prediction [1, 5040, 85]
+
+80 classes
+
+85
+
+[0] -> center_x
+[1] -> center_y
+[2] -> width
+[3] -> height
+[4] -> box_score
+[5]-[84] -> class_score
+"""
+
+
+class Model(nn.Module):
+ def __init__(self):
+ super(Model, self).__init__()
+
+ def forward(self, x):
+ boxes = x[..., :4] # xywh [n, boxes, 4]
+ box_scores = x[..., 4:5] # [n, boxes, 1]
+ class_scores = x[..., 5:] # [n, boxes, 80]
+ scores = box_scores * class_scores
+ # scores = torch.sqrt(scores)
+ scores = scores.permute(0,2,1)
+ return boxes, scores
+
+
+if __name__ == "__main__":
+ parser = ArgumentParser()
+ parser.add_argument(
+ '-o',
+ '--opset',
+ type=int,
+ default=11,
+ help='onnx opset'
+ )
+ parser.add_argument(
+ '-b',
+ '--batches',
+ type=int,
+ default=1,
+ help='batch size'
+ )
+ parser.add_argument(
+ '-x',
+ '--boxes',
+ type=int,
+ default=5040,
+ help='boxes'
+ )
+ parser.add_argument(
+ '-c',
+ '--classes',
+ type=int,
+ default=80,
+ help='classes'
+ )
+ args = parser.parse_args()
+
+ model = Model()
+
+ MODEL = f'01_boxes_scores'
+ OPSET=args.opset
+ BATCHES = args.batches
+ BOXES = args.boxes
+ CLASSES = args.classes
+
+ onnx_file = f"{MODEL}_{BOXES}.onnx"
+ x = torch.randn(BATCHES, BOXES, CLASSES+5)
+
+ torch.onnx.export(
+ model,
+ args=(x),
+ f=onnx_file,
+ opset_version=OPSET,
+ input_names = ['predictions'],
+ output_names=['boxes_cxcywh','scores'],
+ )
+ model_onnx1 = onnx.load(onnx_file)
+ model_onnx1 = onnx.shape_inference.infer_shapes(model_onnx1)
+ onnx.save(model_onnx1, onnx_file)
+
+ model_onnx2 = onnx.load(onnx_file)
+ model_simp, check = simplify(model_onnx2)
+ onnx.save(model_simp, onnx_file)
+
diff --git a/421_Gold-YOLO-Head/post_process_gen_tools/make_cxcywh_x1y1x2y2.py b/421_Gold-YOLO-Head/post_process_gen_tools/make_cxcywh_x1y1x2y2.py
new file mode 100644
index 0000000000..3c564b2466
--- /dev/null
+++ b/421_Gold-YOLO-Head/post_process_gen_tools/make_cxcywh_x1y1x2y2.py
@@ -0,0 +1,72 @@
+#! /usr/bin/env python
+
+import torch
+import torch.nn as nn
+import numpy as np
+import onnx
+from onnxsim import simplify
+from argparse import ArgumentParser
+
+class Model(nn.Module):
+ def __init__(self):
+ super(Model, self).__init__()
+
+ def forward(self, cxcywh):
+ x1 = (cxcywh[..., 0:1] - cxcywh[..., 2:3] / 2) # top left x
+ y1 = (cxcywh[..., 1:2] - cxcywh[..., 3:4] / 2) # top left y
+ x2 = (cxcywh[..., 0:1] + cxcywh[..., 2:3] / 2) # bottom right x
+ y2 = (cxcywh[..., 1:2] + cxcywh[..., 3:4] / 2) # bottom right y
+ x1y1x2y2 = torch.cat([x1,y1,x2,y2], dim=2)
+ return x1y1x2y2
+
+
+if __name__ == "__main__":
+ parser = ArgumentParser()
+ parser.add_argument(
+ '-o',
+ '--opset',
+ type=int,
+ default=11,
+ help='onnx opset'
+ )
+ parser.add_argument(
+ '-b',
+ '--batches',
+ type=int,
+ default=1,
+ help='batch size'
+ )
+ parser.add_argument(
+ '-x',
+ '--boxes',
+ type=int,
+ default=5040,
+ help='boxes'
+ )
+ args = parser.parse_args()
+
+ model = Model()
+
+ MODEL = f'cxcywh_x1y1x2y2'
+ OPSET=args.opset
+ BATCHES = args.batches
+ BOXES = args.boxes
+
+ onnx_file = f"{MODEL}_{BOXES}.onnx"
+ cxcywh = torch.randn(BATCHES, BOXES, 4)
+
+ torch.onnx.export(
+ model,
+ args=(cxcywh),
+ f=onnx_file,
+ opset_version=OPSET,
+ input_names = ['cxcywh'],
+ output_names=['x1y1x2y2'],
+ )
+ model_onnx1 = onnx.load(onnx_file)
+ model_onnx1 = onnx.shape_inference.infer_shapes(model_onnx1)
+ onnx.save(model_onnx1, onnx_file)
+
+ model_onnx2 = onnx.load(onnx_file)
+ model_simp, check = simplify(model_onnx2)
+ onnx.save(model_simp, onnx_file)
diff --git a/421_Gold-YOLO-Head/post_process_gen_tools/make_cxcywh_y1x1y2x2.py b/421_Gold-YOLO-Head/post_process_gen_tools/make_cxcywh_y1x1y2x2.py
new file mode 100644
index 0000000000..705ac5b0e0
--- /dev/null
+++ b/421_Gold-YOLO-Head/post_process_gen_tools/make_cxcywh_y1x1y2x2.py
@@ -0,0 +1,78 @@
+#! /usr/bin/env python
+
+import torch
+import torch.nn as nn
+import numpy as np
+import onnx
+from onnxsim import simplify
+from argparse import ArgumentParser
+
+class Model(nn.Module):
+ def __init__(self):
+ super(Model, self).__init__()
+
+ def forward(self, cxcywh):
+ x1 = (cxcywh[..., 0:1] - cxcywh[..., 2:3] / 2) # top left x
+ y1 = (cxcywh[..., 1:2] - cxcywh[..., 3:4] / 2) # top left y
+ x2 = (cxcywh[..., 0:1] + cxcywh[..., 2:3] / 2) # bottom right x
+ y2 = (cxcywh[..., 1:2] + cxcywh[..., 3:4] / 2) # bottom right y
+ y1x1y2x2 = torch.cat([y1,x1,y2,x2], dim=2)
+ x1y1x2y2 = torch.cat([x1,y1,x2,y2], dim=2)
+ return y1x1y2x2, x1y1x2y2
+
+
+if __name__ == "__main__":
+ parser = ArgumentParser()
+ parser.add_argument(
+ '-o',
+ '--opset',
+ type=int,
+ default=11,
+ help='onnx opset'
+ )
+ parser.add_argument(
+ '-b',
+ '--batches',
+ type=int,
+ default=1,
+ help='batch size'
+ )
+ parser.add_argument(
+ '-x',
+ '--boxes',
+ type=int,
+ default=5040,
+ help='boxes'
+ )
+ args = parser.parse_args()
+
+ model = Model()
+
+ MODEL = f'02_cxcywh_y1x1y2x2'
+ OPSET=args.opset
+ BATCHES = args.batches
+ BOXES = args.boxes
+
+ onnx_file = f"{MODEL}_{BOXES}.onnx"
+ cxcywh = torch.randn(BATCHES, BOXES, 4)
+
+ torch.onnx.export(
+ model,
+ args=(cxcywh),
+ f=onnx_file,
+ opset_version=OPSET,
+ input_names = [
+ 'cxcywh',
+ ],
+ output_names=[
+ 'y1x1y2x2',
+ 'x1y1x2y2',
+ ],
+ )
+ model_onnx1 = onnx.load(onnx_file)
+ model_onnx1 = onnx.shape_inference.infer_shapes(model_onnx1)
+ onnx.save(model_onnx1, onnx_file)
+
+ model_onnx2 = onnx.load(onnx_file)
+ model_simp, check = simplify(model_onnx2)
+ onnx.save(model_simp, onnx_file)
diff --git a/421_Gold-YOLO-Head/post_process_gen_tools/make_final_batch_nums_final_class_nums_final_box_nums.py b/421_Gold-YOLO-Head/post_process_gen_tools/make_final_batch_nums_final_class_nums_final_box_nums.py
new file mode 100644
index 0000000000..dace921053
--- /dev/null
+++ b/421_Gold-YOLO-Head/post_process_gen_tools/make_final_batch_nums_final_class_nums_final_box_nums.py
@@ -0,0 +1,61 @@
+#! /usr/bin/env python
+
+import torch
+import torch.nn as nn
+import onnx
+import numpy as np
+from onnxsim import simplify
+from argparse import ArgumentParser
+
+class Model(nn.Module):
+ def __init__(self):
+ super(Model, self).__init__()
+
+ def forward(self, x):
+ batch_nums = x[:, 0:1].to(torch.float32) # batch number
+ class_nums = x[:, 1:2].to(torch.float32) # class ids
+ box_nums = x[:, [0,2]] # batch number + box number
+ return batch_nums, class_nums, box_nums
+
+
+if __name__ == "__main__":
+ parser = ArgumentParser()
+ parser.add_argument(
+ '-o',
+ '--opset',
+ type=int,
+ default=11,
+ help='onnx opset'
+ )
+ args = parser.parse_args()
+
+ model = Model()
+
+ MODEL = f'17_nms_final_batch_nums_final_class_nums_final_box_nums'
+ OPSET=args.opset
+
+ onnx_file = f"{MODEL}.onnx"
+ x = torch.ones([1, 3], dtype=torch.int64)
+
+ torch.onnx.export(
+ model,
+ args=(x),
+ f=onnx_file,
+ opset_version=OPSET,
+ input_names=['bc_input'],
+ output_names=['final_batch_nums','final_class_nums','final_box_nums'],
+ dynamic_axes={
+ 'bc_input': {0: 'N'},
+ 'final_batch_nums': {0: 'N'},
+ 'final_class_nums': {0: 'N'},
+ 'final_box_nums': {0: 'N'},
+ }
+ )
+ model_onnx1 = onnx.load(onnx_file)
+ model_onnx1 = onnx.shape_inference.infer_shapes(model_onnx1)
+ onnx.save(model_onnx1, onnx_file)
+
+ model_onnx2 = onnx.load(onnx_file)
+ model_simp, check = simplify(model_onnx2)
+ onnx.save(model_simp, onnx_file)
+
diff --git a/421_Gold-YOLO-Head/post_process_gen_tools/make_input_output_shape_update.py b/421_Gold-YOLO-Head/post_process_gen_tools/make_input_output_shape_update.py
new file mode 100644
index 0000000000..f00d8fc5dc
--- /dev/null
+++ b/421_Gold-YOLO-Head/post_process_gen_tools/make_input_output_shape_update.py
@@ -0,0 +1,76 @@
+import onnx
+from onnx.tools import update_model_dims
+from argparse import ArgumentParser
+
+
+if __name__ == "__main__":
+ parser = ArgumentParser()
+ parser.add_argument(
+ '-if',
+ '--input_onnx_file_path',
+ type=str,
+ required=True,
+ help='INPUT ONNX file path'
+ )
+ parser.add_argument(
+ '-of',
+ '--output_onnx_file_path',
+ type=str,
+ required=True,
+ help='OUTPUT ONNX file path'
+ )
+ parser.add_argument(
+ '-i',
+ '--input_names',
+ type=str,
+ action='append',
+ help='input names'
+ )
+ parser.add_argument(
+ '-is',
+ '--input_shapes',
+ type=str,
+ nargs='+',
+ action='append',
+ help='input shapes'
+ )
+ parser.add_argument(
+ '-o',
+ '--output_names',
+ type=str,
+ action='append',
+ help='output names'
+ )
+ parser.add_argument(
+ '-os',
+ '--output_shapes',
+ type=str,
+ nargs='+',
+ action='append',
+ help='output shapes'
+ )
+
+ args = parser.parse_args()
+ INPUT_MODEL_PATH = args.input_onnx_file_path
+ OUTPUT_MODEL_PATH = args.output_onnx_file_path
+ INPUT_NAMES = args.input_names
+ INPUT_SHAPES = args.input_shapes
+ OUTPUT_NAMES = args.output_names
+ OUTPUT_SHAPES = args.output_shapes
+
+ input_names = [name for name in INPUT_NAMES]
+ input_shapes = [shape for shape in INPUT_SHAPES]
+ output_names = [name for name in OUTPUT_NAMES]
+ output_shapes = [shape for shape in OUTPUT_SHAPES]
+
+ input_dicts = {name:shape for (name, shape) in zip(input_names, input_shapes)}
+ output_dicts = {name:shape for (name, shape) in zip(output_names, output_shapes)}
+
+ model = onnx.load(INPUT_MODEL_PATH)
+ updated_model = update_model_dims.update_inputs_outputs_dims(
+ model=model,
+ input_dims=input_dicts,
+ output_dims=output_dicts,
+ )
+
+ onnx.save(updated_model, OUTPUT_MODEL_PATH)
\ No newline at end of file
diff --git a/421_Gold-YOLO-Head/post_process_gen_tools/make_nms_outputs_merge.py b/421_Gold-YOLO-Head/post_process_gen_tools/make_nms_outputs_merge.py
new file mode 100644
index 0000000000..296da32b96
--- /dev/null
+++ b/421_Gold-YOLO-Head/post_process_gen_tools/make_nms_outputs_merge.py
@@ -0,0 +1,64 @@
+#! /usr/bin/env python
+
+import torch
+import torch.nn as nn
+import onnx
+from onnxsim import simplify
+from argparse import ArgumentParser
+
+
+class Model(nn.Module):
+ def __init__(self):
+ super(Model, self).__init__()
+
+ def forward(self, batch, classid, x1y1x2y2, score):
+ batchno_classid_x1y1x2y2_score_cat = torch.cat([batch, classid, x1y1x2y2, score], dim=1)
+ return batchno_classid_x1y1x2y2_score_cat
+
+
+if __name__ == "__main__":
+ parser = ArgumentParser()
+ parser.add_argument(
+ '-o',
+ '--opset',
+ type=int,
+ default=11,
+ help='onnx opset'
+ )
+ args = parser.parse_args()
+
+ model = Model()
+
+ MODEL = f'24_nms_batchno_classid_x1y1x2y2_score_cat'
+
+ onnx_file = f"{MODEL}.onnx"
+ OPSET=args.opset
+
+ x1 = torch.ones([1, 1], dtype=torch.float32)
+ x2 = torch.ones([1, 1], dtype=torch.float32)
+ x3 = torch.ones([1, 4], dtype=torch.float32)
+ x4 = torch.ones([1, 1], dtype=torch.float32)
+
+ torch.onnx.export(
+ model,
+ args=(x1,x2,x3,x4),
+ f=onnx_file,
+ opset_version=OPSET,
+ input_names=['cat_batch','cat_classid','cat_x1y1x2y2','cat_score'],
+ output_names=['batchno_classid_x1y1x2y2_score'],
+ dynamic_axes={
+ 'cat_batch': {0: 'N'},
+ 'cat_classid': {0: 'N'},
+ 'cat_x1y1x2y2': {0: 'N'},
+ 'cat_score': {0: 'N'},
+ 'batchno_classid_x1y1x2y2_score': {0: 'N'},
+ }
+ )
+ model_onnx1 = onnx.load(onnx_file)
+ model_onnx1 = onnx.shape_inference.infer_shapes(model_onnx1)
+ onnx.save(model_onnx1, onnx_file)
+
+ model_onnx2 = onnx.load(onnx_file)
+ model_simp, check = simplify(model_onnx2)
+ onnx.save(model_simp, onnx_file)
+
diff --git a/421_Gold-YOLO-Head/post_process_gen_tools/make_score_gather_nd.py b/421_Gold-YOLO-Head/post_process_gen_tools/make_score_gather_nd.py
new file mode 100644
index 0000000000..c9cbc0f8a5
--- /dev/null
+++ b/421_Gold-YOLO-Head/post_process_gen_tools/make_score_gather_nd.py
@@ -0,0 +1,72 @@
+import os
+os.environ['CUDA_VISIBLE_DEVICES'] = '-1'
+import tensorflow as tf
+import numpy as np
+np.random.seed(0)
+from argparse import ArgumentParser
+
+
+if __name__ == "__main__":
+ parser = ArgumentParser()
+ parser.add_argument(
+ '-b',
+ '--batches',
+ type=int,
+ default=1,
+ help='batch size'
+ )
+ parser.add_argument(
+ '-x',
+ '--boxes',
+ type=int,
+ default=5040,
+ help='boxes'
+ )
+ parser.add_argument(
+ '-c',
+ '--classes',
+ type=int,
+ default=80,
+ help='classes'
+ )
+ args = parser.parse_args()
+ BATCHES = args.batches
+ BOXES = args.boxes
+ CLASSES = args.classes
+
+
+ # Create a model
+ scores = tf.keras.layers.Input(
+ shape=[
+ CLASSES,
+ BOXES,
+ ],
+ batch_size=BATCHES,
+ dtype=tf.float32,
+ )
+
+ selected_indices = tf.keras.layers.Input(
+ shape=[
+ 3,
+ ],
+ dtype=tf.int64,
+ )
+
+ gathered_scores = tf.gather_nd(
+ scores,
+ selected_indices,
+ batch_dims=0,
+ )
+ expands_scores = gathered_scores[:,np.newaxis]
+
+ model = tf.keras.models.Model(inputs=[scores,selected_indices], outputs=[expands_scores])
+ model.summary()
+ output_path = 'saved_model_postprocess'
+ tf.saved_model.save(model, output_path)
+ converter = tf.lite.TFLiteConverter.from_keras_model(model)
+ converter.target_spec.supported_ops = [
+ tf.lite.OpsSet.TFLITE_BUILTINS,
+ tf.lite.OpsSet.SELECT_TF_OPS
+ ]
+ tflite_model = converter.convert()
+ open(f"{output_path}/nms_score_gather_nd.tflite", "wb").write(tflite_model)
\ No newline at end of file
diff --git a/421_Gold-YOLO-Head/url.txt b/421_Gold-YOLO-Head/url.txt
new file mode 100644
index 0000000000..f3d10f3536
--- /dev/null
+++ b/421_Gold-YOLO-Head/url.txt
@@ -0,0 +1,5 @@
+https://github.com/huawei-noah/Efficient-Computing/tree/master/Detection/Gold-YOLO
+
+https://github.com/PINTO0309/onnx2tf
+https://github.com/PINTO0309/simple-onnx-processing-tools
+
diff --git a/README.md b/README.md
index f448ce4d83..df411697a4 100644
--- a/README.md
+++ b/README.md
@@ -217,6 +217,7 @@ I have been working on quantization of various models as a hobby, but I have ski
|399|RetinaFace_MobileNetv2|[■■■](https://github.com/PINTO0309/PINTO_model_zoo/tree/main/399_RetinaFace_MobileNetv2)|||||||||||⚫||
|410|FaceMeshV2|[■■■](https://github.com/PINTO0309/PINTO_model_zoo/tree/main/410_FaceMeshV2)|⚫|⚫|⚫||⚫||⚫||||⚫|MediaPipe|
|414|STAR|[■■■](https://github.com/PINTO0309/PINTO_model_zoo/tree/main/414_STAR)|⚫|⚫|⚫||⚫||⚫||||⚫||
+|421|Gold-YOLO-Head|[■■■](https://github.com/PINTO0309/PINTO_model_zoo/tree/main/421_Gold-YOLO-Head)|||||||||||⚫|Head (not Face)|
### 5. 2D/3D Hand Detection
|No.|Model Name|Link|FP32|FP16|INT8|TPU|DQ|WQ|OV|CM|TFJS|TF-TRT|ONNX|Remarks|
|:-|:-|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-|