From b6b6291016545d48f084cc5b5e2b6c93a3e6b651 Mon Sep 17 00:00:00 2001 From: FrostNov4 <97688822+FrostNov4@users.noreply.github.com> Date: Sun, 15 Oct 2023 16:57:28 +1000 Subject: [PATCH 01/45] initialised --- LICENSE | 875 ++++++++++++++++++++++++++++++++---------- README.md | 196 +++++++++- evaluate.py | 40 ++ predict.py | 117 ++++++ requirements.txt | 5 + train.py | 237 ++++++++++++ unet/__init__.py | 1 + unet/unet_model.py | 48 +++ unet/unet_parts.py | 77 ++++ utils/__init__.py | 0 utils/data_loading.py | 117 ++++++ utils/dice_score.py | 28 ++ utils/utils.py | 13 + 13 files changed, 1542 insertions(+), 212 deletions(-) create mode 100644 evaluate.py create mode 100755 predict.py create mode 100644 requirements.txt create mode 100644 train.py create mode 100644 unet/__init__.py create mode 100644 unet/unet_model.py create mode 100644 unet/unet_parts.py create mode 100644 utils/__init__.py create mode 100644 utils/data_loading.py create mode 100644 utils/dice_score.py create mode 100644 utils/utils.py diff --git a/LICENSE b/LICENSE index 261eeb9e9..94a9ed024 100644 --- a/LICENSE +++ b/LICENSE @@ -1,201 +1,674 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/README.md b/README.md index 4a064f841..cb4d4c986 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,189 @@ -# Pattern Analysis -Pattern Analysis of various datasets by COMP3710 students at the University of Queensland. +# U-Net: Semantic segmentation with PyTorch + + + + -We create pattern recognition and image processing library for Tensorflow (TF), PyTorch or JAX. +![input and output for a random image in the test dataset](https://i.imgur.com/GD8FcB7.png) -This library is created and maintained by The University of Queensland [COMP3710](https://my.uq.edu.au/programs-courses/course.html?course_code=comp3710) students. -The library includes the following implemented in Tensorflow: -* fractals -* recognition problems +Customized implementation of the [U-Net](https://arxiv.org/abs/1505.04597) in PyTorch for Kaggle's [Carvana Image Masking Challenge](https://www.kaggle.com/c/carvana-image-masking-challenge) from high definition images. -In the recognition folder, you will find many recognition problems solved including: -* OASIS brain segmentation -* Classification -etc. +- [Quick start](#quick-start) + - [Without Docker](#without-docker) + - [With Docker](#with-docker) +- [Description](#description) +- [Usage](#usage) + - [Docker](#docker) + - [Training](#training) + - [Prediction](#prediction) +- [Weights & Biases](#weights--biases) +- [Pretrained model](#pretrained-model) +- [Data](#data) + +## Quick start + +### Without Docker + +1. [Install CUDA](https://developer.nvidia.com/cuda-downloads) + +2. [Install PyTorch 1.13 or later](https://pytorch.org/get-started/locally/) + +3. Install dependencies +```bash +pip install -r requirements.txt +``` + +4. Download the data and run training: +```bash +bash scripts/download_data.sh +python train.py --amp +``` + +### With Docker + +1. [Install Docker 19.03 or later:](https://docs.docker.com/get-docker/) +```bash +curl https://get.docker.com | sh && sudo systemctl --now enable docker +``` +2. [Install the NVIDIA container toolkit:](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/install-guide.html) +```bash +distribution=$(. /etc/os-release;echo $ID$VERSION_ID) \ + && curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add - \ + && curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list | sudo tee /etc/apt/sources.list.d/nvidia-docker.list +sudo apt-get update +sudo apt-get install -y nvidia-docker2 +sudo systemctl restart docker +``` +3. [Download and run the image:](https://hub.docker.com/repository/docker/milesial/unet) +```bash +sudo docker run --rm --shm-size=8g --ulimit memlock=-1 --gpus all -it milesial/unet +``` + +4. Download the data and run training: +```bash +bash scripts/download_data.sh +python train.py --amp +``` + +## Description +This model was trained from scratch with 5k images and scored a [Dice coefficient](https://en.wikipedia.org/wiki/S%C3%B8rensen%E2%80%93Dice_coefficient) of 0.988423 on over 100k test images. + +It can be easily used for multiclass segmentation, portrait segmentation, medical segmentation, ... + + +## Usage +**Note : Use Python 3.6 or newer** + +### Docker + +A docker image containing the code and the dependencies is available on [DockerHub](https://hub.docker.com/repository/docker/milesial/unet). +You can download and jump in the container with ([docker >=19.03](https://docs.docker.com/get-docker/)): + +```console +docker run -it --rm --shm-size=8g --ulimit memlock=-1 --gpus all milesial/unet +``` + + +### Training + +```console +> python train.py -h +usage: train.py [-h] [--epochs E] [--batch-size B] [--learning-rate LR] + [--load LOAD] [--scale SCALE] [--validation VAL] [--amp] + +Train the UNet on images and target masks + +optional arguments: + -h, --help show this help message and exit + --epochs E, -e E Number of epochs + --batch-size B, -b B Batch size + --learning-rate LR, -l LR + Learning rate + --load LOAD, -f LOAD Load model from a .pth file + --scale SCALE, -s SCALE + Downscaling factor of the images + --validation VAL, -v VAL + Percent of the data that is used as validation (0-100) + --amp Use mixed precision +``` + +By default, the `scale` is 0.5, so if you wish to obtain better results (but use more memory), set it to 1. + +Automatic mixed precision is also available with the `--amp` flag. [Mixed precision](https://arxiv.org/abs/1710.03740) allows the model to use less memory and to be faster on recent GPUs by using FP16 arithmetic. Enabling AMP is recommended. + + +### Prediction + +After training your model and saving it to `MODEL.pth`, you can easily test the output masks on your images via the CLI. + +To predict a single image and save it: + +`python predict.py -i image.jpg -o output.jpg` + +To predict a multiple images and show them without saving them: + +`python predict.py -i image1.jpg image2.jpg --viz --no-save` + +```console +> python predict.py -h +usage: predict.py [-h] [--model FILE] --input INPUT [INPUT ...] + [--output INPUT [INPUT ...]] [--viz] [--no-save] + [--mask-threshold MASK_THRESHOLD] [--scale SCALE] + +Predict masks from input images + +optional arguments: + -h, --help show this help message and exit + --model FILE, -m FILE + Specify the file in which the model is stored + --input INPUT [INPUT ...], -i INPUT [INPUT ...] + Filenames of input images + --output INPUT [INPUT ...], -o INPUT [INPUT ...] + Filenames of output images + --viz, -v Visualize the images as they are processed + --no-save, -n Do not save the output masks + --mask-threshold MASK_THRESHOLD, -t MASK_THRESHOLD + Minimum probability value to consider a mask pixel white + --scale SCALE, -s SCALE + Scale factor for the input images +``` +You can specify which model file to use with `--model MODEL.pth`. + +## Weights & Biases + +The training progress can be visualized in real-time using [Weights & Biases](https://wandb.ai/). Loss curves, validation curves, weights and gradient histograms, as well as predicted masks are logged to the platform. + +When launching a training, a link will be printed in the console. Click on it to go to your dashboard. If you have an existing W&B account, you can link it + by setting the `WANDB_API_KEY` environment variable. If not, it will create an anonymous run which is automatically deleted after 7 days. + + +## Pretrained model +A [pretrained model](https://github.com/milesial/Pytorch-UNet/releases/tag/v3.0) is available for the Carvana dataset. It can also be loaded from torch.hub: + +```python +net = torch.hub.load('milesial/Pytorch-UNet', 'unet_carvana', pretrained=True, scale=0.5) +``` +Available scales are 0.5 and 1.0. + +## Data +The Carvana data is available on the [Kaggle website](https://www.kaggle.com/c/carvana-image-masking-challenge/data). + +You can also download it using the helper script: + +``` +bash scripts/download_data.sh +``` + +The input images and target masks should be in the `data/imgs` and `data/masks` folders respectively (note that the `imgs` and `masks` folder should not contain any sub-folder or any other files, due to the greedy data-loader). For Carvana, images are RGB and masks are black and white. + +You can use your own dataset as long as you make sure it is loaded properly in `utils/data_loading.py`. + + +--- + +Original paper by Olaf Ronneberger, Philipp Fischer, Thomas Brox: + +[U-Net: Convolutional Networks for Biomedical Image Segmentation](https://arxiv.org/abs/1505.04597) + +![network architecture](https://i.imgur.com/jeDVpqF.png) diff --git a/evaluate.py b/evaluate.py new file mode 100644 index 000000000..9a4e3ba2b --- /dev/null +++ b/evaluate.py @@ -0,0 +1,40 @@ +import torch +import torch.nn.functional as F +from tqdm import tqdm + +from utils.dice_score import multiclass_dice_coeff, dice_coeff + + +@torch.inference_mode() +def evaluate(net, dataloader, device, amp): + net.eval() + num_val_batches = len(dataloader) + dice_score = 0 + + # iterate over the validation set + with torch.autocast(device.type if device.type != 'mps' else 'cpu', enabled=amp): + for batch in tqdm(dataloader, total=num_val_batches, desc='Validation round', unit='batch', leave=False): + image, mask_true = batch['image'], batch['mask'] + + # move images and labels to correct device and type + image = image.to(device=device, dtype=torch.float32, memory_format=torch.channels_last) + mask_true = mask_true.to(device=device, dtype=torch.long) + + # predict the mask + mask_pred = net(image) + + if net.n_classes == 1: + assert mask_true.min() >= 0 and mask_true.max() <= 1, 'True mask indices should be in [0, 1]' + mask_pred = (F.sigmoid(mask_pred) > 0.5).float() + # compute the Dice score + dice_score += dice_coeff(mask_pred, mask_true, reduce_batch_first=False) + else: + assert mask_true.min() >= 0 and mask_true.max() < net.n_classes, 'True mask indices should be in [0, n_classes[' + # convert to one-hot format + mask_true = F.one_hot(mask_true, net.n_classes).permute(0, 3, 1, 2).float() + mask_pred = F.one_hot(mask_pred.argmax(dim=1), net.n_classes).permute(0, 3, 1, 2).float() + # compute the Dice score, ignoring background + dice_score += multiclass_dice_coeff(mask_pred[:, 1:], mask_true[:, 1:], reduce_batch_first=False) + + net.train() + return dice_score / max(num_val_batches, 1) diff --git a/predict.py b/predict.py new file mode 100755 index 000000000..b74c4608d --- /dev/null +++ b/predict.py @@ -0,0 +1,117 @@ +import argparse +import logging +import os + +import numpy as np +import torch +import torch.nn.functional as F +from PIL import Image +from torchvision import transforms + +from utils.data_loading import BasicDataset +from unet import UNet +from utils.utils import plot_img_and_mask + +def predict_img(net, + full_img, + device, + scale_factor=1, + out_threshold=0.5): + net.eval() + img = torch.from_numpy(BasicDataset.preprocess(None, full_img, scale_factor, is_mask=False)) + img = img.unsqueeze(0) + img = img.to(device=device, dtype=torch.float32) + + with torch.no_grad(): + output = net(img).cpu() + output = F.interpolate(output, (full_img.size[1], full_img.size[0]), mode='bilinear') + if net.n_classes > 1: + mask = output.argmax(dim=1) + else: + mask = torch.sigmoid(output) > out_threshold + + return mask[0].long().squeeze().numpy() + + +def get_args(): + parser = argparse.ArgumentParser(description='Predict masks from input images') + parser.add_argument('--model', '-m', default='MODEL.pth', metavar='FILE', + help='Specify the file in which the model is stored') + parser.add_argument('--input', '-i', metavar='INPUT', nargs='+', help='Filenames of input images', required=True) + parser.add_argument('--output', '-o', metavar='OUTPUT', nargs='+', help='Filenames of output images') + parser.add_argument('--viz', '-v', action='store_true', + help='Visualize the images as they are processed') + parser.add_argument('--no-save', '-n', action='store_true', help='Do not save the output masks') + parser.add_argument('--mask-threshold', '-t', type=float, default=0.5, + help='Minimum probability value to consider a mask pixel white') + parser.add_argument('--scale', '-s', type=float, default=0.5, + help='Scale factor for the input images') + parser.add_argument('--bilinear', action='store_true', default=False, help='Use bilinear upsampling') + parser.add_argument('--classes', '-c', type=int, default=2, help='Number of classes') + + return parser.parse_args() + + +def get_output_filenames(args): + def _generate_name(fn): + return f'{os.path.splitext(fn)[0]}_OUT.png' + + return args.output or list(map(_generate_name, args.input)) + + +def mask_to_image(mask: np.ndarray, mask_values): + if isinstance(mask_values[0], list): + out = np.zeros((mask.shape[-2], mask.shape[-1], len(mask_values[0])), dtype=np.uint8) + elif mask_values == [0, 1]: + out = np.zeros((mask.shape[-2], mask.shape[-1]), dtype=bool) + else: + out = np.zeros((mask.shape[-2], mask.shape[-1]), dtype=np.uint8) + + if mask.ndim == 3: + mask = np.argmax(mask, axis=0) + + for i, v in enumerate(mask_values): + out[mask == i] = v + + return Image.fromarray(out) + + +if __name__ == '__main__': + args = get_args() + logging.basicConfig(level=logging.INFO, format='%(levelname)s: %(message)s') + + in_files = args.input + out_files = get_output_filenames(args) + + net = UNet(n_channels=3, n_classes=args.classes, bilinear=args.bilinear) + + device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') + logging.info(f'Loading model {args.model}') + logging.info(f'Using device {device}') + + net.to(device=device) + state_dict = torch.load(args.model, map_location=device) + mask_values = state_dict.pop('mask_values', [0, 1]) + net.load_state_dict(state_dict) + + logging.info('Model loaded!') + + for i, filename in enumerate(in_files): + logging.info(f'Predicting image {filename} ...') + img = Image.open(filename) + + mask = predict_img(net=net, + full_img=img, + scale_factor=args.scale, + out_threshold=args.mask_threshold, + device=device) + + if not args.no_save: + out_filename = out_files[i] + result = mask_to_image(mask, mask_values) + result.save(out_filename) + logging.info(f'Mask saved to {out_filename}') + + if args.viz: + logging.info(f'Visualizing results for image {filename}, close to continue...') + plot_img_and_mask(img, mask) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 000000000..256fb596a --- /dev/null +++ b/requirements.txt @@ -0,0 +1,5 @@ +matplotlib==3.6.2 +numpy==1.23.5 +Pillow==9.3.0 +tqdm==4.64.1 +wandb==0.13.5 diff --git a/train.py b/train.py new file mode 100644 index 000000000..c7d27e2a3 --- /dev/null +++ b/train.py @@ -0,0 +1,237 @@ +import argparse +import logging +import os +import random +import sys +import torch +import torch.nn as nn +import torch.nn.functional as F +import torchvision.transforms as transforms +import torchvision.transforms.functional as TF +from pathlib import Path +from torch import optim +from torch.utils.data import DataLoader, random_split +from tqdm import tqdm + +import wandb +from evaluate import evaluate +from unet import UNet +from utils.data_loading import BasicDataset, CarvanaDataset +from utils.dice_score import dice_loss + +dir_img = Path('./data/imgs/') +dir_mask = Path('./data/masks/') +dir_checkpoint = Path('./checkpoints/') + + +def train_model( + model, + device, + epochs: int = 5, + batch_size: int = 1, + learning_rate: float = 1e-5, + val_percent: float = 0.1, + save_checkpoint: bool = True, + img_scale: float = 0.5, + amp: bool = False, + weight_decay: float = 1e-8, + momentum: float = 0.999, + gradient_clipping: float = 1.0, +): + # 1. Create dataset + try: + dataset = CarvanaDataset(dir_img, dir_mask, img_scale) + except (AssertionError, RuntimeError, IndexError): + dataset = BasicDataset(dir_img, dir_mask, img_scale) + + # 2. Split into train / validation partitions + n_val = int(len(dataset) * val_percent) + n_train = len(dataset) - n_val + train_set, val_set = random_split(dataset, [n_train, n_val], generator=torch.Generator().manual_seed(0)) + + # 3. Create data loaders + loader_args = dict(batch_size=batch_size, num_workers=os.cpu_count(), pin_memory=True) + train_loader = DataLoader(train_set, shuffle=True, **loader_args) + val_loader = DataLoader(val_set, shuffle=False, drop_last=True, **loader_args) + + # (Initialize logging) + experiment = wandb.init(project='U-Net', resume='allow', anonymous='must') + experiment.config.update( + dict(epochs=epochs, batch_size=batch_size, learning_rate=learning_rate, + val_percent=val_percent, save_checkpoint=save_checkpoint, img_scale=img_scale, amp=amp) + ) + + logging.info(f'''Starting training: + Epochs: {epochs} + Batch size: {batch_size} + Learning rate: {learning_rate} + Training size: {n_train} + Validation size: {n_val} + Checkpoints: {save_checkpoint} + Device: {device.type} + Images scaling: {img_scale} + Mixed Precision: {amp} + ''') + + # 4. Set up the optimizer, the loss, the learning rate scheduler and the loss scaling for AMP + optimizer = optim.RMSprop(model.parameters(), + lr=learning_rate, weight_decay=weight_decay, momentum=momentum, foreach=True) + scheduler = optim.lr_scheduler.ReduceLROnPlateau(optimizer, 'max', patience=5) # goal: maximize Dice score + grad_scaler = torch.cuda.amp.GradScaler(enabled=amp) + criterion = nn.CrossEntropyLoss() if model.n_classes > 1 else nn.BCEWithLogitsLoss() + global_step = 0 + + # 5. Begin training + for epoch in range(1, epochs + 1): + model.train() + epoch_loss = 0 + with tqdm(total=n_train, desc=f'Epoch {epoch}/{epochs}', unit='img') as pbar: + for batch in train_loader: + images, true_masks = batch['image'], batch['mask'] + + assert images.shape[1] == model.n_channels, \ + f'Network has been defined with {model.n_channels} input channels, ' \ + f'but loaded images have {images.shape[1]} channels. Please check that ' \ + 'the images are loaded correctly.' + + images = images.to(device=device, dtype=torch.float32, memory_format=torch.channels_last) + true_masks = true_masks.to(device=device, dtype=torch.long) + + with torch.autocast(device.type if device.type != 'mps' else 'cpu', enabled=amp): + masks_pred = model(images) + if model.n_classes == 1: + loss = criterion(masks_pred.squeeze(1), true_masks.float()) + loss += dice_loss(F.sigmoid(masks_pred.squeeze(1)), true_masks.float(), multiclass=False) + else: + loss = criterion(masks_pred, true_masks) + loss += dice_loss( + F.softmax(masks_pred, dim=1).float(), + F.one_hot(true_masks, model.n_classes).permute(0, 3, 1, 2).float(), + multiclass=True + ) + + optimizer.zero_grad(set_to_none=True) + grad_scaler.scale(loss).backward() + torch.nn.utils.clip_grad_norm_(model.parameters(), gradient_clipping) + grad_scaler.step(optimizer) + grad_scaler.update() + + pbar.update(images.shape[0]) + global_step += 1 + epoch_loss += loss.item() + experiment.log({ + 'train loss': loss.item(), + 'step': global_step, + 'epoch': epoch + }) + pbar.set_postfix(**{'loss (batch)': loss.item()}) + + # Evaluation round + division_step = (n_train // (5 * batch_size)) + if division_step > 0: + if global_step % division_step == 0: + histograms = {} + for tag, value in model.named_parameters(): + tag = tag.replace('/', '.') + if not (torch.isinf(value) | torch.isnan(value)).any(): + histograms['Weights/' + tag] = wandb.Histogram(value.data.cpu()) + if not (torch.isinf(value.grad) | torch.isnan(value.grad)).any(): + histograms['Gradients/' + tag] = wandb.Histogram(value.grad.data.cpu()) + + val_score = evaluate(model, val_loader, device, amp) + scheduler.step(val_score) + + logging.info('Validation Dice score: {}'.format(val_score)) + try: + experiment.log({ + 'learning rate': optimizer.param_groups[0]['lr'], + 'validation Dice': val_score, + 'images': wandb.Image(images[0].cpu()), + 'masks': { + 'true': wandb.Image(true_masks[0].float().cpu()), + 'pred': wandb.Image(masks_pred.argmax(dim=1)[0].float().cpu()), + }, + 'step': global_step, + 'epoch': epoch, + **histograms + }) + except: + pass + + if save_checkpoint: + Path(dir_checkpoint).mkdir(parents=True, exist_ok=True) + state_dict = model.state_dict() + state_dict['mask_values'] = dataset.mask_values + torch.save(state_dict, str(dir_checkpoint / 'checkpoint_epoch{}.pth'.format(epoch))) + logging.info(f'Checkpoint {epoch} saved!') + + +def get_args(): + parser = argparse.ArgumentParser(description='Train the UNet on images and target masks') + parser.add_argument('--epochs', '-e', metavar='E', type=int, default=5, help='Number of epochs') + parser.add_argument('--batch-size', '-b', dest='batch_size', metavar='B', type=int, default=1, help='Batch size') + parser.add_argument('--learning-rate', '-l', metavar='LR', type=float, default=1e-5, + help='Learning rate', dest='lr') + parser.add_argument('--load', '-f', type=str, default=False, help='Load model from a .pth file') + parser.add_argument('--scale', '-s', type=float, default=0.5, help='Downscaling factor of the images') + parser.add_argument('--validation', '-v', dest='val', type=float, default=10.0, + help='Percent of the data that is used as validation (0-100)') + parser.add_argument('--amp', action='store_true', default=False, help='Use mixed precision') + parser.add_argument('--bilinear', action='store_true', default=False, help='Use bilinear upsampling') + parser.add_argument('--classes', '-c', type=int, default=2, help='Number of classes') + + return parser.parse_args() + + +if __name__ == '__main__': + args = get_args() + + logging.basicConfig(level=logging.INFO, format='%(levelname)s: %(message)s') + device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') + logging.info(f'Using device {device}') + + # Change here to adapt to your data + # n_channels=3 for RGB images + # n_classes is the number of probabilities you want to get per pixel + model = UNet(n_channels=3, n_classes=args.classes, bilinear=args.bilinear) + model = model.to(memory_format=torch.channels_last) + + logging.info(f'Network:\n' + f'\t{model.n_channels} input channels\n' + f'\t{model.n_classes} output channels (classes)\n' + f'\t{"Bilinear" if model.bilinear else "Transposed conv"} upscaling') + + if args.load: + state_dict = torch.load(args.load, map_location=device) + del state_dict['mask_values'] + model.load_state_dict(state_dict) + logging.info(f'Model loaded from {args.load}') + + model.to(device=device) + try: + train_model( + model=model, + epochs=args.epochs, + batch_size=args.batch_size, + learning_rate=args.lr, + device=device, + img_scale=args.scale, + val_percent=args.val / 100, + amp=args.amp + ) + except torch.cuda.OutOfMemoryError: + logging.error('Detected OutOfMemoryError! ' + 'Enabling checkpointing to reduce memory usage, but this slows down training. ' + 'Consider enabling AMP (--amp) for fast and memory efficient training') + torch.cuda.empty_cache() + model.use_checkpointing() + train_model( + model=model, + epochs=args.epochs, + batch_size=args.batch_size, + learning_rate=args.lr, + device=device, + img_scale=args.scale, + val_percent=args.val / 100, + amp=args.amp + ) diff --git a/unet/__init__.py b/unet/__init__.py new file mode 100644 index 000000000..2e9b63b67 --- /dev/null +++ b/unet/__init__.py @@ -0,0 +1 @@ +from .unet_model import UNet diff --git a/unet/unet_model.py b/unet/unet_model.py new file mode 100644 index 000000000..caf79f47f --- /dev/null +++ b/unet/unet_model.py @@ -0,0 +1,48 @@ +""" Full assembly of the parts to form the complete network """ + +from .unet_parts import * + + +class UNet(nn.Module): + def __init__(self, n_channels, n_classes, bilinear=False): + super(UNet, self).__init__() + self.n_channels = n_channels + self.n_classes = n_classes + self.bilinear = bilinear + + self.inc = (DoubleConv(n_channels, 64)) + self.down1 = (Down(64, 128)) + self.down2 = (Down(128, 256)) + self.down3 = (Down(256, 512)) + factor = 2 if bilinear else 1 + self.down4 = (Down(512, 1024 // factor)) + self.up1 = (Up(1024, 512 // factor, bilinear)) + self.up2 = (Up(512, 256 // factor, bilinear)) + self.up3 = (Up(256, 128 // factor, bilinear)) + self.up4 = (Up(128, 64, bilinear)) + self.outc = (OutConv(64, n_classes)) + + def forward(self, x): + x1 = self.inc(x) + x2 = self.down1(x1) + x3 = self.down2(x2) + x4 = self.down3(x3) + x5 = self.down4(x4) + x = self.up1(x5, x4) + x = self.up2(x, x3) + x = self.up3(x, x2) + x = self.up4(x, x1) + logits = self.outc(x) + return logits + + def use_checkpointing(self): + self.inc = torch.utils.checkpoint(self.inc) + self.down1 = torch.utils.checkpoint(self.down1) + self.down2 = torch.utils.checkpoint(self.down2) + self.down3 = torch.utils.checkpoint(self.down3) + self.down4 = torch.utils.checkpoint(self.down4) + self.up1 = torch.utils.checkpoint(self.up1) + self.up2 = torch.utils.checkpoint(self.up2) + self.up3 = torch.utils.checkpoint(self.up3) + self.up4 = torch.utils.checkpoint(self.up4) + self.outc = torch.utils.checkpoint(self.outc) \ No newline at end of file diff --git a/unet/unet_parts.py b/unet/unet_parts.py new file mode 100644 index 000000000..986ba251f --- /dev/null +++ b/unet/unet_parts.py @@ -0,0 +1,77 @@ +""" Parts of the U-Net model """ + +import torch +import torch.nn as nn +import torch.nn.functional as F + + +class DoubleConv(nn.Module): + """(convolution => [BN] => ReLU) * 2""" + + def __init__(self, in_channels, out_channels, mid_channels=None): + super().__init__() + if not mid_channels: + mid_channels = out_channels + self.double_conv = nn.Sequential( + nn.Conv2d(in_channels, mid_channels, kernel_size=3, padding=1, bias=False), + nn.BatchNorm2d(mid_channels), + nn.ReLU(inplace=True), + nn.Conv2d(mid_channels, out_channels, kernel_size=3, padding=1, bias=False), + nn.BatchNorm2d(out_channels), + nn.ReLU(inplace=True) + ) + + def forward(self, x): + return self.double_conv(x) + + +class Down(nn.Module): + """Downscaling with maxpool then double conv""" + + def __init__(self, in_channels, out_channels): + super().__init__() + self.maxpool_conv = nn.Sequential( + nn.MaxPool2d(2), + DoubleConv(in_channels, out_channels) + ) + + def forward(self, x): + return self.maxpool_conv(x) + + +class Up(nn.Module): + """Upscaling then double conv""" + + def __init__(self, in_channels, out_channels, bilinear=True): + super().__init__() + + # if bilinear, use the normal convolutions to reduce the number of channels + if bilinear: + self.up = nn.Upsample(scale_factor=2, mode='bilinear', align_corners=True) + self.conv = DoubleConv(in_channels, out_channels, in_channels // 2) + else: + self.up = nn.ConvTranspose2d(in_channels, in_channels // 2, kernel_size=2, stride=2) + self.conv = DoubleConv(in_channels, out_channels) + + def forward(self, x1, x2): + x1 = self.up(x1) + # input is CHW + diffY = x2.size()[2] - x1.size()[2] + diffX = x2.size()[3] - x1.size()[3] + + x1 = F.pad(x1, [diffX // 2, diffX - diffX // 2, + diffY // 2, diffY - diffY // 2]) + # if you have padding issues, see + # https://github.com/HaiyongJiang/U-Net-Pytorch-Unstructured-Buggy/commit/0e854509c2cea854e247a9c615f175f76fbb2e3a + # https://github.com/xiaopeng-liao/Pytorch-UNet/commit/8ebac70e633bac59fc22bb5195e513d5832fb3bd + x = torch.cat([x2, x1], dim=1) + return self.conv(x) + + +class OutConv(nn.Module): + def __init__(self, in_channels, out_channels): + super(OutConv, self).__init__() + self.conv = nn.Conv2d(in_channels, out_channels, kernel_size=1) + + def forward(self, x): + return self.conv(x) diff --git a/utils/__init__.py b/utils/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/utils/data_loading.py b/utils/data_loading.py new file mode 100644 index 000000000..11296e78b --- /dev/null +++ b/utils/data_loading.py @@ -0,0 +1,117 @@ +import logging +import numpy as np +import torch +from PIL import Image +from functools import lru_cache +from functools import partial +from itertools import repeat +from multiprocessing import Pool +from os import listdir +from os.path import splitext, isfile, join +from pathlib import Path +from torch.utils.data import Dataset +from tqdm import tqdm + + +def load_image(filename): + ext = splitext(filename)[1] + if ext == '.npy': + return Image.fromarray(np.load(filename)) + elif ext in ['.pt', '.pth']: + return Image.fromarray(torch.load(filename).numpy()) + else: + return Image.open(filename) + + +def unique_mask_values(idx, mask_dir, mask_suffix): + mask_file = list(mask_dir.glob(idx + mask_suffix + '.*'))[0] + mask = np.asarray(load_image(mask_file)) + if mask.ndim == 2: + return np.unique(mask) + elif mask.ndim == 3: + mask = mask.reshape(-1, mask.shape[-1]) + return np.unique(mask, axis=0) + else: + raise ValueError(f'Loaded masks should have 2 or 3 dimensions, found {mask.ndim}') + + +class BasicDataset(Dataset): + def __init__(self, images_dir: str, mask_dir: str, scale: float = 1.0, mask_suffix: str = ''): + self.images_dir = Path(images_dir) + self.mask_dir = Path(mask_dir) + assert 0 < scale <= 1, 'Scale must be between 0 and 1' + self.scale = scale + self.mask_suffix = mask_suffix + + self.ids = [splitext(file)[0] for file in listdir(images_dir) if isfile(join(images_dir, file)) and not file.startswith('.')] + if not self.ids: + raise RuntimeError(f'No input file found in {images_dir}, make sure you put your images there') + + logging.info(f'Creating dataset with {len(self.ids)} examples') + logging.info('Scanning mask files to determine unique values') + with Pool() as p: + unique = list(tqdm( + p.imap(partial(unique_mask_values, mask_dir=self.mask_dir, mask_suffix=self.mask_suffix), self.ids), + total=len(self.ids) + )) + + self.mask_values = list(sorted(np.unique(np.concatenate(unique), axis=0).tolist())) + logging.info(f'Unique mask values: {self.mask_values}') + + def __len__(self): + return len(self.ids) + + @staticmethod + def preprocess(mask_values, pil_img, scale, is_mask): + w, h = pil_img.size + newW, newH = int(scale * w), int(scale * h) + assert newW > 0 and newH > 0, 'Scale is too small, resized images would have no pixel' + pil_img = pil_img.resize((newW, newH), resample=Image.NEAREST if is_mask else Image.BICUBIC) + img = np.asarray(pil_img) + + if is_mask: + mask = np.zeros((newH, newW), dtype=np.int64) + for i, v in enumerate(mask_values): + if img.ndim == 2: + mask[img == v] = i + else: + mask[(img == v).all(-1)] = i + + return mask + + else: + if img.ndim == 2: + img = img[np.newaxis, ...] + else: + img = img.transpose((2, 0, 1)) + + if (img > 1).any(): + img = img / 255.0 + + return img + + def __getitem__(self, idx): + name = self.ids[idx] + mask_file = list(self.mask_dir.glob(name + self.mask_suffix + '.*')) + img_file = list(self.images_dir.glob(name + '.*')) + + assert len(img_file) == 1, f'Either no image or multiple images found for the ID {name}: {img_file}' + assert len(mask_file) == 1, f'Either no mask or multiple masks found for the ID {name}: {mask_file}' + mask = load_image(mask_file[0]) + img = load_image(img_file[0]) + + assert img.size == mask.size, \ + f'Image and mask {name} should be the same size, but are {img.size} and {mask.size}' + + img = self.preprocess(self.mask_values, img, self.scale, is_mask=False) + mask = self.preprocess(self.mask_values, mask, self.scale, is_mask=True) + + return { + 'image': torch.as_tensor(img.copy()).float().contiguous(), + 'mask': torch.as_tensor(mask.copy()).long().contiguous() + } + + +class CarvanaDataset(BasicDataset): + def __init__(self, images_dir, mask_dir, scale=1): + super().__init__(images_dir, mask_dir, scale, mask_suffix='_mask') diff --git a/utils/dice_score.py b/utils/dice_score.py new file mode 100644 index 000000000..c89eebee7 --- /dev/null +++ b/utils/dice_score.py @@ -0,0 +1,28 @@ +import torch +from torch import Tensor + + +def dice_coeff(input: Tensor, target: Tensor, reduce_batch_first: bool = False, epsilon: float = 1e-6): + # Average of Dice coefficient for all batches, or for a single mask + assert input.size() == target.size() + assert input.dim() == 3 or not reduce_batch_first + + sum_dim = (-1, -2) if input.dim() == 2 or not reduce_batch_first else (-1, -2, -3) + + inter = 2 * (input * target).sum(dim=sum_dim) + sets_sum = input.sum(dim=sum_dim) + target.sum(dim=sum_dim) + sets_sum = torch.where(sets_sum == 0, inter, sets_sum) + + dice = (inter + epsilon) / (sets_sum + epsilon) + return dice.mean() + + +def multiclass_dice_coeff(input: Tensor, target: Tensor, reduce_batch_first: bool = False, epsilon: float = 1e-6): + # Average of Dice coefficient for all classes + return dice_coeff(input.flatten(0, 1), target.flatten(0, 1), reduce_batch_first, epsilon) + + +def dice_loss(input: Tensor, target: Tensor, multiclass: bool = False): + # Dice loss (objective to minimize) between 0 and 1 + fn = multiclass_dice_coeff if multiclass else dice_coeff + return 1 - fn(input, target, reduce_batch_first=True) diff --git a/utils/utils.py b/utils/utils.py new file mode 100644 index 000000000..5e6e04128 --- /dev/null +++ b/utils/utils.py @@ -0,0 +1,13 @@ +import matplotlib.pyplot as plt + + +def plot_img_and_mask(img, mask): + classes = mask.max() + 1 + fig, ax = plt.subplots(1, classes + 1) + ax[0].set_title('Input image') + ax[0].imshow(img) + for i in range(classes): + ax[i + 1].set_title(f'Mask (class {i + 1})') + ax[i + 1].imshow(mask == i) + plt.xticks([]), plt.yticks([]) + plt.show() From 3195294949dfa1967dff6454957d193282ee6c76 Mon Sep 17 00:00:00 2001 From: FrostNov4 <97688822+FrostNov4@users.noreply.github.com> Date: Sun, 15 Oct 2023 17:04:11 +1000 Subject: [PATCH 02/45] update dataloader --- utils/data_loading.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/utils/data_loading.py b/utils/data_loading.py index 11296e78b..186ac00cd 100644 --- a/utils/data_loading.py +++ b/utils/data_loading.py @@ -115,3 +115,8 @@ def __getitem__(self, idx): class CarvanaDataset(BasicDataset): def __init__(self, images_dir, mask_dir, scale=1): super().__init__(images_dir, mask_dir, scale, mask_suffix='_mask') + + +class ISICDataset(BasicDataset): + def __init__(self, images_dir, mask_dir, scale=1): + super().__init__(images_dir, mask_dir, scale, mask_suffix="_segmentation") From cd85663cbd1192d49014ee0891f297df63ad522b Mon Sep 17 00:00:00 2001 From: FrostNov4 <97688822+FrostNov4@users.noreply.github.com> Date: Sun, 15 Oct 2023 17:46:15 +1000 Subject: [PATCH 03/45] Read me update --- README.md | 189 ------------------------------------------------------ 1 file changed, 189 deletions(-) diff --git a/README.md b/README.md index cb4d4c986..e69de29bb 100644 --- a/README.md +++ b/README.md @@ -1,189 +0,0 @@ -# U-Net: Semantic segmentation with PyTorch - - - - - -![input and output for a random image in the test dataset](https://i.imgur.com/GD8FcB7.png) - - -Customized implementation of the [U-Net](https://arxiv.org/abs/1505.04597) in PyTorch for Kaggle's [Carvana Image Masking Challenge](https://www.kaggle.com/c/carvana-image-masking-challenge) from high definition images. - -- [Quick start](#quick-start) - - [Without Docker](#without-docker) - - [With Docker](#with-docker) -- [Description](#description) -- [Usage](#usage) - - [Docker](#docker) - - [Training](#training) - - [Prediction](#prediction) -- [Weights & Biases](#weights--biases) -- [Pretrained model](#pretrained-model) -- [Data](#data) - -## Quick start - -### Without Docker - -1. [Install CUDA](https://developer.nvidia.com/cuda-downloads) - -2. [Install PyTorch 1.13 or later](https://pytorch.org/get-started/locally/) - -3. Install dependencies -```bash -pip install -r requirements.txt -``` - -4. Download the data and run training: -```bash -bash scripts/download_data.sh -python train.py --amp -``` - -### With Docker - -1. [Install Docker 19.03 or later:](https://docs.docker.com/get-docker/) -```bash -curl https://get.docker.com | sh && sudo systemctl --now enable docker -``` -2. [Install the NVIDIA container toolkit:](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/install-guide.html) -```bash -distribution=$(. /etc/os-release;echo $ID$VERSION_ID) \ - && curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add - \ - && curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list | sudo tee /etc/apt/sources.list.d/nvidia-docker.list -sudo apt-get update -sudo apt-get install -y nvidia-docker2 -sudo systemctl restart docker -``` -3. [Download and run the image:](https://hub.docker.com/repository/docker/milesial/unet) -```bash -sudo docker run --rm --shm-size=8g --ulimit memlock=-1 --gpus all -it milesial/unet -``` - -4. Download the data and run training: -```bash -bash scripts/download_data.sh -python train.py --amp -``` - -## Description -This model was trained from scratch with 5k images and scored a [Dice coefficient](https://en.wikipedia.org/wiki/S%C3%B8rensen%E2%80%93Dice_coefficient) of 0.988423 on over 100k test images. - -It can be easily used for multiclass segmentation, portrait segmentation, medical segmentation, ... - - -## Usage -**Note : Use Python 3.6 or newer** - -### Docker - -A docker image containing the code and the dependencies is available on [DockerHub](https://hub.docker.com/repository/docker/milesial/unet). -You can download and jump in the container with ([docker >=19.03](https://docs.docker.com/get-docker/)): - -```console -docker run -it --rm --shm-size=8g --ulimit memlock=-1 --gpus all milesial/unet -``` - - -### Training - -```console -> python train.py -h -usage: train.py [-h] [--epochs E] [--batch-size B] [--learning-rate LR] - [--load LOAD] [--scale SCALE] [--validation VAL] [--amp] - -Train the UNet on images and target masks - -optional arguments: - -h, --help show this help message and exit - --epochs E, -e E Number of epochs - --batch-size B, -b B Batch size - --learning-rate LR, -l LR - Learning rate - --load LOAD, -f LOAD Load model from a .pth file - --scale SCALE, -s SCALE - Downscaling factor of the images - --validation VAL, -v VAL - Percent of the data that is used as validation (0-100) - --amp Use mixed precision -``` - -By default, the `scale` is 0.5, so if you wish to obtain better results (but use more memory), set it to 1. - -Automatic mixed precision is also available with the `--amp` flag. [Mixed precision](https://arxiv.org/abs/1710.03740) allows the model to use less memory and to be faster on recent GPUs by using FP16 arithmetic. Enabling AMP is recommended. - - -### Prediction - -After training your model and saving it to `MODEL.pth`, you can easily test the output masks on your images via the CLI. - -To predict a single image and save it: - -`python predict.py -i image.jpg -o output.jpg` - -To predict a multiple images and show them without saving them: - -`python predict.py -i image1.jpg image2.jpg --viz --no-save` - -```console -> python predict.py -h -usage: predict.py [-h] [--model FILE] --input INPUT [INPUT ...] - [--output INPUT [INPUT ...]] [--viz] [--no-save] - [--mask-threshold MASK_THRESHOLD] [--scale SCALE] - -Predict masks from input images - -optional arguments: - -h, --help show this help message and exit - --model FILE, -m FILE - Specify the file in which the model is stored - --input INPUT [INPUT ...], -i INPUT [INPUT ...] - Filenames of input images - --output INPUT [INPUT ...], -o INPUT [INPUT ...] - Filenames of output images - --viz, -v Visualize the images as they are processed - --no-save, -n Do not save the output masks - --mask-threshold MASK_THRESHOLD, -t MASK_THRESHOLD - Minimum probability value to consider a mask pixel white - --scale SCALE, -s SCALE - Scale factor for the input images -``` -You can specify which model file to use with `--model MODEL.pth`. - -## Weights & Biases - -The training progress can be visualized in real-time using [Weights & Biases](https://wandb.ai/). Loss curves, validation curves, weights and gradient histograms, as well as predicted masks are logged to the platform. - -When launching a training, a link will be printed in the console. Click on it to go to your dashboard. If you have an existing W&B account, you can link it - by setting the `WANDB_API_KEY` environment variable. If not, it will create an anonymous run which is automatically deleted after 7 days. - - -## Pretrained model -A [pretrained model](https://github.com/milesial/Pytorch-UNet/releases/tag/v3.0) is available for the Carvana dataset. It can also be loaded from torch.hub: - -```python -net = torch.hub.load('milesial/Pytorch-UNet', 'unet_carvana', pretrained=True, scale=0.5) -``` -Available scales are 0.5 and 1.0. - -## Data -The Carvana data is available on the [Kaggle website](https://www.kaggle.com/c/carvana-image-masking-challenge/data). - -You can also download it using the helper script: - -``` -bash scripts/download_data.sh -``` - -The input images and target masks should be in the `data/imgs` and `data/masks` folders respectively (note that the `imgs` and `masks` folder should not contain any sub-folder or any other files, due to the greedy data-loader). For Carvana, images are RGB and masks are black and white. - -You can use your own dataset as long as you make sure it is loaded properly in `utils/data_loading.py`. - - ---- - -Original paper by Olaf Ronneberger, Philipp Fischer, Thomas Brox: - -[U-Net: Convolutional Networks for Biomedical Image Segmentation](https://arxiv.org/abs/1505.04597) - -![network architecture](https://i.imgur.com/jeDVpqF.png) From 4ff482d4aa43a35b3ea752f44669e41270725a5a Mon Sep 17 00:00:00 2001 From: FrostNov4 <97688822+FrostNov4@users.noreply.github.com> Date: Tue, 17 Oct 2023 23:16:21 +1000 Subject: [PATCH 04/45] Readme updated --- README.md | 16 ++++++++++++++++ train.py | 1 + 2 files changed, 17 insertions(+) diff --git a/README.md b/README.md index e69de29bb..a2129c473 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,16 @@ +COMP_3710_Report + +This report is focus on the first task (a) + +Segment the ISIC data set with the Improved UNet +with all labels having a minimum Dice similarity coefficient of 0.8 on the test set. + +The structure of Improved UNet is based on the paper. +"Brain Tumor Segmentation and Radiomics Survival Prediction: Contribution to the BRATS 2017 Challenge" +https://arxiv.org/abs/1802.10508v1 + + + + + + diff --git a/train.py b/train.py index c7d27e2a3..5793fc0b8 100644 --- a/train.py +++ b/train.py @@ -234,4 +234,5 @@ def get_args(): img_scale=args.scale, val_percent=args.val / 100, amp=args.amp + ) From 5a15fd175b3c476686293269339a7221603b8ae1 Mon Sep 17 00:00:00 2001 From: FrostNov4 <97688822+FrostNov4@users.noreply.github.com> Date: Mon, 23 Oct 2023 00:19:20 +1000 Subject: [PATCH 05/45] Model updated. Add ContextModule --- unet/unet_model.py | 87 +++++++++++++++++++++++----------------------- 1 file changed, 44 insertions(+), 43 deletions(-) diff --git a/unet/unet_model.py b/unet/unet_model.py index caf79f47f..83bb4a321 100644 --- a/unet/unet_model.py +++ b/unet/unet_model.py @@ -3,46 +3,47 @@ from .unet_parts import * -class UNet(nn.Module): - def __init__(self, n_channels, n_classes, bilinear=False): - super(UNet, self).__init__() - self.n_channels = n_channels - self.n_classes = n_classes - self.bilinear = bilinear - - self.inc = (DoubleConv(n_channels, 64)) - self.down1 = (Down(64, 128)) - self.down2 = (Down(128, 256)) - self.down3 = (Down(256, 512)) - factor = 2 if bilinear else 1 - self.down4 = (Down(512, 1024 // factor)) - self.up1 = (Up(1024, 512 // factor, bilinear)) - self.up2 = (Up(512, 256 // factor, bilinear)) - self.up3 = (Up(256, 128 // factor, bilinear)) - self.up4 = (Up(128, 64, bilinear)) - self.outc = (OutConv(64, n_classes)) - - def forward(self, x): - x1 = self.inc(x) - x2 = self.down1(x1) - x3 = self.down2(x2) - x4 = self.down3(x3) - x5 = self.down4(x4) - x = self.up1(x5, x4) - x = self.up2(x, x3) - x = self.up3(x, x2) - x = self.up4(x, x1) - logits = self.outc(x) - return logits - - def use_checkpointing(self): - self.inc = torch.utils.checkpoint(self.inc) - self.down1 = torch.utils.checkpoint(self.down1) - self.down2 = torch.utils.checkpoint(self.down2) - self.down3 = torch.utils.checkpoint(self.down3) - self.down4 = torch.utils.checkpoint(self.down4) - self.up1 = torch.utils.checkpoint(self.up1) - self.up2 = torch.utils.checkpoint(self.up2) - self.up3 = torch.utils.checkpoint(self.up3) - self.up4 = torch.utils.checkpoint(self.up4) - self.outc = torch.utils.checkpoint(self.outc) \ No newline at end of file + +class ContextModule(nn.Module): + """ + Context Module: Consists of two convolutional layers for feature extraction and a dropout layer + for regularization, aimed at capturing and preserving the context information in the features. + """ + def __init__(self, in_channels, out_channels): + """ + Initialize the Context Module. + + Parameters: + - in_channels (int): Number of input channels. + - out_channels (int): Number of output channels. + """ + super(ContextModule, self).__init__() + # 2 3x3 convolution layer followed by instance normalization and leaky ReLU activation + self.conv1 = nn.Sequential( + nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=1, padding=1), + nn.BatchNorm2d(out_channels), + nn.ReLU(inplace=True), + ) + self.conv2 = nn.Sequential( + nn.Conv2d(out_channels, out_channels, kernel_size=3, stride=1, padding=1), + nn.BatchNorm2d(out_channels), + nn.ReLU(inplace=True), + ) + # Dropout layer to prevent overfitting + self.dropout = nn.Dropout2d(p=0.3) + + def forward(self, x): + """ + Forward pass through the context module. Input is put through 2 3x3 stride 1 convolutions with a dropout + layer in between + + Parameters: + - x (Tensor): The input tensor. + + Returns: + - Tensor: The output tensor after passing through the context module. + """ + x = self.conv1(x) + x = self.dropout(x) + x = self.conv2(x) + return x \ No newline at end of file From 8f5b5ad9b128a2f47110b3fb6d5e733cd20519f2 Mon Sep 17 00:00:00 2001 From: FrostNov4 <97688822+FrostNov4@users.noreply.github.com> Date: Mon, 23 Oct 2023 00:23:29 +1000 Subject: [PATCH 06/45] Model updated. Add Segmentation Layer --- unet/unet_model.py | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/unet/unet_model.py b/unet/unet_model.py index 83bb4a321..fce578625 100644 --- a/unet/unet_model.py +++ b/unet/unet_model.py @@ -46,4 +46,38 @@ def forward(self, x): x = self.conv1(x) x = self.dropout(x) x = self.conv2(x) - return x \ No newline at end of file + return x + + +class SegmentationLayer(nn.Module): + """ + SegmentationLayer: A convolutional layer specifically utilized to generate a segmentation map. + """ + + def __init__(self, in_channels, out_channels): + """ + Initialize the SegmentationLayer. + + Parameters: + - in_channels (int): Number of input channels. + - out_channels (int): Number of output channels, often equal to the number of classes in segmentation. + """ + super(SegmentationLayer, self).__init__() + # A convolutional layer that produces segmentation map + self.conv = nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=1, padding=1) + + def forward(self, x): + """ + Forward pass through the SegmentationLayer. + + Parameters: + - x (Tensor): The input tensor. + + Returns: + - Tensor: The output tensor after applying the convolution, serving as a segmentation map. + """ + # Applying convolution + x = self.conv(x) + + return x + From b203d1627b2368b53bab8d4809988acdf6df8787 Mon Sep 17 00:00:00 2001 From: FrostNov4 <97688822+FrostNov4@users.noreply.github.com> Date: Mon, 23 Oct 2023 00:29:16 +1000 Subject: [PATCH 07/45] Model updated. Add Up sampling Layer --- unet/unet_model.py | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/unet/unet_model.py b/unet/unet_model.py index fce578625..631d43c95 100644 --- a/unet/unet_model.py +++ b/unet/unet_model.py @@ -78,6 +78,37 @@ def forward(self, x): """ # Applying convolution x = self.conv(x) + return x + + +class UpscalingLayer(nn.Module): + """ + UpscalingLayer: A layer designed to upscale feature maps by a factor of 2. + """ + + def __init__(self, scale_factor=2, mode='nearest'): + """ + Initialize the UpscalingLayer. + + Parameters: + - scale_factor (int, optional): Factor by which to upscale the input. Default is 2. + - mode (str, optional): Algorithm used for upscaling: 'nearest', 'bilinear', etc. Default is 'nearest'. + """ + super(UpscalingLayer, self).__init__() + # An upsampling layer that increases the spatial dimensions of the feature map + self.upsample = nn.Upsample(scale_factor=scale_factor, mode=mode) + def forward(self, x): + """ + Forward pass through the UpscalingLayer. + + Parameters: + - x (Tensor): The input tensor. + + Returns: + - Tensor: The output tensor after applying the upscaling, having increased spatial dimensions. + """ + # Applying upscaling + x = self.upsample(x) return x From 10ef43910aa9180d7f8124d0ab7e796854837067 Mon Sep 17 00:00:00 2001 From: FrostNov4 <97688822+FrostNov4@users.noreply.github.com> Date: Mon, 23 Oct 2023 00:29:38 +1000 Subject: [PATCH 08/45] Model updated. Add UpscalingLayer --- unet/unet_model.py | 1 + 1 file changed, 1 insertion(+) diff --git a/unet/unet_model.py b/unet/unet_model.py index 631d43c95..cff643707 100644 --- a/unet/unet_model.py +++ b/unet/unet_model.py @@ -86,6 +86,7 @@ class UpscalingLayer(nn.Module): UpscalingLayer: A layer designed to upscale feature maps by a factor of 2. """ + def __init__(self, scale_factor=2, mode='nearest'): """ Initialize the UpscalingLayer. From 77cfa6c16e387c64e53f14d8255f23067aa43544 Mon Sep 17 00:00:00 2001 From: FrostNov4 <97688822+FrostNov4@users.noreply.github.com> Date: Mon, 23 Oct 2023 00:31:18 +1000 Subject: [PATCH 09/45] Update README.md --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index a2129c473..07dab1014 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ COMP_3710_Report -This report is focus on the first task (a) +Medical condition, Extended to 27 OCT + +This report is focused on the first task (a) Segment the ISIC data set with the Improved UNet with all labels having a minimum Dice similarity coefficient of 0.8 on the test set. From d853af72d1ee19b15eb6d840bc60baad522763a6 Mon Sep 17 00:00:00 2001 From: FrostNov4 <97688822+FrostNov4@users.noreply.github.com> Date: Mon, 23 Oct 2023 15:38:11 +1000 Subject: [PATCH 10/45] Model updated. Add Localisation module and Upsampling module --- unet/unet_model.py | 79 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 77 insertions(+), 2 deletions(-) diff --git a/unet/unet_model.py b/unet/unet_model.py index cff643707..85d26b2c8 100644 --- a/unet/unet_model.py +++ b/unet/unet_model.py @@ -3,12 +3,12 @@ from .unet_parts import * - class ContextModule(nn.Module): """ Context Module: Consists of two convolutional layers for feature extraction and a dropout layer for regularization, aimed at capturing and preserving the context information in the features. """ + def __init__(self, in_channels, out_channels): """ Initialize the Context Module. @@ -86,7 +86,6 @@ class UpscalingLayer(nn.Module): UpscalingLayer: A layer designed to upscale feature maps by a factor of 2. """ - def __init__(self, scale_factor=2, mode='nearest'): """ Initialize the UpscalingLayer. @@ -113,3 +112,79 @@ def forward(self, x): x = self.upsample(x) return x + +class LocalisationModule(nn.Module): + """ + Localisation Module: Focused on up-sampling the received feature map and reducing the + number of feature channels, working towards recovering the spatial resolution of the input data. + """ + + def __init__(self, in_channels, out_channels): + """ + Initialize the Localisation Module. + + Parameters: + - in_channels (int): Number of input channels. + - out_channels (int): Number of output channels. + """ + super(LocalisationModule, self).__init__() + # Using a simple upscale by repeating the feature pixels twice + self.upsample = nn.Upsample(scale_factor=2, mode='nearest') + # 3x3 convolution to process concatenated features + self.conv1 = nn.Conv2d(in_channels, in_channels, kernel_size=3, stride=1, padding=1) + # 1x1 convolution to reduce the number of feature maps + self.conv2 = nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=1, padding=1) + + def forward(self, x): + """ + Forward pass through the localisation module. Input is put through 2 3x3 stride 1 convolutions + with leaky ReLU applied in between + + Parameters: + - x (Tensor): The input tensor. + + Returns: + - Tensor: The output tensor after passing through the localisation module. + """ + x = self.conv1(x) + x = F.relu(x) + x = self.conv2(x) + x = F.relu(x) + return x + + +class UpsamplingModule(nn.Module): + """ + Upsampling Module: Handles the up-sampling of feature maps in the decoder part of the UNet, + contributing to incrementing the spatial dimensions of the input feature map. + """ + + def __init__(self, in_channels, out_channels): + """ + Initialize the Upsampling Module. + + Parameters: + - in_channels (int): Number of input channels. + - out_channels (int): Number of output channels. + """ + super(UpsamplingModule, self).__init__() + # Using a simple upscale by repeating the feature pixels twice + self.upsample = nn.Upsample(scale_factor=2, mode='nearest') + # 3x3 convolution that halves the number of feature maps + self.conv = nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=1, padding=1) + + def forward(self, x): + """ + Forward pass through the upsampling module. First the input is upsampled, then undergoes stride 1 + 3x3 convolution followed by leaky ReLU. + + Parameters: + - x (Tensor): The input tensor. + + Returns: + - Tensor: The output tensor after passing through the upsampling module. + """ + x = self.upsample(x) + x = self.conv(x) + x = F.relu(x) + return x From 7f542ba46f79b2a1f457054ba9154ffae16448cf Mon Sep 17 00:00:00 2001 From: FrostNov4 <97688822+FrostNov4@users.noreply.github.com> Date: Mon, 23 Oct 2023 16:30:53 +1000 Subject: [PATCH 11/45] Model updated. Add Localisation module and Upsampling module --- unet/unet_model.py | 1 + 1 file changed, 1 insertion(+) diff --git a/unet/unet_model.py b/unet/unet_model.py index 85d26b2c8..6ca182770 100644 --- a/unet/unet_model.py +++ b/unet/unet_model.py @@ -187,4 +187,5 @@ def forward(self, x): x = self.upsample(x) x = self.conv(x) x = F.relu(x) + return x From b2781c5c439ae1fe9bcb491f4e3120358a1d9b23 Mon Sep 17 00:00:00 2001 From: FrostNov4 <97688822+FrostNov4@users.noreply.github.com> Date: Thu, 26 Oct 2023 02:38:04 +1000 Subject: [PATCH 12/45] Model updated. Add UpscalingLayer --- unet/unet_model.py | 115 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 115 insertions(+) diff --git a/unet/unet_model.py b/unet/unet_model.py index 6ca182770..0ae879415 100644 --- a/unet/unet_model.py +++ b/unet/unet_model.py @@ -189,3 +189,118 @@ def forward(self, x): x = F.relu(x) return x + + +class UNet_For_Brain(nn.Module): + """ + UNet2D: An Improved U-Net model implmented as the provided Improved U-Net documentation. + """ + + def __init__(self, in_channels, num_classes=2): + """ + Initialize the UNet2D model. + + Parameters: + - in_channels (int): Number of input channels. + - num_classes (int): Number of output classes for segmentation. + """ + super(UNet_For_Brain, self).__init__() + + # Encoder + self.enc1 = nn.Conv2d(in_channels, 16 * 4, kernel_size=3, stride=1, padding=1) + self.context1 = ContextModule(16 * 4, 16 * 4) + self.enc2 = nn.Conv2d(16 * 4, 32 * 4, kernel_size=3, stride=2, padding=1) + self.context2 = ContextModule(32 * 4, 32 * 4) + self.enc3 = nn.Conv2d(32 * 4, 64 * 4, kernel_size=3, stride=2, padding=1) + self.context3 = ContextModule(64 * 4, 64 * 4) + self.enc4 = nn.Conv2d(64 * 4, 128 * 4, kernel_size=3, stride=2, padding=1) + self.context4 = ContextModule(128 * 4, 128 * 4) + + # Bottleneck + self.bottleneck = nn.Conv2d(128 * 4, 256 * 4, kernel_size=3, stride=2, padding=1) + self.bottleneck_context = ContextModule(256 * 4, 256 * 4) + self.up_bottleneck = UpsamplingModule(256 * 4, 128 * 4) + + # Decoder + self.local1 = LocalisationModule(256 * 4, 128 * 4) + self.up1 = UpsamplingModule(128 * 4, 64 * 4) + + self.local2 = LocalisationModule(128 * 4, 64 * 4) + self.up2 = UpsamplingModule(64 * 4, 32 * 4) + + self.seg1 = SegmentationLayer(64 * 4, num_classes) + self.upsample_seg1 = UpscalingLayer() + + self.local3 = LocalisationModule(64 * 4, 32 * 4) + self.up3 = UpsamplingModule(32 * 4, 16 * 4) + + self.seg2 = SegmentationLayer(32 * 4, num_classes) + self.upsample_seg2 = UpscalingLayer() + + self.final_conv = nn.Conv2d(32 * 4, 32 * 4, kernel_size=3, stride=1, padding=1) + + self.seg3 = SegmentationLayer(32 * 4, num_classes) + self.upsample_seg3 = UpscalingLayer() + + def forward(self, x): + """ + Define the forward pass through the UNet2D model. + + Parameters: + - x (Tensor): Input tensor. + + Returns: + - Tensor: The output tensor after passing through the model. + """ + y1 = self.enc1(x) + x1 = self.context1(y1) + x1 = x1 + y1 + + y2 = self.enc2(x1) + x2 = self.context2(y2) + x2 = x2 + y2 + + y3 = self.enc3(x2) + x3 = self.context3(y3) + x3 = x3 + y3 + + y4 = self.enc4(x3) + x4 = self.context4(y4) + x4 = x4 + y4 + + # Bottleneck + bottleneck_conv = self.bottleneck(x4) + + bottleneck = self.bottleneck_context(bottleneck_conv) + bottleneck = bottleneck + bottleneck_conv + + up_bottleneck = self.up_bottleneck(bottleneck) + + # Decoder + x = self.local1(torch.cat((x4, up_bottleneck), dim=1)) + x = self.up1(x) + + x = self.local2(torch.cat((x3, x), dim=1)) + seg1 = self.seg1(x) + x = self.up2(x) + + seg1_upsampled = self.upsample_seg1(seg1) + + x = self.local3(torch.cat((x2, x), dim=1)) + seg2 = self.seg2(x) + x = self.up3(x) + + seg12 = seg1_upsampled + seg2 + seg12_up = self.upsample_seg2(seg12) + + x = self.final_conv(torch.cat((x1, x), dim=1)) + + seg3 = self.seg3(x) + seg123 = seg3 + seg12_up + + out = seg123 + # out = nn.functional.softmax(seg123, dim=1) + # out = torch.sigmoid(seg123) + # print("out shape: ", out.size()) + + return out From ab7a362694d325d473372284cafe38b2ed16f58d Mon Sep 17 00:00:00 2001 From: FrostNov4 <97688822+FrostNov4@users.noreply.github.com> Date: Thu, 26 Oct 2023 03:05:51 +1000 Subject: [PATCH 13/45] Model updated. Add UpscalingLayer --- unet/__init__.py | 1 - unet/unet_model.py | 306 ------------------------------------------ unet/unet_parts.py | 77 ----------- utils/__init__.py | 0 utils/data_loading.py | 122 ----------------- utils/dice_score.py | 28 ---- utils/utils.py | 13 -- 7 files changed, 547 deletions(-) delete mode 100644 unet/__init__.py delete mode 100644 unet/unet_model.py delete mode 100644 unet/unet_parts.py delete mode 100644 utils/__init__.py delete mode 100644 utils/data_loading.py delete mode 100644 utils/dice_score.py delete mode 100644 utils/utils.py diff --git a/unet/__init__.py b/unet/__init__.py deleted file mode 100644 index 2e9b63b67..000000000 --- a/unet/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .unet_model import UNet diff --git a/unet/unet_model.py b/unet/unet_model.py deleted file mode 100644 index 0ae879415..000000000 --- a/unet/unet_model.py +++ /dev/null @@ -1,306 +0,0 @@ -""" Full assembly of the parts to form the complete network """ - -from .unet_parts import * - - -class ContextModule(nn.Module): - """ - Context Module: Consists of two convolutional layers for feature extraction and a dropout layer - for regularization, aimed at capturing and preserving the context information in the features. - """ - - def __init__(self, in_channels, out_channels): - """ - Initialize the Context Module. - - Parameters: - - in_channels (int): Number of input channels. - - out_channels (int): Number of output channels. - """ - super(ContextModule, self).__init__() - # 2 3x3 convolution layer followed by instance normalization and leaky ReLU activation - self.conv1 = nn.Sequential( - nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=1, padding=1), - nn.BatchNorm2d(out_channels), - nn.ReLU(inplace=True), - ) - self.conv2 = nn.Sequential( - nn.Conv2d(out_channels, out_channels, kernel_size=3, stride=1, padding=1), - nn.BatchNorm2d(out_channels), - nn.ReLU(inplace=True), - ) - # Dropout layer to prevent overfitting - self.dropout = nn.Dropout2d(p=0.3) - - def forward(self, x): - """ - Forward pass through the context module. Input is put through 2 3x3 stride 1 convolutions with a dropout - layer in between - - Parameters: - - x (Tensor): The input tensor. - - Returns: - - Tensor: The output tensor after passing through the context module. - """ - x = self.conv1(x) - x = self.dropout(x) - x = self.conv2(x) - return x - - -class SegmentationLayer(nn.Module): - """ - SegmentationLayer: A convolutional layer specifically utilized to generate a segmentation map. - """ - - def __init__(self, in_channels, out_channels): - """ - Initialize the SegmentationLayer. - - Parameters: - - in_channels (int): Number of input channels. - - out_channels (int): Number of output channels, often equal to the number of classes in segmentation. - """ - super(SegmentationLayer, self).__init__() - # A convolutional layer that produces segmentation map - self.conv = nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=1, padding=1) - - def forward(self, x): - """ - Forward pass through the SegmentationLayer. - - Parameters: - - x (Tensor): The input tensor. - - Returns: - - Tensor: The output tensor after applying the convolution, serving as a segmentation map. - """ - # Applying convolution - x = self.conv(x) - return x - - -class UpscalingLayer(nn.Module): - """ - UpscalingLayer: A layer designed to upscale feature maps by a factor of 2. - """ - - def __init__(self, scale_factor=2, mode='nearest'): - """ - Initialize the UpscalingLayer. - - Parameters: - - scale_factor (int, optional): Factor by which to upscale the input. Default is 2. - - mode (str, optional): Algorithm used for upscaling: 'nearest', 'bilinear', etc. Default is 'nearest'. - """ - super(UpscalingLayer, self).__init__() - # An upsampling layer that increases the spatial dimensions of the feature map - self.upsample = nn.Upsample(scale_factor=scale_factor, mode=mode) - - def forward(self, x): - """ - Forward pass through the UpscalingLayer. - - Parameters: - - x (Tensor): The input tensor. - - Returns: - - Tensor: The output tensor after applying the upscaling, having increased spatial dimensions. - """ - # Applying upscaling - x = self.upsample(x) - return x - - -class LocalisationModule(nn.Module): - """ - Localisation Module: Focused on up-sampling the received feature map and reducing the - number of feature channels, working towards recovering the spatial resolution of the input data. - """ - - def __init__(self, in_channels, out_channels): - """ - Initialize the Localisation Module. - - Parameters: - - in_channels (int): Number of input channels. - - out_channels (int): Number of output channels. - """ - super(LocalisationModule, self).__init__() - # Using a simple upscale by repeating the feature pixels twice - self.upsample = nn.Upsample(scale_factor=2, mode='nearest') - # 3x3 convolution to process concatenated features - self.conv1 = nn.Conv2d(in_channels, in_channels, kernel_size=3, stride=1, padding=1) - # 1x1 convolution to reduce the number of feature maps - self.conv2 = nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=1, padding=1) - - def forward(self, x): - """ - Forward pass through the localisation module. Input is put through 2 3x3 stride 1 convolutions - with leaky ReLU applied in between - - Parameters: - - x (Tensor): The input tensor. - - Returns: - - Tensor: The output tensor after passing through the localisation module. - """ - x = self.conv1(x) - x = F.relu(x) - x = self.conv2(x) - x = F.relu(x) - return x - - -class UpsamplingModule(nn.Module): - """ - Upsampling Module: Handles the up-sampling of feature maps in the decoder part of the UNet, - contributing to incrementing the spatial dimensions of the input feature map. - """ - - def __init__(self, in_channels, out_channels): - """ - Initialize the Upsampling Module. - - Parameters: - - in_channels (int): Number of input channels. - - out_channels (int): Number of output channels. - """ - super(UpsamplingModule, self).__init__() - # Using a simple upscale by repeating the feature pixels twice - self.upsample = nn.Upsample(scale_factor=2, mode='nearest') - # 3x3 convolution that halves the number of feature maps - self.conv = nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=1, padding=1) - - def forward(self, x): - """ - Forward pass through the upsampling module. First the input is upsampled, then undergoes stride 1 - 3x3 convolution followed by leaky ReLU. - - Parameters: - - x (Tensor): The input tensor. - - Returns: - - Tensor: The output tensor after passing through the upsampling module. - """ - x = self.upsample(x) - x = self.conv(x) - x = F.relu(x) - - return x - - -class UNet_For_Brain(nn.Module): - """ - UNet2D: An Improved U-Net model implmented as the provided Improved U-Net documentation. - """ - - def __init__(self, in_channels, num_classes=2): - """ - Initialize the UNet2D model. - - Parameters: - - in_channels (int): Number of input channels. - - num_classes (int): Number of output classes for segmentation. - """ - super(UNet_For_Brain, self).__init__() - - # Encoder - self.enc1 = nn.Conv2d(in_channels, 16 * 4, kernel_size=3, stride=1, padding=1) - self.context1 = ContextModule(16 * 4, 16 * 4) - self.enc2 = nn.Conv2d(16 * 4, 32 * 4, kernel_size=3, stride=2, padding=1) - self.context2 = ContextModule(32 * 4, 32 * 4) - self.enc3 = nn.Conv2d(32 * 4, 64 * 4, kernel_size=3, stride=2, padding=1) - self.context3 = ContextModule(64 * 4, 64 * 4) - self.enc4 = nn.Conv2d(64 * 4, 128 * 4, kernel_size=3, stride=2, padding=1) - self.context4 = ContextModule(128 * 4, 128 * 4) - - # Bottleneck - self.bottleneck = nn.Conv2d(128 * 4, 256 * 4, kernel_size=3, stride=2, padding=1) - self.bottleneck_context = ContextModule(256 * 4, 256 * 4) - self.up_bottleneck = UpsamplingModule(256 * 4, 128 * 4) - - # Decoder - self.local1 = LocalisationModule(256 * 4, 128 * 4) - self.up1 = UpsamplingModule(128 * 4, 64 * 4) - - self.local2 = LocalisationModule(128 * 4, 64 * 4) - self.up2 = UpsamplingModule(64 * 4, 32 * 4) - - self.seg1 = SegmentationLayer(64 * 4, num_classes) - self.upsample_seg1 = UpscalingLayer() - - self.local3 = LocalisationModule(64 * 4, 32 * 4) - self.up3 = UpsamplingModule(32 * 4, 16 * 4) - - self.seg2 = SegmentationLayer(32 * 4, num_classes) - self.upsample_seg2 = UpscalingLayer() - - self.final_conv = nn.Conv2d(32 * 4, 32 * 4, kernel_size=3, stride=1, padding=1) - - self.seg3 = SegmentationLayer(32 * 4, num_classes) - self.upsample_seg3 = UpscalingLayer() - - def forward(self, x): - """ - Define the forward pass through the UNet2D model. - - Parameters: - - x (Tensor): Input tensor. - - Returns: - - Tensor: The output tensor after passing through the model. - """ - y1 = self.enc1(x) - x1 = self.context1(y1) - x1 = x1 + y1 - - y2 = self.enc2(x1) - x2 = self.context2(y2) - x2 = x2 + y2 - - y3 = self.enc3(x2) - x3 = self.context3(y3) - x3 = x3 + y3 - - y4 = self.enc4(x3) - x4 = self.context4(y4) - x4 = x4 + y4 - - # Bottleneck - bottleneck_conv = self.bottleneck(x4) - - bottleneck = self.bottleneck_context(bottleneck_conv) - bottleneck = bottleneck + bottleneck_conv - - up_bottleneck = self.up_bottleneck(bottleneck) - - # Decoder - x = self.local1(torch.cat((x4, up_bottleneck), dim=1)) - x = self.up1(x) - - x = self.local2(torch.cat((x3, x), dim=1)) - seg1 = self.seg1(x) - x = self.up2(x) - - seg1_upsampled = self.upsample_seg1(seg1) - - x = self.local3(torch.cat((x2, x), dim=1)) - seg2 = self.seg2(x) - x = self.up3(x) - - seg12 = seg1_upsampled + seg2 - seg12_up = self.upsample_seg2(seg12) - - x = self.final_conv(torch.cat((x1, x), dim=1)) - - seg3 = self.seg3(x) - seg123 = seg3 + seg12_up - - out = seg123 - # out = nn.functional.softmax(seg123, dim=1) - # out = torch.sigmoid(seg123) - # print("out shape: ", out.size()) - - return out diff --git a/unet/unet_parts.py b/unet/unet_parts.py deleted file mode 100644 index 986ba251f..000000000 --- a/unet/unet_parts.py +++ /dev/null @@ -1,77 +0,0 @@ -""" Parts of the U-Net model """ - -import torch -import torch.nn as nn -import torch.nn.functional as F - - -class DoubleConv(nn.Module): - """(convolution => [BN] => ReLU) * 2""" - - def __init__(self, in_channels, out_channels, mid_channels=None): - super().__init__() - if not mid_channels: - mid_channels = out_channels - self.double_conv = nn.Sequential( - nn.Conv2d(in_channels, mid_channels, kernel_size=3, padding=1, bias=False), - nn.BatchNorm2d(mid_channels), - nn.ReLU(inplace=True), - nn.Conv2d(mid_channels, out_channels, kernel_size=3, padding=1, bias=False), - nn.BatchNorm2d(out_channels), - nn.ReLU(inplace=True) - ) - - def forward(self, x): - return self.double_conv(x) - - -class Down(nn.Module): - """Downscaling with maxpool then double conv""" - - def __init__(self, in_channels, out_channels): - super().__init__() - self.maxpool_conv = nn.Sequential( - nn.MaxPool2d(2), - DoubleConv(in_channels, out_channels) - ) - - def forward(self, x): - return self.maxpool_conv(x) - - -class Up(nn.Module): - """Upscaling then double conv""" - - def __init__(self, in_channels, out_channels, bilinear=True): - super().__init__() - - # if bilinear, use the normal convolutions to reduce the number of channels - if bilinear: - self.up = nn.Upsample(scale_factor=2, mode='bilinear', align_corners=True) - self.conv = DoubleConv(in_channels, out_channels, in_channels // 2) - else: - self.up = nn.ConvTranspose2d(in_channels, in_channels // 2, kernel_size=2, stride=2) - self.conv = DoubleConv(in_channels, out_channels) - - def forward(self, x1, x2): - x1 = self.up(x1) - # input is CHW - diffY = x2.size()[2] - x1.size()[2] - diffX = x2.size()[3] - x1.size()[3] - - x1 = F.pad(x1, [diffX // 2, diffX - diffX // 2, - diffY // 2, diffY - diffY // 2]) - # if you have padding issues, see - # https://github.com/HaiyongJiang/U-Net-Pytorch-Unstructured-Buggy/commit/0e854509c2cea854e247a9c615f175f76fbb2e3a - # https://github.com/xiaopeng-liao/Pytorch-UNet/commit/8ebac70e633bac59fc22bb5195e513d5832fb3bd - x = torch.cat([x2, x1], dim=1) - return self.conv(x) - - -class OutConv(nn.Module): - def __init__(self, in_channels, out_channels): - super(OutConv, self).__init__() - self.conv = nn.Conv2d(in_channels, out_channels, kernel_size=1) - - def forward(self, x): - return self.conv(x) diff --git a/utils/__init__.py b/utils/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/utils/data_loading.py b/utils/data_loading.py deleted file mode 100644 index 186ac00cd..000000000 --- a/utils/data_loading.py +++ /dev/null @@ -1,122 +0,0 @@ -import logging -import numpy as np -import torch -from PIL import Image -from functools import lru_cache -from functools import partial -from itertools import repeat -from multiprocessing import Pool -from os import listdir -from os.path import splitext, isfile, join -from pathlib import Path -from torch.utils.data import Dataset -from tqdm import tqdm - - -def load_image(filename): - ext = splitext(filename)[1] - if ext == '.npy': - return Image.fromarray(np.load(filename)) - elif ext in ['.pt', '.pth']: - return Image.fromarray(torch.load(filename).numpy()) - else: - return Image.open(filename) - - -def unique_mask_values(idx, mask_dir, mask_suffix): - mask_file = list(mask_dir.glob(idx + mask_suffix + '.*'))[0] - mask = np.asarray(load_image(mask_file)) - if mask.ndim == 2: - return np.unique(mask) - elif mask.ndim == 3: - mask = mask.reshape(-1, mask.shape[-1]) - return np.unique(mask, axis=0) - else: - raise ValueError(f'Loaded masks should have 2 or 3 dimensions, found {mask.ndim}') - - -class BasicDataset(Dataset): - def __init__(self, images_dir: str, mask_dir: str, scale: float = 1.0, mask_suffix: str = ''): - self.images_dir = Path(images_dir) - self.mask_dir = Path(mask_dir) - assert 0 < scale <= 1, 'Scale must be between 0 and 1' - self.scale = scale - self.mask_suffix = mask_suffix - - self.ids = [splitext(file)[0] for file in listdir(images_dir) if isfile(join(images_dir, file)) and not file.startswith('.')] - if not self.ids: - raise RuntimeError(f'No input file found in {images_dir}, make sure you put your images there') - - logging.info(f'Creating dataset with {len(self.ids)} examples') - logging.info('Scanning mask files to determine unique values') - with Pool() as p: - unique = list(tqdm( - p.imap(partial(unique_mask_values, mask_dir=self.mask_dir, mask_suffix=self.mask_suffix), self.ids), - total=len(self.ids) - )) - - self.mask_values = list(sorted(np.unique(np.concatenate(unique), axis=0).tolist())) - logging.info(f'Unique mask values: {self.mask_values}') - - def __len__(self): - return len(self.ids) - - @staticmethod - def preprocess(mask_values, pil_img, scale, is_mask): - w, h = pil_img.size - newW, newH = int(scale * w), int(scale * h) - assert newW > 0 and newH > 0, 'Scale is too small, resized images would have no pixel' - pil_img = pil_img.resize((newW, newH), resample=Image.NEAREST if is_mask else Image.BICUBIC) - img = np.asarray(pil_img) - - if is_mask: - mask = np.zeros((newH, newW), dtype=np.int64) - for i, v in enumerate(mask_values): - if img.ndim == 2: - mask[img == v] = i - else: - mask[(img == v).all(-1)] = i - - return mask - - else: - if img.ndim == 2: - img = img[np.newaxis, ...] - else: - img = img.transpose((2, 0, 1)) - - if (img > 1).any(): - img = img / 255.0 - - return img - - def __getitem__(self, idx): - name = self.ids[idx] - mask_file = list(self.mask_dir.glob(name + self.mask_suffix + '.*')) - img_file = list(self.images_dir.glob(name + '.*')) - - assert len(img_file) == 1, f'Either no image or multiple images found for the ID {name}: {img_file}' - assert len(mask_file) == 1, f'Either no mask or multiple masks found for the ID {name}: {mask_file}' - mask = load_image(mask_file[0]) - img = load_image(img_file[0]) - - assert img.size == mask.size, \ - f'Image and mask {name} should be the same size, but are {img.size} and {mask.size}' - - img = self.preprocess(self.mask_values, img, self.scale, is_mask=False) - mask = self.preprocess(self.mask_values, mask, self.scale, is_mask=True) - - return { - 'image': torch.as_tensor(img.copy()).float().contiguous(), - 'mask': torch.as_tensor(mask.copy()).long().contiguous() - } - - -class CarvanaDataset(BasicDataset): - def __init__(self, images_dir, mask_dir, scale=1): - super().__init__(images_dir, mask_dir, scale, mask_suffix='_mask') - - -class ISICDataset(BasicDataset): - def __init__(self, images_dir, mask_dir, scale=1): - super().__init__(images_dir, mask_dir, scale, mask_suffix="_segmentation") diff --git a/utils/dice_score.py b/utils/dice_score.py deleted file mode 100644 index c89eebee7..000000000 --- a/utils/dice_score.py +++ /dev/null @@ -1,28 +0,0 @@ -import torch -from torch import Tensor - - -def dice_coeff(input: Tensor, target: Tensor, reduce_batch_first: bool = False, epsilon: float = 1e-6): - # Average of Dice coefficient for all batches, or for a single mask - assert input.size() == target.size() - assert input.dim() == 3 or not reduce_batch_first - - sum_dim = (-1, -2) if input.dim() == 2 or not reduce_batch_first else (-1, -2, -3) - - inter = 2 * (input * target).sum(dim=sum_dim) - sets_sum = input.sum(dim=sum_dim) + target.sum(dim=sum_dim) - sets_sum = torch.where(sets_sum == 0, inter, sets_sum) - - dice = (inter + epsilon) / (sets_sum + epsilon) - return dice.mean() - - -def multiclass_dice_coeff(input: Tensor, target: Tensor, reduce_batch_first: bool = False, epsilon: float = 1e-6): - # Average of Dice coefficient for all classes - return dice_coeff(input.flatten(0, 1), target.flatten(0, 1), reduce_batch_first, epsilon) - - -def dice_loss(input: Tensor, target: Tensor, multiclass: bool = False): - # Dice loss (objective to minimize) between 0 and 1 - fn = multiclass_dice_coeff if multiclass else dice_coeff - return 1 - fn(input, target, reduce_batch_first=True) diff --git a/utils/utils.py b/utils/utils.py deleted file mode 100644 index 5e6e04128..000000000 --- a/utils/utils.py +++ /dev/null @@ -1,13 +0,0 @@ -import matplotlib.pyplot as plt - - -def plot_img_and_mask(img, mask): - classes = mask.max() + 1 - fig, ax = plt.subplots(1, classes + 1) - ax[0].set_title('Input image') - ax[0].imshow(img) - for i in range(classes): - ax[i + 1].set_title(f'Mask (class {i + 1})') - ax[i + 1].imshow(mask == i) - plt.xticks([]), plt.yticks([]) - plt.show() From 8166c1aa5bc5c175afe5e617af13c2782189ae71 Mon Sep 17 00:00:00 2001 From: FrostNov4 <97688822+FrostNov4@users.noreply.github.com> Date: Thu, 26 Oct 2023 04:02:11 +1000 Subject: [PATCH 14/45] File location update --- .idea/.gitignore | 8 + .idea/PatternAnalysis-2023.iml | 14 + .idea/inspectionProfiles/Project_Default.xml | 41 +++ .../inspectionProfiles/profiles_settings.xml | 6 + .idea/misc.xml | 4 + .idea/modules.xml | 8 + .idea/vcs.xml | 6 + __init__.py | 3 + data_loading.py | 121 +++++++ dice_score.py | 31 ++ unet_model.py | 313 ++++++++++++++++++ utils.py | 18 + 12 files changed, 573 insertions(+) create mode 100644 .idea/.gitignore create mode 100644 .idea/PatternAnalysis-2023.iml create mode 100644 .idea/inspectionProfiles/Project_Default.xml create mode 100644 .idea/inspectionProfiles/profiles_settings.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/vcs.xml create mode 100644 __init__.py create mode 100644 data_loading.py create mode 100644 dice_score.py create mode 100644 unet_model.py create mode 100644 utils.py diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 000000000..13566b81b --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/PatternAnalysis-2023.iml b/.idea/PatternAnalysis-2023.iml new file mode 100644 index 000000000..136187df6 --- /dev/null +++ b/.idea/PatternAnalysis-2023.iml @@ -0,0 +1,14 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 000000000..c2745e30b --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,41 @@ + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 000000000..105ce2da2 --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 000000000..a971a2c93 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 000000000..b55eb140b --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 000000000..35eb1ddfb --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/__init__.py b/__init__.py new file mode 100644 index 000000000..2cf6a655c --- /dev/null +++ b/__init__.py @@ -0,0 +1,3 @@ +from .unet_model import UNet + + diff --git a/data_loading.py b/data_loading.py new file mode 100644 index 000000000..0ea6027c5 --- /dev/null +++ b/data_loading.py @@ -0,0 +1,121 @@ +import logging +import numpy as np +import torch +from PIL import Image +from functools import lru_cache +from functools import partial +from itertools import repeat +from multiprocessing import Pool +from os import listdir +from os.path import splitext, isfile, join +from pathlib import Path +from torch.utils.data import Dataset +from tqdm import tqdm +# Updated +def load_image(filename): + ext = splitext(filename)[1] + if ext == '.npy': + return Image.fromarray(np.load(filename)) + elif ext in ['.pt', '.pth']: + return Image.fromarray(torch.load(filename).numpy()) + else: + return Image.open(filename) + + +def unique_mask_values(idx, mask_dir, mask_suffix): + mask_file = list(mask_dir.glob(idx + mask_suffix + '.*'))[0] + mask = np.asarray(load_image(mask_file)) + if mask.ndim == 2: + return np.unique(mask) + elif mask.ndim == 3: + mask = mask.reshape(-1, mask.shape[-1]) + return np.unique(mask, axis=0) + else: + raise ValueError(f'Loaded masks should have 2 or 3 dimensions, found {mask.ndim}') + + +class BasicDataset(Dataset): + def __init__(self, images_dir: str, mask_dir: str, scale: float = 1.0, mask_suffix: str = ''): + self.images_dir = Path(images_dir) + self.mask_dir = Path(mask_dir) + assert 0 < scale <= 1, 'Scale must be between 0 and 1' + self.scale = scale + self.mask_suffix = mask_suffix + + self.ids = [splitext(file)[0] for file in listdir(images_dir) if isfile(join(images_dir, file)) and not file.startswith('.')] + if not self.ids: + raise RuntimeError(f'No input file found in {images_dir}, make sure you put your images there') + + logging.info(f'Creating dataset with {len(self.ids)} examples') + logging.info('Scanning mask files to determine unique values') + with Pool() as p: + unique = list(tqdm( + p.imap(partial(unique_mask_values, mask_dir=self.mask_dir, mask_suffix=self.mask_suffix), self.ids), + total=len(self.ids) + )) + + self.mask_values = list(sorted(np.unique(np.concatenate(unique), axis=0).tolist())) + logging.info(f'Unique mask values: {self.mask_values}') + + def __len__(self): + return len(self.ids) + + @staticmethod + def preprocess(mask_values, pil_img, scale, is_mask): + w, h = pil_img.size + newW, newH = int(scale * w), int(scale * h) + assert newW > 0 and newH > 0, 'Scale is too small, resized images would have no pixel' + pil_img = pil_img.resize((newW, newH), resample=Image.NEAREST if is_mask else Image.BICUBIC) + img = np.asarray(pil_img) + + if is_mask: + mask = np.zeros((newH, newW), dtype=np.int64) + for i, v in enumerate(mask_values): + if img.ndim == 2: + mask[img == v] = i + else: + mask[(img == v).all(-1)] = i + + return mask + + else: + if img.ndim == 2: + img = img[np.newaxis, ...] + else: + img = img.transpose((2, 0, 1)) + + if (img > 1).any(): + img = img / 255.0 + + return img + + def __getitem__(self, idx): + name = self.ids[idx] + mask_file = list(self.mask_dir.glob(name + self.mask_suffix + '.*')) + img_file = list(self.images_dir.glob(name + '.*')) + + assert len(img_file) == 1, f'Either no image or multiple images found for the ID {name}: {img_file}' + assert len(mask_file) == 1, f'Either no mask or multiple masks found for the ID {name}: {mask_file}' + mask = load_image(mask_file[0]) + img = load_image(img_file[0]) + + assert img.size == mask.size, \ + f'Image and mask {name} should be the same size, but are {img.size} and {mask.size}' + + img = self.preprocess(self.mask_values, img, self.scale, is_mask=False) + mask = self.preprocess(self.mask_values, mask, self.scale, is_mask=True) + + return { + 'image': torch.as_tensor(img.copy()).float().contiguous(), + 'mask': torch.as_tensor(mask.copy()).long().contiguous() + } + + +class CarvanaDataset(BasicDataset): + def __init__(self, images_dir, mask_dir, scale=1): + super().__init__(images_dir, mask_dir, scale, mask_suffix='_mask') + + +class ISICDataset(BasicDataset): + def __init__(self, images_dir, mask_dir, scale=1): + super().__init__(images_dir, mask_dir, scale, mask_suffix="_segmentation") diff --git a/dice_score.py b/dice_score.py new file mode 100644 index 000000000..84a219789 --- /dev/null +++ b/dice_score.py @@ -0,0 +1,31 @@ +import torch +from torch import Tensor + + +def dice_coeff(input: Tensor, target: Tensor, reduce_batch_first: bool = False, epsilon: float = 1e-6): + # Average of Dice coefficient for all batches, or for a single mask + assert input.size() == target.size() + assert input.dim() == 3 or not reduce_batch_first + + + sum_dim = (-1, -2) if input.dim() == 2 or not reduce_batch_first else (-1, -2, -3) + + inter = 2 * (input * target).sum(dim=sum_dim) + sets_sum = input.sum(dim=sum_dim) + target.sum(dim=sum_dim) + sets_sum = torch.where(sets_sum == 0, inter, sets_sum) + + dice = (inter + epsilon) / (sets_sum + epsilon) + + return dice.mean() + +def multiclass_dice_coeff(input: Tensor, target: Tensor, reduce_batch_first: bool = False, epsilon: float = 1e-6): + # Average of Dice coefficient for all classes + return dice_coeff(input.flatten(0, 1), target.flatten(0, 1), reduce_batch_first, epsilon) + + +def dice_loss(input: Tensor, target: Tensor, multiclass: bool = False): + # Dice loss (objective to minimize) between 0 and 1 + fn = multiclass_dice_coeff if multiclass else dice_coeff + return 1 - fn(input, target, reduce_batch_first=True) + +# Updated \ No newline at end of file diff --git a/unet_model.py b/unet_model.py new file mode 100644 index 000000000..3e7bf5a7a --- /dev/null +++ b/unet_model.py @@ -0,0 +1,313 @@ +""" Full assembly of the parts to form the complete network """ +from __future__ import print_function, division +import torch.nn as nn +import torch.nn.functional as F +import torch.utils.data +import torch + + + +class ContextModule(nn.Module): + """ + Context Module: Consists of two convolutional layers for feature extraction and a dropout layer + for regularization, aimed at capturing and preserving the context information in the features. + """ + + def __init__(self, in_channels, out_channels): + """ + Initialize the Context Module. + + Parameters: + - in_channels (int): Number of input channels. + - out_channels (int): Number of output channels. + """ + + super(ContextModule, self).__init__() + # 2 3x3 convolution layer followed by instance normalization and leaky ReLU activation + self.conv1 = nn.Sequential( + nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=1, padding=1), + nn.BatchNorm2d(out_channels), + nn.ReLU(inplace=True), + ) + self.conv2 = nn.Sequential( + nn.Conv2d(out_channels, out_channels, kernel_size=3, stride=1, padding=1), + nn.BatchNorm2d(out_channels), + nn.ReLU(inplace=True), + ) + # Dropout layer to prevent overfitting + self.dropout = nn.Dropout2d(p=0.3) + + def forward(self, x): + """ + Forward pass through the context module. Input is put through 2 3x3 stride 1 convolutions with a dropout + layer in between + + Parameters: + - x (Tensor): The input tensor. + + Returns: + - Tensor: The output tensor after passing through the context module. + """ + x = self.conv1(x) + x = self.dropout(x) + x = self.conv2(x) + return x + + +class SegmentationLayer(nn.Module): + """ + SegmentationLayer: A convolutional layer specifically utilized to generate a segmentation map. + """ + + def __init__(self, in_channels, out_channels): + """ + Initialize the SegmentationLayer. + + Parameters: + - in_channels (int): Number of input channels. + - out_channels (int): Number of output channels, often equal to the number of classes in segmentation. + """ + super(SegmentationLayer, self).__init__() + # A convolutional layer that produces segmentation map + self.conv = nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=1, padding=1) + + def forward(self, x): + """ + Forward pass through the SegmentationLayer. + + Parameters: + - x (Tensor): The input tensor. + + Returns: + - Tensor: The output tensor after applying the convolution, serving as a segmentation map. + """ + # Applying convolution + x = self.conv(x) + return x + + +class UpscalingLayer(nn.Module): + """ + UpscalingLayer: A layer designed to upscale feature maps by a factor of 2. + """ + + def __init__(self, scale_factor=2, mode='nearest'): + """ + Initialize the UpscalingLayer. + + Parameters: + - scale_factor (int, optional): Factor by which to upscale the input. Default is 2. + - mode (str, optional): Algorithm used for upscaling: 'nearest', 'bilinear', etc. Default is 'nearest'. + """ + super(UpscalingLayer, self).__init__() + # An upsampling layer that increases the spatial dimensions of the feature map + self.upsample = nn.Upsample(scale_factor=scale_factor, mode=mode) + + def forward(self, x): + """ + Forward pass through the UpscalingLayer. + + Parameters: + - x (Tensor): The input tensor. + + Returns: + - Tensor: The output tensor after applying the upscaling, having increased spatial dimensions. + """ + # Applying upscaling + x = self.upsample(x) + return x + + +class LocalisationModule(nn.Module): + """ + Localisation Module: Focused on up-sampling the received feature map and reducing the + number of feature channels, working towards recovering the spatial resolution of the input data. + """ + + def __init__(self, in_channels, out_channels): + """ + Initialize the Localisation Module. + + Parameters: + - in_channels (int): Number of input channels. + - out_channels (int): Number of output channels. + """ + super(LocalisationModule, self).__init__() + # Using a simple upscale by repeating the feature pixels twice + self.upsample = nn.Upsample(scale_factor=2, mode='nearest') + # 3x3 convolution to process concatenated features + self.conv1 = nn.Conv2d(in_channels, in_channels, kernel_size=3, stride=1, padding=1) + # 1x1 convolution to reduce the number of feature maps + self.conv2 = nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=1, padding=1) + + def forward(self, x): + """ + Forward pass through the localisation module. Input is put through 2 3x3 stride 1 convolutions + with leaky ReLU applied in between + + Parameters: + - x (Tensor): The input tensor. + + Returns: + - Tensor: The output tensor after passing through the localisation module. + """ + x = self.conv1(x) + x = F.relu(x) + x = self.conv2(x) + x = F.relu(x) + return x + + +class UpsamplingModule(nn.Module): + """ + Upsampling Module: Handles the up-sampling of feature maps in the decoder part of the UNet, + contributing to incrementing the spatial dimensions of the input feature map. + """ + + def __init__(self, in_channels, out_channels): + """ + Initialize the Upsampling Module. + + Parameters: + - in_channels (int): Number of input channels. + - out_channels (int): Number of output channels. + """ + super(UpsamplingModule, self).__init__() + # Using a simple upscale by repeating the feature pixels twice + self.upsample = nn.Upsample(scale_factor=2, mode='nearest') + # 3x3 convolution that halves the number of feature maps + self.conv = nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=1, padding=1) + + def forward(self, x): + """ + Forward pass through the upsampling module. First the input is upsampled, then undergoes stride 1 + 3x3 convolution followed by leaky ReLU. + + Parameters: + - x (Tensor): The input tensor. + + Returns: + - Tensor: The output tensor after passing through the upsampling module. + """ + x = self.upsample(x) + x = self.conv(x) + x = F.relu(x) + + return x + + +class UNet_For_Brain(nn.Module): + """ + UNet2D: An Improved U-Net model implmented as the provided Improved U-Net paper + """ + + def __init__(self, in_channels, num_classes=2): + """ + Initialize the UNet2D model. + + Parameters: + - in_channels (int): Number of input channels. + - num_classes (int): Number of output classes for segmentation. + """ + super(UNet_For_Brain, self).__init__() + + # Encoder + self.enc1 = nn.Conv2d(in_channels, 16 * 4, kernel_size=3, stride=1, padding=1) + self.context1 = ContextModule(16 * 4, 16 * 4) + self.enc2 = nn.Conv2d(16 * 4, 32 * 4, kernel_size=3, stride=2, padding=1) + self.context2 = ContextModule(32 * 4, 32 * 4) + self.enc3 = nn.Conv2d(32 * 4, 64 * 4, kernel_size=3, stride=2, padding=1) + self.context3 = ContextModule(64 * 4, 64 * 4) + self.enc4 = nn.Conv2d(64 * 4, 128 * 4, kernel_size=3, stride=2, padding=1) + self.context4 = ContextModule(128 * 4, 128 * 4) + + # Bottleneck + self.bottleneck = nn.Conv2d(128 * 4, 256 * 4, kernel_size=3, stride=2, padding=1) + self.bottleneck_context = ContextModule(256 * 4, 256 * 4) + self.up_bottleneck = UpsamplingModule(256 * 4, 128 * 4) + + # Decoder + self.local1 = LocalisationModule(256 * 4, 128 * 4) + self.up1 = UpsamplingModule(128 * 4, 64 * 4) + + self.local2 = LocalisationModule(128 * 4, 64 * 4) + self.up2 = UpsamplingModule(64 * 4, 32 * 4) + + self.seg1 = SegmentationLayer(64 * 4, num_classes) + self.upsample_seg1 = UpscalingLayer() + + self.local3 = LocalisationModule(64 * 4, 32 * 4) + self.up3 = UpsamplingModule(32 * 4, 16 * 4) + + self.seg2 = SegmentationLayer(32 * 4, num_classes) + self.upsample_seg2 = UpscalingLayer() + + self.final_conv = nn.Conv2d(32 * 4, 32 * 4, kernel_size=3, stride=1, padding=1) + + self.seg3 = SegmentationLayer(32 * 4, num_classes) + self.upsample_seg3 = UpscalingLayer() + + def forward(self, x): + """ + Define the forward pass through the UNet2D model. + + Parameters: + - x (Tensor): Input tensor. + + Returns: + - Tensor: The output tensor after passing through the model. + """ + y1 = self.enc1(x) + x1 = self.context1(y1) + x1 = x1 + y1 + + y2 = self.enc2(x1) + x2 = self.context2(y2) + x2 = x2 + y2 + + y3 = self.enc3(x2) + x3 = self.context3(y3) + x3 = x3 + y3 + + y4 = self.enc4(x3) + x4 = self.context4(y4) + x4 = x4 + y4 + + # Bottleneck + bottleneck_conv = self.bottleneck(x4) + + bottleneck = self.bottleneck_context(bottleneck_conv) + bottleneck = bottleneck + bottleneck_conv + + up_bottleneck = self.up_bottleneck(bottleneck) + + # Decoder + x = self.local1(torch.cat((x4, up_bottleneck), dim=1)) + x = self.up1(x) + + x = self.local2(torch.cat((x3, x), dim=1)) + seg1 = self.seg1(x) + x = self.up2(x) + + seg1_upsampled = self.upsample_seg1(seg1) + + x = self.local3(torch.cat((x2, x), dim=1)) + seg2 = self.seg2(x) + x = self.up3(x) + + seg12 = seg1_upsampled + seg2 + seg12_up = self.upsample_seg2(seg12) + + x = self.final_conv(torch.cat((x1, x), dim=1)) + + seg3 = self.seg3(x) + seg123 = seg3 + seg12_up + + out = seg123 + # out = nn.functional.softmax(seg123, dim=1) + # out = torch.sigmoid(seg123) + # print("out shape: ", out.size()) + + return out + +# Updated \ No newline at end of file diff --git a/utils.py b/utils.py new file mode 100644 index 000000000..9f3b54559 --- /dev/null +++ b/utils.py @@ -0,0 +1,18 @@ +import matplotlib.pyplot as plt + + +def plot_img_and_mask(img, mask): + classes = mask.max() + 1 + fig, ax = plt.subplots(1, classes + 1) + ax[0].set_title('Input image') + ax[0].imshow(img) + for i in range(classes): + ax[i + 1].set_title(f'Mask (class {i + 1})') + ax[i + 1].imshow(mask == i) + plt.xticks([]), plt.yticks([]) + + + plt.show() + + +# Updated \ No newline at end of file From f6901bb85951e7f1c48f42944c5d2fdd620a73c1 Mon Sep 17 00:00:00 2001 From: FrostNov4 <97688822+FrostNov4@users.noreply.github.com> Date: Thu, 26 Oct 2023 04:32:19 +1000 Subject: [PATCH 15/45] File location update --- Data_Loader.py | 116 ++++++ Losses.py | 61 ++++ Metrics.py | 55 +++ unet_model.py => Modules.py | 0 Ploting.py | 207 +++++++++++ __init__.py | 2 +- data_loading.py | 121 ------- train.py | 685 +++++++++++++++++++++++------------- 8 files changed, 890 insertions(+), 357 deletions(-) create mode 100644 Data_Loader.py create mode 100644 Losses.py create mode 100644 Metrics.py rename unet_model.py => Modules.py (100%) create mode 100644 Ploting.py delete mode 100644 data_loading.py diff --git a/Data_Loader.py b/Data_Loader.py new file mode 100644 index 000000000..42df1a874 --- /dev/null +++ b/Data_Loader.py @@ -0,0 +1,116 @@ +from __future__ import print_function, division +import os +from PIL import Image +import torch +import torch.utils.data +import torchvision +from skimage import io +from torch.utils.data import Dataset +import random +import numpy as np + + +class Images_Dataset(Dataset): + """Class for getting data as a Dict + Args: + images_dir = path of input images + labels_dir = path of labeled images + transformI = Input Images transformation (default: None) + transformM = Input Labels transformation (default: None) + Output: + sample : Dict of images and labels""" + + def __init__(self, images_dir, labels_dir, transformI=None, transformM=None): + + self.labels_dir = labels_dir + self.images_dir = images_dir + self.transformI = transformI + self.transformM = transformM + + def __len__(self): + return len(self.images_dir) + + def __getitem__(self, idx): + + for i in range(len(self.images_dir)): + image = io.imread(self.images_dir[i]) + label = io.imread(self.labels_dir[i]) + if self.transformI: + image = self.transformI(image) + if self.transformM: + label = self.transformM(label) + sample = {'images': image, 'labels': label} + + return sample + + +class Images_Dataset_folder(torch.utils.data.Dataset): + """Class for getting individual transformations and data + Args: + images_dir = path of input images + labels_dir = path of labeled images + transformI = Input Images transformation (default: None) + transformM = Input Labels transformation (default: None) + Output: + tx = Transformed images + lx = Transformed labels""" + + def __init__(self, images_dir, labels_dir, transformI=None, transformM=None): + self.images = sorted(os.listdir(images_dir)) + self.labels = sorted(os.listdir(labels_dir)) + self.images_dir = images_dir + self.labels_dir = labels_dir + self.transformI = transformI + self.transformM = transformM + + if self.transformI: + self.tx = self.transformI + else: + self.tx = torchvision.transforms.Compose([ + torchvision.transforms.Resize((128, 128)), + # torchvision.transforms.CenterCrop(96), + # torchvision.transforms.RandomRotation((-10,10)), + # torchvision.transforms.RandomHorizontalFlip(), + # torchvision.transforms.ColorJitter(brightness=0.4, contrast=0.4, saturation=0.4), + torchvision.transforms.ToTensor(), + # torchvision.transforms.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5]) + ]) + + if self.transformM: + self.lx = self.transformM + else: + self.lx = torchvision.transforms.Compose([ + torchvision.transforms.Resize((128, 128)), + # torchvision.transforms.CenterCrop(96), + # torchvision.transforms.RandomRotation((-10,10)), + # torchvision.transforms.Grayscale(), + torchvision.transforms.ToTensor(), + # torchvision.transforms.Lambda(lambda x: torch.cat([x, 1 - x], dim=0)) + ]) + + def __len__(self): + + return len(self.images) + + def __getitem__(self, i): + i1 = Image.open(self.images_dir + self.images[i]).convert("RGB") + l1 = Image.open(self.labels_dir + self.labels[i]).convert("L") + # np_i1 = np.array(i1) + # np_l1 = np.array(l1) + # print(np_i1.shape) + # print(np_l1.shape) + + seed = np.random.randint(0, 2 ** 32) # make a seed with numpy generator + + # apply this seed to img tranfsorms + random.seed(seed) + torch.manual_seed(seed) + img = self.tx(i1) + + # apply this seed to target/label tranfsorms + random.seed(seed) + torch.manual_seed(seed) + label = self.lx(l1) + + return img, label + diff --git a/Losses.py b/Losses.py new file mode 100644 index 000000000..65813cf5c --- /dev/null +++ b/Losses.py @@ -0,0 +1,61 @@ +from __future__ import print_function, division +import torch.nn.functional as F + +# Implemented from https://github.com/bigmb/Unet-Segmentation-Pytorch-Nest-of-Unets +def dice_loss(prediction, target): + """Calculating the dice loss + Args: + prediction = predicted image + target = Targeted image + Output: + dice_loss""" + + smooth = 1.0 + + i_flat = prediction.view(-1) + t_flat = target.view(-1) + + intersection = (i_flat * t_flat).sum() + + return 1 - ((2. * intersection + smooth) / (i_flat.sum() + t_flat.sum() + smooth)) + + +def calc_loss(prediction, target, bce_weight=0.5): + """Calculating the loss and metrics + Args: + prediction = predicted image + target = Targeted image + metrics = Metrics printed + bce_weight = 0.5 (default) + Output: + loss : dice loss of the epoch """ + bce = F.binary_cross_entropy_with_logits(prediction, target) + prediction = F.sigmoid(prediction) + dice = dice_loss(prediction, target) + + loss = bce * bce_weight + dice * (1 - bce_weight) + + return loss + + +def threshold_predictions_v(predictions, thr=150): + thresholded_preds = predictions[:] + # hist = cv2.calcHist([predictions], [0], None, [2], [0, 2]) + # plt.plot(hist) + # plt.xlim([0, 2]) + # plt.show() + low_values_indices = thresholded_preds < thr + thresholded_preds[low_values_indices] = 0 + low_values_indices = thresholded_preds >= thr + thresholded_preds[low_values_indices] = 255 + return thresholded_preds + + +def threshold_predictions_p(predictions, thr=0.01): + thresholded_preds = predictions[:] + #hist = cv2.calcHist([predictions], [0], None, [256], [0, 256]) + low_values_indices = thresholded_preds < thr + thresholded_preds[low_values_indices] = 0 + low_values_indices = thresholded_preds >= thr + thresholded_preds[low_values_indices] = 1 + return thresholded_preds \ No newline at end of file diff --git a/Metrics.py b/Metrics.py new file mode 100644 index 000000000..233be8455 --- /dev/null +++ b/Metrics.py @@ -0,0 +1,55 @@ +# From https://github.com/bigmb/Unet-Segmentation-Pytorch-Nest-of-Unets + + +import numpy as np +from scipy import spatial + + +def dice_coeff(im1, im2, empty_score=1.0): + """Calculates the dice coefficient for the images""" + + im1 = np.asarray(im1).astype(np.bool) + im2 = np.asarray(im2).astype(np.bool) + + if im1.shape != im2.shape: + raise ValueError("Shape mismatch: im1 and im2 must have the same shape.") + + im1 = im1 > 0.5 + im2 = im2 > 0.5 + + im_sum = im1.sum() + im2.sum() + if im_sum == 0: + return empty_score + + # Compute Dice coefficient + intersection = np.logical_and(im1, im2) + #print(im_sum) + + return 2. * intersection.sum() / im_sum + + +def numeric_score(prediction, groundtruth): + """Computes scores: + FP = False Positives + FN = False Negatives + TP = True Positives + TN = True Negatives + return: FP, FN, TP, TN""" + + FP = np.float(np.sum((prediction == 1) & (groundtruth == 0))) + FN = np.float(np.sum((prediction == 0) & (groundtruth == 1))) + TP = np.float(np.sum((prediction == 1) & (groundtruth == 1))) + TN = np.float(np.sum((prediction == 0) & (groundtruth == 0))) + + return FP, FN, TP, TN + + +def accuracy_score(prediction, groundtruth): + """Getting the accuracy of the model""" + + FP, FN, TP, TN = numeric_score(prediction, groundtruth) + N = FP + FN + TP + TN + # accuracy = np.divide(TP + TN, N) + print("2*TP: ", 2*TP, "FP+2*TP+FN: ", FP+2*TP+FN) + accuracy = np.divide(2*TP, FP+2*TP+FN) + return accuracy #* 100.0 \ No newline at end of file diff --git a/unet_model.py b/Modules.py similarity index 100% rename from unet_model.py rename to Modules.py diff --git a/Ploting.py b/Ploting.py new file mode 100644 index 000000000..76aac1399 --- /dev/null +++ b/Ploting.py @@ -0,0 +1,207 @@ +import matplotlib.pyplot as plt +from matplotlib.lines import Line2D +import numpy as np +from visdom import Visdom + +def draw_loss(Loss_list,epoch,pic_name): + plt.cla() + x1 = [i for i in range(8)] + y1 = Loss_list + plt.title('Train loss vs. epoches', fontsize=1) + plt.plot(x1, y1, '.-') + plt.xlabel('epoches', fontsize=1) + plt.ylabel('Train loss', fontsize=1) + plt.grid() + plt.savefig(pic_name) + plt.show() + +def show_images(images, labels): + """Show image with label + Args: + images = input images + labels = input labels + Output: + plt = concatenated image and label """ + + plt.imshow(images.permute(1, 2, 0)) + plt.imshow(labels, alpha=0.7, cmap='gray') + plt.figure() + + +def show_training_dataset(training_dataset): + """Showing the images in training set for dict images and labels + Args: + training_dataset = dictionary of images and labels + Output: + figure = 3 images shown""" + + if training_dataset: + print(len(training_dataset)) + + for i in range(len(training_dataset)): + sample = training_dataset[i] + + print(i, sample['images'].shape, sample['labels'].shape) + + ax = plt.subplot(1, 4, i + 1) + plt.tight_layout() + ax.set_title('Sample #{}'.format(i)) + ax.axis('off') + show_images(sample['images'],sample['labels']) + + if i == 3: + plt.show() + break + +class VisdomLinePlotter(object): + + """Plots to Visdom""" + + def __init__(self, env_name='main'): + self.viz = Visdom() + self.env = env_name + self.plots = {} + + def plot(self, var_name, split_name, title_name, x, y): + if var_name not in self.plots: + self.plots[var_name] = self.viz.line(X=np.array([x,x]), Y=np.array([y,y]), env=self.env, opts=dict( + legend=[split_name], + title=title_name, + xlabel='Epochs', + ylabel=var_name + )) + else: + self.viz.line(X=np.array([x]), Y=np.array([y]), env=self.env, win=self.plots[var_name], name=split_name, update = 'append') + + +def input_images(x, y, i, n_iter, k=1): + """ + + :param x: takes input image + :param y: take input label + :param i: the epoch number + :param n_iter: + :param k: for keeping it in loop + :return: Returns a image and label + """ + if k == 1: + x1 = x + y1 = y + + x2 = x1.to('cpu') + y2 = y1.to('cpu') + x2 = x2.detach().numpy() + y2 = y2.detach().numpy() + + x3 = x2[1, 1, :, :] + y3 = y2[1, 0, :, :] + + fig = plt.figure() + + ax1 = fig.add_subplot(1, 2, 1) + ax1.imshow(x3) + ax1.axis('off') + ax1.set_xticklabels([]) + ax1.set_yticklabels([]) + ax1 = fig.add_subplot(1, 2, 2) + ax1.imshow(y3) + ax1.axis('off') + ax1.set_xticklabels([]) + ax1.set_yticklabels([]) + plt.savefig( + './model/pred/L_' + str(n_iter-1) + '_epoch_' + + str(i)) + + +def plot_kernels(tensor, n_iter, num_cols=5, cmap="gray"): + """Plotting the kernals and layers + Args: + Tensor :Input layer, + n_iter : number of interation, + num_cols : number of columbs required for figure + Output: + Gives the figure of the size decided with output layers activation map + + Default : Last layer will be taken into consideration + """ + if not len(tensor.shape) == 4: + raise Exception("assumes a 4D tensor") + + fig = plt.figure() + i = 0 + t = tensor.data.numpy() + b = 0 + a = 1 + + for t1 in t: + for t2 in t1: + i += 1 + + ax1 = fig.add_subplot(5, num_cols, i) + ax1.imshow(t2, cmap=cmap) + ax1.axis('off') + ax1.set_xticklabels([]) + ax1.set_yticklabels([]) + + if i == 1: + a = 1 + if a == 10: + break + a += 1 + if i % a == 0: + a = 0 + b += 1 + if b == 20: + break + + plt.savefig( + './model/pred/Kernal_' + str(n_iter - 1) + '_epoch_' + + str(i)) + + +class LayerActivations(): + """Getting the hooks on each layer""" + + features = None + + def __init__(self, layer): + self.hook = layer.register_forward_hook(self.hook_fn) + + def hook_fn(self, module, input, output): + self.features = output.cpu() + + def remove(self): + self.hook.remove() + + +#to get gradient flow +#From Pytorch-forums +def plot_grad_flow(named_parameters,n_iter): + + '''Plots the gradients flowing through different layers in the net during training. + Can be used for checking for possible gradient vanishing / exploding problems. + + Usage: Plug this function in Trainer class after loss.backwards() as + "plot_grad_flow(self.model.named_parameters())" to visualize the gradient flow''' + ave_grads = [] + max_grads = [] + layers = [] + for n, p in named_parameters: + if (p.requires_grad) and ("bias" not in n): + layers.append(n) + ave_grads.append(p.grad.abs().mean()) + max_grads.append(p.grad.abs().max()) + plt.bar(np.arange(len(max_grads)), max_grads, alpha=0.1, lw=1, color="c") + plt.bar(np.arange(len(max_grads)), ave_grads, alpha=0.1, lw=1, color="b") + plt.hlines(0, 0, len(ave_grads) + 1, lw=2, color="k") + plt.xticks(range(0, len(ave_grads), 1), layers, rotation="vertical") + plt.xlim(left=0, right=len(ave_grads)) + plt.ylim(bottom=-0.001, top=0.02) # zoom in on the lower gradient regions + plt.xlabel("Layers") + plt.ylabel("average gradient") + plt.title("Gradient flow") + plt.grid(True) + plt.legend([Line2D([0], [0], color="c", lw=4), + Line2D([0], [0], color="b", lw=4), + Line2D([0], [0], color="k", lw=4)], ['max-gradient', 'mean-gradient', 'zero-gradient']) + #plt.savefig('./model/pred/Grad_Flow_' + str(n_iter - 1)) diff --git a/__init__.py b/__init__.py index 2cf6a655c..279eecc85 100644 --- a/__init__.py +++ b/__init__.py @@ -1,3 +1,3 @@ -from .unet_model import UNet +from .Modules import UNet diff --git a/data_loading.py b/data_loading.py deleted file mode 100644 index 0ea6027c5..000000000 --- a/data_loading.py +++ /dev/null @@ -1,121 +0,0 @@ -import logging -import numpy as np -import torch -from PIL import Image -from functools import lru_cache -from functools import partial -from itertools import repeat -from multiprocessing import Pool -from os import listdir -from os.path import splitext, isfile, join -from pathlib import Path -from torch.utils.data import Dataset -from tqdm import tqdm -# Updated -def load_image(filename): - ext = splitext(filename)[1] - if ext == '.npy': - return Image.fromarray(np.load(filename)) - elif ext in ['.pt', '.pth']: - return Image.fromarray(torch.load(filename).numpy()) - else: - return Image.open(filename) - - -def unique_mask_values(idx, mask_dir, mask_suffix): - mask_file = list(mask_dir.glob(idx + mask_suffix + '.*'))[0] - mask = np.asarray(load_image(mask_file)) - if mask.ndim == 2: - return np.unique(mask) - elif mask.ndim == 3: - mask = mask.reshape(-1, mask.shape[-1]) - return np.unique(mask, axis=0) - else: - raise ValueError(f'Loaded masks should have 2 or 3 dimensions, found {mask.ndim}') - - -class BasicDataset(Dataset): - def __init__(self, images_dir: str, mask_dir: str, scale: float = 1.0, mask_suffix: str = ''): - self.images_dir = Path(images_dir) - self.mask_dir = Path(mask_dir) - assert 0 < scale <= 1, 'Scale must be between 0 and 1' - self.scale = scale - self.mask_suffix = mask_suffix - - self.ids = [splitext(file)[0] for file in listdir(images_dir) if isfile(join(images_dir, file)) and not file.startswith('.')] - if not self.ids: - raise RuntimeError(f'No input file found in {images_dir}, make sure you put your images there') - - logging.info(f'Creating dataset with {len(self.ids)} examples') - logging.info('Scanning mask files to determine unique values') - with Pool() as p: - unique = list(tqdm( - p.imap(partial(unique_mask_values, mask_dir=self.mask_dir, mask_suffix=self.mask_suffix), self.ids), - total=len(self.ids) - )) - - self.mask_values = list(sorted(np.unique(np.concatenate(unique), axis=0).tolist())) - logging.info(f'Unique mask values: {self.mask_values}') - - def __len__(self): - return len(self.ids) - - @staticmethod - def preprocess(mask_values, pil_img, scale, is_mask): - w, h = pil_img.size - newW, newH = int(scale * w), int(scale * h) - assert newW > 0 and newH > 0, 'Scale is too small, resized images would have no pixel' - pil_img = pil_img.resize((newW, newH), resample=Image.NEAREST if is_mask else Image.BICUBIC) - img = np.asarray(pil_img) - - if is_mask: - mask = np.zeros((newH, newW), dtype=np.int64) - for i, v in enumerate(mask_values): - if img.ndim == 2: - mask[img == v] = i - else: - mask[(img == v).all(-1)] = i - - return mask - - else: - if img.ndim == 2: - img = img[np.newaxis, ...] - else: - img = img.transpose((2, 0, 1)) - - if (img > 1).any(): - img = img / 255.0 - - return img - - def __getitem__(self, idx): - name = self.ids[idx] - mask_file = list(self.mask_dir.glob(name + self.mask_suffix + '.*')) - img_file = list(self.images_dir.glob(name + '.*')) - - assert len(img_file) == 1, f'Either no image or multiple images found for the ID {name}: {img_file}' - assert len(mask_file) == 1, f'Either no mask or multiple masks found for the ID {name}: {mask_file}' - mask = load_image(mask_file[0]) - img = load_image(img_file[0]) - - assert img.size == mask.size, \ - f'Image and mask {name} should be the same size, but are {img.size} and {mask.size}' - - img = self.preprocess(self.mask_values, img, self.scale, is_mask=False) - mask = self.preprocess(self.mask_values, mask, self.scale, is_mask=True) - - return { - 'image': torch.as_tensor(img.copy()).float().contiguous(), - 'mask': torch.as_tensor(mask.copy()).long().contiguous() - } - - -class CarvanaDataset(BasicDataset): - def __init__(self, images_dir, mask_dir, scale=1): - super().__init__(images_dir, mask_dir, scale, mask_suffix='_mask') - - -class ISICDataset(BasicDataset): - def __init__(self, images_dir, mask_dir, scale=1): - super().__init__(images_dir, mask_dir, scale, mask_suffix="_segmentation") diff --git a/train.py b/train.py index 5793fc0b8..19b0f3ff2 100644 --- a/train.py +++ b/train.py @@ -1,238 +1,453 @@ -import argparse -import logging +from __future__ import print_function, division import os -import random -import sys +import numpy as np +from PIL import Image +import glob +# import SimpleITK as sitk +from torch import optim +import torch.utils.data import torch -import torch.nn as nn import torch.nn.functional as F -import torchvision.transforms as transforms -import torchvision.transforms.functional as TF -from pathlib import Path -from torch import optim -from torch.utils.data import DataLoader, random_split -from tqdm import tqdm - -import wandb -from evaluate import evaluate -from unet import UNet -from utils.data_loading import BasicDataset, CarvanaDataset -from utils.dice_score import dice_loss - -dir_img = Path('./data/imgs/') -dir_mask = Path('./data/masks/') -dir_checkpoint = Path('./checkpoints/') - - -def train_model( - model, - device, - epochs: int = 5, - batch_size: int = 1, - learning_rate: float = 1e-5, - val_percent: float = 0.1, - save_checkpoint: bool = True, - img_scale: float = 0.5, - amp: bool = False, - weight_decay: float = 1e-8, - momentum: float = 0.999, - gradient_clipping: float = 1.0, -): - # 1. Create dataset - try: - dataset = CarvanaDataset(dir_img, dir_mask, img_scale) - except (AssertionError, RuntimeError, IndexError): - dataset = BasicDataset(dir_img, dir_mask, img_scale) - - # 2. Split into train / validation partitions - n_val = int(len(dataset) * val_percent) - n_train = len(dataset) - n_val - train_set, val_set = random_split(dataset, [n_train, n_val], generator=torch.Generator().manual_seed(0)) - - # 3. Create data loaders - loader_args = dict(batch_size=batch_size, num_workers=os.cpu_count(), pin_memory=True) - train_loader = DataLoader(train_set, shuffle=True, **loader_args) - val_loader = DataLoader(val_set, shuffle=False, drop_last=True, **loader_args) - - # (Initialize logging) - experiment = wandb.init(project='U-Net', resume='allow', anonymous='must') - experiment.config.update( - dict(epochs=epochs, batch_size=batch_size, learning_rate=learning_rate, - val_percent=val_percent, save_checkpoint=save_checkpoint, img_scale=img_scale, amp=amp) - ) - - logging.info(f'''Starting training: - Epochs: {epochs} - Batch size: {batch_size} - Learning rate: {learning_rate} - Training size: {n_train} - Validation size: {n_val} - Checkpoints: {save_checkpoint} - Device: {device.type} - Images scaling: {img_scale} - Mixed Precision: {amp} - ''') - - # 4. Set up the optimizer, the loss, the learning rate scheduler and the loss scaling for AMP - optimizer = optim.RMSprop(model.parameters(), - lr=learning_rate, weight_decay=weight_decay, momentum=momentum, foreach=True) - scheduler = optim.lr_scheduler.ReduceLROnPlateau(optimizer, 'max', patience=5) # goal: maximize Dice score - grad_scaler = torch.cuda.amp.GradScaler(enabled=amp) - criterion = nn.CrossEntropyLoss() if model.n_classes > 1 else nn.BCEWithLogitsLoss() - global_step = 0 - - # 5. Begin training - for epoch in range(1, epochs + 1): - model.train() - epoch_loss = 0 - with tqdm(total=n_train, desc=f'Epoch {epoch}/{epochs}', unit='img') as pbar: - for batch in train_loader: - images, true_masks = batch['image'], batch['mask'] - - assert images.shape[1] == model.n_channels, \ - f'Network has been defined with {model.n_channels} input channels, ' \ - f'but loaded images have {images.shape[1]} channels. Please check that ' \ - 'the images are loaded correctly.' - - images = images.to(device=device, dtype=torch.float32, memory_format=torch.channels_last) - true_masks = true_masks.to(device=device, dtype=torch.long) - - with torch.autocast(device.type if device.type != 'mps' else 'cpu', enabled=amp): - masks_pred = model(images) - if model.n_classes == 1: - loss = criterion(masks_pred.squeeze(1), true_masks.float()) - loss += dice_loss(F.sigmoid(masks_pred.squeeze(1)), true_masks.float(), multiclass=False) - else: - loss = criterion(masks_pred, true_masks) - loss += dice_loss( - F.softmax(masks_pred, dim=1).float(), - F.one_hot(true_masks, model.n_classes).permute(0, 3, 1, 2).float(), - multiclass=True - ) - - optimizer.zero_grad(set_to_none=True) - grad_scaler.scale(loss).backward() - torch.nn.utils.clip_grad_norm_(model.parameters(), gradient_clipping) - grad_scaler.step(optimizer) - grad_scaler.update() - - pbar.update(images.shape[0]) - global_step += 1 - epoch_loss += loss.item() - experiment.log({ - 'train loss': loss.item(), - 'step': global_step, - 'epoch': epoch - }) - pbar.set_postfix(**{'loss (batch)': loss.item()}) - - # Evaluation round - division_step = (n_train // (5 * batch_size)) - if division_step > 0: - if global_step % division_step == 0: - histograms = {} - for tag, value in model.named_parameters(): - tag = tag.replace('/', '.') - if not (torch.isinf(value) | torch.isnan(value)).any(): - histograms['Weights/' + tag] = wandb.Histogram(value.data.cpu()) - if not (torch.isinf(value.grad) | torch.isnan(value.grad)).any(): - histograms['Gradients/' + tag] = wandb.Histogram(value.grad.data.cpu()) - - val_score = evaluate(model, val_loader, device, amp) - scheduler.step(val_score) - - logging.info('Validation Dice score: {}'.format(val_score)) - try: - experiment.log({ - 'learning rate': optimizer.param_groups[0]['lr'], - 'validation Dice': val_score, - 'images': wandb.Image(images[0].cpu()), - 'masks': { - 'true': wandb.Image(true_masks[0].float().cpu()), - 'pred': wandb.Image(masks_pred.argmax(dim=1)[0].float().cpu()), - }, - 'step': global_step, - 'epoch': epoch, - **histograms - }) - except: - pass - - if save_checkpoint: - Path(dir_checkpoint).mkdir(parents=True, exist_ok=True) - state_dict = model.state_dict() - state_dict['mask_values'] = dataset.mask_values - torch.save(state_dict, str(dir_checkpoint / 'checkpoint_epoch{}.pth'.format(epoch))) - logging.info(f'Checkpoint {epoch} saved!') - - -def get_args(): - parser = argparse.ArgumentParser(description='Train the UNet on images and target masks') - parser.add_argument('--epochs', '-e', metavar='E', type=int, default=5, help='Number of epochs') - parser.add_argument('--batch-size', '-b', dest='batch_size', metavar='B', type=int, default=1, help='Batch size') - parser.add_argument('--learning-rate', '-l', metavar='LR', type=float, default=1e-5, - help='Learning rate', dest='lr') - parser.add_argument('--load', '-f', type=str, default=False, help='Load model from a .pth file') - parser.add_argument('--scale', '-s', type=float, default=0.5, help='Downscaling factor of the images') - parser.add_argument('--validation', '-v', dest='val', type=float, default=10.0, - help='Percent of the data that is used as validation (0-100)') - parser.add_argument('--amp', action='store_true', default=False, help='Use mixed precision') - parser.add_argument('--bilinear', action='store_true', default=False, help='Use bilinear upsampling') - parser.add_argument('--classes', '-c', type=int, default=2, help='Number of classes') - - return parser.parse_args() - - -if __name__ == '__main__': - args = get_args() - - logging.basicConfig(level=logging.INFO, format='%(levelname)s: %(message)s') - device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') - logging.info(f'Using device {device}') - - # Change here to adapt to your data - # n_channels=3 for RGB images - # n_classes is the number of probabilities you want to get per pixel - model = UNet(n_channels=3, n_classes=args.classes, bilinear=args.bilinear) - model = model.to(memory_format=torch.channels_last) - - logging.info(f'Network:\n' - f'\t{model.n_channels} input channels\n' - f'\t{model.n_classes} output channels (classes)\n' - f'\t{"Bilinear" if model.bilinear else "Transposed conv"} upscaling') - - if args.load: - state_dict = torch.load(args.load, map_location=device) - del state_dict['mask_values'] - model.load_state_dict(state_dict) - logging.info(f'Model loaded from {args.load}') - - model.to(device=device) - try: - train_model( - model=model, - epochs=args.epochs, - batch_size=args.batch_size, - learning_rate=args.lr, - device=device, - img_scale=args.scale, - val_percent=args.val / 100, - amp=args.amp - ) - except torch.cuda.OutOfMemoryError: - logging.error('Detected OutOfMemoryError! ' - 'Enabling checkpointing to reduce memory usage, but this slows down training. ' - 'Consider enabling AMP (--amp) for fast and memory efficient training') - torch.cuda.empty_cache() - model.use_checkpointing() - train_model( - model=model, - epochs=args.epochs, - batch_size=args.batch_size, - learning_rate=args.lr, - device=device, - img_scale=args.scale, - val_percent=args.val / 100, - amp=args.amp - - ) + +import torch.nn +import torchvision +import matplotlib.pyplot as plt +import natsort +from torch.utils.data.sampler import SubsetRandomSampler +from Data_Loader import Images_Dataset, Images_Dataset_folder +import torchsummary +# from torch.utils.tensorboard import SummaryWriter +# from tensorboardX import SummaryWriter + +import shutil +import random +from Modules import UNet_For_Brain +from Losses import calc_loss, dice_loss, threshold_predictions_v, threshold_predictions_p +from Ploting import plot_kernels, LayerActivations, input_images, plot_grad_flow, draw_loss +from Metrics import dice_coeff, accuracy_score +import time + +# from ploting import VisdomLinePlotter +# from visdom import Visdom + + +####################################################### +# Checking if GPU is used +####################################################### + +train_on_gpu = torch.cuda.is_available() + +if not train_on_gpu: + print('CUDA is not available. Training on CPU') +else: + print('CUDA is available. Training on GPU') + +# os.environ['CUDA_VISIBLE_DEVICES'] = '1,2,3,4' +device = torch.device("cuda:0" if train_on_gpu else "cpu") + +####################################################### +# Setting the basic paramters of the model +####################################################### + +batch_size = 16 +print('batch_size = ' + str(batch_size)) + +valid_size = 0.15 + +epoch = 400 +print('epoch = ' + str(epoch)) + +random_seed = random.randint(1, 100) +print('random_seed = ' + str(random_seed)) + +shuffle = True +valid_loss_min = np.Inf +num_workers = 24 +lossT = [] +lossL = [] +lossL.append(np.inf) +lossT.append(np.inf) +epoch_valid = epoch - 2 +n_iter = 1 +i_valid = 0 + +pin_memory = False +if train_on_gpu: + pin_memory = True + +# plotter = VisdomLinePlotter(env_name='Tutorial Plots') + +####################################################### +# Setting up the model +####################################################### + +model_Inputs = [UNet_For_Brain] + + +def model_unet(model_input, in_channel=1, out_channel=1): + model_test = model_input(in_channel, out_channel) + return model_test + + +# passsing this string so that if it's AttU_Net or R2ATTU_Net it doesn't throw an error at torchSummary + + +model_test = model_unet(model_Inputs[-1], 3, 1) + +model_test.to(device) + +####################################################### +# Getting the Summary of Model +####################################################### + +torchsummary.summary(model_test, input_size=(3, 128, 128)) + +####################################################### +# Passing the Dataset of Images and Labels +####################################################### + + +#ISIC2018 data +t_data = './ISIC2018/ISIC2018_Task1-2_Training_Input_x2/' +l_data = './ISIC2018/ISIC2018_Task1_Training_GroundTruth_x2/' +test_image = './keras_png_slices_data/keras_png_slices_test/' +test_label = './keras_png_slices_data/keras_png_slices_seg_test/' +test_folderP = './ISIC2018/ISIC2018_Task1-2_Training_Input_x2/*' +test_folderL = './ISIC2018/ISIC2018_Task1_Training_GroundTruth_x2/*' +valid_image = './ISIC2018/ISIC2018_Task1-2_Training_Input_x2/' +valid_lable = './ISIC2018/ISIC2018_Task1_Training_GroundTruth_x2/' + +Training_Data = Images_Dataset_folder(t_data, l_data) + +Validing_Data = Images_Dataset_folder(valid_image, valid_lable) + +####################################################### +# Giving a transformation for input data +####################################################### + +data_transform = torchvision.transforms.Compose([ + torchvision.transforms.Resize((128, 128)), + # torchvision.transforms.CenterCrop(96), + torchvision.transforms.ToTensor(), + # torchvision.transforms.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5]) +]) + +####################################################### +# Trainging Validation Split +####################################################### + +num_train = len(Training_Data) +indices_train = list(range(num_train)) +# split = int(np.floor(valid_size * num_train)) + +num_valid = len(Validing_Data) +indices_valid = list(range(num_valid)) + +if shuffle: + np.random.seed(random_seed) + np.random.shuffle(indices_train) + np.random.shuffle(indices_valid) + +# train_idx, valid_idx = indices[split:], indices[:split] +train_idx, valid_idx = indices_train, indices_valid +train_sampler = SubsetRandomSampler(train_idx) +valid_sampler = SubsetRandomSampler(valid_idx) + +train_loader = torch.utils.data.DataLoader(Training_Data, batch_size=batch_size, sampler=train_sampler, + num_workers=num_workers, pin_memory=pin_memory, ) + +valid_loader = torch.utils.data.DataLoader(Validing_Data, batch_size=batch_size, sampler=valid_sampler, + num_workers=num_workers, pin_memory=pin_memory, ) + +####################################################### +# Using Adam as Optimizer +####################################################### +# Hyper Parameters +initial_lr = 5e-4 +lr_decay = 0.985 +l2_weight_decay = 1e-5 +# initial_lr = 0.001 +# opt = torch.optim.Adam(model_test.parameters(), lr=initial_lr) # try SGD +# # opt = optim.SGD(model_test.parameters(), lr = initial_lr, momentum=0.99) + +# MAX_STEP = int(1e10) +# eta_min = 1e-2 +# scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(opt, MAX_STEP, eta_min=1e-5) + +# Optimisation & Loss Settings +opt = optim.Adam(model_test.parameters(), lr=initial_lr, weight_decay=l2_weight_decay) +scheduler = optim.lr_scheduler.ExponentialLR(optimizer=opt, gamma=lr_decay) + +New_folder = './model' + +if os.path.exists(New_folder) and os.path.isdir(New_folder): + shutil.rmtree(New_folder) + +try: + os.mkdir(New_folder) +except OSError: + print("Creation of the main directory '%s' failed " % New_folder) +else: + print("Successfully created the main directory '%s' " % New_folder) + +####################################################### +# Setting the folder of saving the predictions +####################################################### + +read_pred = './model/pred' + +####################################################### +# Checking if prediction folder exixts +####################################################### + +if os.path.exists(read_pred) and os.path.isdir(read_pred): + shutil.rmtree(read_pred) + +try: + os.mkdir(read_pred) +except OSError: + print("Creation of the prediction directory '%s' failed of dice loss" % read_pred) +else: + print("Successfully created the prediction directory '%s' of dice loss" % read_pred) + +####################################################### +# checking if the model exists and if true then delete +####################################################### + +read_model_path = './model/Unet_D_' + str(epoch) + '_' + str(batch_size) + +if os.path.exists(read_model_path) and os.path.isdir(read_model_path): + shutil.rmtree(read_model_path) + print('Model folder there, so deleted for newer one') + +try: + os.mkdir(read_model_path) +except OSError: + print("Creation of the model directory '%s' failed" % read_model_path) +else: + print("Successfully created the model directory '%s' " % read_model_path) + +####################################################### +# Training loop +####################################################### + +for i in range(epoch): + + train_loss = 0.0 + valid_loss = 0.0 + train_loss_list = [] + valid_loss_list = [] + since = time.time() + scheduler.step() + # lr = scheduler.get_lr() + + ####################################################### + # Training Data + ####################################################### + + model_test.train() + k = 1 + + for x, y in train_loader: + # print("x: ", x.shape) + # print("y: ", y.shape) + x, y = x.to(device), y.to(device) + + opt.zero_grad() + + y_pred = model_test(x) + lossT = calc_loss(y_pred, y) # Dice_loss Used + + train_loss += lossT.item() * x.size(0) + lossT.backward() + opt.step() + x_size = lossT.item() * x.size(0) + k = 2 + + train_loss_list.append(train_loss) + + ####################################################### + # Validation Step + ####################################################### + + model_test.eval() + torch.no_grad() # to increase the validation process uses less memory + + for x1, y1 in valid_loader: + x1, y1 = x1.to(device), y1.to(device) + + y_pred1 = model_test(x1) + lossL = calc_loss(y_pred1, y1) # Dice_loss Used + + valid_loss += lossL.item() * x1.size(0) + x_size1 = lossL.item() * x1.size(0) + + valid_loss_list.append(valid_loss) + + if (i + 1) % 1 == 0: + print('Epoch: {}/{} \tTraining Loss: {:.6f} \tValidation Loss: {:.6f}'.format(i + 1, epoch, train_loss, + valid_loss)) + ####################################################### + # Early Stopping + ####################################################### + + if valid_loss <= valid_loss_min and epoch_valid >= i: # and i_valid <= 2: + + print('Validation loss decreased ({:.6f} --> {:.6f}). Saving model '.format(valid_loss_min, valid_loss)) + torch.save(model_test.state_dict(), './model/Unet_D_' + + str(epoch) + '_' + str(batch_size) + '/Unet_epoch_' + str(epoch) + + '_batchsize_' + str(batch_size) + '.pth') + + if round(valid_loss, 4) == round(valid_loss_min, 4): + print(i_valid) + i_valid = i_valid + 1 + valid_loss_min = valid_loss + +if torch.cuda.is_available(): + torch.cuda.empty_cache() + +####################################################### +# Loading the model +####################################################### + +model_test.load_state_dict(torch.load('./model/Unet_D_' + + str(epoch) + '_' + str(batch_size) + '/Unet_epoch_' + str(epoch) + + '_batchsize_' + str(batch_size) + '.pth')) + +model_test.eval() + +####################################################### +# opening the test folder and creating a folder for generated images +####################################################### + +read_test_folder = glob.glob(test_folderP) +x_sort_test = natsort.natsorted(read_test_folder) # To sort + +read_test_folder112 = './model/gen_images' + +if os.path.exists(read_test_folder112) and os.path.isdir(read_test_folder112): + shutil.rmtree(read_test_folder112) + +try: + os.mkdir(read_test_folder112) +except OSError: + print("Creation of the testing directory %s failed" % read_test_folder112) +else: + print("Successfully created the testing directory %s " % read_test_folder112) + +# For Prediction Threshold + +read_test_folder_P_Thres = './model/pred_threshold' + +if os.path.exists(read_test_folder_P_Thres) and os.path.isdir(read_test_folder_P_Thres): + shutil.rmtree(read_test_folder_P_Thres) + +try: + os.mkdir(read_test_folder_P_Thres) +except OSError: + print("Creation of the testing directory %s failed" % read_test_folder_P_Thres) +else: + print("Successfully created the testing directory %s " % read_test_folder_P_Thres) + +# For Label Threshold + +read_test_folder_L_Thres = './model/label_threshold' + +if os.path.exists(read_test_folder_L_Thres) and os.path.isdir(read_test_folder_L_Thres): + shutil.rmtree(read_test_folder_L_Thres) + +try: + os.mkdir(read_test_folder_L_Thres) +except OSError: + print("Creation of the testing directory %s failed" % read_test_folder_L_Thres) +else: + print("Successfully created the testing directory %s " % read_test_folder_L_Thres) + +####################################################### +# saving the images in the files +####################################################### + +img_test_no = 0 + +for i in range(len(read_test_folder)): + im = Image.open(x_sort_test[i]).convert("RGB") + + im1 = im + im_n = np.array(im1) + im_n_flat = im_n.reshape(-1, 1) + + for j in range(im_n_flat.shape[0]): + if im_n_flat[j] != 0: + im_n_flat[j] = 255 + + s = data_transform(im) + pred = model_test(s.unsqueeze(0).cuda()).cpu() + pred = F.sigmoid(pred) + pred = pred.detach().numpy() + + # pred = threshold_predictions_p(pred) #Value kept 0.01 as max is 1 and noise is very small. + + if i % 24 == 0: + img_test_no = img_test_no + 1 + + x1 = plt.imsave('./model/gen_images/im_epoch_' + str(epoch) + 'int_' + str(i) + + '_img_no_' + str(img_test_no) + '.png', pred[0][0], cmap='gray') + +#################################################### +# Calculating the Dice Score +#################################################### + +data_transform = torchvision.transforms.Compose([ + torchvision.transforms.Resize((128, 128)), + # torchvision.transforms.CenterCrop(96), + torchvision.transforms.Grayscale(), + # torchvision.transforms.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5]) +]) + +read_test_folderP = glob.glob('./model/gen_images/*') +x_sort_testP = natsort.natsorted(read_test_folderP) + +read_test_folderL = glob.glob(test_folderL) +x_sort_testL = natsort.natsorted(read_test_folderL) # To sort + +dice_score123 = 0.0 +x_count = 0 +x_dice = 0 + +for i in range(len(read_test_folderP)): + + x = Image.open(x_sort_testP[i]).convert("L") + s = data_transform(x) + s = np.array(s) + s = threshold_predictions_v(s) + # print(s) + # print("------------------") + + # save the images + x1 = plt.imsave('./model/pred_threshold/im_epoch_' + str(epoch) + 'int_' + str(i) + + '_img_no_' + str(img_test_no) + '.png', s) + + y = Image.open(x_sort_testL[i]).convert("L") + s2 = data_transform(y) + s3 = np.array(s2) + s2 = threshold_predictions_v(s2) + # print(s3) + + # save the Images + y1 = plt.imsave('./model/label_threshold/im_epoch_' + str(epoch) + 'int_' + str(i) + + '_img_no_' + str(img_test_no) + '.png', s3) + + total = dice_coeff(s, s3) + print(total) + + if total <= 0.8: + x_count += 1 + if total > 0.8: + x_dice = x_dice + total + dice_score123 = dice_score123 + total + +# print('Dice Score : ' + str(dice_score123/len(read_test_folderP))) +print(x_count) +print(x_dice) +print('Dice Score : ' + str(float(x_dice / (len(read_test_folderP) - x_count)))) + From 4afb3db9e61b166a29a5df029855dd98cdb95af6 Mon Sep 17 00:00:00 2001 From: FrostNov4 <97688822+FrostNov4@users.noreply.github.com> Date: Thu, 26 Oct 2023 04:36:11 +1000 Subject: [PATCH 16/45] Update training function including Losses, Matrices and Ploting --- Losses.py | 3 +-- Metrics.py | 1 + Ploting.py | 1 + train.py | 2 ++ 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Losses.py b/Losses.py index 65813cf5c..afbc7c3f3 100644 --- a/Losses.py +++ b/Losses.py @@ -1,7 +1,6 @@ +# From https://github.com/bigmb/Unet-Segmentation-Pytorch-Nest-of-Unets from __future__ import print_function, division import torch.nn.functional as F - -# Implemented from https://github.com/bigmb/Unet-Segmentation-Pytorch-Nest-of-Unets def dice_loss(prediction, target): """Calculating the dice loss Args: diff --git a/Metrics.py b/Metrics.py index 233be8455..a0f7c5d43 100644 --- a/Metrics.py +++ b/Metrics.py @@ -1,6 +1,7 @@ # From https://github.com/bigmb/Unet-Segmentation-Pytorch-Nest-of-Unets + import numpy as np from scipy import spatial diff --git a/Ploting.py b/Ploting.py index 76aac1399..0fded5035 100644 --- a/Ploting.py +++ b/Ploting.py @@ -3,6 +3,7 @@ import numpy as np from visdom import Visdom + def draw_loss(Loss_list,epoch,pic_name): plt.cla() x1 = [i for i in range(8)] diff --git a/train.py b/train.py index 19b0f3ff2..e121b06c0 100644 --- a/train.py +++ b/train.py @@ -1,3 +1,4 @@ +# From https://github.com/bigmb/Unet-Segmentation-Pytorch-Nest-of-Unets from __future__ import print_function, division import os import numpy as np @@ -19,6 +20,7 @@ # from torch.utils.tensorboard import SummaryWriter # from tensorboardX import SummaryWriter + import shutil import random from Modules import UNet_For_Brain From a08b86b799a0f921c2ee3f74b9a2bea41385a043 Mon Sep 17 00:00:00 2001 From: FrostNov4 <97688822+FrostNov4@users.noreply.github.com> Date: Thu, 26 Oct 2023 22:04:17 +1000 Subject: [PATCH 17/45] Update README,train --- README.md | 40 ++++++++++++++++++++++++++++------------ train.py | 4 +--- 2 files changed, 29 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 07dab1014..5a62afec2 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,31 @@ -COMP_3710_Report - -Medical condition, Extended to 27 OCT - -This report is focused on the first task (a) - -Segment the ISIC data set with the Improved UNet -with all labels having a minimum Dice similarity coefficient of 0.8 on the test set. - -The structure of Improved UNet is based on the paper. -"Brain Tumor Segmentation and Radiomics Survival Prediction: Contribution to the BRATS 2017 Challenge" -https://arxiv.org/abs/1802.10508v1 +## COMP_3710_Report + +## Medical condition, Extended to 27 OCT + +## This report is focused on the first task (a) + Segment the ISIC data set with the Improved UNet + with all labels having a minimum Dice similarity coefficient of 0.8 on the test set. + +## The structure of Improved UNet is based on the paper. + "Brain Tumor Segmentation and Radiomics Survival Prediction: Contribution to the BRATS 2017 Challenge" + https://arxiv.org/abs/1802.10508v1 + + U-Net is a convolutional neural network architecture primarily used for biomedical image segmentation. + Its U-shaped structure consists of a contracting path, which captures context, and an expansive path, + which enables precise localization. Through skip connections, features from the contracting path are concatenated + with the expansive path, enhancing localization capabilities. + +## Dataset + In this report, the ISIC 2018 dataset will be used. + The ISIC 2018 dataset is a publicly available dataset for skin lesion image segmentation, + provided by the International Skin Imaging Collaboration (ISIC). Given that the real-world + images in the dataset come in different sizes, they are uniformly resized to a 128x128 dimension. + These images use RGB with 3 color channels for input. The label data, which indicates where the lesions are, + is treated in the same way as the real data. However, these labels are input as grayscale images with a single channel, + making them simpler and more focused on the lesion's location and shape. + +## Model + diff --git a/train.py b/train.py index e121b06c0..6d51bfe13 100644 --- a/train.py +++ b/train.py @@ -91,8 +91,6 @@ def model_unet(model_input, in_channel=1, out_channel=1): return model_test -# passsing this string so that if it's AttU_Net or R2ATTU_Net it doesn't throw an error at torchSummary - model_test = model_unet(model_Inputs[-1], 3, 1) @@ -109,7 +107,7 @@ def model_unet(model_input, in_channel=1, out_channel=1): ####################################################### -#ISIC2018 data +# ISIC2018 data t_data = './ISIC2018/ISIC2018_Task1-2_Training_Input_x2/' l_data = './ISIC2018/ISIC2018_Task1_Training_GroundTruth_x2/' test_image = './keras_png_slices_data/keras_png_slices_test/' From 49fb68bc1669b772933221477408a54ff4449b32 Mon Sep 17 00:00:00 2001 From: "Shakes (WhiteOut)" Date: Sun, 17 Sep 2023 21:47:51 +1000 Subject: [PATCH 18/45] Added recognition branch and README for info. --- recognition/README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 recognition/README.md diff --git a/recognition/README.md b/recognition/README.md new file mode 100644 index 000000000..5c646231c --- /dev/null +++ b/recognition/README.md @@ -0,0 +1,10 @@ +# Recognition Tasks +Various recognition tasks solved in deep learning frameworks. + +Tasks may include: +* Image Segmentation +* Object detection +* Graph node classification +* Image super resolution +* Disease classification +* Generative modelling with StyleGAN and Stable Diffusion From 35aafc356bf2f5ab7ad2d9c8859e32e472880c5f Mon Sep 17 00:00:00 2001 From: FrostNov4 <97688822+FrostNov4@users.noreply.github.com> Date: Thu, 26 Oct 2023 22:08:24 +1000 Subject: [PATCH 19/45] Update move files --- recognition/__init__.py | 0 .../s4627182_Improved_Unet/Data_Loader.py | 0 .../s4627182_Improved_Unet/LICENSE | 0 .../s4627182_Improved_Unet/Losses.py | 0 .../s4627182_Improved_Unet/Metrics.py | 0 .../s4627182_Improved_Unet/Modules.py | 0 .../s4627182_Improved_Unet/Ploting.py | 0 .../s4627182_Improved_Unet/README.md | 0 .../s4627182_Improved_Unet/__init__.py | 0 .../s4627182_Improved_Unet/dice_score.py | 0 .../s4627182_Improved_Unet/evaluate.py | 0 .../s4627182_Improved_Unet/predict.py | 0 .../s4627182_Improved_Unet/requirements.txt | 0 .../s4627182_Improved_Unet/train.py | 0 .../s4627182_Improved_Unet/utils.py | 34 +++++++++---------- 15 files changed, 17 insertions(+), 17 deletions(-) create mode 100644 recognition/__init__.py rename Data_Loader.py => recognition/s4627182_Improved_Unet/Data_Loader.py (100%) rename LICENSE => recognition/s4627182_Improved_Unet/LICENSE (100%) rename Losses.py => recognition/s4627182_Improved_Unet/Losses.py (100%) rename Metrics.py => recognition/s4627182_Improved_Unet/Metrics.py (100%) rename Modules.py => recognition/s4627182_Improved_Unet/Modules.py (100%) rename Ploting.py => recognition/s4627182_Improved_Unet/Ploting.py (100%) rename README.md => recognition/s4627182_Improved_Unet/README.md (100%) rename __init__.py => recognition/s4627182_Improved_Unet/__init__.py (100%) rename dice_score.py => recognition/s4627182_Improved_Unet/dice_score.py (100%) rename evaluate.py => recognition/s4627182_Improved_Unet/evaluate.py (100%) rename predict.py => recognition/s4627182_Improved_Unet/predict.py (100%) rename requirements.txt => recognition/s4627182_Improved_Unet/requirements.txt (100%) rename train.py => recognition/s4627182_Improved_Unet/train.py (100%) rename utils.py => recognition/s4627182_Improved_Unet/utils.py (95%) diff --git a/recognition/__init__.py b/recognition/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/Data_Loader.py b/recognition/s4627182_Improved_Unet/Data_Loader.py similarity index 100% rename from Data_Loader.py rename to recognition/s4627182_Improved_Unet/Data_Loader.py diff --git a/LICENSE b/recognition/s4627182_Improved_Unet/LICENSE similarity index 100% rename from LICENSE rename to recognition/s4627182_Improved_Unet/LICENSE diff --git a/Losses.py b/recognition/s4627182_Improved_Unet/Losses.py similarity index 100% rename from Losses.py rename to recognition/s4627182_Improved_Unet/Losses.py diff --git a/Metrics.py b/recognition/s4627182_Improved_Unet/Metrics.py similarity index 100% rename from Metrics.py rename to recognition/s4627182_Improved_Unet/Metrics.py diff --git a/Modules.py b/recognition/s4627182_Improved_Unet/Modules.py similarity index 100% rename from Modules.py rename to recognition/s4627182_Improved_Unet/Modules.py diff --git a/Ploting.py b/recognition/s4627182_Improved_Unet/Ploting.py similarity index 100% rename from Ploting.py rename to recognition/s4627182_Improved_Unet/Ploting.py diff --git a/README.md b/recognition/s4627182_Improved_Unet/README.md similarity index 100% rename from README.md rename to recognition/s4627182_Improved_Unet/README.md diff --git a/__init__.py b/recognition/s4627182_Improved_Unet/__init__.py similarity index 100% rename from __init__.py rename to recognition/s4627182_Improved_Unet/__init__.py diff --git a/dice_score.py b/recognition/s4627182_Improved_Unet/dice_score.py similarity index 100% rename from dice_score.py rename to recognition/s4627182_Improved_Unet/dice_score.py diff --git a/evaluate.py b/recognition/s4627182_Improved_Unet/evaluate.py similarity index 100% rename from evaluate.py rename to recognition/s4627182_Improved_Unet/evaluate.py diff --git a/predict.py b/recognition/s4627182_Improved_Unet/predict.py similarity index 100% rename from predict.py rename to recognition/s4627182_Improved_Unet/predict.py diff --git a/requirements.txt b/recognition/s4627182_Improved_Unet/requirements.txt similarity index 100% rename from requirements.txt rename to recognition/s4627182_Improved_Unet/requirements.txt diff --git a/train.py b/recognition/s4627182_Improved_Unet/train.py similarity index 100% rename from train.py rename to recognition/s4627182_Improved_Unet/train.py diff --git a/utils.py b/recognition/s4627182_Improved_Unet/utils.py similarity index 95% rename from utils.py rename to recognition/s4627182_Improved_Unet/utils.py index 9f3b54559..f53213e26 100644 --- a/utils.py +++ b/recognition/s4627182_Improved_Unet/utils.py @@ -1,18 +1,18 @@ -import matplotlib.pyplot as plt - - -def plot_img_and_mask(img, mask): - classes = mask.max() + 1 - fig, ax = plt.subplots(1, classes + 1) - ax[0].set_title('Input image') - ax[0].imshow(img) - for i in range(classes): - ax[i + 1].set_title(f'Mask (class {i + 1})') - ax[i + 1].imshow(mask == i) - plt.xticks([]), plt.yticks([]) - - - plt.show() - - +import matplotlib.pyplot as plt + + +def plot_img_and_mask(img, mask): + classes = mask.max() + 1 + fig, ax = plt.subplots(1, classes + 1) + ax[0].set_title('Input image') + ax[0].imshow(img) + for i in range(classes): + ax[i + 1].set_title(f'Mask (class {i + 1})') + ax[i + 1].imshow(mask == i) + plt.xticks([]), plt.yticks([]) + + + plt.show() + + # Updated \ No newline at end of file From b54388cb88cd427fba323cc53888933a5a449f18 Mon Sep 17 00:00:00 2001 From: FrostNov4 <97688822+FrostNov4@users.noreply.github.com> Date: Thu, 26 Oct 2023 22:16:46 +1000 Subject: [PATCH 20/45] Deleted no need file --- .../s4627182_Improved_Unet/evaluate.py | 40 ------------------- 1 file changed, 40 deletions(-) delete mode 100644 recognition/s4627182_Improved_Unet/evaluate.py diff --git a/recognition/s4627182_Improved_Unet/evaluate.py b/recognition/s4627182_Improved_Unet/evaluate.py deleted file mode 100644 index 9a4e3ba2b..000000000 --- a/recognition/s4627182_Improved_Unet/evaluate.py +++ /dev/null @@ -1,40 +0,0 @@ -import torch -import torch.nn.functional as F -from tqdm import tqdm - -from utils.dice_score import multiclass_dice_coeff, dice_coeff - - -@torch.inference_mode() -def evaluate(net, dataloader, device, amp): - net.eval() - num_val_batches = len(dataloader) - dice_score = 0 - - # iterate over the validation set - with torch.autocast(device.type if device.type != 'mps' else 'cpu', enabled=amp): - for batch in tqdm(dataloader, total=num_val_batches, desc='Validation round', unit='batch', leave=False): - image, mask_true = batch['image'], batch['mask'] - - # move images and labels to correct device and type - image = image.to(device=device, dtype=torch.float32, memory_format=torch.channels_last) - mask_true = mask_true.to(device=device, dtype=torch.long) - - # predict the mask - mask_pred = net(image) - - if net.n_classes == 1: - assert mask_true.min() >= 0 and mask_true.max() <= 1, 'True mask indices should be in [0, 1]' - mask_pred = (F.sigmoid(mask_pred) > 0.5).float() - # compute the Dice score - dice_score += dice_coeff(mask_pred, mask_true, reduce_batch_first=False) - else: - assert mask_true.min() >= 0 and mask_true.max() < net.n_classes, 'True mask indices should be in [0, n_classes[' - # convert to one-hot format - mask_true = F.one_hot(mask_true, net.n_classes).permute(0, 3, 1, 2).float() - mask_pred = F.one_hot(mask_pred.argmax(dim=1), net.n_classes).permute(0, 3, 1, 2).float() - # compute the Dice score, ignoring background - dice_score += multiclass_dice_coeff(mask_pred[:, 1:], mask_true[:, 1:], reduce_batch_first=False) - - net.train() - return dice_score / max(num_val_batches, 1) From 172102561b3df4be0e90fdb218aa76f7b0e94971 Mon Sep 17 00:00:00 2001 From: FrostNov4 <97688822+FrostNov4@users.noreply.github.com> Date: Thu, 26 Oct 2023 22:37:04 +1000 Subject: [PATCH 21/45] Updated ReadMe (Model finished) --- recognition/s4627182_Improved_Unet/Modules.py | 3 +-- recognition/s4627182_Improved_Unet/README.md | 5 +++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/recognition/s4627182_Improved_Unet/Modules.py b/recognition/s4627182_Improved_Unet/Modules.py index 3e7bf5a7a..8678185db 100644 --- a/recognition/s4627182_Improved_Unet/Modules.py +++ b/recognition/s4627182_Improved_Unet/Modules.py @@ -6,7 +6,6 @@ import torch - class ContextModule(nn.Module): """ Context Module: Consists of two convolutional layers for feature extraction and a dropout layer @@ -310,4 +309,4 @@ def forward(self, x): return out -# Updated \ No newline at end of file +# Updated diff --git a/recognition/s4627182_Improved_Unet/README.md b/recognition/s4627182_Improved_Unet/README.md index 5a62afec2..c0005a986 100644 --- a/recognition/s4627182_Improved_Unet/README.md +++ b/recognition/s4627182_Improved_Unet/README.md @@ -25,6 +25,11 @@ making them simpler and more focused on the lesion's location and shape. ## Model + The activations in the context pathway are computed by context modules. + Each context module is in fact a pre-activation residual block with two 3x3x3 convolutional + layers and a dropout layer (p_drop = 0.3) in between. Context modules are connected + by 3x3x3 convolutions with input stride 2 to reduce the resolution of the feature maps and allow + for more features while descending the aggregation pathway. From d5ffbe91f73abc3edb2924e92058e0b7d20ff53a Mon Sep 17 00:00:00 2001 From: FrostNov4 <97688822+FrostNov4@users.noreply.github.com> Date: Thu, 26 Oct 2023 23:00:18 +1000 Subject: [PATCH 22/45] Add Test.py --- recognition/s4627182_Improved_Unet/Ploting.py | 2 + recognition/s4627182_Improved_Unet/README.md | 12 +- recognition/s4627182_Improved_Unet/test.py | 442 ++++++++++++++++++ 3 files changed, 451 insertions(+), 5 deletions(-) create mode 100644 recognition/s4627182_Improved_Unet/test.py diff --git a/recognition/s4627182_Improved_Unet/Ploting.py b/recognition/s4627182_Improved_Unet/Ploting.py index 0fded5035..691b40f2d 100644 --- a/recognition/s4627182_Improved_Unet/Ploting.py +++ b/recognition/s4627182_Improved_Unet/Ploting.py @@ -1,3 +1,5 @@ +# From https://github.com/bigmb/Unet-Segmentation-Pytorch-Nest-of-Unets + import matplotlib.pyplot as plt from matplotlib.lines import Line2D import numpy as np diff --git a/recognition/s4627182_Improved_Unet/README.md b/recognition/s4627182_Improved_Unet/README.md index c0005a986..dc25ead3c 100644 --- a/recognition/s4627182_Improved_Unet/README.md +++ b/recognition/s4627182_Improved_Unet/README.md @@ -15,6 +15,12 @@ which enables precise localization. Through skip connections, features from the contracting path are concatenated with the expansive path, enhancing localization capabilities. + The activations in the context pathway are computed by context modules. + Each context module is in fact a pre-activation residual block with two 3x3x3 convolutional + layers and a dropout layer (p_drop = 0.3) in between. Context modules are connected + by 3x3x3 convolutions with input stride 2 to reduce the resolution of the feature maps and allow + for more features while descending the aggregation pathway. + ## Dataset In this report, the ISIC 2018 dataset will be used. The ISIC 2018 dataset is a publicly available dataset for skin lesion image segmentation, @@ -25,11 +31,7 @@ making them simpler and more focused on the lesion's location and shape. ## Model - The activations in the context pathway are computed by context modules. - Each context module is in fact a pre-activation residual block with two 3x3x3 convolutional - layers and a dropout layer (p_drop = 0.3) in between. Context modules are connected - by 3x3x3 convolutions with input stride 2 to reduce the resolution of the feature maps and allow - for more features while descending the aggregation pathway. + T diff --git a/recognition/s4627182_Improved_Unet/test.py b/recognition/s4627182_Improved_Unet/test.py new file mode 100644 index 000000000..56e1a7d20 --- /dev/null +++ b/recognition/s4627182_Improved_Unet/test.py @@ -0,0 +1,442 @@ +from __future__ import print_function, division +import os +import numpy as np +from PIL import Image +import glob +# import SimpleITK as sitk +from torch import optim +import torch.utils.data +import torch +import torch.nn.functional as F + +import torch.nn +import torchvision +import matplotlib.pyplot as plt +import natsort +from torch.utils.data.sampler import SubsetRandomSampler +from Data_Loader import Images_Dataset, Images_Dataset_folder +import torchsummary +# from torch.utils.tensorboard import SummaryWriter +# from tensorboardX import SummaryWriter + +import shutil +import random +from Modules import UNet_For_Brain +from Losses import calc_loss, dice_loss, threshold_predictions_v, threshold_predictions_p +from Ploting import plot_kernels, LayerActivations, input_images, plot_grad_flow, draw_loss +from Metrics import dice_coeff, accuracy_score +import time + +####################################################### +# Checking if GPU is used +####################################################### + +train_on_gpu = torch.cuda.is_available() + +if not train_on_gpu: + print('CUDA is not available. Training on CPU') +else: + print('CUDA is available. Training on GPU') + +# os.environ['CUDA_VISIBLE_DEVICES'] = '1,2,3,4' +device = torch.device("cuda:0" if train_on_gpu else "cpu") + +####################################################### +# Setting the basic paramters of the model +####################################################### + +batch_size = 16 +print('batch_size = ' + str(batch_size)) + +valid_size = 0.15 +epoch = 400 +print('epoch = ' + str(epoch)) + +random_seed = random.randint(1, 100) +print('random_seed = ' + str(random_seed)) + +shuffle = True +valid_loss_min = np.Inf +num_workers = 24 +lossT = [] +lossL = [] +lossL.append(np.inf) +lossT.append(np.inf) +epoch_valid = epoch - 2 +n_iter = 1 +i_valid = 0 + +pin_memory = False +if train_on_gpu: + pin_memory = True + +# plotter = VisdomLinePlotter(env_name='Tutorial Plots') + +####################################################### +# Setting up the model +####################################################### + +model_Inputs = UNet_For_Brain + + +def model_unet(model_input, in_channel=1, out_channel=1): + model_test = model_input(in_channel, out_channel) + return model_test + + +model_test = model_unet(model_Inputs[-1], 3, 1) + +model_test.to(device) + +####################################################### +# Getting the Summary of Model +####################################################### + +torchsummary.summary(model_test, input_size=(3, 128, 128)) + +####################################################### +# Passing the Dataset of Images and Labels +####################################################### + +# for ISIC2018 data +t_data = './ISIC2018/ISIC2018_Task1-2_Training_Input_x2/' +l_data = './ISIC2018/ISIC2018_Task1_Training_GroundTruth_x2/' +test_image = './keras_png_slices_data/keras_png_slices_test/' +test_label = './keras_png_slices_data/keras_png_slices_seg_test/' +test_folderP = './ISIC2018/ISIC2018_Task1-2_Training_Input_x2/*' +test_folderL = './ISIC2018/ISIC2018_Task1_Training_GroundTruth_x2/*' +valid_image = './ISIC2018/ISIC2018_Task1-2_Training_Input_x2/' +valid_label = './ISIC2018/ISIC2018_Task1_Training_GroundTruth_x2/' + +Training_Data = Images_Dataset_folder(t_data, l_data) +valid_Data = Images_Dataset_folder(valid_image, valid_label) + +####################################################### +# Giving a transformation for input data +####################################################### + +data_transform = torchvision.transforms.Compose([ + torchvision.transforms.Resize((128, 128)), + # torchvision.transforms.CenterCrop(96), + torchvision.transforms.ToTensor(), + # torchvision.transforms.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5]) +]) + +####################################################### +# Training Validation Split +####################################################### + +num_train = len(Training_Data) +indices_train = list(range(num_train)) +# split = int(np.floor(valid_size * num_train)) + +num_valid = len(valid_Data) +indices_valid = list(range(num_valid)) + +if shuffle: + np.random.seed(random_seed) + np.random.shuffle(indices_train) + np.random.shuffle(indices_valid) + +# train_idx, valid_idx = indices[split:], indices[:split] +train_idx, valid_idx = indices_train, indices_valid +train_sampler = SubsetRandomSampler(train_idx) +valid_sampler = SubsetRandomSampler(valid_idx) + +train_loader = torch.utils.data.DataLoader(Training_Data, batch_size=batch_size, sampler=train_sampler, + num_workers=num_workers, pin_memory=pin_memory, ) + +valid_loader = torch.utils.data.DataLoader(valid_Data, batch_size=batch_size, sampler=valid_sampler, + num_workers=num_workers, pin_memory=pin_memory, ) + +####################################################### +# Using Adam as Optimizer +####################################################### +# Hyper Parameters +initial_lr = 5e-4 +lr_decay = 0.985 +l2_weight_decay = 1e-5 +# initial_lr = 0.001 +# opt = torch.optim.Adam(model_test.parameters(), lr=initial_lr) # try SGD +# # opt = optim.SGD(model_test.parameters(), lr = initial_lr, momentum=0.99) + +# MAX_STEP = int(1e10) +# eta_min = 1e-2 +# scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(opt, MAX_STEP, eta_min=1e-5) + +# Optimisation & Loss Settings +opt = optim.Adam(model_test.parameters(), lr=initial_lr, weight_decay=l2_weight_decay) +scheduler = optim.lr_scheduler.ExponentialLR(optimizer=opt, gamma=lr_decay) + +New_folder = './model' + +if os.path.exists(New_folder) and os.path.isdir(New_folder): + shutil.rmtree(New_folder) + +try: + os.mkdir(New_folder) +except OSError: + print("Creation of the main directory '%s' failed " % New_folder) +else: + print("Successfully created the main directory '%s' " % New_folder) + +####################################################### +# Setting the folder of saving the predictions +####################################################### + +read_pred = './model/pred' + +####################################################### +# Checking if prediction folder exixts +####################################################### + +if os.path.exists(read_pred) and os.path.isdir(read_pred): + shutil.rmtree(read_pred) + +try: + os.mkdir(read_pred) +except OSError: + print("Creation of the prediction directory '%s' failed of dice loss" % read_pred) +else: + print("Successfully created the prediction directory '%s' of dice loss" % read_pred) + +####################################################### +# checking if the model exists and if true then delete +####################################################### + +read_model_path = './model/Unet_D_' + str(epoch) + '_' + str(batch_size) + +if os.path.exists(read_model_path) and os.path.isdir(read_model_path): + shutil.rmtree(read_model_path) + print('Model folder there, so deleted for newer one') + +try: + os.mkdir(read_model_path) +except OSError: + print("Creation of the model directory '%s' failed" % read_model_path) +else: + print("Successfully created the model directory '%s' " % read_model_path) + +####################################################### +# Training loop +####################################################### + +for i in range(epoch): + + train_loss = 0.0 + valid_loss = 0.0 + train_loss_list = [] + valid_loss_list = [] + since = time.time() + scheduler.step() + # lr = scheduler.get_lr() + + ####################################################### + # Training Data + ####################################################### + + model_test.train() + k = 1 + + for x, y in train_loader: + # print("x: ", x.shape) + # print("y: ", y.shape) + x, y = x.to(device), y.to(device) + + opt.zero_grad() + + y_pred = model_test(x) + lossT = calc_loss(y_pred, y) # Dice_loss Used + + train_loss += lossT.item() * x.size(0) + lossT.backward() + opt.step() + x_size = lossT.item() * x.size(0) + k = 2 + + train_loss_list.append(train_loss) + + ####################################################### + # Validation Step + ####################################################### + + model_test.eval() + torch.no_grad() # to increase the validation process uses less memory + + for x1, y1 in valid_loader: + x1, y1 = x1.to(device), y1.to(device) + + y_pred1 = model_test(x1) + lossL = calc_loss(y_pred1, y1) # Dice_loss Used + + valid_loss += lossL.item() * x1.size(0) + x_size1 = lossL.item() * x1.size(0) + + valid_loss_list.append(valid_loss) + + if (i + 1) % 1 == 0: + print('Epoch: {}/{} \tTraining Loss: {:.6f} \tValidation Loss: {:.6f}'.format(i + 1, epoch, train_loss, + valid_loss)) + ####################################################### + # Early Stopping + ####################################################### + + if valid_loss <= valid_loss_min and epoch_valid >= i: # and i_valid <= 2: + + print('Validation loss decreased ({:.6f} --> {:.6f}). Saving model '.format(valid_loss_min, valid_loss)) + torch.save(model_test.state_dict(), './model/Unet_D_' + + str(epoch) + '_' + str(batch_size) + '/Unet_epoch_' + str(epoch) + + '_batchsize_' + str(batch_size) + '.pth') + + if round(valid_loss, 4) == round(valid_loss_min, 4): + print(i_valid) + i_valid = i_valid + 1 + valid_loss_min = valid_loss + +if torch.cuda.is_available(): + torch.cuda.empty_cache() + +####################################################### +# Loading the model +####################################################### + +model_test.load_state_dict(torch.load('./model/Unet_D_' + + str(epoch) + '_' + str(batch_size) + '/Unet_epoch_' + str(epoch) + + '_batchsize_' + str(batch_size) + '.pth')) + +model_test.eval() + +####################################################### +# opening the test folder and creating a folder for generated images +####################################################### + +read_test_folder = glob.glob(test_folderP) +x_sort_test = natsort.natsorted(read_test_folder) # To sort + +read_test_folder112 = './model/gen_images' + +if os.path.exists(read_test_folder112) and os.path.isdir(read_test_folder112): + shutil.rmtree(read_test_folder112) + +try: + os.mkdir(read_test_folder112) +except OSError: + print("Creation of the testing directory %s failed" % read_test_folder112) +else: + print("Successfully created the testing directory %s " % read_test_folder112) + +# For Prediction Threshold + +read_test_folder_P_Thres = './model/pred_threshold' + +if os.path.exists(read_test_folder_P_Thres) and os.path.isdir(read_test_folder_P_Thres): + shutil.rmtree(read_test_folder_P_Thres) + +try: + os.mkdir(read_test_folder_P_Thres) +except OSError: + print("Creation of the testing directory %s failed" % read_test_folder_P_Thres) +else: + print("Successfully created the testing directory %s " % read_test_folder_P_Thres) + +# For Label Threshold + +read_test_folder_L_Thres = './model/label_threshold' + +if os.path.exists(read_test_folder_L_Thres) and os.path.isdir(read_test_folder_L_Thres): + shutil.rmtree(read_test_folder_L_Thres) + +try: + os.mkdir(read_test_folder_L_Thres) +except OSError: + print("Creation of the testing directory %s failed" % read_test_folder_L_Thres) +else: + print("Successfully created the testing directory %s " % read_test_folder_L_Thres) + +####################################################### +# saving the images in the files +####################################################### + +img_test_no = 0 + +for i in range(len(read_test_folder)): + im = Image.open(x_sort_test[i]).convert("RGB") + + im1 = im + im_n = np.array(im1) + im_n_flat = im_n.reshape(-1, 1) + + for j in range(im_n_flat.shape[0]): + if im_n_flat[j] != 0: + im_n_flat[j] = 255 + + s = data_transform(im) + pred = model_test(s.unsqueeze(0).cuda()).cpu() + pred = F.sigmoid(pred) + pred = pred.detach().numpy() + + # pred = threshold_predictions_p(pred) #Value kept 0.01 as max is 1 and noise is very small. + + if i % 24 == 0: + img_test_no = img_test_no + 1 + + x1 = plt.imsave('./model/gen_images/im_epoch_' + str(epoch) + 'int_' + str(i) + + '_img_no_' + str(img_test_no) + '.png', pred[0][0], cmap='gray') + +#################################################### +# Calculating the Dice Score +#################################################### + +data_transform = torchvision.transforms.Compose([ + torchvision.transforms.Resize((128, 128)), + # torchvision.transforms.CenterCrop(96), + torchvision.transforms.Grayscale(), + # torchvision.transforms.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5]) +]) + +read_test_folderP = glob.glob('./model/gen_images/*') +x_sort_testP = natsort.natsorted(read_test_folderP) + +read_test_folderL = glob.glob(test_folderL) +x_sort_testL = natsort.natsorted(read_test_folderL) # To sort + +dice_score123 = 0.0 +x_count = 0 +x_dice = 0 + +for i in range(len(read_test_folderP)): + + x = Image.open(x_sort_testP[i]).convert("L") + s = data_transform(x) + s = np.array(s) + s = threshold_predictions_v(s) + # print(s) + # print("------------------") + + # save the images + x1 = plt.imsave('./model/pred_threshold/im_epoch_' + str(epoch) + 'int_' + str(i) + + '_img_no_' + str(img_test_no) + '.png', s) + + y = Image.open(x_sort_testL[i]).convert("L") + s2 = data_transform(y) + s3 = np.array(s2) + s2 = threshold_predictions_v(s2) + # print(s3) + + # save the Images + y1 = plt.imsave('./model/label_threshold/im_epoch_' + str(epoch) + 'int_' + str(i) + + '_img_no_' + str(img_test_no) + '.png', s3) + + total = dice_coeff(s, s3) + print(total) + + if total <= 0.8: + x_count += 1 + if total > 0.8: + x_dice = x_dice + total + dice_score123 = dice_score123 + total + +# print('Dice Score : ' + str(dice_score123/len(read_test_folderP))) +print(x_count) +print(x_dice) +print('Dice Score : ' + str(float(x_dice / (len(read_test_folderP) - x_count)))) From 143775cf621eab897405975e0b6a25252849dee1 Mon Sep 17 00:00:00 2001 From: FrostNov4 <97688822+FrostNov4@users.noreply.github.com> Date: Fri, 27 Oct 2023 03:12:29 +1000 Subject: [PATCH 23/45] Update readme and deleted wrong predict.py --- recognition/s4627182_Improved_Unet/README.md | 39 +++++- recognition/s4627182_Improved_Unet/predict.py | 117 ------------------ 2 files changed, 37 insertions(+), 119 deletions(-) delete mode 100755 recognition/s4627182_Improved_Unet/predict.py diff --git a/recognition/s4627182_Improved_Unet/README.md b/recognition/s4627182_Improved_Unet/README.md index dc25ead3c..8a7690c3b 100644 --- a/recognition/s4627182_Improved_Unet/README.md +++ b/recognition/s4627182_Improved_Unet/README.md @@ -30,9 +30,44 @@ is treated in the same way as the real data. However, these labels are input as grayscale images with a single channel, making them simpler and more focused on the lesion's location and shape. -## Model - T + +## Data_Loader + Class for getting data as a Dict + Args: + images_dir = path of input images + labels_dir = path of labeled images + transformI = Input Images transformation + transformM = Input Labels transformation +## Dice_score +measures the similarity between two sets. +Specifically in medical imaging, it's used to quantify the overlap +between predicted and ground truth binary segmentations. +Values range between 0 (no overlap) to 1 (perfect overlap). +It's a common metric for evaluating the accuracy of image segmentation models, +highlighting the spatial overlap accuracy between prediction and truth. + +## Losses +Quantifies how well a model's predictions match the actual data. +In machine learning, it measures the difference between predicted and true values. + Args: + prediction = predicted image + target = Targeted image + metrics = Metrics printed + bce_weight = 0.5 (default) + Output: + loss : dice loss of the epoch + + +## Metrics +Dice Coefficient will be calculated +It is a statistical measure used to evaluate the similarity between two sets. +It is especially popular in medical imaging for quantifying the overlap between +predicted and ground truth binary segmentations. +The coefficient ranges from 0 (no overlap) to 1 (perfect overlap). + + + diff --git a/recognition/s4627182_Improved_Unet/predict.py b/recognition/s4627182_Improved_Unet/predict.py deleted file mode 100755 index b74c4608d..000000000 --- a/recognition/s4627182_Improved_Unet/predict.py +++ /dev/null @@ -1,117 +0,0 @@ -import argparse -import logging -import os - -import numpy as np -import torch -import torch.nn.functional as F -from PIL import Image -from torchvision import transforms - -from utils.data_loading import BasicDataset -from unet import UNet -from utils.utils import plot_img_and_mask - -def predict_img(net, - full_img, - device, - scale_factor=1, - out_threshold=0.5): - net.eval() - img = torch.from_numpy(BasicDataset.preprocess(None, full_img, scale_factor, is_mask=False)) - img = img.unsqueeze(0) - img = img.to(device=device, dtype=torch.float32) - - with torch.no_grad(): - output = net(img).cpu() - output = F.interpolate(output, (full_img.size[1], full_img.size[0]), mode='bilinear') - if net.n_classes > 1: - mask = output.argmax(dim=1) - else: - mask = torch.sigmoid(output) > out_threshold - - return mask[0].long().squeeze().numpy() - - -def get_args(): - parser = argparse.ArgumentParser(description='Predict masks from input images') - parser.add_argument('--model', '-m', default='MODEL.pth', metavar='FILE', - help='Specify the file in which the model is stored') - parser.add_argument('--input', '-i', metavar='INPUT', nargs='+', help='Filenames of input images', required=True) - parser.add_argument('--output', '-o', metavar='OUTPUT', nargs='+', help='Filenames of output images') - parser.add_argument('--viz', '-v', action='store_true', - help='Visualize the images as they are processed') - parser.add_argument('--no-save', '-n', action='store_true', help='Do not save the output masks') - parser.add_argument('--mask-threshold', '-t', type=float, default=0.5, - help='Minimum probability value to consider a mask pixel white') - parser.add_argument('--scale', '-s', type=float, default=0.5, - help='Scale factor for the input images') - parser.add_argument('--bilinear', action='store_true', default=False, help='Use bilinear upsampling') - parser.add_argument('--classes', '-c', type=int, default=2, help='Number of classes') - - return parser.parse_args() - - -def get_output_filenames(args): - def _generate_name(fn): - return f'{os.path.splitext(fn)[0]}_OUT.png' - - return args.output or list(map(_generate_name, args.input)) - - -def mask_to_image(mask: np.ndarray, mask_values): - if isinstance(mask_values[0], list): - out = np.zeros((mask.shape[-2], mask.shape[-1], len(mask_values[0])), dtype=np.uint8) - elif mask_values == [0, 1]: - out = np.zeros((mask.shape[-2], mask.shape[-1]), dtype=bool) - else: - out = np.zeros((mask.shape[-2], mask.shape[-1]), dtype=np.uint8) - - if mask.ndim == 3: - mask = np.argmax(mask, axis=0) - - for i, v in enumerate(mask_values): - out[mask == i] = v - - return Image.fromarray(out) - - -if __name__ == '__main__': - args = get_args() - logging.basicConfig(level=logging.INFO, format='%(levelname)s: %(message)s') - - in_files = args.input - out_files = get_output_filenames(args) - - net = UNet(n_channels=3, n_classes=args.classes, bilinear=args.bilinear) - - device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') - logging.info(f'Loading model {args.model}') - logging.info(f'Using device {device}') - - net.to(device=device) - state_dict = torch.load(args.model, map_location=device) - mask_values = state_dict.pop('mask_values', [0, 1]) - net.load_state_dict(state_dict) - - logging.info('Model loaded!') - - for i, filename in enumerate(in_files): - logging.info(f'Predicting image {filename} ...') - img = Image.open(filename) - - mask = predict_img(net=net, - full_img=img, - scale_factor=args.scale, - out_threshold=args.mask_threshold, - device=device) - - if not args.no_save: - out_filename = out_files[i] - result = mask_to_image(mask, mask_values) - result.save(out_filename) - logging.info(f'Mask saved to {out_filename}') - - if args.viz: - logging.info(f'Visualizing results for image {filename}, close to continue...') - plot_img_and_mask(img, mask) From bf112994211937c2b3c9b508b19289be7b417746 Mon Sep 17 00:00:00 2001 From: FrostNov4 <97688822+FrostNov4@users.noreply.github.com> Date: Fri, 27 Oct 2023 03:14:00 +1000 Subject: [PATCH 24/45] Update readme --- recognition/s4627182_Improved_Unet/README.md | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/recognition/s4627182_Improved_Unet/README.md b/recognition/s4627182_Improved_Unet/README.md index 8a7690c3b..20007a072 100644 --- a/recognition/s4627182_Improved_Unet/README.md +++ b/recognition/s4627182_Improved_Unet/README.md @@ -10,6 +10,8 @@ "Brain Tumor Segmentation and Radiomics Survival Prediction: Contribution to the BRATS 2017 Challenge" https://arxiv.org/abs/1802.10508v1 + +## Model U-Net is a convolutional neural network architecture primarily used for biomedical image segmentation. Its U-shaped structure consists of a contracting path, which captures context, and an expansive path, which enables precise localization. Through skip connections, features from the contracting path are concatenated @@ -59,12 +61,6 @@ In machine learning, it measures the difference between predicted and true value loss : dice loss of the epoch -## Metrics -Dice Coefficient will be calculated -It is a statistical measure used to evaluate the similarity between two sets. -It is especially popular in medical imaging for quantifying the overlap between -predicted and ground truth binary segmentations. -The coefficient ranges from 0 (no overlap) to 1 (perfect overlap). From 7fff553d382128749b9066ef7a5e017c085bfe3b Mon Sep 17 00:00:00 2001 From: FrostNov4 <97688822+FrostNov4@users.noreply.github.com> Date: Fri, 27 Oct 2023 03:24:51 +1000 Subject: [PATCH 25/45] Update readme --- recognition/s4627182_Improved_Unet/README.md | 31 ++++++++++++++------ 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/recognition/s4627182_Improved_Unet/README.md b/recognition/s4627182_Improved_Unet/README.md index 20007a072..c7e4dfb6c 100644 --- a/recognition/s4627182_Improved_Unet/README.md +++ b/recognition/s4627182_Improved_Unet/README.md @@ -6,9 +6,10 @@ Segment the ISIC data set with the Improved UNet with all labels having a minimum Dice similarity coefficient of 0.8 on the test set. -## The structure of Improved UNet is based on the paper. - "Brain Tumor Segmentation and Radiomics Survival Prediction: Contribution to the BRATS 2017 Challenge" - https://arxiv.org/abs/1802.10508v1 +## Background +The structure of Improved UNet is based on the paper. +"Brain Tumor Segmentation and Radiomics Survival Prediction: Contribution to the BRATS 2017 Challenge" +https://arxiv.org/abs/1802.10508v1 ## Model @@ -34,12 +35,13 @@ ## Data_Loader - Class for getting data as a Dict - Args: - images_dir = path of input images - labels_dir = path of labeled images - transformI = Input Images transformation - transformM = Input Labels transformation +Class for getting data as a Dict + + Args: + images_dir = path of input images + labels_dir = path of labeled images + transformI = Input Images transformation + transformM = Input Labels transformation ## Dice_score measures the similarity between two sets. @@ -52,6 +54,7 @@ highlighting the spatial overlap accuracy between prediction and truth. ## Losses Quantifies how well a model's predictions match the actual data. In machine learning, it measures the difference between predicted and true values. + Args: prediction = predicted image target = Targeted image @@ -60,6 +63,16 @@ In machine learning, it measures the difference between predicted and true value Output: loss : dice loss of the epoch +## Environment + python 3.9 + pytorch=2.0.1 + numpy==1.23.5 + torchvision=0.15.2 + matplotlib==3.7.2 + + + + From 7420d1ad6aa0f394f58703b27ffccdcd9a6d5f38 Mon Sep 17 00:00:00 2001 From: FrostNov4 <97688822+FrostNov4@users.noreply.github.com> Date: Fri, 27 Oct 2023 04:14:30 +1000 Subject: [PATCH 26/45] add predict --- recognition/s4627182_Improved_Unet/predict.py | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 recognition/s4627182_Improved_Unet/predict.py diff --git a/recognition/s4627182_Improved_Unet/predict.py b/recognition/s4627182_Improved_Unet/predict.py new file mode 100644 index 000000000..e30cb7de2 --- /dev/null +++ b/recognition/s4627182_Improved_Unet/predict.py @@ -0,0 +1,31 @@ +import torch +from torchvision import transforms +from PIL import Image +import numpy as np + + +def segment_image(model_path, image_path, device='cuda'): + + # Load the pre-trained model + model = torch.load(model_path) + model.to(device) + model.eval() + + # Load and preprocess the image + img = Image.open(image_path) # Adjust the size as per your model's requirements + img_np = np.array(img) / 255.0 + img_tensor = torch.tensor(img_np).to(device) + + # Predict the mask + with torch.no_grad(): + predicted_mask = model(img_tensor) + + # Convert mask to numpy array + predicted_mask = predicted_mask.squeeze().cpu().numpy() + predicted_mask_image = (predicted_mask * 255).astype(np.uint8) + + return predicted_mask_image + +# Example usage: +# segmented_img = segment_image("path_to_model.pth", "path_to_image.jpg") +# Image.fromarray(segmented_img).save("segmented_output.png") From 36aa396c105cc436635063e2a801807b52518017 Mon Sep 17 00:00:00 2001 From: FrostNov4 <97688822+FrostNov4@users.noreply.github.com> Date: Fri, 27 Oct 2023 04:21:32 +1000 Subject: [PATCH 27/45] add predict --- recognition/s4627182_Improved_Unet/predict.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/recognition/s4627182_Improved_Unet/predict.py b/recognition/s4627182_Improved_Unet/predict.py index e30cb7de2..6f1ed7263 100644 --- a/recognition/s4627182_Improved_Unet/predict.py +++ b/recognition/s4627182_Improved_Unet/predict.py @@ -3,8 +3,9 @@ from PIL import Image import numpy as np +device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") -def segment_image(model_path, image_path, device='cuda'): +def segment_image(model_path, image_path, output_path): # Load the pre-trained model model = torch.load(model_path) @@ -24,6 +25,8 @@ def segment_image(model_path, image_path, device='cuda'): predicted_mask = predicted_mask.squeeze().cpu().numpy() predicted_mask_image = (predicted_mask * 255).astype(np.uint8) + predicted_mask_image.save(output_path) + return predicted_mask_image # Example usage: From b66fa637634f3b971c786fb1d21ca0f4df3ca134 Mon Sep 17 00:00:00 2001 From: FrostNov4 <97688822+FrostNov4@users.noreply.github.com> Date: Fri, 27 Oct 2023 13:01:33 +1000 Subject: [PATCH 28/45] update images of training,testing and prediction. --- recognition/s4627182_Improved_Unet/README.md | 3 + .../additional_Images/ISIC_0000003.jpg | Bin 0 -> 13179 bytes .../additional_Images/ISIC_0000003_out.jpg | Bin 0 -> 5693 bytes .../Train_loss_vs_Epoches.png | Bin 0 -> 25480 bytes .../additional_Images/Unet.png | Bin 0 -> 135777 bytes .../valid_loss_vs_epoches.png | Bin 0 -> 21912 bytes .../s4627182_Improved_Unet/test_1027.log | 2559 +++++++++++++++++ .../s4627182_Improved_Unet/train_1027.log | 655 +++++ 8 files changed, 3217 insertions(+) create mode 100644 recognition/s4627182_Improved_Unet/additional_Images/ISIC_0000003.jpg create mode 100644 recognition/s4627182_Improved_Unet/additional_Images/ISIC_0000003_out.jpg create mode 100755 recognition/s4627182_Improved_Unet/additional_Images/Train_loss_vs_Epoches.png create mode 100644 recognition/s4627182_Improved_Unet/additional_Images/Unet.png create mode 100755 recognition/s4627182_Improved_Unet/additional_Images/valid_loss_vs_epoches.png create mode 100755 recognition/s4627182_Improved_Unet/test_1027.log create mode 100755 recognition/s4627182_Improved_Unet/train_1027.log diff --git a/recognition/s4627182_Improved_Unet/README.md b/recognition/s4627182_Improved_Unet/README.md index c7e4dfb6c..3a8680c77 100644 --- a/recognition/s4627182_Improved_Unet/README.md +++ b/recognition/s4627182_Improved_Unet/README.md @@ -69,6 +69,9 @@ In machine learning, it measures the difference between predicted and true value numpy==1.23.5 torchvision=0.15.2 matplotlib==3.7.2 + Pillow==9.3.0 + tqdm==4.64.1 + wandb==0.13.5 diff --git a/recognition/s4627182_Improved_Unet/additional_Images/ISIC_0000003.jpg b/recognition/s4627182_Improved_Unet/additional_Images/ISIC_0000003.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2b6702f642dd071b198ee3db8fbd653ab20f8059 GIT binary patch literal 13179 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 D#S1B5 literal 0 HcmV?d00001 diff --git a/recognition/s4627182_Improved_Unet/additional_Images/Unet.png b/recognition/s4627182_Improved_Unet/additional_Images/Unet.png new file mode 100644 index 0000000000000000000000000000000000000000..1356bc65699d1506f4e5292a8d974d7352014cd1 GIT binary patch literal 135777 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 qv{V(*CAT61oDKPPNkikA2P|4 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 MQbD3z%)s~m0+nGf&;S4c literal 0 HcmV?d00001 diff --git a/recognition/s4627182_Improved_Unet/additional_Images/valid_loss_vs_epoches.png b/recognition/s4627182_Improved_Unet/additional_Images/valid_loss_vs_epoches.png new file mode 100755 index 0000000000000000000000000000000000000000..ea35c943771add514703a0a050b4a450e99e1570 GIT binary patch literal 21912 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 912.424372). Saving model +Epoch: 2/400 Training Loss: 807.341524 Validation Loss: 676.565119 +Validation loss decreased (912.424372 --> 676.565119). Saving model +Epoch: 3/400 Training Loss: 788.169664 Validation Loss: 737.945829 +Epoch: 4/400 Training Loss: 685.314689 Validation Loss: 658.081859 +Validation loss decreased (676.565119 --> 658.081859). Saving model +Epoch: 5/400 Training Loss: 622.998050 Validation Loss: 859.964467 +Epoch: 6/400 Training Loss: 633.571476 Validation Loss: 587.444989 +Validation loss decreased (658.081859 --> 587.444989). Saving model +Epoch: 7/400 Training Loss: 571.380931 Validation Loss: 524.536493 +Validation loss decreased (587.444989 --> 524.536493). Saving model +Epoch: 8/400 Training Loss: 532.268150 Validation Loss: 643.475564 +Epoch: 9/400 Training Loss: 511.374725 Validation Loss: 463.643838 +Validation loss decreased (524.536493 --> 463.643838). Saving model +Epoch: 10/400 Training Loss: 485.633548 Validation Loss: 460.078441 +Validation loss decreased (463.643838 --> 460.078441). Saving model +Epoch: 11/400 Training Loss: 487.347852 Validation Loss: 450.552999 +Validation loss decreased (460.078441 --> 450.552999). Saving model +Epoch: 12/400 Training Loss: 473.160938 Validation Loss: 473.249527 +Epoch: 13/400 Training Loss: 468.547054 Validation Loss: 442.757757 +Validation loss decreased (450.552999 --> 442.757757). Saving model +Epoch: 14/400 Training Loss: 462.058998 Validation Loss: 415.449000 +Validation loss decreased (442.757757 --> 415.449000). Saving model +Epoch: 15/400 Training Loss: 439.305906 Validation Loss: 405.742114 +Validation loss decreased (415.449000 --> 405.742114). Saving model +Epoch: 16/400 Training Loss: 467.854116 Validation Loss: 415.819749 +Epoch: 17/400 Training Loss: 424.860595 Validation Loss: 418.844686 +Epoch: 18/400 Training Loss: 430.135481 Validation Loss: 457.015388 +Epoch: 19/400 Training Loss: 416.098201 Validation Loss: 388.079262 +Validation loss decreased (405.742114 --> 388.079262). Saving model +Epoch: 20/400 Training Loss: 411.228808 Validation Loss: 403.862916 +Epoch: 21/400 Training Loss: 403.458714 Validation Loss: 366.746401 +Validation loss decreased (388.079262 --> 366.746401). Saving model +Epoch: 22/400 Training Loss: 394.347869 Validation Loss: 359.135790 +Validation loss decreased (366.746401 --> 359.135790). Saving model +Epoch: 23/400 Training Loss: 394.740691 Validation Loss: 349.929157 +Validation loss decreased (359.135790 --> 349.929157). Saving model +Epoch: 24/400 Training Loss: 388.239514 Validation Loss: 357.371899 +Epoch: 25/400 Training Loss: 394.745241 Validation Loss: 342.020035 +Validation loss decreased (349.929157 --> 342.020035). Saving model +Epoch: 26/400 Training Loss: 379.792490 Validation Loss: 333.376750 +Validation loss decreased (342.020035 --> 333.376750). Saving model +Epoch: 27/400 Training Loss: 378.106891 Validation Loss: 333.158253 +Validation loss decreased (333.376750 --> 333.158253). Saving model +Epoch: 28/400 Training Loss: 374.005240 Validation Loss: 341.534550 +Epoch: 29/400 Training Loss: 365.381918 Validation Loss: 343.385013 +Epoch: 30/400 Training Loss: 360.885176 Validation Loss: 326.890084 +Validation loss decreased (333.158253 --> 326.890084). Saving model +Epoch: 31/400 Training Loss: 353.897421 Validation Loss: 325.702542 +Validation loss decreased (326.890084 --> 325.702542). Saving model +Epoch: 32/400 Training Loss: 347.723119 Validation Loss: 317.366541 +Validation loss decreased (325.702542 --> 317.366541). Saving model +Epoch: 33/400 Training Loss: 335.829830 Validation Loss: 294.269661 +Validation loss decreased (317.366541 --> 294.269661). Saving model +Epoch: 34/400 Training Loss: 323.665230 Validation Loss: 307.029580 +Epoch: 35/400 Training Loss: 323.621175 Validation Loss: 283.969697 +Validation loss decreased (294.269661 --> 283.969697). Saving model +Epoch: 36/400 Training Loss: 313.112701 Validation Loss: 282.973031 +Validation loss decreased (283.969697 --> 282.973031). Saving model +Epoch: 37/400 Training Loss: 312.241401 Validation Loss: 269.916116 +Validation loss decreased (282.973031 --> 269.916116). Saving model +Epoch: 38/400 Training Loss: 293.589954 Validation Loss: 293.864337 +Epoch: 39/400 Training Loss: 301.954354 Validation Loss: 290.813052 +Epoch: 40/400 Training Loss: 334.603461 Validation Loss: 280.672247 +Epoch: 41/400 Training Loss: 286.081750 Validation Loss: 338.717083 +Epoch: 42/400 Training Loss: 284.131328 Validation Loss: 245.798872 +Validation loss decreased (269.916116 --> 245.798872). Saving model +Epoch: 43/400 Training Loss: 264.045146 Validation Loss: 237.293003 +Validation loss decreased (245.798872 --> 237.293003). Saving model +Epoch: 44/400 Training Loss: 256.878089 Validation Loss: 240.130936 +Epoch: 45/400 Training Loss: 250.128028 Validation Loss: 226.022200 +Validation loss decreased (237.293003 --> 226.022200). Saving model +Epoch: 46/400 Training Loss: 241.849316 Validation Loss: 217.071646 +Validation loss decreased (226.022200 --> 217.071646). Saving model +Epoch: 47/400 Training Loss: 243.367964 Validation Loss: 209.199570 +Validation loss decreased (217.071646 --> 209.199570). Saving model +Epoch: 48/400 Training Loss: 239.409878 Validation Loss: 209.252160 +Epoch: 49/400 Training Loss: 228.180571 Validation Loss: 203.223335 +Validation loss decreased (209.199570 --> 203.223335). Saving model +Epoch: 50/400 Training Loss: 215.992252 Validation Loss: 204.272842 +Epoch: 51/400 Training Loss: 205.904881 Validation Loss: 187.108767 +Validation loss decreased (203.223335 --> 187.108767). Saving model +Epoch: 52/400 Training Loss: 197.824698 Validation Loss: 189.644662 +Epoch: 53/400 Training Loss: 209.248301 Validation Loss: 180.081342 +Validation loss decreased (187.108767 --> 180.081342). Saving model +Epoch: 54/400 Training Loss: 188.223354 Validation Loss: 164.384920 +Validation loss decreased (180.081342 --> 164.384920). Saving model +Epoch: 55/400 Training Loss: 186.443871 Validation Loss: 170.529489 +Epoch: 56/400 Training Loss: 181.579567 Validation Loss: 155.423865 +Validation loss decreased (164.384920 --> 155.423865). Saving model +Epoch: 57/400 Training Loss: 168.306167 Validation Loss: 158.810373 +Epoch: 58/400 Training Loss: 201.065988 Validation Loss: 157.144164 +Epoch: 59/400 Training Loss: 167.387380 Validation Loss: 149.855929 +Validation loss decreased (155.423865 --> 149.855929). Saving model +Epoch: 60/400 Training Loss: 159.051860 Validation Loss: 141.215441 +Validation loss decreased (149.855929 --> 141.215441). Saving model +Epoch: 61/400 Training Loss: 149.556400 Validation Loss: 142.026790 +Epoch: 62/400 Training Loss: 150.121404 Validation Loss: 204.188889 +Epoch: 63/400 Training Loss: 212.495137 Validation Loss: 150.139140 +Epoch: 64/400 Training Loss: 152.832260 Validation Loss: 135.541699 +Validation loss decreased (141.215441 --> 135.541699). Saving model +Epoch: 65/400 Training Loss: 142.707832 Validation Loss: 123.365094 +Validation loss decreased (135.541699 --> 123.365094). Saving model +Epoch: 66/400 Training Loss: 132.423079 Validation Loss: 118.708302 +Validation loss decreased (123.365094 --> 118.708302). Saving model +Epoch: 67/400 Training Loss: 127.058920 Validation Loss: 118.077027 +Validation loss decreased (118.708302 --> 118.077027). Saving model +Epoch: 68/400 Training Loss: 125.902745 Validation Loss: 113.771395 +Validation loss decreased (118.077027 --> 113.771395). Saving model +Epoch: 69/400 Training Loss: 122.589851 Validation Loss: 108.309938 +Validation loss decreased (113.771395 --> 108.309938). Saving model +Epoch: 70/400 Training Loss: 116.520732 Validation Loss: 104.185483 +Validation loss decreased (108.309938 --> 104.185483). Saving model +Epoch: 71/400 Training Loss: 113.282104 Validation Loss: 105.094542 +Epoch: 72/400 Training Loss: 113.073582 Validation Loss: 102.034964 +Validation loss decreased (104.185483 --> 102.034964). Saving model +Epoch: 73/400 Training Loss: 110.196319 Validation Loss: 100.578707 +Validation loss decreased (102.034964 --> 100.578707). Saving model +Epoch: 74/400 Training Loss: 106.790912 Validation Loss: 97.823300 +Validation loss decreased (100.578707 --> 97.823300). Saving model +Epoch: 75/400 Training Loss: 103.676990 Validation Loss: 93.663480 +Validation loss decreased (97.823300 --> 93.663480). Saving model +Epoch: 76/400 Training Loss: 109.075983 Validation Loss: 97.628516 +Epoch: 77/400 Training Loss: 98.466418 Validation Loss: 88.127295 +Validation loss decreased (93.663480 --> 88.127295). Saving model +Epoch: 78/400 Training Loss: 95.558790 Validation Loss: 87.354366 +Validation loss decreased (88.127295 --> 87.354366). Saving model +Epoch: 79/400 Training Loss: 90.693348 Validation Loss: 84.092111 +Validation loss decreased (87.354366 --> 84.092111). Saving model +Epoch: 80/400 Training Loss: 90.096241 Validation Loss: 89.972719 +Epoch: 81/400 Training Loss: 102.071019 Validation Loss: 82.813178 +Validation loss decreased (84.092111 --> 82.813178). Saving model +Epoch: 82/400 Training Loss: 87.752623 Validation Loss: 81.717514 +Validation loss decreased (82.813178 --> 81.717514). Saving model +Epoch: 83/400 Training Loss: 83.925954 Validation Loss: 79.330445 +Validation loss decreased (81.717514 --> 79.330445). Saving model +Epoch: 84/400 Training Loss: 82.089971 Validation Loss: 77.713488 +Validation loss decreased (79.330445 --> 77.713488). Saving model +Epoch: 85/400 Training Loss: 80.846364 Validation Loss: 75.438952 +Validation loss decreased (77.713488 --> 75.438952). Saving model +Epoch: 86/400 Training Loss: 96.945972 Validation Loss: 81.830757 +Epoch: 87/400 Training Loss: 84.374791 Validation Loss: 92.017662 +Epoch: 88/400 Training Loss: 94.547236 Validation Loss: 78.743844 +Epoch: 89/400 Training Loss: 80.129562 Validation Loss: 70.094970 +Validation loss decreased (75.438952 --> 70.094970). Saving model +Epoch: 90/400 Training Loss: 75.148027 Validation Loss: 67.952423 +Validation loss decreased (70.094970 --> 67.952423). Saving model +Epoch: 91/400 Training Loss: 71.516357 Validation Loss: 67.441796 +Validation loss decreased (67.952423 --> 67.441796). Saving model +Epoch: 92/400 Training Loss: 71.059545 Validation Loss: 65.321013 +Validation loss decreased (67.441796 --> 65.321013). Saving model +Epoch: 93/400 Training Loss: 68.354872 Validation Loss: 64.376034 +Validation loss decreased (65.321013 --> 64.376034). Saving model +Epoch: 94/400 Training Loss: 68.523620 Validation Loss: 62.674626 +Validation loss decreased (64.376034 --> 62.674626). Saving model +Epoch: 95/400 Training Loss: 69.379274 Validation Loss: 66.370282 +Epoch: 96/400 Training Loss: 68.092619 Validation Loss: 64.087731 +Epoch: 97/400 Training Loss: 66.519958 Validation Loss: 61.443635 +Validation loss decreased (62.674626 --> 61.443635). Saving model +Epoch: 98/400 Training Loss: 64.315551 Validation Loss: 60.731580 +Validation loss decreased (61.443635 --> 60.731580). Saving model +Epoch: 99/400 Training Loss: 63.353009 Validation Loss: 58.652497 +Validation loss decreased (60.731580 --> 58.652497). Saving model +Epoch: 100/400 Training Loss: 62.265917 Validation Loss: 58.877543 +Epoch: 101/400 Training Loss: 62.211798 Validation Loss: 59.258699 +Epoch: 102/400 Training Loss: 61.719767 Validation Loss: 57.461481 +Validation loss decreased (58.652497 --> 57.461481). Saving model +Epoch: 103/400 Training Loss: 61.639149 Validation Loss: 58.533605 +Epoch: 104/400 Training Loss: 61.445636 Validation Loss: 56.639582 +Validation loss decreased (57.461481 --> 56.639582). Saving model +Epoch: 105/400 Training Loss: 59.362152 Validation Loss: 56.656629 +Epoch: 106/400 Training Loss: 58.756677 Validation Loss: 55.231681 +Validation loss decreased (56.639582 --> 55.231681). Saving model +Epoch: 107/400 Training Loss: 63.281795 Validation Loss: 59.757134 +Epoch: 108/400 Training Loss: 60.515866 Validation Loss: 56.276711 +Epoch: 109/400 Training Loss: 59.133282 Validation Loss: 54.909756 +Validation loss decreased (55.231681 --> 54.909756). Saving model +Epoch: 110/400 Training Loss: 56.366112 Validation Loss: 53.538045 +Validation loss decreased (54.909756 --> 53.538045). Saving model +Epoch: 111/400 Training Loss: 55.936860 Validation Loss: 52.752753 +Validation loss decreased (53.538045 --> 52.752753). Saving model +Epoch: 112/400 Training Loss: 54.518844 Validation Loss: 51.101270 +Validation loss decreased (52.752753 --> 51.101270). Saving model +Epoch: 113/400 Training Loss: 53.827186 Validation Loss: 51.879462 +Epoch: 114/400 Training Loss: 54.255090 Validation Loss: 52.402470 +Epoch: 115/400 Training Loss: 55.552549 Validation Loss: 52.249155 +Epoch: 116/400 Training Loss: 54.331744 Validation Loss: 51.474586 +Epoch: 117/400 Training Loss: 52.897610 Validation Loss: 50.664583 +Validation loss decreased (51.101270 --> 50.664583). Saving model +Epoch: 118/400 Training Loss: 53.051793 Validation Loss: 49.519841 +Validation loss decreased (50.664583 --> 49.519841). Saving model +Epoch: 119/400 Training Loss: 51.708255 Validation Loss: 48.992335 +Validation loss decreased (49.519841 --> 48.992335). Saving model +Epoch: 120/400 Training Loss: 51.274171 Validation Loss: 48.874392 +Validation loss decreased (48.992335 --> 48.874392). Saving model +Epoch: 121/400 Training Loss: 52.212324 Validation Loss: 48.913681 +Epoch: 122/400 Training Loss: 51.692998 Validation Loss: 49.134355 +Epoch: 123/400 Training Loss: 50.945224 Validation Loss: 48.389371 +Validation loss decreased (48.874392 --> 48.389371). Saving model +Epoch: 124/400 Training Loss: 49.741009 Validation Loss: 47.859187 +Validation loss decreased (48.389371 --> 47.859187). Saving model +Epoch: 125/400 Training Loss: 49.479254 Validation Loss: 47.683828 +Validation loss decreased (47.859187 --> 47.683828). Saving model +Epoch: 126/400 Training Loss: 48.915316 Validation Loss: 53.546905 +Epoch: 127/400 Training Loss: 57.852731 Validation Loss: 49.623144 +Epoch: 128/400 Training Loss: 51.117120 Validation Loss: 47.488822 +Validation loss decreased (47.683828 --> 47.488822). Saving model +Epoch: 129/400 Training Loss: 48.605621 Validation Loss: 45.941612 +Validation loss decreased (47.488822 --> 45.941612). Saving model +Epoch: 130/400 Training Loss: 48.412892 Validation Loss: 46.984053 +Epoch: 131/400 Training Loss: 47.991114 Validation Loss: 45.708279 +Validation loss decreased (45.941612 --> 45.708279). Saving model +Epoch: 132/400 Training Loss: 47.777391 Validation Loss: 45.016074 +Validation loss decreased (45.708279 --> 45.016074). Saving model +Epoch: 133/400 Training Loss: 46.889140 Validation Loss: 45.438185 +Epoch: 134/400 Training Loss: 46.800847 Validation Loss: 47.303258 +Epoch: 135/400 Training Loss: 52.601026 Validation Loss: 45.895785 +Epoch: 136/400 Training Loss: 47.599701 Validation Loss: 44.792831 +Validation loss decreased (45.016074 --> 44.792831). Saving model +Epoch: 137/400 Training Loss: 46.174252 Validation Loss: 43.981920 +Validation loss decreased (44.792831 --> 43.981920). Saving model +Epoch: 138/400 Training Loss: 45.656598 Validation Loss: 44.252446 +Epoch: 139/400 Training Loss: 46.298585 Validation Loss: 43.861838 +Validation loss decreased (43.981920 --> 43.861838). Saving model +Epoch: 140/400 Training Loss: 44.998418 Validation Loss: 43.118733 +Validation loss decreased (43.861838 --> 43.118733). Saving model +Epoch: 141/400 Training Loss: 44.791426 Validation Loss: 43.134085 +Epoch: 142/400 Training Loss: 44.572067 Validation Loss: 43.680795 +Epoch: 143/400 Training Loss: 44.453955 Validation Loss: 43.107780 +Validation loss decreased (43.118733 --> 43.107780). Saving model +Epoch: 144/400 Training Loss: 44.313050 Validation Loss: 42.907387 +Validation loss decreased (43.107780 --> 42.907387). Saving model +Epoch: 145/400 Training Loss: 46.588209 Validation Loss: 44.384092 +Epoch: 146/400 Training Loss: 44.924211 Validation Loss: 43.206105 +Epoch: 147/400 Training Loss: 43.884377 Validation Loss: 42.442903 +Validation loss decreased (42.907387 --> 42.442903). Saving model +Epoch: 148/400 Training Loss: 43.893250 Validation Loss: 42.110008 +Validation loss decreased (42.442903 --> 42.110008). Saving model +Epoch: 149/400 Training Loss: 43.428452 Validation Loss: 41.762002 +Validation loss decreased (42.110008 --> 41.762002). Saving model +Epoch: 150/400 Training Loss: 43.283952 Validation Loss: 42.395872 +Epoch: 151/400 Training Loss: 43.003662 Validation Loss: 41.741479 +Validation loss decreased (41.762002 --> 41.741479). Saving model +Epoch: 152/400 Training Loss: 43.225669 Validation Loss: 42.388687 +Epoch: 153/400 Training Loss: 43.092538 Validation Loss: 41.619283 +Validation loss decreased (41.741479 --> 41.619283). Saving model +Epoch: 154/400 Training Loss: 42.947855 Validation Loss: 41.708224 +Epoch: 155/400 Training Loss: 42.891883 Validation Loss: 41.685392 +Epoch: 156/400 Training Loss: 42.733508 Validation Loss: 41.269432 +Validation loss decreased (41.619283 --> 41.269432). Saving model +Epoch: 157/400 Training Loss: 42.313471 Validation Loss: 40.984817 +Validation loss decreased (41.269432 --> 40.984817). Saving model +Epoch: 158/400 Training Loss: 42.311620 Validation Loss: 40.896179 +Validation loss decreased (40.984817 --> 40.896179). Saving model +Epoch: 159/400 Training Loss: 42.232660 Validation Loss: 41.509980 +Epoch: 160/400 Training Loss: 42.047981 Validation Loss: 40.929867 +Epoch: 161/400 Training Loss: 41.933024 Validation Loss: 40.683537 +Validation loss decreased (40.896179 --> 40.683537). Saving model +Epoch: 162/400 Training Loss: 41.699801 Validation Loss: 40.343880 +Validation loss decreased (40.683537 --> 40.343880). Saving model +Epoch: 163/400 Training Loss: 41.563602 Validation Loss: 40.642308 +Epoch: 164/400 Training Loss: 41.486409 Validation Loss: 40.040694 +Validation loss decreased (40.343880 --> 40.040694). Saving model +Epoch: 165/400 Training Loss: 41.254304 Validation Loss: 40.393017 +Epoch: 166/400 Training Loss: 41.210776 Validation Loss: 40.261863 +Epoch: 167/400 Training Loss: 41.541789 Validation Loss: 40.360627 +Epoch: 168/400 Training Loss: 41.157151 Validation Loss: 40.250205 +Epoch: 169/400 Training Loss: 41.989366 Validation Loss: 42.370234 +Epoch: 170/400 Training Loss: 41.887676 Validation Loss: 40.112599 +Epoch: 171/400 Training Loss: 40.685515 Validation Loss: 39.714005 +Validation loss decreased (40.040694 --> 39.714005). Saving model +Epoch: 172/400 Training Loss: 41.004848 Validation Loss: 39.738895 +Epoch: 173/400 Training Loss: 40.674297 Validation Loss: 39.434154 +Validation loss decreased (39.714005 --> 39.434154). Saving model +Epoch: 174/400 Training Loss: 40.587094 Validation Loss: 39.242333 +Validation loss decreased (39.434154 --> 39.242333). Saving model +Epoch: 175/400 Training Loss: 40.486195 Validation Loss: 39.002650 +Validation loss decreased (39.242333 --> 39.002650). Saving model +Epoch: 176/400 Training Loss: 39.985531 Validation Loss: 39.069855 +Epoch: 177/400 Training Loss: 39.864383 Validation Loss: 38.980456 +Validation loss decreased (39.002650 --> 38.980456). Saving model +Epoch: 178/400 Training Loss: 39.853218 Validation Loss: 38.901299 +Validation loss decreased (38.980456 --> 38.901299). Saving model +Epoch: 179/400 Training Loss: 39.868983 Validation Loss: 39.527089 +Epoch: 180/400 Training Loss: 40.102557 Validation Loss: 39.190627 +Epoch: 181/400 Training Loss: 40.005243 Validation Loss: 38.496270 +Validation loss decreased (38.901299 --> 38.496270). Saving model +Epoch: 182/400 Training Loss: 39.427758 Validation Loss: 38.700621 +Epoch: 183/400 Training Loss: 39.492923 Validation Loss: 38.747272 +Epoch: 184/400 Training Loss: 39.435629 Validation Loss: 38.377984 +Validation loss decreased (38.496270 --> 38.377984). Saving model +Epoch: 185/400 Training Loss: 39.413908 Validation Loss: 38.559451 +Epoch: 186/400 Training Loss: 39.329538 Validation Loss: 39.410018 +Epoch: 187/400 Training Loss: 40.684599 Validation Loss: 38.781829 +Epoch: 188/400 Training Loss: 39.577623 Validation Loss: 38.443941 +Epoch: 189/400 Training Loss: 39.549838 Validation Loss: 41.486069 +Epoch: 190/400 Training Loss: 39.959455 Validation Loss: 38.302380 +Validation loss decreased (38.377984 --> 38.302380). Saving model +Epoch: 191/400 Training Loss: 38.908573 Validation Loss: 37.864371 +Validation loss decreased (38.302380 --> 37.864371). Saving model +Epoch: 192/400 Training Loss: 38.743048 Validation Loss: 37.868151 +Epoch: 193/400 Training Loss: 38.394250 Validation Loss: 37.694380 +Validation loss decreased (37.864371 --> 37.694380). Saving model +Epoch: 194/400 Training Loss: 38.828681 Validation Loss: 37.958403 +Epoch: 195/400 Training Loss: 38.752893 Validation Loss: 37.957136 +Epoch: 196/400 Training Loss: 38.409605 Validation Loss: 37.551361 +Validation loss decreased (37.694380 --> 37.551361). Saving model +Epoch: 197/400 Training Loss: 38.336854 Validation Loss: 37.440372 +Validation loss decreased (37.551361 --> 37.440372). Saving model +Epoch: 198/400 Training Loss: 38.231873 Validation Loss: 37.687851 +Epoch: 199/400 Training Loss: 38.642446 Validation Loss: 37.598394 +Epoch: 200/400 Training Loss: 38.528422 Validation Loss: 37.477254 +Epoch: 201/400 Training Loss: 38.445154 Validation Loss: 37.707065 +Epoch: 202/400 Training Loss: 38.792979 Validation Loss: 37.561648 +Epoch: 203/400 Training Loss: 38.120606 Validation Loss: 37.257866 +Validation loss decreased (37.440372 --> 37.257866). Saving model +Epoch: 204/400 Training Loss: 38.300913 Validation Loss: 37.454947 +Epoch: 205/400 Training Loss: 38.287117 Validation Loss: 37.332837 +Epoch: 206/400 Training Loss: 38.050789 Validation Loss: 37.087106 +Validation loss decreased (37.257866 --> 37.087106). Saving model +Epoch: 207/400 Training Loss: 38.731873 Validation Loss: 38.400833 +Epoch: 208/400 Training Loss: 38.476804 Validation Loss: 37.324264 +Epoch: 209/400 Training Loss: 37.865620 Validation Loss: 37.177320 +Epoch: 210/400 Training Loss: 37.778688 Validation Loss: 37.013744 +Validation loss decreased (37.087106 --> 37.013744). Saving model +Epoch: 211/400 Training Loss: 37.715953 Validation Loss: 37.004627 +Validation loss decreased (37.013744 --> 37.004627). Saving model +Epoch: 212/400 Training Loss: 37.601938 Validation Loss: 36.834124 +Validation loss decreased (37.004627 --> 36.834124). Saving model +Epoch: 213/400 Training Loss: 37.725169 Validation Loss: 37.036269 +Epoch: 214/400 Training Loss: 37.587018 Validation Loss: 36.880560 +Epoch: 215/400 Training Loss: 37.765382 Validation Loss: 36.922154 +Epoch: 216/400 Training Loss: 37.603968 Validation Loss: 36.944878 +Epoch: 217/400 Training Loss: 37.388321 Validation Loss: 36.995525 +Epoch: 218/400 Training Loss: 37.586586 Validation Loss: 36.817358 +Validation loss decreased (36.834124 --> 36.817358). Saving model +Epoch: 219/400 Training Loss: 37.450390 Validation Loss: 36.823903 +Epoch: 220/400 Training Loss: 37.438260 Validation Loss: 37.091443 +Epoch: 221/400 Training Loss: 37.451868 Validation Loss: 36.699982 +Validation loss decreased (36.817358 --> 36.699982). Saving model +Epoch: 222/400 Training Loss: 37.331056 Validation Loss: 36.738586 +Epoch: 223/400 Training Loss: 37.156265 Validation Loss: 36.625559 +Validation loss decreased (36.699982 --> 36.625559). Saving model +Epoch: 224/400 Training Loss: 37.350534 Validation Loss: 36.672745 +Epoch: 225/400 Training Loss: 37.220693 Validation Loss: 36.429339 +Validation loss decreased (36.625559 --> 36.429339). Saving model +Epoch: 226/400 Training Loss: 37.199577 Validation Loss: 36.518238 +Epoch: 227/400 Training Loss: 37.168482 Validation Loss: 36.388669 +Validation loss decreased (36.429339 --> 36.388669). Saving model +Epoch: 228/400 Training Loss: 37.127311 Validation Loss: 36.633259 +Epoch: 229/400 Training Loss: 37.344308 Validation Loss: 36.621206 +Epoch: 230/400 Training Loss: 37.074235 Validation Loss: 36.627502 +Epoch: 231/400 Training Loss: 37.000811 Validation Loss: 36.341521 +Validation loss decreased (36.388669 --> 36.341521). Saving model +Epoch: 232/400 Training Loss: 37.035148 Validation Loss: 36.203529 +Validation loss decreased (36.341521 --> 36.203529). Saving model +Epoch: 233/400 Training Loss: 37.067683 Validation Loss: 36.297363 +Epoch: 234/400 Training Loss: 37.004985 Validation Loss: 36.260934 +Epoch: 235/400 Training Loss: 36.946609 Validation Loss: 36.577809 +Epoch: 236/400 Training Loss: 36.942857 Validation Loss: 36.271908 +Epoch: 237/400 Training Loss: 36.907607 Validation Loss: 36.323314 +Epoch: 238/400 Training Loss: 37.072438 Validation Loss: 36.282375 +Epoch: 239/400 Training Loss: 36.799831 Validation Loss: 36.083367 +Validation loss decreased (36.203529 --> 36.083367). Saving model +Epoch: 240/400 Training Loss: 36.706383 Validation Loss: 36.036335 +Validation loss decreased (36.083367 --> 36.036335). Saving model +Epoch: 241/400 Training Loss: 36.653450 Validation Loss: 36.083683 +Epoch: 242/400 Training Loss: 36.545019 Validation Loss: 36.034166 +Validation loss decreased (36.036335 --> 36.034166). Saving model +Epoch: 243/400 Training Loss: 36.691423 Validation Loss: 35.944579 +Validation loss decreased (36.034166 --> 35.944579). Saving model +Epoch: 244/400 Training Loss: 36.574901 Validation Loss: 36.199194 +Epoch: 245/400 Training Loss: 36.611505 Validation Loss: 36.025941 +Epoch: 246/400 Training Loss: 36.616985 Validation Loss: 36.046562 +Epoch: 247/400 Training Loss: 36.615386 Validation Loss: 36.105086 +Epoch: 248/400 Training Loss: 36.528197 Validation Loss: 36.000503 +Epoch: 249/400 Training Loss: 36.674049 Validation Loss: 35.928313 +Validation loss decreased (35.944579 --> 35.928313). Saving model +Epoch: 250/400 Training Loss: 36.648528 Validation Loss: 35.889539 +Validation loss decreased (35.928313 --> 35.889539). Saving model +Epoch: 251/400 Training Loss: 36.515298 Validation Loss: 36.009999 +Epoch: 252/400 Training Loss: 36.653539 Validation Loss: 35.923156 +Epoch: 253/400 Training Loss: 36.393023 Validation Loss: 35.890542 +Epoch: 254/400 Training Loss: 36.387751 Validation Loss: 35.684786 +Validation loss decreased (35.889539 --> 35.684786). Saving model +Epoch: 255/400 Training Loss: 36.471658 Validation Loss: 35.767071 +Epoch: 256/400 Training Loss: 36.582039 Validation Loss: 35.866774 +Epoch: 257/400 Training Loss: 36.207661 Validation Loss: 35.746829 +Epoch: 258/400 Training Loss: 36.290627 Validation Loss: 35.873632 +Epoch: 259/400 Training Loss: 36.349402 Validation Loss: 35.786994 +Epoch: 260/400 Training Loss: 36.296049 Validation Loss: 35.640916 +Validation loss decreased (35.684786 --> 35.640916). Saving model +Epoch: 261/400 Training Loss: 36.175508 Validation Loss: 35.711282 +Epoch: 262/400 Training Loss: 36.327963 Validation Loss: 35.795329 +Epoch: 263/400 Training Loss: 36.067179 Validation Loss: 35.680037 +Epoch: 264/400 Training Loss: 36.246835 Validation Loss: 35.588320 +Validation loss decreased (35.640916 --> 35.588320). Saving model +Epoch: 265/400 Training Loss: 36.159220 Validation Loss: 35.692542 +Epoch: 266/400 Training Loss: 36.330259 Validation Loss: 35.616240 +Epoch: 267/400 Training Loss: 36.303258 Validation Loss: 35.582822 +Validation loss decreased (35.588320 --> 35.582822). Saving model +Epoch: 268/400 Training Loss: 36.185820 Validation Loss: 35.724909 +Epoch: 269/400 Training Loss: 36.100423 Validation Loss: 35.613948 +Epoch: 270/400 Training Loss: 36.136594 Validation Loss: 35.768814 +Epoch: 271/400 Training Loss: 36.169090 Validation Loss: 35.609937 +Epoch: 272/400 Training Loss: 36.289563 Validation Loss: 35.545124 +Validation loss decreased (35.582822 --> 35.545124). Saving model +Epoch: 273/400 Training Loss: 36.112812 Validation Loss: 35.587169 +Epoch: 274/400 Training Loss: 36.122258 Validation Loss: 35.645974 +Epoch: 275/400 Training Loss: 36.035289 Validation Loss: 35.539972 +Validation loss decreased (35.545124 --> 35.539972). Saving model +Epoch: 276/400 Training Loss: 35.930510 Validation Loss: 35.443530 +Validation loss decreased (35.539972 --> 35.443530). Saving model +Epoch: 277/400 Training Loss: 35.997929 Validation Loss: 35.531496 +Epoch: 278/400 Training Loss: 35.920074 Validation Loss: 35.580903 +Epoch: 279/400 Training Loss: 36.039565 Validation Loss: 35.451800 +Epoch: 280/400 Training Loss: 35.814384 Validation Loss: 35.490255 +Epoch: 281/400 Training Loss: 35.964391 Validation Loss: 35.449806 +Epoch: 282/400 Training Loss: 35.911691 Validation Loss: 35.428894 +Validation loss decreased (35.443530 --> 35.428894). Saving model +Epoch: 283/400 Training Loss: 36.079780 Validation Loss: 35.466443 +Epoch: 284/400 Training Loss: 35.985788 Validation Loss: 35.404902 +Validation loss decreased (35.428894 --> 35.404902). Saving model +Epoch: 285/400 Training Loss: 35.966939 Validation Loss: 35.424501 +Epoch: 286/400 Training Loss: 35.802884 Validation Loss: 35.527387 +Epoch: 287/400 Training Loss: 36.004797 Validation Loss: 35.450703 +Epoch: 288/400 Training Loss: 35.952135 Validation Loss: 35.408934 +Epoch: 289/400 Training Loss: 35.921758 Validation Loss: 35.346544 +Validation loss decreased (35.404902 --> 35.346544). Saving model +Epoch: 290/400 Training Loss: 35.826612 Validation Loss: 35.302454 +Validation loss decreased (35.346544 --> 35.302454). Saving model +Epoch: 291/400 Training Loss: 35.871033 Validation Loss: 35.224123 +Validation loss decreased (35.302454 --> 35.224123). Saving model +Epoch: 292/400 Training Loss: 35.697640 Validation Loss: 35.284427 +Epoch: 293/400 Training Loss: 35.830342 Validation Loss: 35.478160 +Epoch: 294/400 Training Loss: 35.812215 Validation Loss: 35.377393 +Epoch: 295/400 Training Loss: 35.787164 Validation Loss: 35.467429 +Epoch: 296/400 Training Loss: 35.738947 Validation Loss: 35.309890 +Epoch: 297/400 Training Loss: 35.678421 Validation Loss: 35.349601 +Epoch: 298/400 Training Loss: 35.681317 Validation Loss: 35.229902 +Epoch: 299/400 Training Loss: 35.771867 Validation Loss: 35.207690 +Validation loss decreased (35.224123 --> 35.207690). Saving model +Epoch: 300/400 Training Loss: 35.669558 Validation Loss: 35.227980 +Epoch: 301/400 Training Loss: 35.909636 Validation Loss: 35.141825 +Validation loss decreased (35.207690 --> 35.141825). Saving model +Epoch: 302/400 Training Loss: 35.605330 Validation Loss: 35.157807 +Epoch: 303/400 Training Loss: 35.526230 Validation Loss: 35.268457 +Epoch: 304/400 Training Loss: 35.771165 Validation Loss: 35.160081 +Epoch: 305/400 Training Loss: 35.574597 Validation Loss: 35.065030 +Validation loss decreased (35.141825 --> 35.065030). Saving model +Epoch: 306/400 Training Loss: 35.636006 Validation Loss: 35.221144 +Epoch: 307/400 Training Loss: 35.827217 Validation Loss: 35.126165 +Epoch: 308/400 Training Loss: 35.690998 Validation Loss: 35.216920 +Epoch: 309/400 Training Loss: 35.818968 Validation Loss: 35.191586 +Epoch: 310/400 Training Loss: 35.679373 Validation Loss: 35.166155 +Epoch: 311/400 Training Loss: 35.701209 Validation Loss: 35.221721 +Epoch: 312/400 Training Loss: 35.751489 Validation Loss: 35.197836 +Epoch: 313/400 Training Loss: 35.648732 Validation Loss: 35.127778 +Epoch: 314/400 Training Loss: 35.762243 Validation Loss: 35.182191 +Epoch: 315/400 Training Loss: 35.609246 Validation Loss: 35.010854 +Validation loss decreased (35.065030 --> 35.010854). Saving model +Epoch: 316/400 Training Loss: 35.624881 Validation Loss: 34.904401 +Validation loss decreased (35.010854 --> 34.904401). Saving model +Epoch: 317/400 Training Loss: 35.745198 Validation Loss: 35.119743 +Epoch: 318/400 Training Loss: 35.504421 Validation Loss: 35.270239 +Epoch: 319/400 Training Loss: 35.501269 Validation Loss: 35.066054 +Epoch: 320/400 Training Loss: 35.547222 Validation Loss: 35.106576 +Epoch: 321/400 Training Loss: 35.595175 Validation Loss: 35.012387 +Epoch: 322/400 Training Loss: 35.706941 Validation Loss: 35.041986 +Epoch: 323/400 Training Loss: 35.536717 Validation Loss: 35.367278 +Epoch: 324/400 Training Loss: 35.521726 Validation Loss: 35.201117 +Epoch: 325/400 Training Loss: 35.522929 Validation Loss: 35.227608 +Epoch: 326/400 Training Loss: 35.459869 Validation Loss: 35.049248 +Epoch: 327/400 Training Loss: 35.646445 Validation Loss: 34.991243 +Epoch: 328/400 Training Loss: 35.498541 Validation Loss: 35.107256 +Epoch: 329/400 Training Loss: 35.422763 Validation Loss: 35.004238 +Epoch: 330/400 Training Loss: 35.472972 Validation Loss: 34.993232 +Epoch: 331/400 Training Loss: 35.633071 Validation Loss: 35.013275 +Epoch: 332/400 Training Loss: 35.582032 Validation Loss: 34.986335 +Epoch: 333/400 Training Loss: 35.478102 Validation Loss: 34.958489 +Epoch: 334/400 Training Loss: 35.693917 Validation Loss: 34.979960 +Epoch: 335/400 Training Loss: 35.497017 Validation Loss: 35.058331 +Epoch: 336/400 Training Loss: 35.623244 Validation Loss: 35.075855 +Epoch: 337/400 Training Loss: 35.445398 Validation Loss: 35.159738 +Epoch: 338/400 Training Loss: 35.492002 Validation Loss: 35.043491 +Epoch: 339/400 Training Loss: 35.467680 Validation Loss: 34.838678 +Validation loss decreased (34.904401 --> 34.838678). Saving model +Epoch: 340/400 Training Loss: 35.502719 Validation Loss: 35.057292 +Epoch: 341/400 Training Loss: 35.448149 Validation Loss: 34.946772 +Epoch: 342/400 Training Loss: 35.393385 Validation Loss: 34.991840 +Epoch: 343/400 Training Loss: 35.340270 Validation Loss: 34.932102 +Epoch: 344/400 Training Loss: 35.391920 Validation Loss: 35.173562 +Epoch: 345/400 Training Loss: 35.452600 Validation Loss: 34.985145 +Epoch: 346/400 Training Loss: 35.410507 Validation Loss: 34.904968 +Epoch: 347/400 Training Loss: 35.498900 Validation Loss: 35.014148 +Epoch: 348/400 Training Loss: 35.509837 Validation Loss: 35.039991 +Epoch: 349/400 Training Loss: 35.489143 Validation Loss: 35.103308 +Epoch: 350/400 Training Loss: 35.517627 Validation Loss: 35.070972 +Epoch: 351/400 Training Loss: 35.444653 Validation Loss: 35.124124 +Epoch: 352/400 Training Loss: 35.406604 Validation Loss: 34.929038 +Epoch: 353/400 Training Loss: 35.338097 Validation Loss: 34.979883 +Epoch: 354/400 Training Loss: 35.357802 Validation Loss: 34.981022 +Epoch: 355/400 Training Loss: 35.378860 Validation Loss: 34.853696 +Epoch: 356/400 Training Loss: 35.410955 Validation Loss: 34.961032 +Epoch: 357/400 Training Loss: 35.363086 Validation Loss: 34.888832 +Epoch: 358/400 Training Loss: 35.275725 Validation Loss: 35.009721 +Epoch: 359/400 Training Loss: 35.301255 Validation Loss: 35.031714 +Epoch: 360/400 Training Loss: 35.318381 Validation Loss: 34.923461 +Epoch: 361/400 Training Loss: 35.406656 Validation Loss: 34.971957 +Epoch: 362/400 Training Loss: 35.268640 Validation Loss: 34.784278 +Validation loss decreased (34.838678 --> 34.784278). Saving model +Epoch: 363/400 Training Loss: 35.324945 Validation Loss: 35.102740 +Epoch: 364/400 Training Loss: 35.456010 Validation Loss: 34.875634 +Epoch: 365/400 Training Loss: 35.284824 Validation Loss: 35.025704 +Epoch: 366/400 Training Loss: 35.267500 Validation Loss: 34.949517 +Epoch: 367/400 Training Loss: 35.325632 Validation Loss: 34.842817 +Epoch: 368/400 Training Loss: 35.307169 Validation Loss: 34.867529 +Epoch: 369/400 Training Loss: 35.240334 Validation Loss: 34.896460 +Epoch: 370/400 Training Loss: 35.275042 Validation Loss: 34.920585 +Epoch: 371/400 Training Loss: 35.357192 Validation Loss: 34.983611 +Epoch: 372/400 Training Loss: 35.298193 Validation Loss: 34.794387 +Epoch: 373/400 Training Loss: 35.378478 Validation Loss: 34.884846 +Epoch: 374/400 Training Loss: 35.250771 Validation Loss: 34.990587 +Epoch: 375/400 Training Loss: 35.256680 Validation Loss: 34.857173 +Epoch: 376/400 Training Loss: 35.229192 Validation Loss: 34.916108 +Epoch: 377/400 Training Loss: 35.275788 Validation Loss: 34.925675 +Epoch: 378/400 Training Loss: 35.375301 Validation Loss: 34.916054 +Epoch: 379/400 Training Loss: 35.150901 Validation Loss: 34.926220 +Epoch: 380/400 Training Loss: 35.321856 Validation Loss: 34.867128 +Epoch: 381/400 Training Loss: 35.316582 Validation Loss: 34.908194 +Epoch: 382/400 Training Loss: 35.261150 Validation Loss: 34.828085 +Epoch: 383/400 Training Loss: 35.296560 Validation Loss: 34.850617 +Epoch: 384/400 Training Loss: 35.366144 Validation Loss: 34.857956 +Epoch: 385/400 Training Loss: 35.329152 Validation Loss: 34.789192 +Epoch: 386/400 Training Loss: 35.404383 Validation Loss: 35.007324 +Epoch: 387/400 Training Loss: 35.272891 Validation Loss: 34.885933 +Epoch: 388/400 Training Loss: 35.472208 Validation Loss: 34.675356 +Validation loss decreased (34.784278 --> 34.675356). Saving model +Epoch: 389/400 Training Loss: 35.287885 Validation Loss: 34.888716 +Epoch: 390/400 Training Loss: 35.205883 Validation Loss: 34.952520 +Epoch: 391/400 Training Loss: 35.218121 Validation Loss: 34.893261 +Epoch: 392/400 Training Loss: 35.275568 Validation Loss: 34.903638 +Epoch: 393/400 Training Loss: 35.295596 Validation Loss: 34.884959 +Epoch: 394/400 Training Loss: 35.259685 Validation Loss: 34.944981 +Epoch: 395/400 Training Loss: 35.291020 Validation Loss: 34.830115 +Epoch: 396/400 Training Loss: 35.251440 Validation Loss: 34.809096 +Epoch: 397/400 Training Loss: 35.290915 Validation Loss: 34.924404 +Epoch: 398/400 Training Loss: 35.311043 Validation Loss: 34.721922 +Epoch: 399/400 Training Loss: 35.194690 Validation Loss: 34.917457 +Epoch: 400/400 Training Loss: 35.225279 Validation Loss: 34.860954 +Successfully created the testing directory ./model/gen_images +Successfully created the testing directory ./model/pred_threshold +Successfully created the testing directory ./model/label_threshold +Traceback (most recent call last): + File "./train.py", line 409, in + if im_n_flat[j] != 0: +KeyboardInterrupt From 92d97051e1da97759ea25232ab02637480795ce8 Mon Sep 17 00:00:00 2001 From: FrostNov4 <97688822+FrostNov4@users.noreply.github.com> Date: Fri, 27 Oct 2023 13:13:02 +1000 Subject: [PATCH 29/45] Update, readme. Conclusion --- recognition/s4627182_Improved_Unet/README.md | 27 +++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/recognition/s4627182_Improved_Unet/README.md b/recognition/s4627182_Improved_Unet/README.md index 3a8680c77..a9d53f740 100644 --- a/recognition/s4627182_Improved_Unet/README.md +++ b/recognition/s4627182_Improved_Unet/README.md @@ -18,6 +18,8 @@ https://arxiv.org/abs/1802.10508v1 which enables precise localization. Through skip connections, features from the contracting path are concatenated with the expansive path, enhancing localization capabilities. + ![Subnetworks architecture](./additional_images/unet) + The activations in the context pathway are computed by context modules. Each context module is in fact a pre-activation residual block with two 3x3x3 convolutional layers and a dropout layer (p_drop = 0.3) in between. Context modules are connected @@ -73,8 +75,31 @@ In machine learning, it measures the difference between predicted and true value tqdm==4.64.1 wandb==0.13.5 +## Training loss vs Epoches + + ![Subnetworks architecture](./additional_images/Train_loss_vs_Epoches) + + +## Valid loss vs Epoches + + ![Subnetworks architecture](./additional_images/valid_loss_vs_epoches) + + +## Predict + + The input is + ![Subnetworks architecture](./additional_images/ISIC_0000003) + + The output is + ![Subnetworks architecture](./additional_images/ISIC_0000003_out) + + - +## Results + The final model get a Mean Dice Score : 0.9940897984524689. + + + From be106f33f9cedac56477795924f4280094da8be9 Mon Sep 17 00:00:00 2001 From: FrostNov4 <97688822+FrostNov4@users.noreply.github.com> Date: Fri, 27 Oct 2023 13:15:08 +1000 Subject: [PATCH 30/45] Update, readme. --- recognition/s4627182_Improved_Unet/README.md | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/recognition/s4627182_Improved_Unet/README.md b/recognition/s4627182_Improved_Unet/README.md index a9d53f740..d0c4332d3 100644 --- a/recognition/s4627182_Improved_Unet/README.md +++ b/recognition/s4627182_Improved_Unet/README.md @@ -18,7 +18,7 @@ https://arxiv.org/abs/1802.10508v1 which enables precise localization. Through skip connections, features from the contracting path are concatenated with the expansive path, enhancing localization capabilities. - ![Subnetworks architecture](./additional_images/unet) + ![Subnetworks architecture](./additional_images/unet.png) The activations in the context pathway are computed by context modules. Each context module is in fact a pre-activation residual block with two 3x3x3 convolutional @@ -77,21 +77,23 @@ In machine learning, it measures the difference between predicted and true value ## Training loss vs Epoches - ![Subnetworks architecture](./additional_images/Train_loss_vs_Epoches) + ![Subnetworks architecture](./additional_images/Train_loss_vs_Epoches.png) ## Valid loss vs Epoches - ![Subnetworks architecture](./additional_images/valid_loss_vs_epoches) + ![Subnetworks architecture](./additional_images/valid_loss_vs_epoches.png) -## Predict - +## Predict The input is - ![Subnetworks architecture](./additional_images/ISIC_0000003) + + ![Subnetworks architecture](./additional_images/ISIC_0000003.jpg) + The output is - ![Subnetworks architecture](./additional_images/ISIC_0000003_out) + + ![Subnetworks architecture](./additional_images/ISIC_0000003_out.jpg) From 7ec417009a5ab6fd83df32bcd25163ee5fcb5db1 Mon Sep 17 00:00:00 2001 From: FrostNov4 <97688822+FrostNov4@users.noreply.github.com> Date: Fri, 27 Oct 2023 13:18:49 +1000 Subject: [PATCH 31/45] Update, readme. --- recognition/s4627182_Improved_Unet/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/recognition/s4627182_Improved_Unet/README.md b/recognition/s4627182_Improved_Unet/README.md index d0c4332d3..aa723ed7e 100644 --- a/recognition/s4627182_Improved_Unet/README.md +++ b/recognition/s4627182_Improved_Unet/README.md @@ -80,6 +80,7 @@ In machine learning, it measures the difference between predicted and true value ![Subnetworks architecture](./additional_images/Train_loss_vs_Epoches.png) + ## Valid loss vs Epoches ![Subnetworks architecture](./additional_images/valid_loss_vs_epoches.png) From 002139e816bcde1afca6f1e9a0423421fce177de Mon Sep 17 00:00:00 2001 From: FrostNov4 <97688822+FrostNov4@users.noreply.github.com> Date: Fri, 27 Oct 2023 13:19:56 +1000 Subject: [PATCH 32/45] Update, readme. --- recognition/s4627182_Improved_Unet/README.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/recognition/s4627182_Improved_Unet/README.md b/recognition/s4627182_Improved_Unet/README.md index aa723ed7e..63db7c682 100644 --- a/recognition/s4627182_Improved_Unet/README.md +++ b/recognition/s4627182_Improved_Unet/README.md @@ -77,24 +77,23 @@ In machine learning, it measures the difference between predicted and true value ## Training loss vs Epoches - ![Subnetworks architecture](./additional_images/Train_loss_vs_Epoches.png) - + ![Unet](./additional_images/Train_loss_vs_Epoches.png) ## Valid loss vs Epoches - ![Subnetworks architecture](./additional_images/valid_loss_vs_epoches.png) + ![valid_vs_epoches](./additional_images/valid_loss_vs_epoches.png) ## Predict The input is - ![Subnetworks architecture](./additional_images/ISIC_0000003.jpg) + ![Input](./additional_images/ISIC_0000003.jpg) The output is - ![Subnetworks architecture](./additional_images/ISIC_0000003_out.jpg) + ![Output](./additional_images/ISIC_0000003_out.jpg) From 184577c86d00c700ef1d045e6441c91ad4e4b007 Mon Sep 17 00:00:00 2001 From: FrostNov4 <97688822+FrostNov4@users.noreply.github.com> Date: Fri, 27 Oct 2023 13:20:36 +1000 Subject: [PATCH 33/45] Update, readme. --- recognition/s4627182_Improved_Unet/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/recognition/s4627182_Improved_Unet/README.md b/recognition/s4627182_Improved_Unet/README.md index 63db7c682..40a2d0869 100644 --- a/recognition/s4627182_Improved_Unet/README.md +++ b/recognition/s4627182_Improved_Unet/README.md @@ -18,7 +18,7 @@ https://arxiv.org/abs/1802.10508v1 which enables precise localization. Through skip connections, features from the contracting path are concatenated with the expansive path, enhancing localization capabilities. - ![Subnetworks architecture](./additional_images/unet.png) + ![Unet](./additional_images/unet.png) The activations in the context pathway are computed by context modules. Each context module is in fact a pre-activation residual block with two 3x3x3 convolutional From 5dcfa503f938ddafbb8c819855bb7b03447e4cb1 Mon Sep 17 00:00:00 2001 From: FrostNov4 <97688822+FrostNov4@users.noreply.github.com> Date: Fri, 27 Oct 2023 13:21:51 +1000 Subject: [PATCH 34/45] Update, readme. --- recognition/s4627182_Improved_Unet/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/recognition/s4627182_Improved_Unet/README.md b/recognition/s4627182_Improved_Unet/README.md index 40a2d0869..5f67eeb6b 100644 --- a/recognition/s4627182_Improved_Unet/README.md +++ b/recognition/s4627182_Improved_Unet/README.md @@ -77,7 +77,7 @@ In machine learning, it measures the difference between predicted and true value ## Training loss vs Epoches - ![Unet](./additional_images/Train_loss_vs_Epoches.png) + ![train_vs_Epoches](./additional_images/Train_loss_vs_Epoches.png) ## Valid loss vs Epoches From fa109c4b98acc188cca5aea1a701087458bf4513 Mon Sep 17 00:00:00 2001 From: FrostNov4 <97688822+FrostNov4@users.noreply.github.com> Date: Fri, 27 Oct 2023 13:40:20 +1000 Subject: [PATCH 35/45] Update, readme. --- recognition/s4627182_Improved_Unet/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/recognition/s4627182_Improved_Unet/README.md b/recognition/s4627182_Improved_Unet/README.md index 5f67eeb6b..73a126987 100644 --- a/recognition/s4627182_Improved_Unet/README.md +++ b/recognition/s4627182_Improved_Unet/README.md @@ -77,23 +77,23 @@ In machine learning, it measures the difference between predicted and true value ## Training loss vs Epoches - ![train_vs_Epoches](./additional_images/Train_loss_vs_Epoches.png) + ![train_vs_Epoches](./additional_Images/Train_loss_vs_Epoches.png) ## Valid loss vs Epoches - ![valid_vs_epoches](./additional_images/valid_loss_vs_epoches.png) + ![valid_vs_epoches](./additional_Images/valid_loss_vs_epoches.png) ## Predict The input is - ![Input](./additional_images/ISIC_0000003.jpg) + ![Input](./additional_Images/ISIC_0000003.jpg) The output is - ![Output](./additional_images/ISIC_0000003_out.jpg) + ![Output](./additional_Images/ISIC_0000003_out.jpg) From f1812a12d605da734d4d37245f74966521002874 Mon Sep 17 00:00:00 2001 From: FrostNov4 <97688822+FrostNov4@users.noreply.github.com> Date: Tue, 28 Nov 2023 04:15:07 +1000 Subject: [PATCH 36/45] model modified to follow the structure in the paper. --- recognition/s4627182_Improved_Unet/Modules.py | 42 +++++++++---------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/recognition/s4627182_Improved_Unet/Modules.py b/recognition/s4627182_Improved_Unet/Modules.py index 8678185db..4bc70e28f 100644 --- a/recognition/s4627182_Improved_Unet/Modules.py +++ b/recognition/s4627182_Improved_Unet/Modules.py @@ -211,39 +211,39 @@ def __init__(self, in_channels, num_classes=2): super(UNet_For_Brain, self).__init__() # Encoder - self.enc1 = nn.Conv2d(in_channels, 16 * 4, kernel_size=3, stride=1, padding=1) - self.context1 = ContextModule(16 * 4, 16 * 4) - self.enc2 = nn.Conv2d(16 * 4, 32 * 4, kernel_size=3, stride=2, padding=1) - self.context2 = ContextModule(32 * 4, 32 * 4) - self.enc3 = nn.Conv2d(32 * 4, 64 * 4, kernel_size=3, stride=2, padding=1) - self.context3 = ContextModule(64 * 4, 64 * 4) - self.enc4 = nn.Conv2d(64 * 4, 128 * 4, kernel_size=3, stride=2, padding=1) - self.context4 = ContextModule(128 * 4, 128 * 4) + self.enc1 = nn.Conv2d(in_channels, 16, kernel_size=3, stride=1, padding=1) + self.context1 = ContextModule(16, 16) + self.enc2 = nn.Conv2d(16, 32, kernel_size=3, stride=2, padding=1) + self.context2 = ContextModule(32, 32) + self.enc3 = nn.Conv2d(32, 64, kernel_size=3, stride=2, padding=1) + self.context3 = ContextModule(64, 64) + self.enc4 = nn.Conv2d(64, 128, kernel_size=3, stride=2, padding=1) + self.context4 = ContextModule(128, 128) # Bottleneck - self.bottleneck = nn.Conv2d(128 * 4, 256 * 4, kernel_size=3, stride=2, padding=1) - self.bottleneck_context = ContextModule(256 * 4, 256 * 4) - self.up_bottleneck = UpsamplingModule(256 * 4, 128 * 4) + self.bottleneck = nn.Conv2d(128, 256, kernel_size=3, stride=2, padding=1) + self.bottleneck_context = ContextModule(256, 256) + self.up_bottleneck = UpsamplingModule(256, 128) # Decoder - self.local1 = LocalisationModule(256 * 4, 128 * 4) - self.up1 = UpsamplingModule(128 * 4, 64 * 4) + self.local1 = LocalisationModule(256, 128) + self.up1 = UpsamplingModule(128, 64) - self.local2 = LocalisationModule(128 * 4, 64 * 4) - self.up2 = UpsamplingModule(64 * 4, 32 * 4) + self.local2 = LocalisationModule(128, 64) + self.up2 = UpsamplingModule(64, 32) - self.seg1 = SegmentationLayer(64 * 4, num_classes) + self.seg1 = SegmentationLayer(64, num_classes) self.upsample_seg1 = UpscalingLayer() - self.local3 = LocalisationModule(64 * 4, 32 * 4) - self.up3 = UpsamplingModule(32 * 4, 16 * 4) + self.local3 = LocalisationModule(64, 32) + self.up3 = UpsamplingModule(32, 16) - self.seg2 = SegmentationLayer(32 * 4, num_classes) + self.seg2 = SegmentationLayer(32, num_classes) self.upsample_seg2 = UpscalingLayer() - self.final_conv = nn.Conv2d(32 * 4, 32 * 4, kernel_size=3, stride=1, padding=1) + self.final_conv = nn.Conv2d(32, 32, kernel_size=3, stride=1, padding=1) - self.seg3 = SegmentationLayer(32 * 4, num_classes) + self.seg3 = SegmentationLayer(32, num_classes) self.upsample_seg3 = UpscalingLayer() def forward(self, x): From 6775abe556beeb2e4623fe40b774098800dc7b04 Mon Sep 17 00:00:00 2001 From: FrostNov4 <97688822+FrostNov4@users.noreply.github.com> Date: Tue, 28 Nov 2023 04:23:59 +1000 Subject: [PATCH 37/45] data normalisation and augmentations added --- recognition/s4627182_Improved_Unet/Data_Loader.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/recognition/s4627182_Improved_Unet/Data_Loader.py b/recognition/s4627182_Improved_Unet/Data_Loader.py index 42df1a874..a88090fda 100644 --- a/recognition/s4627182_Improved_Unet/Data_Loader.py +++ b/recognition/s4627182_Improved_Unet/Data_Loader.py @@ -69,11 +69,11 @@ def __init__(self, images_dir, labels_dir, transformI=None, transformM=None): self.tx = torchvision.transforms.Compose([ torchvision.transforms.Resize((128, 128)), # torchvision.transforms.CenterCrop(96), - # torchvision.transforms.RandomRotation((-10,10)), + torchvision.transforms.RandomRotation((-10,10)), # torchvision.transforms.RandomHorizontalFlip(), # torchvision.transforms.ColorJitter(brightness=0.4, contrast=0.4, saturation=0.4), torchvision.transforms.ToTensor(), - # torchvision.transforms.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5]) + torchvision.transforms.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5]) ]) if self.transformM: From e3243a1a9f9aa075bd04978e7e2713d6edfe4cb5 Mon Sep 17 00:00:00 2001 From: FrostNov4 <97688822+FrostNov4@users.noreply.github.com> Date: Tue, 28 Nov 2023 04:31:56 +1000 Subject: [PATCH 38/45] data leackage solved by spliting the whole tr data into a tr data and a val data --- recognition/s4627182_Improved_Unet/train.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/recognition/s4627182_Improved_Unet/train.py b/recognition/s4627182_Improved_Unet/train.py index 6d51bfe13..89acd4ff8 100644 --- a/recognition/s4627182_Improved_Unet/train.py +++ b/recognition/s4627182_Improved_Unet/train.py @@ -28,6 +28,7 @@ from Ploting import plot_kernels, LayerActivations, input_images, plot_grad_flow, draw_loss from Metrics import dice_coeff, accuracy_score import time +from torch.utils.data import random_split # from ploting import VisdomLinePlotter # from visdom import Visdom @@ -117,9 +118,12 @@ def model_unet(model_input, in_channel=1, out_channel=1): valid_image = './ISIC2018/ISIC2018_Task1-2_Training_Input_x2/' valid_lable = './ISIC2018/ISIC2018_Task1_Training_GroundTruth_x2/' -Training_Data = Images_Dataset_folder(t_data, l_data) +Training_Data_Whole = Images_Dataset_folder(t_data, l_data) -Validing_Data = Images_Dataset_folder(valid_image, valid_lable) +train_size = int(0.8 * len(Training_Data_Whole)) +val_size = len(Training_Data_Whole) - train_size + +Training_Data, Validing_Data = random_split(Training_Data_Whole, [train_size, val_size]) ####################################################### # Giving a transformation for input data From e2d815d4e971e80c7a9f883a46ac85e499678b62 Mon Sep 17 00:00:00 2001 From: FrostNov4 <97688822+FrostNov4@users.noreply.github.com> Date: Tue, 28 Nov 2023 11:05:56 +1000 Subject: [PATCH 39/45] prediction can be run to get the segmentation shown in readme. --- recognition/s4627182_Improved_Unet/predict.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/recognition/s4627182_Improved_Unet/predict.py b/recognition/s4627182_Improved_Unet/predict.py index 6f1ed7263..5cb067126 100644 --- a/recognition/s4627182_Improved_Unet/predict.py +++ b/recognition/s4627182_Improved_Unet/predict.py @@ -29,6 +29,7 @@ def segment_image(model_path, image_path, output_path): return predicted_mask_image -# Example usage: -# segmented_img = segment_image("path_to_model.pth", "path_to_image.jpg") -# Image.fromarray(segmented_img).save("segmented_output.png") +path_to_model = './model/Unet_D_400_16.pth' +path_to_image = './ISIC2018/ISIC2018_Task1-2_Training_Input_x2/ISIC_0000003.jpg' +segmented_img = segment_image(path_to_model, path_to_image) +Image.fromarray(segmented_img).save("ISIC_0000003_out.png") From d983b85ddeaee474b0987a09f8f5e73e2dd5dab4 Mon Sep 17 00:00:00 2001 From: FrostNov4 <97688822+FrostNov4@users.noreply.github.com> Date: Tue, 28 Nov 2023 12:53:48 +1000 Subject: [PATCH 40/45] code usage examples added, more explaination added, references added. --- recognition/s4627182_Improved_Unet/README.md | 144 +++++++++++-------- 1 file changed, 87 insertions(+), 57 deletions(-) diff --git a/recognition/s4627182_Improved_Unet/README.md b/recognition/s4627182_Improved_Unet/README.md index 73a126987..7bae903a0 100644 --- a/recognition/s4627182_Improved_Unet/README.md +++ b/recognition/s4627182_Improved_Unet/README.md @@ -6,6 +6,7 @@ Segment the ISIC data set with the Improved UNet with all labels having a minimum Dice similarity coefficient of 0.8 on the test set. + ## Background The structure of Improved UNet is based on the paper. "Brain Tumor Segmentation and Radiomics Survival Prediction: Contribution to the BRATS 2017 Challenge" @@ -13,92 +14,121 @@ https://arxiv.org/abs/1802.10508v1 ## Model - U-Net is a convolutional neural network architecture primarily used for biomedical image segmentation. - Its U-shaped structure consists of a contracting path, which captures context, and an expansive path, - which enables precise localization. Through skip connections, features from the contracting path are concatenated - with the expansive path, enhancing localization capabilities. +U-Net is a convolutional neural network architecture primarily used for biomedical image segmentation. +Its U-shaped structure consists of a contracting path, which captures context, and an expansive path, +which enables precise localization. Through skip connections, features from the contracting path are concatenated +with the expansive path, enhancing localization capabilities. + +![Unet](./additional_images/unet.png) + +The improved U-Net architecture introduces several key enhancements over the original U-Net architecture: + +- **Context Module**: This module captures contextual information around each pixel, which is crucial for understanding the bigger picture in segmentation tasks. By using multiple convolutions and dropout for regularization, it aims to enhance feature extraction without overfitting. + +- **Upsampling Module**: This module is responsible for increasing the spatial resolution of feature maps. In contrast to simple transposed convolutions from the original U-Net, this could provide smoother and more refined upsampling. - ![Unet](./additional_images/unet.png) +- **Localization Module**: This module focuses on localizing features within the upsampled feature map, helping the network to regain the spatial details lost during downsampling. - The activations in the context pathway are computed by context modules. - Each context module is in fact a pre-activation residual block with two 3x3x3 convolutional - layers and a dropout layer (p_drop = 0.3) in between. Context modules are connected - by 3x3x3 convolutions with input stride 2 to reduce the resolution of the feature maps and allow - for more features while descending the aggregation pathway. +- **Segmentation Layer**: This layer is dedicated to producing the final segmentation map from the feature maps. ## Dataset - In this report, the ISIC 2018 dataset will be used. - The ISIC 2018 dataset is a publicly available dataset for skin lesion image segmentation, - provided by the International Skin Imaging Collaboration (ISIC). Given that the real-world - images in the dataset come in different sizes, they are uniformly resized to a 128x128 dimension. - These images use RGB with 3 color channels for input. The label data, which indicates where the lesions are, - is treated in the same way as the real data. However, these labels are input as grayscale images with a single channel, - making them simpler and more focused on the lesion's location and shape. - - -## Data_Loader -Class for getting data as a Dict - - Args: - images_dir = path of input images - labels_dir = path of labeled images - transformI = Input Images transformation - transformM = Input Labels transformation - +In this report, the ISIC 2018 dataset will be used. +The ISIC 2018 dataset is a publicly available dataset for skin lesion image segmentation, +provided by the International Skin Imaging Collaboration (ISIC). Given that the real-world +images in the dataset come in different sizes, they are uniformly resized to a 128x128 dimension. +These images use RGB with 3 color channels for input. The label data, which indicates where the lesions are, +is treated in the same way as the real data. However, these labels are input as grayscale images with a single channel, +making them simpler and more focused on the lesion's location and shape. + +### example usage: +``` +Training_Data_Whole = Images_Dataset_folder(t_data, l_data) + +train_size = int(0.8 * len(Training_Data_Whole)) +val_size = len(Training_Data_Whole) - train_size + +Training_Data, Validing_Data = random_split(Training_Data_Whole, [train_size, val_size]) +``` + +## Losses +The loss function used is calculates a combined loss that is a weighted sum of Binary Cross-Entropy (BCE) loss and Dice loss. +It is used to balance between pixel-wise accuracy (captured by BCE) and overlap accuracy (captured by Dice loss) is important. + +### example usage: +``` +lossT = calc_loss(y_pred, y) +``` + ## Dice_score -measures the similarity between two sets. -Specifically in medical imaging, it's used to quantify the overlap -between predicted and ground truth binary segmentations. +Dice score measures the similarity between two sets. +Specifically, it's used to quantify the overlap between predicted and ground truth binary segmentations. Values range between 0 (no overlap) to 1 (perfect overlap). It's a common metric for evaluating the accuracy of image segmentation models, highlighting the spatial overlap accuracy between prediction and truth. -## Losses -Quantifies how well a model's predictions match the actual data. -In machine learning, it measures the difference between predicted and true values. +![dice_score](./additional_images/dice_score.png) - Args: - prediction = predicted image - target = Targeted image - metrics = Metrics printed - bce_weight = 0.5 (default) - Output: - loss : dice loss of the epoch +### example usage: +``` +dice_score = dice_coeff(s, s3) +``` -## Environment - python 3.9 - pytorch=2.0.1 - numpy==1.23.5 - torchvision=0.15.2 - matplotlib==3.7.2 - Pillow==9.3.0 - tqdm==4.64.1 - wandb==0.13.5 +## Training and Validation +After data pre-processing, the model is trained using Adam optimizer with +an initial learning rate of 0.0005 and L2 weight decay of 0.000001. +A learning rate scheduler is also used for adjusting the learning rate during training. +Besides, 400 epoches are trained with a bach size of 16. + +### example usage: +``` +python3 train.py +``` -## Training loss vs Epoches +### Training loss vs Epoches ![train_vs_Epoches](./additional_Images/Train_loss_vs_Epoches.png) -## Valid loss vs Epoches +### Valid loss vs Epoches ![valid_vs_epoches](./additional_Images/valid_loss_vs_epoches.png) ## Predict - The input is - ![Input](./additional_Images/ISIC_0000003.jpg) +### example usage: +``` +python3 predict.py +``` +The input is - The output is +![Input](./additional_Images/ISIC_0000003.jpg) - ![Output](./additional_Images/ISIC_0000003_out.jpg) + +The output is + +![Output](./additional_Images/ISIC_0000003_out.jpg) ## Results - The final model get a Mean Dice Score : 0.9940897984524689. +The final model get a Mean Dice Score : 0.9940897984524689. + +## Environment + python 3.9 + pytorch=2.0.1 + numpy==1.23.5 + torchvision=0.15.2 + matplotlib==3.7.2 + Pillow==9.3.0 + tqdm==4.64.1 + wandb==0.13.5 + +## References +- F. Isensee, P. Kickingereder, W. Wick, M. Bendszus, and K. H. Maier-Hein, +“Brain Tumor Segmentation and Radiomics Survival Prediction: Contribution to the BRATS 2017 Challenge,” +Feb. 2018. [Online]. Available: https://arxiv.org/abs/1802.10508v1 From 360442f2fa394e462ae469e2fe4e16f7504b2448 Mon Sep 17 00:00:00 2001 From: FrostNov4 <97688822+FrostNov4@users.noreply.github.com> Date: Tue, 28 Nov 2023 12:56:38 +1000 Subject: [PATCH 41/45] refined the structure --- recognition/s4627182_Improved_Unet/README.md | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/recognition/s4627182_Improved_Unet/README.md b/recognition/s4627182_Improved_Unet/README.md index 7bae903a0..f2f6bc4d5 100644 --- a/recognition/s4627182_Improved_Unet/README.md +++ b/recognition/s4627182_Improved_Unet/README.md @@ -1,25 +1,17 @@ ## COMP_3710_Report - -## Medical condition, Extended to 27 OCT +( Medical condition, Extended to 27 OCT) ## This report is focused on the first task (a) Segment the ISIC data set with the Improved UNet with all labels having a minimum Dice similarity coefficient of 0.8 on the test set. - -## Background -The structure of Improved UNet is based on the paper. -"Brain Tumor Segmentation and Radiomics Survival Prediction: Contribution to the BRATS 2017 Challenge" -https://arxiv.org/abs/1802.10508v1 - - ## Model U-Net is a convolutional neural network architecture primarily used for biomedical image segmentation. Its U-shaped structure consists of a contracting path, which captures context, and an expansive path, which enables precise localization. Through skip connections, features from the contracting path are concatenated with the expansive path, enhancing localization capabilities. -![Unet](./additional_images/unet.png) + ![Unet](./additional_images/unet.png) The improved U-Net architecture introduces several key enhancements over the original U-Net architecture: @@ -66,7 +58,7 @@ Values range between 0 (no overlap) to 1 (perfect overlap). It's a common metric for evaluating the accuracy of image segmentation models, highlighting the spatial overlap accuracy between prediction and truth. -![dice_score](./additional_images/dice_score.png) + ![dice_score](./additional_images/dice_score.png) ### example usage: ``` From d89c906745dd31ea592fcfaeb18dc456759fd605 Mon Sep 17 00:00:00 2001 From: FrostNov4 <97688822+FrostNov4@users.noreply.github.com> Date: Tue, 28 Nov 2023 12:59:08 +1000 Subject: [PATCH 42/45] refined the structure --- recognition/s4627182_Improved_Unet/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/recognition/s4627182_Improved_Unet/README.md b/recognition/s4627182_Improved_Unet/README.md index f2f6bc4d5..f2e8fb21f 100644 --- a/recognition/s4627182_Improved_Unet/README.md +++ b/recognition/s4627182_Improved_Unet/README.md @@ -1,6 +1,7 @@ ## COMP_3710_Report ( Medical condition, Extended to 27 OCT) + ## This report is focused on the first task (a) Segment the ISIC data set with the Improved UNet with all labels having a minimum Dice similarity coefficient of 0.8 on the test set. From ff9fe37b9191afedbfa8cdd24254a76e515934e2 Mon Sep 17 00:00:00 2001 From: FrostNov4 <97688822+FrostNov4@users.noreply.github.com> Date: Tue, 28 Nov 2023 13:00:56 +1000 Subject: [PATCH 43/45] add image of fomula of diced score --- .../additional_Images/dice_score.png | Bin 0 -> 238859 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 recognition/s4627182_Improved_Unet/additional_Images/dice_score.png diff --git a/recognition/s4627182_Improved_Unet/additional_Images/dice_score.png b/recognition/s4627182_Improved_Unet/additional_Images/dice_score.png new file mode 100644 index 0000000000000000000000000000000000000000..c30623a4fb416b8ea2723fde9a760595711db2ae GIT binary patch literal 238859 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�ZUY0BtIUwK&Bhpz_sgzxY~{lo+4U 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 Date: Tue, 28 Nov 2023 13:03:40 +1000 Subject: [PATCH 44/45] hope to solve the images not showing problem --- recognition/s4627182_Improved_Unet/README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/recognition/s4627182_Improved_Unet/README.md b/recognition/s4627182_Improved_Unet/README.md index f2e8fb21f..0d4a435dc 100644 --- a/recognition/s4627182_Improved_Unet/README.md +++ b/recognition/s4627182_Improved_Unet/README.md @@ -12,7 +12,7 @@ Its U-shaped structure consists of a contracting path, which captures context, a which enables precise localization. Through skip connections, features from the contracting path are concatenated with the expansive path, enhancing localization capabilities. - ![Unet](./additional_images/unet.png) +![Unet_Structure](./additional_images/unet.png) The improved U-Net architecture introduces several key enhancements over the original U-Net architecture: @@ -59,8 +59,7 @@ Values range between 0 (no overlap) to 1 (perfect overlap). It's a common metric for evaluating the accuracy of image segmentation models, highlighting the spatial overlap accuracy between prediction and truth. - ![dice_score](./additional_images/dice_score.png) - +![dice_score_img](./additional_Images/dice_score.png) ### example usage: ``` dice_score = dice_coeff(s, s3) From 8e014a54d05252d0fcfa42defb8c367a21f59d8b Mon Sep 17 00:00:00 2001 From: FrostNov4 <97688822+FrostNov4@users.noreply.github.com> Date: Tue, 28 Nov 2023 13:06:06 +1000 Subject: [PATCH 45/45] hope to solve the unet structure not showing problem --- recognition/s4627182_Improved_Unet/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/recognition/s4627182_Improved_Unet/README.md b/recognition/s4627182_Improved_Unet/README.md index 0d4a435dc..87ad01505 100644 --- a/recognition/s4627182_Improved_Unet/README.md +++ b/recognition/s4627182_Improved_Unet/README.md @@ -12,7 +12,7 @@ Its U-shaped structure consists of a contracting path, which captures context, a which enables precise localization. Through skip connections, features from the contracting path are concatenated with the expansive path, enhancing localization capabilities. -![Unet_Structure](./additional_images/unet.png) +![Unet_Structure](./additional_Images/unet.png) The improved U-Net architecture introduces several key enhancements over the original U-Net architecture: