diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 00000000..14577543 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,663 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (c) 2023 AUTOMATIC1111 + + 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 Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are 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. + + 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. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + 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 Affero 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. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + 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 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 work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero 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 Affero 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 Affero 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 Affero 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 Affero 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 Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + 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 AGPL, see +. diff --git a/README.md b/README.md index d783fdf0..9c0cd1ef 100644 --- a/README.md +++ b/README.md @@ -49,9 +49,9 @@ A browser interface based on Gradio library for Stable Diffusion. - Running arbitrary python code from UI (must run with --allow-code to enable) - Mouseover hints for most UI elements - Possible to change defaults/mix/max/step values for UI elements via text config -- Random artist button - Tiling support, a checkbox to create images that can be tiled like textures - Progress bar and live image generation preview + - Can use a separate neural network to produce previews with almost none VRAM or compute requirement - Negative prompt, an extra text field that allows you to list what you don't want to see in generated image - Styles, a way to save part of prompt and easily apply them via dropdown later - Variations, a way to generate same image but with tiny differences @@ -76,13 +76,22 @@ A browser interface based on Gradio library for Stable Diffusion. - hypernetworks and embeddings options - Preprocessing images: cropping, mirroring, autotagging using BLIP or deepdanbooru (for anime) - Clip skip -- Use Hypernetworks -- Use VAEs +- Hypernetworks +- Loras (same as Hypernetworks but more pretty) +- A sparate UI where you can choose, with preview, which embeddings, hypernetworks or Loras to add to your prompt. +- Can select to load a different VAE from settings screen - Estimated completion time in progress bar - API - Support for dedicated [inpainting model](https://github.com/runwayml/stable-diffusion#inpainting-with-stable-diffusion) by RunwayML. - via extension: [Aesthetic Gradients](https://github.com/AUTOMATIC1111/stable-diffusion-webui-aesthetic-gradients), a way to generate images with a specific aesthetic by using clip images embeds (implementation of [https://github.com/vicgalle/stable-diffusion-aesthetic-gradients](https://github.com/vicgalle/stable-diffusion-aesthetic-gradients)) - [Stable Diffusion 2.0](https://github.com/Stability-AI/stablediffusion) support - see [wiki](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Features#stable-diffusion-20) for instructions +- [Alt-Diffusion](https://arxiv.org/abs/2211.06679) support - see [wiki](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Features#alt-diffusion) for instructions +- Now without any bad letters! +- Load checkpoints in safetensors format +- Eased resolution restriction: generated image's domension must be a multiple of 8 rather than 64 +- Now with a license! +- Reorder elements in the UI from settings screen +- ## Installation and Running Make sure the required [dependencies](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Dependencies) are met and follow the instructions available for both [NVidia](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Install-and-Run-on-NVidia-GPUs) (recommended) and [AMD](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Install-and-Run-on-AMD-GPUs) GPUs. diff --git a/artists.csv b/artists.csv deleted file mode 100644 index 1a61ed88..00000000 --- a/artists.csv +++ /dev/null @@ -1,3041 +0,0 @@ -artist,score,category -Peter Max,0.99715996,weird -Roy Lichtenstein,0.98272276,cartoon -Romero Britto,0.9498342,scribbles -Keith Haring,0.9431302,weird -Hiroshige,0.93995106,ukioe -Joan Miró,0.9169429,scribbles -Jean-Michel Basquiat,0.90080947,scribbles -Katsushika Hokusai,0.8887236,ukioe -Paul Klee,0.8868682,scribbles -Marc Chagall,0.8868168,scribbles -Karl Schmidt-Rottluff,0.88444495,scribbles -Howard Hodgkin,0.8808578,scribbles -Jean Metzinger,0.88056004,scribbles -Alma Thomas,0.87658304,weird -Rufino Tamayo,0.8749848,scribbles -Utagawa Hiroshige,0.8728796,ukioe -Chagall,0.8718535,scribbles -Harumi Hironaka,0.86914605,scribbles -Hans Hofmann,0.8686159,scribbles -Kawanabe Kyōsai,0.86612236,ukioe -Andy Warhol,0.8654825,scribbles -Barbara Takenaga,0.86223894,scribbles -Tatsuro Kiuchi,0.8597267,cartoon -Vincent Van Gogh,0.85538065,scribbles -Wassily Kandinsky,0.85490596,scribbles -Georges Seurat,0.8534801,scribbles -Karel Appel,0.8529153,scribbles -Sonia Delaunay,0.8506156,scribbles -Hokusai,0.85046995,ukioe -Eduardo Kobra,0.85036755,weird -Fra Angelico,0.84984255,fineart -Milton Avery,0.849746,scribbles -David Hockney,0.8496144,scribbles -Hiroshi Nagai,0.847129,cartoon -Aristarkh Lentulov,0.846537,scribbles -Lyonel Feininger,0.84573764,scribbles -Mary Blair,0.845709,scribbles -Ellsworth Kelly,0.8455428,scribbles -Jun Kaneko,0.8448367,scribbles -Roz Chast,0.8432013,weird -Ida Rentoul Outhwaite,0.84275174,scribbles -Robert Motherwell,0.8409468,scribbles -Garry Winogrand,0.83994275,black-white -Andrei Rublev,0.83950496,fineart -Alexander Calder,0.83832693,scribbles -Tomokazu Matsuyama,0.8376121,scribbles -August Macke,0.8362022,scribbles -Kazimir Malevich,0.8356527,scribbles -Richard Scarry,0.83554685,scribbles -Victor Vasarely,0.8335438,scribbles -Kitagawa Utamaro,0.83333457,ukioe -Matt Bors,0.83252287,scribbles -Emil Nolde,0.8323225,scribbles -Patrick Caulfield,0.8322225,scribbles -Charles Blackman,0.83200824,scribbles -Peter Doig,0.83111644,scribbles -Alexej von Jawlensky,0.8308932,scribbles -Rumiko Takahashi,0.8301817,anime -Eileen Agar,0.82945526,scribbles -Ernst Ludwig Kirchner,0.82756275,scribbles -Nicolas Delort,0.8261329,scribbles -Marsden Hartley,0.8250993,scribbles -Keith Negley,0.8212553,scribbles -Jamini Roy,0.8212199,scribbles -Quentin Blake,0.82115215,scribbles -Andy Kehoe,0.82063186,cartoon -George barbier,0.82046914,fineart -Frans Masereel,0.81997275,scribbles -Umberto Boccioni,0.81921184,scribbles -Conrad Roset,0.8190752,cartoon -Paul Ranson,0.81903255,scribbles -Yayoi Kusama,0.81886625,weird -Tomi Ungerer,0.81848705,scribbles -Saul Steinberg,0.81778854,scribbles -Jon Klassen,0.81773067,scribbles -W.W. Denslow,0.81708044,fineart -Helen Frankenthaler,0.81704986,scribbles -Jean Jullien,0.816437,scribbles -Brett Whiteley,0.81601924,scribbles -Giotto Di Bondone,0.81427747,fineart -Takashi Murakami,0.81338763,weird -Howard Finster,0.81333554,scribbles -Eduardo Paolozzi,0.81312317,scribbles -Charles Rennie Mackintosh,0.81297064,scribbles -Brandon Mably,0.8128239,weird -Rebecca Louise Law,0.81214285,weird -Victo Ngai,0.81195843,cartoon -Hanabusa Itchō II,0.81187993,ukioe -Edmund Dulac,0.81104875,scribbles -Ben Shahn,0.8104582,scribbles -Howard Arkley,0.8103746,scribbles -Wilfredo Lam,0.8096211,scribbles -Michael Deforge,0.8095954,scribbles -John Hoyland,0.8094592,fineart -Francesco Clemente,0.8090387,scribbles -Leonetto Cappiello,0.8087691,scribbles -Norman Ackroyd,0.80788493,scribbles -Bhupen Khakhar,0.8077607,scribbles -Jeremiah Ketner,0.8075384,cartoon -Chris Ofili,0.8073793,scribbles -Banksy,0.80695426,scribbles -Tom Whalen,0.805867,scribbles -Ernst Wilhelm Nay,0.805295,scribbles -Henri Rousseau,0.8049866,scribbles -Kunisada,0.80493814,ukioe -Naoko Takeuchi,0.80482674,anime -Kaethe Butcher,0.80406916,scribbles -Hasui Kawase,0.8040483,ukioe -Alvin Langdon Coburn,0.8035004,black-white -Stanley Donwood,0.8033054,scribbles -Agnes Martin,0.8028028,scribbles -Osamu Tezuka,0.8005524,cartoon -Frank Stella,0.80049455,scribbles -Dale Chihuly,0.79982775,digipa-high-impact -Evgeni Gordiets,0.79967916,scribbles -Janek Sedlar,0.7993992,fineart -Alasdair Gray,0.7992301,scribbles -Yasuo Kuniyoshi,0.79870003,ukioe -Edward Gorey,0.7984938,scribbles -Johannes Itten,0.798481,scribbles -Cuno Amiet,0.7979497,scribbles -M.C. Escher,0.7976657,scribbles -Albert Irvin,0.79688835,scribbles -Jack Gaughan,0.79443675,scribbles -Ravi Zupa,0.7939542,scribbles -Kay Nielsen,0.79385525,scribbles -Agnolo Gaddi,0.79369193,fineart -Alessandro Gottardo,0.79321593,scribbles -Paul Laffoley,0.79196846,scribbles -Giovanni Battista Piranesi,0.79111177,fineart -Adrian Tomine,0.79109013,scribbles -Adolph Gottlieb,0.79061794,scribbles -Milton Caniff,0.7905358,cartoon -Philip Guston,0.78994095,scribbles -Debbie Criswell,0.7895031,cartoon -Alice Pasquini,0.78949904,cartoon -Johannes Vermeer,0.78931487,fineart -Lisa Frank,0.7892591,cartoon -Patrick Heron,0.78889126,scribbles -Mikhail Nesterov,0.78814346,fineart -Cézanne,0.7879481,scribbles -Tristan Eaton,0.787513,scribbles -Jillian Tamaki,0.7868066,scribbles -Takato Yamamoto,0.78460765,ukioe -Martiros Saryan,0.7844924,scribbles -Emil Orlik,0.7842625,scribbles -Armand Guillaumin,0.7840431,scribbles -Jane Newland,0.7837676,scribbles -Paul Cézanne,0.78368753,scribbles -Tove Jansson,0.78356475,scribbles -Guido Crepax,0.7835321,cartoon -OSGEMEOS,0.7829088,weird -Albert Watson,0.48901254,digipa-med-impact -Emory Douglas,0.78179604,scribbles -Chris Van Allsburg,0.66413003,fineart -Ohara Koson,0.78132576,ukioe -Nicolas de Stael,0.7802779,scribbles -Aubrey Beardsley,0.77970016,scribbles -Hishikawa Moronobu,0.7794119,ukioe -Alfred Wallis,0.77926695,scribbles -Friedensreich Hundertwasser,0.7791805,scribbles -Eyvind Earle,0.7788089,scribbles -Giotto,0.7785216,fineart -Simone Martini,0.77843,fineart -Ivan Bilibin,0.77720606,fineart -Karl Blossfeldt,0.77652574,black-white -Duy Huynh,0.77634746,scribbles -Giovanni da Udina,0.7763063,fineart -Henri-Edmond Cross,0.7762994,fineart -Barry McGee,0.77618384,scribbles -William Kentridge,0.77615225,scribbles -Alexander Archipenko,0.7759824,scribbles -Jaume Plensa,0.7756799,weird -Bill Jacklin,0.77504414,fineart -Alberto Vargas,0.7747376,cartoon -Jean Dubuffet,0.7744374,scribbles -Eugène Grasset,0.7741958,fineart -Arthur Rackham,0.77418125,fineart -Yves Tanguy,0.77380997,scribbles -Elsa Beskow,0.7736908,fineart -Georgia O’Keeffe,0.77368987,scribbles -Georgia O'Keeffe,0.77368987,scribbles -Henri Cartier-Bresson,0.7735415,black-white -Andrea del Verrocchio,0.77307427,fineart -Mark Rothko,0.77294236,scribbles -Bruce Gilden,0.7256681,black-white -Gino Severini,0.77247965,scribbles -Delphin Enjolras,0.5594248,fineart -Alena Aenami,0.77210015,cartoon -Ed Freeman,0.42526615,digipa-low-impact -Apollonia Saintclair,0.7718383,anime -László Moholy-Nagy,0.771497,scribbles -Louis Glackens,0.7713224,fineart -Fang Lijun,0.77097225,fineart -Alfred Kubin,0.74409986,fineart -David Wojnarowicz,0.7705802,scribbles -Tara McPherson,0.77023256,scribbles -Gustav Doré,0.7367536,fineart -Patricia Polacco,0.7696109,scribbles -Norman Bluhm,0.7692634,fineart -Elizabeth Gadd,0.7691194,digipa-high-impact -Gabriele Münter,0.7690926,scribbles -David Inshaw,0.76905304,scribbles -Maurice Sendak,0.7690118,cartoon -Harry Clarke,0.7688428,cartoon -Howardena Pindell,0.7686921,n -Jamie Hewlett,0.7680373,scribbles -Steve Ditko,0.76725733,scribbles -Annie Soudain,0.7671485,scribbles -Albert Gleizes,0.76658314,scribbles -Henry Fuseli,0.69147265,fineart -Alain Laboile,0.67634284,c -Albrecht Altdorfer,0.7663378,fineart -Jack Butler Yeats,0.7661406,fineart -Yue Minjun,0.76583517,scribbles -Art Spiegelman,0.7656343,scribbles -Grete Stern,0.7656276,fineart -Mordecai Ardon,0.7648692,scribbles -Joel Sternfeld,0.76456416,digipa-high-impact -Milton Glaser,0.7641823,scribbles -Eishōsai Chōki,0.7639659,scribbles -Domenico Ghirlandaio,0.76372653,fineart -Alex Timmermans,0.64443207,digipa-high-impact -Andreas Vesalius,0.763446,fineart -Bruce McLean,0.76335883,scribbles -Jacob Lawrence,0.76330304,scribbles -Alex Katz,0.76317835,scribbles -Henri de Toulouse-Lautrec,0.76268333,scribbles -Franz Sedlacek,0.762062,scribbles -Paul Lehr,0.70854837,cartoon -Nicholas Roerich,0.76117516,scribbles -Henri Matisse,0.76110923,scribbles -Colin McCahon,0.76086944,scribbles -Max Dupain,0.6661642,black-white -Stephen Gammell,0.74001735,weird -Alberto Giacometti,0.7596302,scribbles -Goyō Hashiguchi,0.7595048,ukioe -Gustave Doré,0.7018832,fineart -Butcher Billy,0.7593378,cartoon -Pieter de Hooch,0.75916564,fineart -Gaetano Pesce,0.75906265,scribbles -Winsor McCay,0.7589382,scribbles -Claude Cahun,0.7588153,weird -Roger Ballen,0.64683115,black-white -Ellen Gallagher,0.758621,scribbles -Anton Corbijn,0.5550669,digipa-high-impact -Margaret Macdonald Mackintosh,0.75781375,fineart -Franz Kline,0.7576461,scribbles -Cimabue,0.75720495,fineart -André Kertész,0.7319392,black-white -Hans Hartung,0.75718236,scribbles -J. J. Grandville,0.7321584,fineart -David Octavius Hill,0.6333561,digipa-high-impact -teamLab,0.7566472,digipa-high-impact -Paul Gauguin,0.75635266,scribbles -Etel Adnan,0.75631833,scribbles -Barbara Kruger,0.7562784,scribbles -Franz Marc,0.75538874,scribbles -Saul Bass,0.75496316,scribbles -El Lissitzky,0.7549487,scribbles -Thomas Moran,0.6507399,fineart -Claude Monet,0.7541377,fineart -David Young Cameron,0.7541016,scribbles -W. Heath Robinson,0.75374347,cartoon -Yves Klein,0.7536262,fineart -Albert Pinkham Ryder,0.7338848,fineart -Elizabeth Shippen Green,0.7533686,fineart -Robert Stivers,0.5516287,fineart -Emily Kame Kngwarreye,0.7532016,weird -Charline von Heyl,0.753142,scribbles -Frida Kahlo,0.75303876,scribbles -Amy Sillman,0.752921,scribbles -Emperor Huizong of Song,0.7525214,ukioe -Edward Burne-Jones,0.75220466,fineart -Brett Weston,0.6891357,black-white -Charles E. Burchfield,0.75174403,scribbles -Hishida Shunsō,0.751617,fareast -Elaine de Kooning,0.7514996,scribbles -Gary Panter,0.7514598,scribbles -Frederick Hammersley,0.7514268,scribbles -Gustave Dore,0.6735896,fineart -Ephraim Moses Lilien,0.7510494,fineart -Hannah Hoch,0.7509496,scribbles -Shepard Fairey,0.7508583,scribbles -Richard Burlet,0.7506659,scribbles -Bill Brandt,0.6833408,black-white -Herbert List,0.68455493,black-white -Joseph Cornell,0.75023884,nudity -Nathan Wirth,0.6436741,black-white -John Kenn Mortensen,0.74758303,anime -Andre De Dienes,0.5683014,digipa-high-impact -Albert Robida,0.7485741,cartoon -Shintaro Kago,0.7484431,anime -Sidney Nolan,0.74809414,scribbles -Patrice Murciano,0.61973965,fineart -Brian Stelfreeze,0.7478351,scribbles -Francisco De Goya,0.6954584,fineart -William Morris,0.7478111,fineart -Honoré Daumier,0.74767774,scribbles -Hubert Robert,0.6863421,fineart -Marianne von Werefkin,0.7475825,fineart -Edvard Munch,0.74719715,scribbles -Victor Brauner,0.74719006,scribbles -George Inness,0.7470588,fineart -Naoki Urasawa,0.7469665,anime -Kilian Eng,0.7468486,scribbles -Bordalo II,0.7467364,digipa-high-impact -Katsuhiro Otomo,0.746364,anime -Maximilien Luce,0.74609685,fineart -Amy Earles,0.74603415,fineart -Jeanloup Sieff,0.7196009,black-white -William Zorach,0.74574494,scribbles -Pascale Campion,0.74516207,fineart -Dorothy Lathrop,0.74418795,fineart -Sofonisba Anguissola,0.74418664,fineart -Natalia Goncharova,0.74414873,scribbles -August Sander,0.6644566,black-white -Jasper Johns,0.74395454,scribbles -Arthur Dove,0.74383533,scribbles -Darwyn Cooke,0.7435789,scribbles -Leonardo Da Vinci,0.6825216,fineart -Fra Filippo Lippi,0.7433891,fineart -Pierre-Auguste Renoir,0.742464,fineart -Jeff Lemire,0.7422893,scribbles -Al Williamson,0.742113,cartoon -Childe Hassam,0.7418015,fineart -Francisco Goya,0.69522625,fineart -Alphonse Mucha,0.74171394,special -Cleon Peterson,0.74163914,scribbles -J.M.W. Turner,0.65582645,fineart -Walter Crane,0.74146044,fineart -Brassaï,0.6361966,digipa-high-impact -Virgil Finlay,0.74133486,fineart -Fernando Botero,0.7412504,nudity -Ben Nicholson,0.7411573,scribbles -Robert Rauschenberg,0.7410054,fineart -David Wiesner,0.7406237,scribbles -Bartolome Esteban Murillo,0.6933951,fineart -Jean Arp,0.7403873,scribbles -Andre Kertesz,0.7228358,black-white -Simeon Solomon,0.66441345,fineart -Hugh Ferriss,0.72443527,black-white -Agnes Lawrence Pelton,0.73960555,scribbles -Charles Camoin,0.7395686,scribbles -Paul Strand,0.7080332,black-white -Charles Gwathmey,0.7394747,scribbles -Bartolomé Esteban Murillo,0.7011274,fineart -Oskar Kokoschka,0.7392038,scribbles -Bruno Munari,0.73918355,weird -Willem de Kooning,0.73916197,scribbles -Hans Memling,0.7387886,fineart -Chris Mars,0.5861489,digipa-high-impact -Hiroshi Yoshida,0.73787534,ukioe -Hundertwasser,0.7377672,fineart -David Bowie,0.73773724,weird -Ettore Sottsass,0.7376095,digipa-high-impact -Antanas Sutkus,0.7369492,black-white -Leonora Carrington,0.73726475,scribbles -Hieronymus Bosch,0.7369955,scribbles -A. J. Casson,0.73666203,scribbles -Chaim Soutine,0.73662066,scribbles -Artur Bordalo,0.7364549,weird -Thomas Allom,0.68792284,fineart -Louis Comfort Tiffany,0.7363504,fineart -Philippe Druillet,0.7363382,cartoon -Jan Van Eyck,0.7360621,fineart -Sandro Botticelli,0.7359395,fineart -Hieronim Bosch,0.7359308,scribbles -Everett Shinn,0.7355817,fineart -Camille Corot,0.7355603,fineart -Nick Sharratt,0.73470485,scribbles -Fernand Léger,0.7079839,scribbles -Robert S. Duncanson,0.7346282,fineart -Hieronymous Bosch,0.73453265,scribbles -Charles Addams,0.7344034,scribbles -Studio Ghibli,0.73439026,anime -Archibald Motley,0.7343683,scribbles -Anton Fadeev,0.73433846,cartoon -Uemura Shoen,0.7342118,ukioe -Ando Fuchs,0.73406494,black-white -Jessie Willcox Smith,0.73398125,fineart -Alex Garant,0.7333658,scribbles -Lawren Harris,0.73331416,scribbles -Anne Truitt,0.73297834,scribbles -Richard Lindner,0.7328564,scribbles -Sailor Moon,0.73281246,anime -Bridget Bate Tichenor,0.73274165,scribbles -Ralph Steadman,0.7325864,scribbles -Annibale Carracci,0.73251307,fineart -Dürer,0.7324789,fineart -Abigail Larson,0.7319012,cartoon -Bill Traylor,0.73189163,scribbles -Louis Rhead,0.7318623,fineart -David Burliuk,0.731803,scribbles -Camille Pissarro,0.73172396,fineart -Catrin Welz-Stein,0.73117495,scribbles -William Etty,0.6497544,nudity -Pierre Bonnard,0.7310132,scribbles -Benoit B. Mandelbrot,0.5033001,digipa-med-impact -Théodore Géricault,0.692039,fineart -Andy Goldsworthy,0.7307565,digipa-high-impact -Alfred Sisley,0.7306032,fineart -Charles-Francois Daubigny,0.73057353,fineart -Karel Thole,0.7305395,cartoon -Andre Derain,0.73050404,scribbles -Larry Poons,0.73023695,fineart -Beauford Delaney,0.72999024,scribbles -Ruth Bernhard,0.72990334,black-white -David Alfaro Siqueiros,0.7297947,scribbles -Gaugin,0.729636,fineart -Carl Larsson,0.7296195,cartoon -Albrecht Dürer,0.72946966,fineart -Henri De Toulouse Lautrec,0.7294263,cartoon -Shotaro Ishinomori,0.7292093,anime -Hope Gangloff,0.729082,scribbles -Vivian Maier,0.72897506,digipa-high-impact -Alex Andreev,0.6442978,digipa-high-impact -Julie Blackmon,0.72862685,c -Arthur Melville,0.7286146,fineart -Henri Michaux,0.599607,fineart -William Steig,0.7283096,scribbles -Octavio Ocampo,0.72814554,scribbles -Cy Twombly,0.72814107,scribbles -Guy Denning,0.67375445,fineart -Maxfield Parrish,0.7280283,fineart -Randolph Caldecott,0.7279564,fineart -Duccio,0.72795,fineart -Ray Donley,0.5837457,fineart -Hiroshi Sugimoto,0.6497892,digipa-high-impact -Daniela Uhlig,0.4691466,special -Go Nagai,0.72770613,anime -Carlo Crivelli,0.72764605,fineart -Helmut Newton,0.44433144,digipa-low-impact -Josef Albers,0.7061394,scribbles -Henry Moret,0.7274567,fineart -André Masson,0.727404,scribbles -Henri Fantin Latour,0.72732764,fineart -Theo van Rysselberghe,0.7272843,fineart -John Wayne Gacy,0.72686327,scribbles -Carlos Schwabe,0.7267612,fineart -Herbert Bayer,0.7094297,scribbles -Domenichino,0.72667265,fineart -Liam Wong,0.7262276,special -George Caleb Bingham,0.7262154,digipa-high-impact -Gigadō Ashiyuki,0.7261864,fineart -Chaïm Soutine,0.72603923,scribbles -Ary Scheffer,0.64913243,fineart -Rockwell Kent,0.7257272,scribbles -Jean-Paul Riopelle,0.72570604,fineart -Ed Mell,0.6637067,cartoon -Ismail Inceoglu,0.72561014,special -Edgar Degas,0.72538006,fineart -Giorgione,0.7252798,fineart -Charles-François Daubigny,0.7252482,fineart -Arthur Lismer,0.7251765,scribbles -Aaron Siskind,0.4852289,digipa-med-impact -Arkhip Kuindzhi,0.7249981,fineart -Joseph Mallord William Turner,0.6834406,fineart -Dante Gabriel Rossetti,0.7244541,fineart -Ernst Haeckel,0.6660129,fineart -Rebecca Guay,0.72439146,cartoon -Anthony Gerace,0.636678,digipa-high-impact -Martin Kippenberger,0.72418386,scribbles -Diego Giacometti,0.72415763,scribbles -Dmitry Kustanovich,0.7241322,cartoon -Dora Carrington,0.7239633,scribbles -Shusei Nagaoko,0.7238965,anime -Odilon Redon,0.72381747,scribbles -Shohei Otomo,0.7132803,nudity -Barnett Newman,0.7236389,scribbles -Jean Fouquet,0.7235963,fineart -Gustav Klimt,0.72356784,nudity -Francisco Josè de Goya,0.6589663,fineart -Bonnard Pierre,0.72309464,nudity -Brooke Shaden,0.61281693,digipa-high-impact -Mao Hamaguchi,0.7228292,scribbles -Frederick Edwin Church,0.64416,fineart -Asher Brown Durand,0.72264796,fineart -George Baselitz,0.7223453,scribbles -Sam Bosma,0.7223237,fineart -Asaf Hanuka,0.72222745,scribbles -David Teniers the Younger,0.7221168,fineart -Nicola Samori,0.68747556,nudity -Claude Lorrain,0.7217102,fineart -Hermenegildo Anglada Camarasa,0.7214374,nudity -Pablo Picasso,0.72142905,scribbles -Howard Chaykin,0.7213998,cartoon -Ferdinand Hodler,0.7213758,nudity -Farel Dalrymple,0.7213298,fineart -Lyubov Popova,0.7213024,scribbles -Albin Egger-Lienz,0.72120845,fineart -Geertgen tot Sint Jans,0.72107565,fineart -Kate Greenaway,0.72069687,fineart -Louise Bourgeois,0.7206516,fineart -Miriam Schapiro,0.72026414,fineart -Pieter Claesz,0.7200939,fineart -George B. Bridgman,0.5592567,fineart -Piet Mondrian,0.71990657,scribbles -Michelangelo Merisi Da Caravaggio,0.7094674,fineart -Marie Spartali Stillman,0.71986604,fineart -Gertrude Abercrombie,0.7196962,scribbles -Louis Icart,0.7195913,fineart -David Driskell,0.719564,scribbles -Paula Modersohn-Becker,0.7193769,scribbles -George Hurrell,0.57496595,digipa-high-impact -Andrea Mantegna,0.7190254,fineart -Silvestro Lega,0.71891177,fineart -Junji Ito,0.7188978,anime -Jacob Hashimoto,0.7186867,digipa-high-impact -Benjamin West,0.6642946,fineart -David Teniers the Elder,0.7181293,fineart -Roberto Matta,0.71808386,fineart -Chiho Aoshima,0.71801454,anime -Amedeo Modigliani,0.71788836,scribbles -Raja Ravi Varma,0.71788085,fineart -Roberto Ferri,0.538221,nudity -Winslow Homer,0.7176876,fineart -Horace Vernet,0.65729,fineart -Lucas Cranach the Elder,0.71738195,fineart -Godfried Schalcken,0.625893,fineart -Affandi,0.7170285,nudity -Diane Arbus,0.655138,digipa-high-impact -Joseph Ducreux,0.65247905,digipa-high-impact -Berthe Morisot,0.7165984,fineart -Hilma af Klint,0.71643853,scribbles -Filippino Lippi,0.7163017,fineart -Leonid Afremov,0.7163005,fineart -Chris Ware,0.71628594,scribbles -Marius Borgeaud,0.7162446,scribbles -M.W. Kaluta,0.71612585,cartoon -Govert Flinck,0.68975246,fineart -Charles Demuth,0.71605396,scribbles -Coles Phillips,0.7158309,scribbles -Oskar Fischinger,0.6721027,digipa-high-impact -David Teniers III,0.71569765,fineart -Jean Delville,0.7156771,fineart -Antonio Saura,0.7155949,scribbles -Bridget Riley,0.7155669,fineart -Gordon Parks,0.5759978,digipa-high-impact -Anselm Kiefer,0.71514887,scribbles -Remedios Varo,0.7150927,weird -Franz Hegi,0.71495223,scribbles -Kati Horna,0.71486115,black-white -Arshile Gorky,0.71459055,scribbles -David LaChapelle,0.7144903,scribbles -Fritz von Dardel,0.71446383,scribbles -Edward Ruscha,0.71438885,fineart -Blanche Hoschedé Monet,0.7143073,fineart -Alexandre Calame,0.5735474,fineart -Sean Scully,0.714154,fineart -Alexandre Benois,0.7141515,fineart -Sally Mann,0.6534312,black-white -Thomas Eakins,0.7141104,fineart -Arnold Böcklin,0.71407956,fineart -Alfonse Mucha,0.7139052,special -Damien Hirst,0.7136273,scribbles -Lee Krasner,0.71362555,scribbles -Dorothea Lange,0.71361613,black-white -Juan Gris,0.7132987,scribbles -Bernardo Bellotto,0.70720065,fineart -John Martin,0.5376847,fineart -Harriet Backer,0.7131594,fineart -Arnold Newman,0.5736342,digipa-high-impact -Gjon Mili,0.46520913,digipa-low-impact -Asger Jorn,0.7129575,scribbles -Chesley Bonestell,0.6063316,fineart -Agostino Carracci,0.7128167,fineart -Peter Wileman,0.71271706,cartoon -Chen Hongshou,0.71268153,ukioe -Catherine Hyde,0.71266896,scribbles -Andrea Pozzo,0.626546,fineart -Kitty Lange Kielland,0.7125735,fineart -Cornelis Saftleven,0.6684047,fineart -Félix Vallotton,0.71237606,fineart -Albrecht Durer,0.7122327,fineart -Jackson Pollock,0.71222305,scribbles -John Bratby,0.7122171,scribbles -Beksinski,0.71218586,fineart -James Thomas Watts,0.5959548,fineart -Konstantin Korovin,0.71188873,fineart -Gustave Caillebotte,0.71181154,fineart -Dean Ellis,0.50233585,fineart -Friedrich von Amerling,0.6420181,fineart -Christopher Balaskas,0.67935324,special -Alexander Rodchenko,0.67415404,scribbles -Alfred Cheney Johnston,0.6647291,fineart -Mikalojus Konstantinas Ciurlionis,0.710677,scribbles -Jean-Antoine Watteau,0.71061164,fineart -Paul Delvaux,0.7105914,scribbles -Francesco del Cossa,0.7104901,nudity -Isaac Cordal,0.71046066,weird -Hikari Shimoda,0.7104546,weird -François Boucher,0.67153126,fineart -Akos Major,0.7103802,digipa-high-impact -Bernard Buffet,0.7103491,cartoon -Brandon Woelfel,0.6727086,digipa-high-impact -Edouard Manet,0.7101296,fineart -Auguste Herbin,0.6866145,scribbles -Eugene Delacroix,0.70995826,fineart -L. Birge Harrison,0.70989627,fineart -Howard Pyle,0.70979863,fineart -Diane Dillon,0.70968723,scribbles -Hans Erni,0.7096618,scribbles -Richard Diebenkorn,0.7096184,scribbles -Thomas Gainsborough,0.6759419,fineart -Maria Sibylla Merian,0.7093275,fineart -François Joseph Heim,0.6175854,fineart -E. H. Shepard,0.7091189,cartoon -Hsiao-Ron Cheng,0.7090618,scribbles -Canaletto,0.7090392,fineart -John Atkinson Grimshaw,0.7087531,fineart -Giovanni Battista Tiepolo,0.6754107,fineart -Cornelis van Poelenburgh,0.69821274,fineart -Raina Telgemeier,0.70846486,scribbles -Francesco Hayez,0.6960006,fineart -Gilbert Stuart,0.659772,fineart -Konstantin Yuon,0.7081486,fineart -Antonello da Messina,0.70806944,fineart -Austin Osman Spare,0.7079903,fineart -James Ensor,0.70781446,scribbles -Claude Bonin-Pissarro,0.70739406,fineart -Mikhail Vrubel,0.70738363,fineart -Angelica Kauffman,0.6748828,fineart -Viktor Vasnetsov,0.7072422,fineart -Alphonse Osbert,0.70724136,fineart -Tsutomu Nihei,0.7070495,anime -Harvey Quaytman,0.63613266,fineart -Jamie Hawkesworth,0.706914,digipa-high-impact -Francesco Guardi,0.70682615,fineart -Jean-Honoré Fragonard,0.6518248,fineart -Brice Marden,0.70673287,digipa-high-impact -Charles-Amédée-Philippe van Loo,0.6725916,fineart -Mati Klarwein,0.7066092,n -Gerard ter Borch,0.706589,fineart -Dan Hillier,0.48966256,digipa-med-impact -Federico Barocci,0.682664,fineart -Henri Le Sidaner,0.70637953,fineart -Olivier Bonhomme,0.7063748,scribbles -Edward Weston,0.7061382,black-white -Giovanni Paolo Cavagna,0.6840265,fineart -Germaine Krull,0.6621777,black-white -Hans Holbein the Younger,0.70590156,fineart -François Bocion,0.6272365,fineart -Georg Baselitz,0.7053314,scribbles -Caravaggio,0.7050303,fineart -Anne Rothenstein,0.70502245,scribbles -Wadim Kashin,0.43714935,digipa-low-impact -Heinrich Lefler,0.7048054,fineart -Jacob van Ruisdael,0.7047918,fineart -Bartholomeus van Bassen,0.6676872,fineart -Jeffrey Smith art,0.56750107,fineart -Anne Packard,0.7046703,weird -Jean-François Millet,0.7045456,fineart -Andrey Remnev,0.7041204,digipa-high-impact -Fujiwara Takanobu,0.70410216,ukioe -Elliott Erwitt,0.69950557,black-white -Fern Coppedge,0.7036215,fineart -Bartholomeus van der Helst,0.66411966,fineart -Rembrandt Van Rijn,0.6979987,fineart -Rene Magritte,0.703457,scribbles -Aelbert Cuyp,0.7033657,fineart -Gerda Wegener,0.70319015,scribbles -Graham Sutherland,0.7031714,scribbles -Gerrit Dou,0.7029986,fineart -August Friedrich Schenck,0.6801586,fineart -George Herriman,0.7028568,scribbles -Stanisław Szukalski,0.6903354,fineart -Slim Aarons,0.70222545,digipa-high-impact -Ernst Thoms,0.70221686,fineart -Louis Wain,0.702186,fineart -Artemisia Gentileschi,0.70198226,fineart -Eugène Delacroix,0.70155394,fineart -Peter Bagge,0.70127463,scribbles -Jeffrey Catherine Jones,0.7012148,cartoon -Eugène Carrière,0.65272695,fineart -Alexander Millar,0.7011144,scribbles -Nobuyoshi Araki,0.70108867,fareast -Tintoretto,0.6702795,fineart -André Derain,0.7009005,scribbles -Charles Maurice Detmold,0.70079994,fineart -Francisco de Zurbarán,0.7007234,fineart -Laurie Greasley,0.70072114,cartoon -Lynda Benglis,0.7006948,digipa-high-impact -Cecil Beaton,0.66362655,black-white -Gustaf Tenggren,0.7006041,cartoon -Abdur Rahman Chughtai,0.7004994,ukioe -Constantin Brancusi,0.7004367,scribbles -Mikhail Larionov,0.7004066,fineart -Jan van Kessel the Elder,0.70040506,fineart -Chantal Joffe,0.70036674,scribbles -Charles-André van Loo,0.6830367,fineart -Reginald Marsh,0.6301042,fineart -Elsa Bleda,0.70005083,digipa-high-impact -Peter Paul Rubens,0.65745676,fineart -Eugène Boudin,0.70001304,fineart -Charles Willson Peale,0.66907954,fineart -Brian Mashburn,0.63395154,digipa-high-impact -Barkley L. Hendricks,0.69986427,n -Yoshiyuki Tomino,0.6998095,anime -Guido Reni,0.6416875,fineart -Lynd Ward,0.69958556,fineart -John Constable,0.6907788,fineart -František Kupka,0.6993329,fineart -Pieter Bruegel The Elder,0.6992879,scribbles -Benjamin Gerritsz Cuyp,0.6992173,fineart -Nicolas Mignard,0.6988214,fineart -Augustus Edwin Mulready,0.6482165,fineart -Andrea del Sarto,0.698532,fineart -Edward Steichen,0.69837445,black-white -James Abbott McNeill Whistler,0.69836813,fineart -Alphonse Legros,0.6983243,fineart -Ivan Aivazovsky,0.64588225,fineart -Giovanni Francesco Barbieri,0.6981316,fineart -Grace Cossington Smith,0.69811064,fineart -Bert Stern,0.53411555,scribbles -Mary Cassatt,0.6980135,fineart -Jules Bastien-Lepage,0.69796044,fineart -Max Ernst,0.69777006,fineart -Kentaro Miura,0.697743,anime -Georges Rouault,0.69758564,scribbles -Josephine Wall,0.6973667,fineart -Anne-Louis Girodet,0.58104825,nudity -Bert Hardy,0.6972966,black-white -Adriaen van de Velde,0.69716156,fineart -Andreas Achenbach,0.61108655,fineart -Hayv Kahraman,0.69705284,fineart -Beatrix Potter,0.6969851,fineart -Elmer Bischoff,0.6968948,fineart -Cornelis de Heem,0.6968436,fineart -Inio Asano,0.6965007,anime -Alfred Henry Maurer,0.6964837,fineart -Gottfried Helnwein,0.6962953,digipa-high-impact -Paul Barson,0.54196984,digipa-high-impact -Roger de La Fresnaye,0.69620967,fineart -Abraham Mignon,0.60605425,fineart -Albert Bloch,0.69573116,nudity -Charles Dana Gibson,0.67155975,fineart -Alexandre-Évariste Fragonard,0.6507174,fineart -Ernst Fuchs,0.6953538,nudity -Alfredo Jaar,0.6952965,digipa-high-impact -Judy Chicago,0.6952246,weird -Frans van Mieris the Younger,0.6951849,fineart -Aertgen van Leyden,0.6951305,fineart -Emily Carr,0.69512105,fineart -Frances MacDonald,0.6950408,scribbles -Hannah Höch,0.69495845,scribbles -Gillis Rombouts,0.58770025,fineart -Käthe Kollwitz,0.6947756,fineart -Barbara Stauffacher Solomon,0.6920825,fineart -Georges Lacombe,0.6944455,fineart -Gwen John,0.6944161,fineart -Terada Katsuya,0.6944026,cartoon -James Gillray,0.6871335,fineart -Robert Crumb,0.69420326,fineart -Bruce Pennington,0.6545669,fineart -David Firth,0.69400465,scribbles -Arthur Boyd,0.69399726,fineart -Antonin Artaud,0.67321455,fineart -Giuseppe Arcimboldo,0.6937329,fineart -Jim Mahfood,0.6936606,cartoon -Ossip Zadkine,0.6494374,scribbles -Atelier Olschinsky,0.69349927,fineart -Carl Frederik von Breda,0.57274634,fineart -Ken Sugimori,0.6932626,anime -Chris Friel,0.5399168,fineart -Andrew Macara,0.69307995,fineart -Alexander Jansson,0.69298327,scribbles -Anne Brigman,0.6865817,black-white -George Ault,0.66756654,fineart -Arkhyp Kuindzhi,0.6928072,digipa-high-impact -Emiliano Ponzi,0.69278395,scribbles -William Holman Hunt,0.6927663,fineart -Tamara Lempicka,0.6386007,scribbles -Mark Ryden,0.69259655,fineart -Giovanni Paolo Pannini,0.6802902,fineart -Carl Barks,0.6923666,cartoon -Fritz Bultman,0.6318746,fineart -Salomon van Ruysdael,0.690313,fineart -Carrie Mae Weems,0.6645416,n -Agostino Arrivabene,0.61166185,fineart -Gustave Boulanger,0.655797,fineart -Henry Justice Ford,0.51214355,fareast -Bernardo Strozzi,0.63510317,fineart -André Lhote,0.68718815,scribbles -Paul Corfield,0.6915611,scribbles -Gifford Beal,0.6914777,fineart -Hirohiko Araki,0.6914078,anime -Emil Carlsen,0.691326,fineart -Frans van Mieris the Elder,0.6912799,fineart -Simon Stalenhag,0.6912775,special -Henry van de Velde,0.64838886,fineart -Eleanor Fortescue-Brickdale,0.6909729,fineart -Thomas W Schaller,0.69093937,special -NHK Animation,0.6907677,cartoon -Euan Uglow,0.69060403,scribbles -Hendrick Goltzius,0.69058937,fineart -William Blake,0.69038224,fineart -Vito Acconci,0.58409876,digipa-high-impact -Billy Childish,0.6902057,scribbles -Ben Quilty,0.6875855,fineart -Mark Briscoe,0.69010437,fineart -Adriaen van de Venne,0.6899867,fineart -Alasdair McLellan,0.6898454,digipa-high-impact -Ed Paschke,0.68974686,scribbles -Guy Rose,0.68960273,fineart -Barbara Hepworth,0.68958247,fineart -Edward Henry Potthast,0.6895703,fineart -Francis Bacon,0.6895397,scribbles -Pawel Kuczynski,0.6894536,fineart -Bjarke Ingels,0.68933153,digipa-high-impact -Henry Ossawa Tanner,0.68932164,fineart -Alessandro Allori,0.6892961,fineart -Abraham van Calraet,0.63841593,fineart -Egon Schiele,0.6891415,scribbles -Tim Doyle,0.5474768,digipa-high-impact -Grandma Moses,0.6890782,fineart -John Frederick Kensett,0.61981744,fineart -Giacomo Balla,0.68893707,fineart -Jamie Baldridge,0.6546651,digipa-high-impact -Max Beckmann,0.6884731,scribbles -Cornelis van Haarlem,0.6677613,fineart -Edward Hopper,0.6884258,special -Barkley Hendricks,0.6883637,n -Patrick Dougherty,0.688321,digipa-high-impact -Karol Bak,0.6367705,fineart -Pierre Puvis de Chavannes,0.6880703,fineart -Antoni Tàpies,0.685689,fineart -Alexander Nasmyth,0.57695735,fineart -Laurent Grasso,0.5793272,fineart -Camille Walala,0.6076875,digipa-high-impact -Fairfield Porter,0.68790644,fineart -Alex Colville,0.68787855,fineart -Herb Ritts,0.51471305,scribbles -Gerhard Munthe,0.687658,fineart -Susan Seddon Boulet,0.68762136,scribbles -Liu Ye,0.68760437,fineart -Robert Antoine Pinchon,0.68744636,fineart -Fujiwara Nobuzane,0.6873439,fineart -Frederick Carl Frieseke,0.6873361,fineart -Aert van der Neer,0.6159286,fineart -Allen Jones,0.6869935,scribbles -Anja Millen,0.6064488,digipa-high-impact -Esaias van de Velde,0.68673944,fineart -Gyoshū Hayami,0.68665624,anime -William Hogarth,0.6720842,fineart -Frederic Church,0.6865637,fineart -Cyril Rolando,0.68644965,cartoon -Frederic Edwin Church,0.6863009,fineart -Thomas Rowlandson,0.66726154,fineart -Joachim Brohm,0.68601763,digipa-high-impact -Cristofano Allori,0.6858083,fineart -Adrianus Eversen,0.58259964,fineart -Richard Dadd,0.68546164,fineart -Ambrosius Bosschaert II,0.6854217,fineart -Paolo Veronese,0.68422073,fineart -Abraham van den Tempel,0.66463804,fineart -Duncan Grant,0.6852565,scribbles -Hendrick Cornelisz. van Vliet,0.6851691,fineart -Geof Darrow,0.6851174,scribbles -Émile Bernard,0.6850957,fineart -Brian Bolland,0.68496394,scribbles -James Gilleard,0.6849431,cartoon -Anton Raphael Mengs,0.6689196,fineart -Augustus Jansson,0.6845705,digipa-high-impact -Hendrik Goltzius,0.6843367,fineart -Domenico Quaglio the Younger,0.65769434,fineart -Cicely Mary Barker,0.6841806,fineart -William Eggleston,0.6840795,digipa-high-impact -David Choe,0.6840449,scribbles -Adam Elsheimer,0.6716068,fineart -Heinrich Danioth,0.5390186,fineart -Franz Stuck,0.6836468,fineart -Bernie Wrightson,0.64101505,fineart -Dorina Costras,0.6835419,fineart -El Greco,0.68343943,fineart -Gatōken Shunshi,0.6833314,anime -Giovanni Bellini,0.67622876,fineart -Aron Wiesenfeld,0.68331146,nudity -Boris Kustodiev,0.68329334,fineart -Alec Soth,0.5597321,digipa-high-impact -Artus Scheiner,0.6313348,fineart -Kelly Vivanco,0.6830933,scribbles -Shaun Tan,0.6830649,fineart -Anthony van Dyck,0.6577681,fineart -Neil Welliver,0.68297863,nudity -Robert McCall,0.68294585,fineart -Sandra Chevrier,0.68284667,scribbles -Yinka Shonibare,0.68256056,n -Arthur Tress,0.6301861,digipa-high-impact -Richard McGuire,0.6820089,scribbles -Anni Albers,0.65708244,digipa-high-impact -Aleksey Savrasov,0.65207493,fineart -Wayne Barlowe,0.6537874,fineart -Giorgio de Chirico,0.6815907,fineart -Ernest Procter,0.6815795,fineart -Adriaen Brouwer,0.6815058,fineart -Ilya Glazunov,0.6813533,fineart -Alison Bechdel,0.68096143,scribbles -Carl Holsoe,0.68082225,fineart -Alfred Edward Chalon,0.6464571,fineart -Gerard David,0.68058,fineart -Basil Blackshaw,0.6805679,fineart -Gerrit Adriaenszoon Berckheyde,0.67340267,fineart -George Hendrik Breitner,0.6804209,fineart -Abraham Bloemaert,0.68036544,fineart -Ferdinand Van Kessel,0.67742276,fineart -Hugo Simberg,0.68031186,fineart -Gaston Bussière,0.665221,fineart -Shawn Coss,0.42407864,digipa-low-impact -Hanabusa Itchō,0.68023074,ukioe -Magnus Enckell,0.6801553,fineart -Gary Larson,0.6801336,scribbles -George Manson,0.68013126,digipa-high-impact -Hayao Miyazaki,0.6800754,anime -Carl Spitzweg,0.66581815,fineart -Ambrosius Holbein,0.6798341,fineart -Domenico Pozzi,0.6434162,fineart -Dorothea Tanning,0.6797955,fineart -Jeannette Guichard-Bunel,0.5251578,digipa-high-impact -Victor Moscoso,0.62962687,fineart -Francis Picabia,0.6795391,scribbles -Charles W. Bartlett,0.67947805,fineart -David A Hardy,0.5554935,fineart -C. R. W. Nevinson,0.67946506,fineart -Man Ray,0.6507145,scribbles -Albert Bierstadt,0.67935765,fineart -Charles Le Brun,0.6758479,fineart -Lovis Corinth,0.67913896,fineart -Herbert Abrams,0.5507507,digipa-high-impact -Giorgio Morandi,0.6789025,fineart -Agnolo Bronzino,0.6787985,fineart -Abraham Pether,0.66922426,fineart -John Bauer,0.6786695,fineart -Arthur Stanley Wilkinson,0.67860866,fineart -Arthur Wardle,0.5510789,fineart -George Romney,0.62868094,fineart -Laurie Lipton,0.5201844,fineart -Mickalene Thomas,0.45433685,digipa-low-impact -Alice Rahon,0.6777824,scribbles -Gustave Van de Woestijne,0.6777346,scribbles -Laurel Burch,0.67766285,fineart -Hendrik Gerritsz Pot,0.67750573,fineart -John William Waterhouse,0.677472,fineart -Conor Harrington,0.5967809,fineart -Gabriel Ba,0.6773366,cartoon -Franz Xaver Winterhalter,0.62229514,fineart -George Cruikshank,0.6473593,fineart -Hyacinthe Rigaud,0.67717785,fineart -Cornelis Claesz van Wieringen,0.6770269,fineart -Adriaen van Outrecht,0.67682564,fineart -Yaacov Agam,0.6767926,fineart -Franz von Lenbach,0.61948,fineart -Clyfford Still,0.67667866,fineart -Alexander Roslin,0.66719526,fineart -Barry Windsor Smith,0.6765375,cartoon -Takeshi Obata,0.67643225,anime -John Harris,0.47712502,fineart -Bruce Davidson,0.6763525,digipa-high-impact -Hendrik Willem Mesdag,0.6762745,fineart -Makoto Shinkai,0.67610705,anime -Andreas Gursky,0.67610145,digipa-high-impact -Mike Winkelmann (Beeple),0.6510196,digipa-high-impact -Gustave Moreau,0.67607844,fineart -Frank Weston Benson,0.6760142,fineart -Eduardo Kingman,0.6759026,fineart -Benjamin Williams Leader,0.5611925,fineart -Hervé Guibert,0.55973417,black-white -Cornelis Dusart,0.6753622,fineart -Amédée Guillemin,0.6752696,fineart -Alessio Albi,0.6752633,digipa-high-impact -Matthias Grünewald,0.6751779,fineart -Fujishima Takeji,0.6751577,anime -Georges Braque,0.67514753,scribbles -John Salminen,0.67498183,fineart -Atey Ghailan,0.674873,scribbles -Giovanni Antonio Galli,0.657484,fineart -Julie Mehretu,0.6748382,fineart -Jean Auguste Dominique Ingres,0.6746286,fineart -Francesco Albani,0.6621554,fineart -Anato Finnstark,0.6744919,digipa-high-impact -Giovanni Bernardino Mazzolini,0.64416045,fineart -Antoine Le Nain,0.6233709,fineart -Ford Madox Brown,0.6743224,fineart -Gerhard Richter,0.67426133,fineart -theCHAMBA,0.6742506,cartoon -Edward Julius Detmold,0.67421955,fineart -George Stubbs,0.6209227,fineart -George Tooker,0.6740602,scribbles -Faith Ringgold,0.6739976,scribbles -Giambattista Pittoni,0.5792371,fineart -George Bellows,0.6737008,fineart -Aldus Manutius,0.67366326,fineart -Ambrosius Bosschaert,0.67364097,digipa-high-impact -Michael Parkes,0.6133628,fineart -Hans Bellmer,0.6735973,nudity -Sir James Guthrie,0.67359626,fineart -Charles Spencelayh,0.67356884,fineart -Ivan Shishkin,0.6734136,fineart -Hans Holbein the Elder,0.6733856,fineart -Filip Hodas,0.60053295,digipa-high-impact -Herman Saftleven,0.6732188,digipa-high-impact -Dirck de Quade van Ravesteyn,0.67309594,fineart -Joe Fenton,0.6730916,scribbles -Arnold Bocklin,0.6730706,fineart -Baiōken Eishun,0.6730663,anime -Giovanni Giacometti,0.6730505,fineart -Giovanni Battista Gaulli,0.65036476,fineart -William Stout,0.672887,fineart -Gavin Hamilton,0.5982757,fineart -John Stezaker,0.6726847,black-white -Frederick McCubbin,0.67263377,fineart -Christoph Ludwig Agricola,0.62750757,fineart -Alice Neel,0.67255914,scribbles -Giovanni Battista Venanzi,0.61996603,fineart -Miho Hirano,0.6724092,anime -Tom Thomson,0.6723876,fineart -Alfred Munnings,0.6723851,fineart -David Wilkie,0.6722781,fineart -Adriaen van Ostade,0.67220736,fineart -Alfred Eisenstaedt,0.67213774,black-white -Leon Kossoff,0.67208946,fineart -Georges de La Tour,0.6421979,fineart -Chuck Close,0.6719756,digipa-high-impact -Herbert MacNair,0.6719506,scribbles -Edward Atkinson Hornel,0.6719265,fineart -Becky Cloonan,0.67192084,cartoon -Gian Lorenzo Bernini,0.58210254,fineart -Hein Gorny,0.4982776,digipa-med-impact -Joe Webb,0.6714884,fineart -Cornelis Pietersz Bega,0.64423996,fineart -Christian Krohg,0.6713641,fineart -Cornelia Parker,0.6712246,fineart -Anna Mary Robertson Moses,0.6709144,fineart -Quentin Tarantino,0.6708354,digipa-high-impact -Frederic Remington,0.67074275,fineart -Barent Fabritius,0.6707407,fineart -Oleg Oprisco,0.6707388,digipa-high-impact -Hendrick van Streeck,0.670666,fineart -Bakemono Zukushi,0.67051035,anime -Lucy Madox Brown,0.67032814,fineart -Paul Wonner,0.6700563,scribbles -Guido Borelli Da Caluso,0.66966087,digipa-high-impact -Emil Alzamora,0.5844039,nudity -Heinrich Brocksieper,0.64469147,fineart -Dan Smith,0.669563,digipa-high-impact -Lois van Baarle,0.6695091,scribbles -Arthur Garfield Dove,0.6694996,scribbles -Matthias Jung,0.66936135,digipa-high-impact -José Clemente Orozco,0.6693544,scribbles -Don Bluth,0.6693046,cartoon -Akseli Gallen-Kallela,0.66927314,fineart -Alex Howitt,0.52858865,digipa-high-impact -Giovanni Bernardino Asoleni,0.6635405,fineart -Frederick Goodall,0.6690712,fineart -Francesco Bartolozzi,0.63431,fineart -Edmund Leighton,0.6689639,fineart -Abraham Willaerts,0.5966594,fineart -François Louis Thomas Francia,0.6207474,fineart -Carel Fabritius,0.6688478,fineart -Flora Macdonald Reid,0.6687404,fineart -Bartholomeus Breenbergh,0.6163084,fineart -Bernardino Mei,0.6486895,fineart -Carel Weight,0.6684968,fineart -Aristide Maillol,0.66843045,scribbles -Chris Leib,0.60567486,fineart -Giovanni Battista Piazzetta,0.65012705,fineart -Daniel Maclise,0.6678073,fineart -Giovanni Bernardino Azzolini,0.65774256,fineart -Aaron Horkey,0.6676864,fineart -Otto Dix,0.667294,scribbles -Ferdinand Bol,0.6414797,fineart -Adriaen Coorte,0.6670663,fineart -William Gropper,0.6669881,scribbles -Gerard de Lairesse,0.6639489,fineart -Mab Graves,0.6668356,scribbles -Fernando Amorsolo,0.66683346,fineart -Pixar Concept Artists,0.6667752,cartoon -Alfred Augustus Glendening,0.64009607,fineart -Diego Velázquez,0.6666799,fineart -Jerry Pinkney,0.6665478,fineart -Antoine Wiertz,0.6143825,fineart -Alberto Burri,0.6618252,scribbles -Max Weber,0.6664029,fineart -Hans Baluschek,0.66636246,fineart -Annie Swynnerton,0.6663346,fineart -Albert Dubois-Pillet,0.57526016,fineart -Dora Maar,0.62862253,digipa-high-impact -Kay Sage,0.5614823,fineart -David A. Hardy,0.51376164,fineart -Alberto Biasi,0.42917693,digipa-low-impact -Fra Bartolomeo,0.6661105,fineart -Hendrick van Balen,0.65754294,fineart -Edwin Austin Abbey,0.66596496,fineart -George Frederic Watts,0.66595024,fineart -Alexei Kondratyevich Savrasov,0.6470352,fineart -Anna Ancher,0.66581213,fineart -Irma Stern,0.66580737,fineart -Frédéric Bazille,0.6657115,fineart -Awataguchi Takamitsu,0.6656272,anime -Edward Sorel,0.6655388,fineart -Edward Lear,0.6655078,fineart -Gabriel Metsu,0.6654555,fineart -Giovanni Battista Innocenzo Colombo,0.6653655,fineart -Scott Naismith,0.6650656,fineart -John Perceval,0.6650283,fineart -Girolamo Muziano,0.64234406,fineart -Cornelis de Man,0.66494393,fineart -Cornelis Bisschop,0.64119905,digipa-high-impact -Hans Leu the Elder,0.64770013,fineart -Michael Hutter,0.62479556,fineart -Cornelia MacIntyre Foley,0.6510235,fineart -Todd McFarlane,0.6647763,cartoon -John James Audubon,0.6279882,digipa-high-impact -William Henry Hunt,0.57340264,fineart -John Anster Fitzgerald,0.6644317,fineart -Tomer Hanuka,0.6643152,cartoon -Alex Prager,0.6641814,fineart -Heinrich Kley,0.6641148,fineart -Anne Redpath,0.66407835,scribbles -Marianne North,0.6640104,fineart -Daniel Merriam,0.6639365,fineart -Bill Carman,0.66390574,fineart -Méret Oppenheim,0.66387725,digipa-high-impact -Erich Heckel,0.66384083,fineart -Iryna Yermolova,0.663623,fineart -Antoine Ignace Melling,0.61502695,fineart -Akira Toriyama,0.6635002,anime -Gregory Crewdson,0.59810174,digipa-high-impact -Helene Schjerfbeck,0.66333634,fineart -Antonio Mancini,0.6631618,fineart -Zanele Muholi,0.58554715,n -Balthasar van der Ast,0.66294503,fineart -Toei Animations,0.6629127,anime -Arthur Quartley,0.6628106,fineart -Diego Rivera,0.6625808,fineart -Hendrik van Steenwijk II,0.6623777,fineart -James Tissot,0.6623415,fineart -Kehinde Wiley,0.66218376,n -Chiharu Shiota,0.6621249,digipa-high-impact -George Grosz,0.6620224,fineart -Peter De Seve,0.6616659,cartoon -Ryan Hewett,0.6615638,fineart -Hasegawa Tōhaku,0.66146004,anime -Apollinary Vasnetsov,0.6613177,fineart -Francis Cadell,0.66119456,fineart -Henri Harpignies,0.6611012,fineart -Henry Macbeth-Raeburn,0.6213787,fineart -Christoffel van den Berghe,0.6609149,fineart -Leiji Matsumoto,0.66089404,anime -Adriaen van der Werff,0.638286,fineart -Ramon Casas,0.6606529,fineart -Arthur Hacker,0.66062653,fineart -Edward Willis Redfield,0.66058433,fineart -Carl Gustav Carus,0.65355223,fineart -Francesca Woodman,0.60435605,digipa-high-impact -Hans Makart,0.5881955,fineart -Carne Griffiths,0.660091,weird -Will Barnet,0.65995145,scribbles -Fitz Henry Lane,0.659841,fineart -Masaaki Sasamoto,0.6597158,anime -Salvador Dali,0.6290813,scribbles -Walt Kelly,0.6596993,digipa-high-impact -Charlotte Nasmyth,0.56481636,fineart -Ferdinand Knab,0.6596528,fineart -Steve Lieber,0.6596117,scribbles -Zhang Kechun,0.6595939,fareast -Olivier Valsecchi,0.5324838,digipa-high-impact -Joel Meyerowitz,0.65937585,digipa-high-impact -Arthur Streeton,0.6592294,fineart -Henriett Seth F.,0.6592273,fineart -Genndy Tartakovsky,0.6591695,scribbles -Otto Marseus van Schrieck,0.65890455,fineart -Hanna-Barbera,0.6588123,cartoon -Mary Anning,0.6588001,fineart -Pamela Colman Smith,0.6587648,fineart -Anton Mauve,0.6586873,fineart -Hendrick Avercamp,0.65866685,fineart -Max Pechstein,0.65860206,scribbles -Franciszek Żmurko,0.56855476,fineart -Felice Casorati,0.6584761,fineart -Louis Janmot,0.65298057,fineart -Thomas Cole,0.5408042,fineart -Peter Mohrbacher,0.58273685,fineart -Arnold Franz Brasz,0.65834284,nudity -Christian Rohlfs,0.6582814,fineart -Basil Gogos,0.658105,fineart -Fitz Hugh Lane,0.657923,fineart -Liubov Sergeevna Popova,0.62325525,fineart -Elizabeth MacNicol,0.65773135,fineart -Zinaida Serebriakova,0.6577016,fineart -Ernest Lawson,0.6575238,fineart -Bruno Catalano,0.6574354,fineart -Albert Namatjira,0.6573372,fineart -Fritz von Uhde,0.6572697,fineart -Edwin Henry Landseer,0.62363374,fineart -Naoto Hattori,0.621745,fareast -Reylia Slaby,0.65709853,fineart -Arthur Burdett Frost,0.6147318,fineart -Frank Miller,0.65707314,digipa-high-impact -Algernon Talmage,0.65702903,fineart -Itō Jakuchū,0.6570199,digipa-high-impact -Billie Waters,0.65684533,digipa-high-impact -Ingrid Baars,0.58558,digipa-high-impact -Pieter Jansz Saenredam,0.6566058,fineart -Egbert van Heemskerck,0.6125889,fineart -John French Sloan,0.6362145,fineart -Craola,0.65639997,scribbles -Benjamin Marra,0.61809736,nudity -Anthony Thieme,0.65609205,fineart -Satoshi Kon,0.65606606,anime -Masamune Shirow,0.65592873,anime -Alfred Stevens,0.6557321,fineart -Hariton Pushwagner,0.6556745,anime -Carlo Carrà,0.6556279,fineart -Stuart Davis,0.6050534,digipa-high-impact -David Shrigley,0.6553904,digipa-high-impact -Albrecht Anker,0.65531695,fineart -Anton Semenov,0.6552501,digipa-high-impact -Fabio Hurtado,0.5955889,fineart -Donald Judd,0.6552257,fineart -Francisco de Burgos Mantilla,0.65516514,fineart -Barthel Bruyn the Younger,0.6551433,fineart -Abram Arkhipov,0.6550962,fineart -Paulus Potter,0.65498203,fineart -Edward Lamson Henry,0.6549521,fineart -Audrey Kawasaki,0.654843,fineart -George Catlin,0.6547183,fineart -Adélaïde Labille-Guiard,0.6066263,fineart -Sandy Skoglund,0.6546999,digipa-high-impact -Hans Baldung,0.654431,fineart -Ethan Van Sciver,0.65442884,cartoon -Frans Hals,0.6542338,fineart -Caspar David Friedrich,0.6542175,fineart -Charles Conder,0.65420866,fineart -Betty Churcher,0.65387225,fineart -Claes Corneliszoon Moeyaert,0.65386075,fineart -David Bomberg,0.6537477,fineart -Abraham Bosschaert,0.6535562,fineart -Giuseppe de Nittis,0.65354455,fineart -John La Farge,0.65342575,fineart -Frits Thaulow,0.65341854,fineart -John Duncan,0.6532379,fineart -Floris van Dyck,0.64900756,fineart -Anton Pieck,0.65310377,fineart -Roger Dean,0.6529647,nudity -Maximilian Pirner,0.65280807,fineart -Dorothy Johnstone,0.65267503,fineart -Govert Dircksz Camphuysen,0.65258145,fineart -Ryohei Hase,0.6168618,fineart -Hans von Aachen,0.62437224,fineart -Gustaf Munch-Petersen,0.6522485,fineart -Earnst Haeckel,0.6344333,fineart -Giovanni Battista Bracelli,0.62635326,fineart -Hendrick Goudt,0.6521433,fineart -Aneurin Jones,0.65191466,fineart -Bryan Hitch,0.6518333,cartoon -Coby Whitmore,0.6515695,fineart -Barthélemy d'Eyck,0.65156406,fineart -Quint Buchholz,0.65151155,fineart -Adriaen Hanneman,0.6514815,fineart -Tom Roberts,0.5855832,fineart -Fernand Khnopff,0.6512954,nudity -Charles Vess,0.6512271,cartoon -Carlo Galli Bibiena,0.6511681,nudity -Alexander Milne Calder,0.6081027,fineart -Josan Gonzalez,0.6193469,cartoon -Barthel Bruyn the Elder,0.6509954,fineart -Jon Whitcomb,0.6046063,fineart -Arcimboldo,0.6509897,fineart -Hendrik van Steenwijk I,0.65086293,fineart -Albert Joseph Pénot,0.65085316,fineart -Edward Wadsworth,0.6308917,scribbles -Andrew Wyeth,0.6507103,fineart -Correggio,0.650689,fineart -Frances Currey,0.65068,fineart -Henryk Siemiradzki,0.56721973,fineart -Worthington Whittredge,0.6504713,fineart -Federico Zandomeneghi,0.65033823,fineart -Isaac Levitan,0.6503356,fineart -Russ Mills,0.65012795,fineart -Edith Lawrence,0.65010095,fineart -Gil Elvgren,0.5614284,digipa-high-impact -Chris Foss,0.56495357,fineart -Francesco Zuccarelli,0.612805,fineart -Hendrick Bloemaert,0.64962655,fineart -Egon von Vietinghoff,0.57180583,fineart -Pixar,0.6495793,cartoon -Daniel Clowes,0.6495775,fineart -Friedrich Ritter von Friedländer-Malheim,0.6493772,fineart -Rebecca Sugar,0.6492679,scribbles -Chen Daofu,0.6492026,fineart -Dustin Nguyen,0.64909416,cartoon -Raymond Duchamp-Villon,0.6489605,nudity -Daniel Garber,0.6489332,fineart -Antonio Canova,0.58764786,fineart -Algernon Blackwood,0.59256804,fineart -Betye Saar,0.64877665,fineart -William S. Burroughs,0.5505619,fineart -Rodney Matthews,0.64844495,fineart -Michelangelo Buonarroti,0.6484401,fineart -Posuka Demizu,0.64843124,anime -Joao Ruas,0.6484134,fineart -Andy Fairhurst,0.6480388,special -"Andries Stock, Dutch Baroque painter",0.6479797,fineart -Antonio de la Gandara,0.6479292,fineart -Bruce Timm,0.6477877,scribbles -Harvey Kurtzman,0.64772683,cartoon -Eiichiro Oda,0.64772165,anime -Edwin Landseer,0.6166703,fineart -Carl Heinrich Bloch,0.64755356,fineart -Adriaen Isenbrant,0.6475428,fineart -Santiago Caruso,0.6473954,fineart -Alfred Guillou,0.6472603,fineart -Clara Peeters,0.64725095,fineart -Kim Jung Gi,0.6472225,cartoon -Milo Manara,0.6471776,cartoon -Phil Noto,0.6470769,anime -Kaws,0.6470336,cartoon -Desmond Morris,0.5951916,fineart -Gediminas Pranckevicius,0.6467787,fineart -Jack Kirby,0.6467424,cartoon -Claes Jansz. Visscher,0.6466888,fineart -Augustin Meinrad Bächtiger,0.6465789,fineart -John Lavery,0.64643383,fineart -Anne Bachelier,0.6464065,fineart -Giuseppe Bernardino Bison,0.64633006,fineart -E. T. A. Hoffmann,0.5887251,fineart -Ambrosius Benson,0.6457839,fineart -Cornelis Verbeeck,0.645782,fineart -H. R. Giger,0.6456823,weird -Adolph Menzel,0.6455246,fineart -Aliza Razell,0.5863178,digipa-high-impact -Gerard Seghers,0.6205679,fineart -David Aja,0.62812066,scribbles -Gustave Courbet,0.64476407,fineart -Alexandre Cabanel,0.63849115,fineart -Albert Marquet,0.64471006,fineart -Harold Harvey,0.64464307,fineart -William Wegman,0.6446265,scribbles -Harold Gilman,0.6445966,fineart -Jeremy Geddes,0.57839495,digipa-high-impact -Abraham van Beijeren,0.6356113,fineart -Eugène Isabey,0.6160607,fineart -Jorge Jacinto,0.58618563,fineart -Frederic Leighton,0.64383554,fineart -Dave McKean,0.6438012,cartoon -Hiromu Arakawa,0.64371413,anime -Aaron Douglas,0.6437089,fineart -Adolf Dietrich,0.590169,fineart -Frederik de Moucheron,0.6435952,fineart -Siya Oum,0.6435919,cartoon -Alberto Morrocco,0.64352196,fineart -Robert Vonnoh,0.6433115,fineart -Tom Bagshaw,0.5322264,fineart -Guerrilla Girls,0.64309967,digipa-high-impact -Johann Wolfgang von Goethe,0.6429888,fineart -Charles Le Roux,0.6426594,fineart -Auguste Toulmouche,0.64261353,fineart -Cindy Sherman,0.58666563,digipa-high-impact -Federico Zuccari,0.6425021,fineart -Mike Mignola,0.642346,cartoon -Cecily Brown,0.6421981,fineart -Brian K. Vaughan,0.64147836,cartoon -RETNA (Marquis Lewis),0.47963,n -Klaus Janson,0.64129144,cartoon -Alessandro Galli Bibiena,0.6412889,fineart -Jeremy Lipking,0.64123213,fineart -Stephen Shore,0.64108944,digipa-high-impact -Heinz Edelmann,0.51325977,digipa-med-impact -Joaquín Sorolla,0.6409732,fineart -Bella Kotak,0.6409608,digipa-high-impact -Cornelis Engebrechtsz,0.64091057,fineart -Bruce Munro,0.64084166,digipa-high-impact -Marjane Satrapi,0.64076495,fineart -Jeremy Mann,0.557744,digipa-high-impact -Heinrich Maria Davringhausen,0.6403986,fineart -Kengo Kuma,0.6402023,digipa-high-impact -Alfred Manessier,0.640153,fineart -Antonio Galli Bibiena,0.6399247,digipa-high-impact -Eduard von Grützner,0.6397164,fineart -Bunny Yeager,0.5455078,digipa-high-impact -Adolphe Willette,0.6396935,fineart -Wangechi Mutu,0.6394607,n -Peter Milligan,0.6391612,digipa-high-impact -Dalí,0.45400402,digipa-low-impact -Élisabeth Vigée Le Brun,0.6388982,fineart -Beth Conklin,0.6388204,digipa-high-impact -Charles Alphonse du Fresnoy,0.63881266,fineart -Thomas Benjamin Kennington,0.56668127,fineart -Jim Woodring,0.5625168,fineart -Francisco Oller,0.63846034,fineart -Csaba Markus,0.6384506,fineart -Botero,0.63843524,scribbles -Bill Henson,0.5394536,digipa-high-impact -Anna Bocek,0.6382304,scribbles -Hugo van der Goes,0.63822484,fineart -Robert William Hume,0.5433574,fineart -Chip Zdarsky,0.6381826,cartoon -Daniel Seghers,0.53494316,fineart -Richard Doyle,0.6377541,fineart -Hendrick Terbrugghen,0.63773805,fineart -Joe Madureira,0.6377177,special -Floris van Schooten,0.6376191,fineart -Jeff Simpson,0.3959046,fineart -Albert Joseph Moore,0.6374316,fineart -Arthur Merric Boyd,0.6373228,fineart -Amadeo de Souza Cardoso,0.5927926,fineart -Os Gemeos,0.6368859,digipa-high-impact -Giovanni Boldini,0.6368698,fineart -Albert Goodwin,0.6368695,fineart -Hans Eduard von Berlepsch-Valendas,0.61562145,fineart -Edmond Xavier Kapp,0.5758474,fineart -François Quesnel,0.6365935,fineart -Nathan Coley,0.6365817,digipa-high-impact -Jasmine Becket-Griffith,0.6365083,digipa-high-impact -Raphaelle Peale,0.6364422,fineart -Candido Portinari,0.63634276,fineart -Edward Dugmore,0.63179636,fineart -Anders Zorn,0.6361722,fineart -Ed Emshwiller,0.63615763,fineart -Francis Coates Jones,0.6361159,fineart -Ernst Haas,0.6361123,digipa-high-impact -Dirck van Baburen,0.6213001,fineart -René Lalique,0.63594735,fineart -Sydney Prior Hall,0.6359345,fineart -Brad Kunkle,0.5659712,fineart -Corneille,0.6356381,fineart -Henry Lamb,0.63560975,fineart -Dirck Hals,0.63559663,fineart -Alex Grey,0.62908936,nudity -Michael Heizer,0.63555753,fineart -Yiannis Moralis,0.61731136,fineart -Emily Murray Paterson,0.4392335,fineart -Georg Friedrich Kersting,0.6256248,fineart -Frances Hodgkins,0.6352128,fineart -Charles Cundall,0.6349486,fineart -Henry Wallis,0.63478243,fineart -Goro Fujita,0.6346491,cartoon -Jean-Léon Gérôme,0.5954844,fineart -August von Pettenkofen,0.60910493,fineart -Abbott Handerson Thayer,0.63428533,fineart -Martin John Heade,0.5926603,fineart -Ellen Jewett,0.63420236,digipa-high-impact -Hidari Jingorō,0.63388014,fareast -Taiyō Matsumoto,0.63372946,special -Emanuel Leutze,0.6007246,fineart -Adam Martinakis,0.48973057,digipa-med-impact -Will Eisner,0.63349223,cartoon -Alexander Stirling Calder,0.6331682,fineart -Saturno Butto,0.6331184,nudity -Cecilia Beaux,0.6330725,fineart -Amandine Van Ray,0.6174208,digipa-high-impact -Bob Eggleton,0.63277495,digipa-high-impact -Sherree Valentine Daines,0.63274443,fineart -Frederick Lord Leighton,0.6299176,fineart -Daniel Ridgway Knight,0.63251615,fineart -Gaetano Previati,0.61743724,fineart -John Berkey,0.63226986,fineart -Richard Misrach,0.63201725,digipa-high-impact -Aaron Jasinski,0.57948315,fineart -"Edward Otho Cresap Ord, II",0.6317712,fineart -Evelyn De Morgan,0.6317376,fineart -Noelle Stevenson,0.63159716,digipa-high-impact -Edward Robert Hughes,0.6315573,fineart -Allan Ramsay,0.63150716,fineart -Balthus,0.6314323,scribbles -Hendrick Cornelisz Vroom,0.63143134,digipa-high-impact -Ilya Repin,0.6313043,fineart -George Lambourn,0.6312267,fineart -Arthur Hughes,0.6310194,fineart -Antonio J. Manzanedo,0.53841716,fineart -John Singleton Copley,0.6264835,fineart -Dennis Miller Bunker,0.63078755,fineart -Ernie Barnes,0.6307126,cartoon -Alison Kinnaird,0.6306353,digipa-high-impact -Alex Toth,0.6305541,digipa-high-impact -Henry Raeburn,0.6155551,fineart -Alice Bailly,0.6305177,fineart -Brian Kesinger,0.63037646,scribbles -Antoine Blanchard,0.63036835,fineart -Ron Walotsky,0.63035095,fineart -Kent Monkman,0.63027304,fineart -Naomi Okubo,0.5782754,fareast -Hercules Seghers,0.62957174,fineart -August Querfurt,0.6295643,fineart -Samuel Melton Fisher,0.6283333,fineart -David Burdeny,0.62950236,digipa-high-impact -George Bain,0.58519644,fineart -Peter Holme III,0.62938106,fineart -Grayson Perry,0.62928164,digipa-high-impact -Chris Claremont,0.6292076,digipa-high-impact -Dod Procter,0.6291759,fineart -Huang Tingjian,0.6290358,fareast -Dorothea Warren O'Hara,0.6290113,fineart -Ivan Albright,0.6289551,fineart -Hubert von Herkomer,0.6288955,fineart -Barbara Nessim,0.60589516,digipa-high-impact -Henry Scott Tuke,0.6286309,fineart -Ditlev Blunck,0.6282925,fineart -Sven Nordqvist,0.62828535,fineart -Lee Madgwick,0.6281731,fineart -Hubert van Eyck,0.6281529,fineart -Edmond Bille,0.62339354,fineart -Ejnar Nielsen,0.6280824,fineart -Arturo Souto,0.6280583,fineart -Jean Giraud,0.6279888,fineart -Storm Thorgerson,0.6277394,digipa-high-impact -Ed Benedict,0.62764007,digipa-high-impact -Christoffer Wilhelm Eckersberg,0.6014842,fineart -Clarence Holbrook Carter,0.5514105,fineart -Dorothy Lockwood,0.6273235,fineart -John Singer Sargent,0.6272487,fineart -Brigid Derham,0.6270125,digipa-high-impact -Henricus Hondius II,0.6268505,fineart -Gertrude Harvey,0.5903887,fineart -Grant Wood,0.6266253,fineart -Fyodor Vasilyev,0.5234919,digipa-med-impact -Cagnaccio di San Pietro,0.6261671,fineart -Doris Boulton-Maude,0.62593174,fineart -Adolf Hirémy-Hirschl,0.5946784,fineart -Harold von Schmidt,0.6256755,fineart -Martine Johanna,0.6256161,digipa-high-impact -Gerald Kelly,0.5579602,digipa-high-impact -Ub Iwerks,0.625396,cartoon -Dirck van der Lisse,0.6253871,fineart -Edouard Riou,0.6250113,fineart -Ilya Yefimovich Repin,0.62491584,fineart -Martin Johnson Heade,0.59421235,fineart -Afarin Sajedi,0.62475824,scribbles -Alfred Thompson Bricher,0.6247515,fineart -Edwin G. Lucas,0.5553578,fineart -Georges Emile Lebacq,0.56175387,fineart -Francis Davis Millet,0.5988504,fineart -Bill Sienkiewicz,0.6125557,digipa-high-impact -Giocondo Albertolli,0.62441677,fineart -Victor Nizovtsev,0.6242258,fineart -Squeak Carnwath,0.62416434,digipa-high-impact -Bill Viola,0.62409425,digipa-high-impact -Annie Abernethie Pirie Quibell,0.6240767,fineart -Jason Edmiston,0.62405366,fineart -Al Capp,0.6239494,fineart -Kobayashi Kiyochika,0.6239368,anime -Albert Anker,0.62389827,fineart -Iain Faulkner,0.62376785,fineart -Todd Schorr,0.6237408,fineart -Charles Ginner,0.62370133,fineart -Emile Auguste Carolus-Duran,0.62353987,fineart -John Philip Falter,0.623418,cartoon -Chizuko Yoshida,0.6233001,fareast -Anna Dittmann,0.62327325,cartoon -Henry Snell Gamley,0.62319934,fineart -Edmund Charles Tarbell,0.6230626,fineart -Rob Gonsalves,0.62298363,fineart -Gladys Dawson,0.6228511,fineart -Tomma Abts,0.61153626,fineart -Kate Beaton,0.53993124,digipa-high-impact -Gustave Buchet,0.62243867,fineart -Gareth Pugh,0.6223551,digipa-high-impact -Caspar van Wittel,0.57871693,fineart -Anton Otto Fischer,0.6222941,fineart -Albert Guillaume,0.56529653,fineart -Felix Octavius Carr Darley,0.62223387,fineart -Bernard van Orley,0.62221646,fineart -Edward John Poynter,0.60147405,fineart -Walter Percy Day,0.62207425,fineart -Franciszek Starowieyski,0.5709621,fineart -Auguste Baud-Bovy,0.6219854,fineart -Chris LaBrooy,0.45497298,digipa-low-impact -Abraham de Vries,0.5859101,fineart -Antoni Gaudi,0.62162614,fineart -Joe Jusko,0.62156093,digipa-high-impact -Lynda Barry,0.62154603,digipa-high-impact -Michal Karcz,0.62154436,digipa-high-impact -Raymond Briggs,0.62150294,fineart -Herbert James Gunn,0.6210927,fineart -Dwight William Tryon,0.620984,fineart -Paul Henry,0.5752968,fineart -Helio Oiticica,0.6203739,digipa-high-impact -Sebastian Errazuriz,0.62036186,digipa-high-impact -Lucian Freud,0.6203146,nudity -Frank Auerbach,0.6201102,weird -Andre-Charles Boulle,0.6200789,fineart -Franz Fedier,0.5669752,fineart -Austin Briggs,0.57675314,fineart -Hugo Sánchez Bonilla,0.61978436,digipa-high-impact -Caroline Chariot-Dayez,0.6195682,digipa-high-impact -Bill Ward,0.61953044,digipa-high-impact -Charles Bird King,0.6194487,fineart -Adrian Ghenie,0.6193521,digipa-high-impact -Agnes Cecile,0.6192814,digipa-high-impact -Augustus John,0.6191995,fineart -Jeffrey T. Larson,0.61913544,fineart -Alexis Simon Belle,0.3190395,digipa-low-impact -Jean-Baptiste Monge,0.5758537,fineart -Adolf Bierbrauer,0.56129396,fineart -Ayako Rokkaku,0.61891204,fareast -Lisa Keene,0.54570895,digipa-high-impact -Edmond Aman-Jean,0.57168096,fineart -Marc Davis,0.61837333,cartoon -Cerith Wyn Evans,0.61829346,digipa-high-impact -George Wyllie,0.61829203,fineart -George Luks,0.6182724,fineart -William-Adolphe Bouguereau,0.618265,c -Grigoriy Myasoyedov,0.61801606,fineart -Hashimoto Gahō,0.61795104,fineart -Charles Ragland Bunnell,0.61772746,fineart -Ambrose McCarthy Patterson,0.61764514,fineart -Bill Brauer,0.5824066,fineart -Mikko Lagerstedt,0.591015,digipa-high-impact -Koson Ohara,0.53635323,fineart -Evaristo Baschenis,0.5857368,fineart -Martin Ansin,0.5294119,fineart -Cory Loftis,0.6168619,cartoon -Joseph Stella,0.6166778,fineart -André Pijet,0.5768274,fineart -Jeff Wall,0.6162895,digipa-high-impact -Eleanor Layfield Davis,0.6158844,fineart -Saul Tepper,0.61579347,fineart -Alex Hirsch,0.6157384,cartoon -Alexandre Falguière,0.55011404,fineart -Malcolm Liepke,0.6155646,fineart -Georg Friedrich Schmidt,0.60364646,fineart -Hendrik Kerstens,0.55099905,digipa-high-impact -Félix Bódog Widder,0.6153954,fineart -Marie Guillemine Benoist,0.61532974,fineart -Kelly Mckernan,0.60047054,digipa-high-impact -Ignacio Zuloaga,0.6151608,fineart -Hubert van Ravesteyn,0.61489964,fineart -Angus McKie,0.61487424,digipa-high-impact -Colin Campbell Cooper,0.6147882,fineart -Pieter Aertsen,0.61454165,fineart -Jan Brett,0.6144608,fineart -Kazuo Koike,0.61438507,fineart -Edith Grace Wheatley,0.61428297,fineart -Ogawa Kazumasa,0.61427975,fareast -Giovanni Battista Cipriani,0.6022825,fineart -André Bauchant,0.57124996,fineart -George Abe,0.6140447,digipa-high-impact -Georges Lemmen,0.6139967,scribbles -Frank Leonard Brooks,0.6139327,fineart -Gai Qi,0.613744,anime -Frank Gehry,0.6136776,digipa-high-impact -Anton Domenico Gabbiani,0.55471313,fineart -Cassandra Austen,0.6135781,fineart -Paul Gustav Fischer,0.613273,fineart -Emiliano Di Cavalcanti,0.6131207,fineart -Meryl McMaster,0.6129995,digipa-high-impact -Domenico di Pace Beccafumi,0.6129922,fineart -Ludwig Mies van der Rohe,0.6126692,fineart -Étienne-Louis Boullée,0.6126158,fineart -Dali,0.5928694,nudity -Shinji Aramaki,0.61246127,anime -Giovanni Fattori,0.59544694,fineart -Bapu,0.6122084,c -Raphael Lacoste,0.5539114,digipa-high-impact -Scarlett Hooft Graafland,0.6119631,digipa-high-impact -Rene Laloux,0.61190474,fineart -Julius Horsthuis,0.59037095,fineart -Gerald van Honthorst,0.6115939,fineart -Dino Valls,0.611533,fineart -Tony DiTerlizzi,0.6114657,cartoon -Michael Cheval,0.61138546,anime -Charles Schulz,0.6113759,digipa-high-impact -Alvar Aalto,0.61122143,digipa-high-impact -Gu Kaizhi,0.6110798,fareast -Eugene von Guerard,0.6109776,fineart -John Cassaday,0.610949,fineart -Elizabeth Forbes,0.61092335,fineart -Edmund Greacen,0.6109115,fineart -Eugène Burnand,0.6107876,fineart -Boris Grigoriev,0.6107853,scribbles -Norman Rockwell,0.6107638,fineart -Barthélemy Menn,0.61064315,fineart -George Biddle,0.61058354,fineart -Edgar Ainsworth,0.5525424,digipa-high-impact -Alfred Leyman,0.5887217,fineart -Tex Avery,0.6104007,cartoon -Beatrice Ethel Lithiby,0.61030364,fineart -Grace Pailthorpe,0.61026484,digipa-high-impact -Brian Oldham,0.396231,digipa-low-impact -Android Jones,0.61023116,fareast -François Girardon,0.5830649,fineart -Ib Eisner,0.61016303,digipa-high-impact -Armand Point,0.610156,fineart -Henri Alphonse Barnoin,0.59465057,fineart -Jean Marc Nattier,0.60987425,fineart -Francisco de Holanda,0.6091294,fineart -Marco Mazzoni,0.60970783,fineart -Esaias Boursse,0.6093308,fineart -Alexander Deyneka,0.55000365,fineart -John Totleben,0.60883725,fineart -Al Feldstein,0.6087723,fineart -Adam Hughes,0.60854626,anime -Ernest Zobole,0.6085073,fineart -Alex Gross,0.60837066,digipa-high-impact -George Jamesone,0.6079673,fineart -Frank Lloyd Wright,0.60793245,scribbles -Brooke DiDonato,0.47680336,digipa-med-impact -Hans Gude,0.60780364,fineart -Ethel Schwabacher,0.60748273,fineart -Gladys Kathleen Bell,0.60747695,fineart -Adolf Fényes,0.54192233,fineart -Carel Willink,0.58120143,fineart -George Henry,0.6070727,digipa-high-impact -Ronald Balfour,0.60697085,fineart -Elsie Dalton Hewland,0.6067718,digipa-high-impact -Alex Maleev,0.6067118,fineart -Anish Kapoor,0.6067015,digipa-high-impact -Aleksandr Ivanovich Laktionov,0.606544,fineart -Kim Keever,0.6037775,digipa-high-impact -Aleksi Briclot,0.46056762,fineart -Raymond Leech,0.6062721,fineart -Richard Eurich,0.6062664,fineart -Phil Jimenez,0.60625625,cartoon -Gao Cen,0.60618126,nudity -Mike Deodato,0.6061201,cartoon -Charles Haslewood Shannon,0.6060581,fineart -Alexandre Jacovleff,0.3991747,digipa-low-impact -André Beauneveu,0.584062,fineart -Hiroshi Honda,0.60507596,digipa-high-impact -Charles Joshua Chaplin,0.60498774,fineart -Domenico Zampieri,0.6049726,fineart -Gusukuma Seihō,0.60479784,fareast -Nikolina Petolas,0.46318632,digipa-low-impact -Casey Weldon,0.6047672,cartoon -Elmyr de Hory,0.6046374,fineart -Nan Goldin,0.6046119,digipa-high-impact -Charles McAuley,0.6045995,fineart -Archibald Skirving,0.6044234,fineart -Elizabeth York Brunton,0.6043737,fineart -Dugald Sutherland MacColl,0.6042907,fineart -Titian,0.60426414,fineart -Ignacy Witkiewicz,0.6042259,fineart -Allie Brosh,0.6042061,digipa-high-impact -H.P. Lovecraft,0.6039597,digipa-high-impact -Andrée Ruellan,0.60395086,fineart -Ralph McQuarrie,0.60380936,fineart -Mead Schaeffer,0.6036558,fineart -Henri-Julien Dumont,0.571257,fineart -Kieron Gillen,0.6035093,fineart -Maginel Wright Enright Barney,0.6034306,nudity -Vincent Di Fate,0.6034131,fineart -Briton Rivière,0.6032918,fineart -Hajime Sorayama,0.60325956,nudity -Béla Czóbel,0.6031023,fineart -Edmund Blampied,0.603072,fineart -E. Simms Campbell,0.6030443,fineart -Hisui Sugiura,0.603034,fareast -Alan Davis,0.6029676,fineart -Glen Keane,0.60287905,cartoon -Frank Holl,0.6027312,fineart -Abbott Fuller Graves,0.6025608,fineart -Albert Servaes,0.60250103,black-white -Hovsep Pushman,0.5937487,fineart -Brian M. Viveros,0.60233414,fineart -Charles Fremont Conner,0.6023278,fineart -Francesco Furini,0.6022654,digipa-high-impact -Camille-Pierre Pambu Bodo,0.60191673,fineart -Yasushi Nirasawa,0.6016714,nudity -Charles Uzzell-Edwards,0.6014683,fineart -Abram Efimovich Arkhipov,0.60128385,fineart -Hedda Sterne,0.6011857,digipa-high-impact -Ben Aronson,0.6011548,fineart -Frank Frazetta,0.551121,nudity -Elizabeth Durack,0.6010842,fineart -Ian Miller,0.42153555,fareast -Charlie Bowater,0.4410439,special -Michael Carson,0.60039437,fineart -Walter Langley,0.6002273,fineart -Cornelis Anthonisz,0.6001956,fineart -Dorothy Elizabeth Bradford,0.6001929,fineart -J.C. Leyendecker,0.5791972,fineart -Willem van Haecht,0.59990716,fineart -Anna and Elena Balbusso,0.59955937,digipa-low-impact -Harrison Fisher,0.59952044,fineart -Bill Medcalf,0.59950054,fineart -Edward Arthur Walton,0.59945667,fineart -Alois Arnegger,0.5991994,fineart -Ray Caesar,0.59902894,digipa-high-impact -Karen Wallis,0.5990094,fineart -Emmanuel Shiu,0.51082766,digipa-med-impact -Thomas Struth,0.5988324,digipa-high-impact -Barbara Longhi,0.5985706,fineart -Richard Deacon,0.59851056,fineart -Constantin Hansen,0.5984213,fineart -Harold Shapinsky,0.5984175,fineart -George Dionysus Ehret,0.5983857,fineart -Doug Wildey,0.5983639,digipa-high-impact -Fernand Toussaint,0.5982694,fineart -Horatio Nelson Poole,0.5982614,fineart -Caesar van Everdingen,0.5981566,fineart -Eva Gonzalès,0.5981396,fineart -Franz Vohwinkel,0.5448179,fineart -Margaret Mee,0.5979592,fineart -Francis Focer Brown,0.59779185,fineart -Henry Moore,0.59767926,nudity -Scott Listfield,0.58795893,fineart -Nikolai Ge,0.5973643,fineart -Jacek Yerka,0.58198756,fineart -Margaret Brundage,0.5969077,fineart -JC Leyendecker,0.5620243,fineart -Ben Templesmith,0.5498991,digipa-high-impact -Armin Hansen,0.59669334,anime -Jean-Louis Prevost,0.5966897,fineart -Daphne Allen,0.59666026,fineart -Franz Karl Basler-Kopp,0.59663445,fineart -"Henry Ives Cobb, Jr.",0.596385,fineart -Michael Sowa,0.546285,fineart -Anna Füssli,0.59600973,fineart -György Rózsahegyi,0.59580946,fineart -Luis Royo,0.59566617,fineart -Émile Gallé,0.5955559,fineart -Antonio Mora,0.5334297,digipa-high-impact -Edward P. Beard Jr.,0.59543866,fineart -Jessica Rossier,0.54958373,special -André Thomkins,0.5343785,digipa-high-impact -David Macbeth Sutherland,0.5949968,fineart -Charles Liu,0.5949787,digipa-high-impact -Edi Rama,0.5949226,digipa-high-impact -Jacques Le Moyne,0.5948843,fineart -Egbert van der Poel,0.59488285,fineart -Georg Jensen,0.594782,digipa-high-impact -Anne Sudworth,0.5947539,fineart -Jan Pietersz Saenredam,0.59472525,fineart -Henryk Stażewski,0.5945748,fineart -André François,0.58402044,fineart -Alexander Runciman,0.5944449,digipa-high-impact -Thomas Kinkade,0.594391,fineart -Robert Williams,0.5567989,digipa-high-impact -George Gardner Symons,0.57431924,fineart -D. Alexander Gregory,0.5334464,fineart -Gerald Brom,0.52473724,fineart -Robert Hagan,0.59406,fineart -Ernest Crichlow,0.5940588,fineart -Viviane Sassen,0.5939927,digipa-high-impact -Enrique Simonet,0.5937546,fineart -Esther Blaikie MacKinnon,0.593747,digipa-high-impact -Jeff Kinney,0.59372896,scribbles -Igor Morski,0.5936732,digipa-high-impact -John Currin,0.5936216,fineart -Bob Ringwood,0.5935273,digipa-high-impact -Jordan Grimmer,0.44948143,digipa-low-impact -François Barraud,0.5933471,fineart -Helen Binyon,0.59331006,digipa-high-impact -Brenda Chamberlain,0.5932333,fineart -Candido Bido,0.59310603,fineart -Abraham Storck,0.5929502,fineart -Raphael,0.59278333,fineart -Larry Sultan,0.59273386,digipa-high-impact -Agostino Tassi,0.59265685,fineart -Alexander V. Kuprin,0.5925917,fineart -Frans Koppelaar,0.5658725,fineart -Richard Corben,0.59251785,fineart -David Gilmour Blythe,0.5924247,digipa-high-impact -František Kaván,0.5924211,fineart -Rob Liefeld,0.5921167,fineart -Ernő Rubik,0.5920297,fineart -Byeon Sang-byeok,0.59200096,fareast -Johfra Bosschart,0.5919376,fineart -Emil Lindenfeld,0.5761086,fineart -Howard Mehring,0.5917471,fineart -Gwenda Morgan,0.5915571,digipa-high-impact -Henry Asencio,0.5915404,fineart -"George Barret, Sr.",0.5914306,fineart -Andrew Ferez,0.5911011,fineart -Ed Brubaker,0.5910869,digipa-high-impact -George Reid,0.59095883,digipa-high-impact -Derek Gores,0.51769906,digipa-med-impact -Charles Rollier,0.5539186,fineart -Terry Oakes,0.590443,fineart -Thomas Blackshear,0.5078616,fineart -Albert Benois,0.5902705,nudity -Krenz Cushart,0.59026587,special -Jeff Koons,0.5902637,digipa-high-impact -Akihiko Yoshida,0.5901294,special -Anja Percival,0.45039332,digipa-low-impact -Eduard von Steinle,0.59008586,fineart -Alex Russell Flint,0.5900352,digipa-high-impact -Edward Okuń,0.5897297,fineart -Emma Lampert Cooper,0.5894849,fineart -Stuart Haygarth,0.58132994,digipa-high-impact -George French Angas,0.5434376,fineart -Edmund F. Ward,0.5892848,fineart -Eleanor Vere Boyle,0.58925456,digipa-high-impact -Evelyn Cheston,0.58924586,fineart -Edwin Dickinson,0.58921975,digipa-high-impact -Christophe Vacher,0.47325426,fineart -Anne Dewailly,0.58905107,fineart -Gertrude Greene,0.5862596,digipa-high-impact -Boris Groh,0.5888809,digipa-high-impact -Douglas Smith,0.588804,digipa-high-impact -Ian Hamilton Finlay,0.5887713,fineart -Derek Jarman,0.5887292,digipa-high-impact -Archibald Thorburn,0.5882001,fineart -Gillis d'Hondecoeter,0.58813053,fineart -I Ketut Soki,0.58801544,digipa-high-impact -Alex Schomburg,0.46614102,digipa-low-impact -Bastien L. Deharme,0.583349,special -František Jakub Prokyš,0.58782333,fineart -Jesper Ejsing,0.58782053,fineart -Odd Nerdrum,0.53551745,digipa-high-impact -Tom Lovell,0.5877577,fineart -Ayami Kojima,0.5877416,fineart -Peter Sculthorpe,0.5875696,fineart -Bernard D’Andrea,0.5874042,fineart -Denis Eden,0.58739066,digipa-high-impact -Alfons Walde,0.58728385,fineart -Jovana Rikalo,0.47006977,digipa-low-impact -Franklin Booth,0.5870834,fineart -Mat Collishaw,0.5870676,digipa-high-impact -Joseph Lorusso,0.586858,fineart -Helen Stevenson,0.454647,digipa-low-impact -Delaunay,0.58657396,fineart -H.R. Millar,0.58655745,fineart -E. Charlton Fortune,0.586376,fineart -Alson Skinner Clark,0.58631575,fineart -Stan And Jan Berenstain,0.5862361,digipa-high-impact -Howard Lyon,0.5862271,fineart -John Blanche,0.586182,fineart -Bernardo Cavallino,0.5858575,fineart -Tomasz Alen Kopera,0.5216588,fineart -Peter Gric,0.58583695,fineart -Guo Pei,0.5857794,fareast -James Turrell,0.5853901,digipa-high-impact -Alexandr Averin,0.58533764,fineart -Bertalan Székely,0.5548113,digipa-high-impact -Brothers Hildebrandt,0.5850233,fineart -Ed Roth,0.5849769,digipa-high-impact -Enki Bilal,0.58492255,fineart -Alan Lee,0.5848701,fineart -Charles H. Woodbury,0.5848688,fineart -André Charles Biéler,0.5847876,fineart -Annie Rose Laing,0.5597829,fineart -Matt Fraction,0.58463776,cartoon -Charles Alston,0.58453286,fineart -Frank Xavier Leyendecker,0.545465,fineart -Alfred Richard Gurrey,0.584306,fineart -Dan Mumford,0.5843051,cartoon -Francisco Martín,0.5842005,fineart -Alvaro Siza,0.58406967,digipa-high-impact -Frank J. Girardin,0.5839858,fineart -Henry Carr,0.58397424,digipa-high-impact -Charles Furneaux,0.58394694,fineart -Daniel F. Gerhartz,0.58389103,fineart -Gilberto Soren Zaragoza,0.5448442,fineart -Bart Sears,0.5838427,cartoon -Allison Bechdel,0.58383805,digipa-high-impact -Frank O'Meara,0.5837992,fineart -Charles Codman,0.5836579,fineart -Francisco Zúñiga,0.58359766,fineart -Vladimir Kush,0.49075457,fineart -Arnold Mesches,0.5834257,fineart -Frank McKelvey,0.5831641,fineart -Allen Butler Talcott,0.5830911,fineart -Eric Zener,0.58300316,fineart -Noah Bradley,0.44176096,digipa-low-impact -Robert Childress,0.58289623,fineart -Frances C. Fairman,0.5827239,fineart -Kathryn Morris Trotter,0.465856,digipa-low-impact -Everett Raymond Kinstler,0.5824819,fineart -Edward Mitchell Bannister,0.5804899,fineart -"George Barret, Jr.",0.5823128,fineart -Greg Hildebrandt,0.4271311,fineart -Anka Zhuravleva,0.5822078,digipa-high-impact -Rolf Armstrong,0.58217514,fineart -Eric Wallis,0.58191466,fineart -Clemens Ascher,0.5480207,digipa-high-impact -Hugo Kārlis Grotuss,0.5818766,fineart -Albert Paris Gütersloh,0.5817827,fineart -Hilda May Gordon,0.5817449,fineart -Hendrik Martenszoon Sorgh,0.5817126,fineart -Pipilotti Rist,0.5816868,digipa-high-impact -Hiroyuki Tajima,0.5816242,fareast -Igor Zenin,0.58159757,digipa-high-impact -Genevieve Springston Lynch,0.4979099,digipa-med-impact -Dan Witz,0.44476372,fineart -David Roberts,0.5255326,fineart -Frieke Janssens,0.5706969,digipa-high-impact -Arnold Schoenberg,0.56520367,fineart -Inoue Naohisa,0.5809933,fareast -Elfriede Lohse-Wächtler,0.58097905,fineart -Alex Ross,0.42460668,digipa-low-impact -Robert Irwin,0.58078,c -Charles Angrand,0.58077514,fineart -Anne Nasmyth,0.54221964,fineart -Henri Bellechose,0.5773891,fineart -De Hirsh Margules,0.58059025,fineart -Hiromitsu Takahashi,0.5805599,fareast -Ilya Kuvshinov,0.5805521,special -Cassius Marcellus Coolidge,0.5805516,c -Dorothy Burroughes,0.5804835,fineart -Emanuel de Witte,0.58027405,fineart -George Herbert Baker,0.5799624,digipa-high-impact -Cheng Zhengkui,0.57990086,fareast -Bernard Fleetwood-Walker,0.57987773,digipa-high-impact -Philippe Parreno,0.57985014,digipa-high-impact -Thornton Oakley,0.57969713,fineart -Greg Rutkowski,0.5203395,special -Ike no Taiga,0.5795857,anime -Eduardo Lefebvre Scovell,0.5795808,fineart -Adolfo Müller-Ury,0.57944727,fineart -Patrick Woodroffe,0.5228063,fineart -Wim Crouwel,0.57933235,digipa-high-impact -Colijn de Coter,0.5792779,fineart -François Boquet,0.57924724,fineart -Gerbrand van den Eeckhout,0.57897866,fineart -Eugenio Granell,0.5392264,fineart -Kuang Hong,0.5782304,digipa-high-impact -Justin Gerard,0.46685404,fineart -Tokujin Yoshioka,0.5779153,digipa-high-impact -Alan Bean,0.57788515,fineart -Ernest Biéler,0.5778079,fineart -Martin Deschambault,0.44401115,digipa-low-impact -Anna Boch,0.577735,fineart -Jack Davis,0.5775291,fineart -Félix Labisse,0.5775142,fineart -Greg Simkins,0.5679761,fineart -David Lynch,0.57751054,digipa-low-impact -Eizō Katō,0.5774127,digipa-high-impact -Grethe Jürgens,0.5773412,digipa-high-impact -Heinrich Bichler,0.5770147,fineart -Barbara Nasmyth,0.5446056,fineart -Domenico Induno,0.5583946,fineart -Gustave Baumann,0.5607866,fineart -Mike Mayhew,0.5765857,cartoon -Delmer J. Yoakum,0.576538,fineart -Aykut Aydogdu,0.43111503,digipa-low-impact -George Barker,0.5763551,fineart -Ernő Grünbaum,0.57634187,fineart -Eliseu Visconti,0.5763241,fineart -Esao Andrews,0.5761547,fineart -JennyBird Alcantara,0.49165845,digipa-med-impact -Joan Tuset,0.5761051,fineart -Angela Barrett,0.55976534,digipa-high-impact -Syd Mead,0.5758396,fineart -Ignacio Bazan-Lazcano,0.5757512,fineart -Franciszek Kostrzewski,0.57570386,fineart -Eero Järnefelt,0.57540673,fineart -Loretta Lux,0.56217635,digipa-high-impact -Gaudi,0.57519895,fineart -Charles Gleyre,0.57490873,fineart -Antoine Verney-Carron,0.56386137,fineart -Albert Edelfelt,0.57466495,fineart -Fabian Perez,0.57444525,fineart -Kevin Sloan,0.5737548,fineart -Stanislav Poltavsky,0.57434607,fineart -Abraham Hondius,0.574326,fineart -Tadao Ando,0.57429105,fareast -Fyodor Slavyansky,0.49796474,digipa-med-impact -David Brewster,0.57385933,digipa-high-impact -Cliff Chiang,0.57375133,digipa-high-impact -Drew Struzan,0.5317983,digipa-high-impact -Henry O. Tanner,0.5736586,fineart -Alberto Sughi,0.5736495,fineart -Albert J. Welti,0.5736257,fineart -Charles Mahoney,0.5735923,digipa-high-impact -Exekias,0.5734506,fineart -Felipe Seade,0.57342744,digipa-high-impact -Henriette Wyeth,0.57330644,digipa-high-impact -Harold Sandys Williamson,0.5443646,fineart -Eddie Campbell,0.57329535,digipa-high-impact -Gao Fenghan,0.5732926,fareast -Cynthia Sheppard,0.51099646,fineart -Henriette Grindat,0.573179,fineart -Yasutomo Oka,0.5731342,fareast -Celia Frances Bedford,0.57313216,fineart -Les Edwards,0.42068473,fineart -Edwin Deakin,0.5031717,fineart -Eero Saarinen,0.5725142,digipa-high-impact -Franciszek Smuglewicz,0.5722554,fineart -Doris Blair,0.57221186,fineart -Seb Mckinnon,0.51721895,digipa-med-impact -Gregorio Lazzarini,0.57204294,fineart -Gerard Sekoto,0.5719927,fineart -Francis Ernest Jackson,0.5506009,fineart -Simon Birch,0.57171595,digipa-high-impact -Bayard Wu,0.57171166,fineart -François Clouet,0.57162094,fineart -Christopher Wren,0.5715372,fineart -Evgeny Lushpin,0.5714827,special -Art Green,0.5714495,digipa-high-impact -Amy Judd,0.57142305,digipa-high-impact -Art Brenner,0.42619684,digipa-low-impact -Travis Louie,0.43916368,digipa-low-impact -James Jean,0.5457318,digipa-high-impact -Ewald Rübsamen,0.57083976,fineart -Donato Giancola,0.57052535,fineart -Carl Arnold Gonzenbach,0.5703996,fineart -Bastien Lecouffe-Deharme,0.5201288,fineart -Howard Chandler Christy,0.5702813,nudity -Dean Cornwell,0.56977296,fineart -Don Maitz,0.4743015,fineart -James Montgomery Flagg,0.56974065,fineart -Andreas Levers,0.42125136,digipa-low-impact -Edgar Schofield Baum,0.56965977,fineart -Alan Parry,0.5694952,digipa-high-impact -An Zhengwen,0.56942475,fareast -Alayna Lemmer,0.48293802,fineart -Edward Marshall Boehm,0.5530143,fineart -Henri Biva,0.54013556,nudity -Fiona Rae,0.4646715,digipa-low-impact -Elizabeth Jane Lloyd,0.5688463,digipa-high-impact -Franklin Carmichael,0.5687844,digipa-high-impact -Dionisius,0.56875896,fineart -Edwin Georgi,0.56868523,fineart -Jenny Saville,0.5686633,fineart -Ernest Hébert,0.56859314,fineart -Stephan Martiniere,0.56856346,digipa-high-impact -Huang Binhong,0.56841767,fineart -August Lemmer,0.5683548,fineart -Camille Bouvagne,0.5678048,fineart -Olga Skomorokhova,0.39401102,digipa-low-impact -Sacha Goldberger,0.5675477,digipa-high-impact -Hilda Annetta Walker,0.5675261,digipa-high-impact -Harvey Pratt,0.51314723,digipa-med-impact -Jean Bourdichon,0.5670543,fineart -Noriyoshi Ohrai,0.56690073,fineart -Kadir Nelson,0.5669006,n -Ilya Ostroukhov,0.5668801,fineart -Eugène Brands,0.56681967,fineart -Achille Leonardi,0.56674325,fineart -Franz Cižek,0.56670356,fineart -George Paul Chalmers,0.5665988,digipa-high-impact -Serge Marshennikov,0.5665971,digipa-high-impact -Mike Worrall,0.56641084,fineart -Dirck van Delen,0.5661764,fineart -Peter Andrew Jones,0.5661655,fineart -Rafael Albuquerque,0.56541103,fineart -Daniel Buren,0.5654043,fineart -Giuseppe Grisoni,0.5432699,fineart -George Fiddes Watt,0.55861616,fineart -Stan Lee,0.5651268,digipa-high-impact -Dorning Rasbotham,0.56511617,fineart -Albert Lynch,0.56497896,fineart -Lorenz Hideyoshi,0.56494075,fineart -Fenghua Zhong,0.56492203,fareast -Caroline Lucy Scott,0.49190843,digipa-med-impact -Victoria Crowe,0.5647996,digipa-high-impact -Hasegawa Settan,0.5647092,fareast -Dennis H. Farber,0.56453323,digipa-high-impact -Dick Bickenbach,0.5644289,fineart -Art Frahm,0.56439924,fineart -Edith Edmonds,0.5643151,fineart -Alfred Heber Hutty,0.56419206,fineart -Henry Tonks,0.56410825,fineart -Peter Howson,0.5640759,fineart -Albert Dorne,0.56395364,fineart -Arthur Adams,0.5639404,fineart -Bernt Tunold,0.56383425,digipa-high-impact -Gianluca Foli,0.5637317,digipa-high-impact -Vittorio Matteo Corcos,0.5636767,fineart -Béla Iványi-Grünwald,0.56355745,nudity -Feng Zhu,0.5634973,fineart -Sam Kieth,0.47251505,digipa-low-impact -Charles Crodel,0.5633834,fineart -Elsie Henderson,0.56310076,digipa-high-impact -George Earl Ortman,0.56295705,fineart -Tari Márk Dávid,0.562937,fineart -Betty Merken,0.56281745,digipa-high-impact -Cecile Walton,0.46672013,digipa-low-impact -Bracha L. Ettinger,0.56237936,fineart -Ken Fairclough,0.56230986,digipa-high-impact -Phil Koch,0.56224954,digipa-high-impact -George Pirie,0.56213045,digipa-high-impact -Chad Knight,0.56194013,digipa-high-impact -Béla Kondor,0.5427164,digipa-high-impact -Barclay Shaw,0.53689134,digipa-high-impact -Tim Hildebrandt,0.47194147,fineart -Hermann Rüdisühli,0.56104004,digipa-high-impact -Ian McQue,0.5342066,digipa-high-impact -Yanjun Cheng,0.5607171,fineart -Heinrich Hofmann,0.56060636,fineart -Henry Raleigh,0.5605958,fineart -Ernest Buckmaster,0.5605704,fineart -Charles Ricketts,0.56055415,fineart -Juergen Teller,0.56051147,digipa-high-impact -Auguste Mambour,0.5604873,fineart -Sean Yoro,0.5601486,digipa-high-impact -Sheilah Beckett,0.55995446,digipa-high-impact -Eugene Tertychnyi,0.5598978,fineart -Dr. Seuss,0.5597466,c -Adolf Wölfli,0.5372333,digipa-high-impact -Enrique Tábara,0.559323,fineart -Dionisio Baixeras Verdaguer,0.5590695,fineart -Aleksander Gierymski,0.5590013,fineart -Augustus Dunbier,0.55872476,fineart -Adolf Born,0.55848217,fineart -Chris Turnham,0.5584234,digipa-high-impact -James C Christensen,0.55837405,fineart -Daphne Fedarb,0.5582459,digipa-high-impact -Andre Kohn,0.5581832,special -Ron Mueck,0.5581811,nudity -Glenn Fabry,0.55786383,fineart -Elizabeth Polunin,0.5578102,digipa-high-impact -Charles S. Kaelin,0.5577954,fineart -Arthur Radebaugh,0.5577016,fineart -Ai Yazawa,0.55768114,fareast -Charles Roka,0.55762553,fineart -Ai Weiwei,0.5576034,digipa-high-impact -Dorothy Bradford,0.55760014,digipa-high-impact -Alfred Leslie,0.557555,fineart -Heinrich Herzig,0.5574423,fineart -Eliot Hodgkin,0.55740607,digipa-high-impact -Albert Kotin,0.55737317,fineart -Carlo Carlone,0.55729353,fineart -Chen Rong,0.5571221,fineart -Ikuo Hirayama,0.5570225,digipa-high-impact -Edward Corbett,0.55701995,nudity -Eugeniusz Żak,0.556925,nudity -Ettore Tito,0.556875,fineart -Helene Knoop,0.5567731,fineart -Amanda Sage,0.37731662,fareast -Annick Bouvattier,0.54647046,fineart -Harvey Dunn,0.55663586,fineart -Hans Sandreuter,0.5562575,digipa-high-impact -Ruan Jia,0.5398549,special -Anton Räderscheidt,0.55618906,fineart -Tyler Shields,0.4081434,digipa-low-impact -Darek Zabrocki,0.49975997,digipa-med-impact -Frank Montague Moore,0.5556432,fineart -Greg Staples,0.5555332,fineart -Endre Bálint,0.5553731,fineart -Augustus Vincent Tack,0.5136602,fineart -Marc Simonetti,0.48602036,fineart -Carlo Randanini,0.55493265,digipa-high-impact -Diego Dayer,0.5549119,fineart -Kelly Freas,0.55476534,fineart -Thomas Saliot,0.5139967,digipa-med-impact -Gijsbert d'Hondecoeter,0.55455256,fineart -Walter Kim,0.554521,digipa-high-impact -Francesco Cozza,0.5155097,digipa-med-impact -Bill Watterson,0.5542879,digipa-high-impact -Mark Keathley,0.4824056,fineart -Béni Ferenczy,0.55405354,digipa-high-impact -Amadou Opa Bathily,0.5536976,n -Giuseppe Antonio Petrini,0.55340284,fineart -Enzo Cucchi,0.55331933,digipa-high-impact -Adolf Schrödter,0.55316544,fineart -George Benjamin Luks,0.548566,fineart -Glenys Cour,0.55304,digipa-high-impact -Andrew Robertson,0.5529603,digipa-high-impact -Claude Rogers,0.55272067,digipa-high-impact -Alexandre Antigna,0.5526737,fineart -Aimé Barraud,0.55265915,digipa-high-impact -György Vastagh,0.55258965,fineart -Bruce Nauman,0.55257386,digipa-high-impact -Benjamin Block,0.55251944,digipa-high-impact -Gonzalo Endara Crow,0.552346,digipa-high-impact -Dirck de Bray,0.55221736,fineart -Gerald Kelley,0.5521059,digipa-high-impact -Dave Gibbons,0.5520954,digipa-high-impact -Béla Nagy Abodi,0.5520624,digipa-high-impact -Faith 47,0.5517006,digipa-high-impact -Anna Razumovskaya,0.5229187,digipa-med-impact -Archibald Robertson,0.55129635,digipa-high-impact -Louise Dahl-Wolfe,0.55120385,digipa-high-impact -Simon Bisley,0.55119276,digipa-high-impact -Eric Fischl,0.55107886,fineart -Hu Zaobin,0.5510481,fareast -Béla Pállik,0.5507963,digipa-high-impact -Eugene J. Martin,0.55078864,fineart -Friedrich Gauermann,0.55063415,fineart -Fritz Baumann,0.5341434,fineart -Michal Lisowski,0.5505639,fineart -Paolo Roversi,0.5503342,digipa-high-impact -Andrew Atroshenko,0.55009747,fineart -Gyula Derkovits,0.5500315,fineart -Hugh Adam Crawford,0.55000615,digipa-high-impact -Béla Apáti Abkarovics,0.5499799,digipa-high-impact -Paul Chadeisson,0.389151,digipa-low-impact -Aurél Bernáth,0.54968774,fineart -Albert Henry Krehbiel,0.54952574,fineart -Piet Hein Eek,0.54918796,digipa-high-impact -Yoshitaka Amano,0.5491855,fareast -Antonio Rotta,0.54909515,fineart -Józef Mehoffer,0.50760424,fineart -Donald Sherwood,0.5490415,digipa-high-impact -Catrin G Grosse,0.5489286,digipa-high-impact -Arthur Webster Emerson,0.5478842,fineart -Incarcerated Jerkfaces,0.5488423,digipa-high-impact -Emanuel Büchel,0.5487217,fineart -Andrew Loomis,0.54854584,fineart -Charles Hopkinson,0.54853606,fineart -Gabor Szikszai,0.5485203,digipa-high-impact -Archibald Standish Hartrick,0.54850936,digipa-high-impact -Aleksander Orłowski,0.546705,nudity -Hans Hinterreiter,0.5483628,fineart -Fred Williams,0.54544824,fineart -Fred A. Precht,0.5481606,fineart -Camille Souter,0.5213742,fineart -Emil Fuchs,0.54807395,fineart -Francesco Bonsignori,0.5478936,fineart -H. R. (Hans Ruedi) Giger,0.547799,fineart -Harriet Zeitlin,0.5477388,digipa-high-impact -Christian Jane Fergusson,0.5396168,fineart -Edward Kemble,0.5476892,fineart -Bernard Aubertin,0.5475396,fineart -Augustyn Mirys,0.5474162,fineart -Alejandro Burdisio,0.47482288,special -Erin Hanson,0.4343264,digipa-low-impact -Amalia Lindegren,0.5471987,digipa-high-impact -Alberto Seveso,0.47735062,fineart -Bartholomeus Strobel,0.54703736,fineart -Jim Davis,0.54703003,digipa-high-impact -Antony Gormley,0.54696125,digipa-high-impact -Charles Marion Russell,0.54696095,fineart -George B. Sutherland,0.5467901,fineart -Almada Negreiros,0.54670584,fineart -Edward Armitage,0.54358315,fineart -Bruno Walpoth,0.546167,digipa-high-impact -Richard Hamilton,0.5461275,nudity -Charles Harold Davis,0.5460415,digipa-high-impact -Fernand Verhaegen,0.54601514,fineart -Bernard Meninsky,0.5302034,digipa-high-impact -Fede Galizia,0.5456873,digipa-high-impact -Alfred Kelsner,0.5455753,nudity -Fritz Puempin,0.5452847,fineart -Alfred Charles Parker,0.54521024,fineart -Ahmed Yacoubi,0.544767,digipa-high-impact -Arthur B. Carles,0.54447794,fineart -Alice Prin,0.54435575,digipa-high-impact -Carl Gustaf Pilo,0.5443212,digipa-high-impact -Ross Tran,0.5259248,special -Hideyuki Kikuchi,0.544193,fareast -Art Fitzpatrick,0.49847245,fineart -Cherryl Fountain,0.5440454,fineart -Skottie Young,0.5440119,cartoon -NC Wyeth,0.54382974,digipa-high-impact -Rudolf Freund,0.5437342,fineart -Mort Kunstler,0.5433619,digipa-high-impact -Ben Goossens,0.53002644,digipa-high-impact -Andreas Rocha,0.49621177,special -Gérard Ernest Schneider,0.5429964,fineart -Francesco Filippini,0.5429598,digipa-high-impact -Alejandro Jodorowsky,0.5429065,digipa-high-impact -Friedrich Traffelet,0.5428817,fineart -Honor C. Appleton,0.5428735,digipa-high-impact -Jason A. Engle,0.542821,fineart -Henry Otto Wix,0.54271996,fineart -Gregory Manchess,0.54270375,fineart -Ann Stookey,0.54269934,digipa-high-impact -Henryk Rodakowski,0.542589,fineart -Albert Welti,0.5425134,digipa-high-impact -Gerard Houckgeest,0.5424413,digipa-high-impact -Dorothy Hood,0.54226196,digipa-high-impact -Frank Schoonover,0.51056194,fineart -Erlund Hudson,0.5422107,digipa-high-impact -Alexander Litovchenko,0.54210097,fineart -Sakai Hōitsu,0.5420294,digipa-high-impact -Benito Quinquela Martín,0.54194224,fineart -David Watson Stevenson,0.54191554,fineart -Ann Thetis Blacker,0.5416629,digipa-high-impact -Frank DuMond,0.51004076,digipa-med-impact -David Dougal Williams,0.5410126,digipa-high-impact -Robert Mcginnis,0.54098356,fineart -Ernest Briggs,0.5408636,fineart -Ferenc Joachim,0.5408625,fineart -Carlos Saenz de Tejada,0.47332364,digipa-low-impact -David Burton-Richardson,0.49659324,digipa-med-impact -Ernest Heber Thompson,0.54039246,digipa-high-impact -Albert Bertelsen,0.54038215,nudity -Giorgio Giulio Clovio,0.5403708,fineart -Eugene Leroy,0.54019785,digipa-high-impact -Anna Findlay,0.54018176,digipa-high-impact -Roy Gjertson,0.54012,digipa-high-impact -Charmion von Wiegand,0.5400893,fineart -Arnold Bronckhorst,0.526247,fineart -Boris Vallejo,0.487253,fineart -Adélaïde Victoire Hall,0.539939,fineart -Earl Norem,0.5398575,fineart -Sanford Kossin,0.53977877,digipa-high-impact -Aert de Gelder,0.519166,digipa-med-impact -Carl Eugen Keel,0.539739,digipa-high-impact -Francis Bourgeois,0.5397272,digipa-high-impact -Bojan Jevtic,0.41141546,fineart -Edward Avedisian,0.5393925,fineart -Gao Xiang,0.5392419,fareast -Charles Hinman,0.53911865,digipa-high-impact -Frits Van den Berghe,0.53896487,fineart -Carlo Martini,0.5384833,digipa-high-impact -Elina Karimova,0.5384318,digipa-high-impact -Anto Carte,0.4708289,digipa-low-impact -Andrey Yefimovich Martynov,0.537721,fineart -Frances Jetter,0.5376904,fineart -Yuri Ivanovich Pimenov,0.5342793,fineart -Gaston Anglade,0.537608,digipa-high-impact -Albert Swinden,0.5375844,fineart -Bob Byerley,0.5375774,fineart -A.B. Frost,0.5375025,fineart -Jaya Suberg,0.5372893,digipa-high-impact -Josh Keyes,0.53654516,digipa-high-impact -Juliana Huxtable,0.5364195,n -Everett Warner,0.53641814,digipa-high-impact -Hugh Kretschmer,0.45171157,digipa-low-impact -Arnold Blanch,0.535774,fineart -Ryan McGinley,0.53572595,digipa-high-impact -Alfons Karpiński,0.53564656,fineart -George Aleef,0.5355317,digipa-high-impact -Hal Foster,0.5351446,fineart -Stuart Immonen,0.53501946,digipa-high-impact -Craig Thompson,0.5346844,digipa-high-impact -Bartolomeo Vivarini,0.53465015,fineart -Hermann Feierabend,0.5346168,digipa-high-impact -Antonio Donghi,0.4610982,digipa-low-impact -Adonna Khare,0.4858036,digipa-med-impact -James Stokoe,0.5015107,digipa-med-impact -Agustín Fernández,0.53403986,fineart -Germán Londoño,0.5338712,fineart -Emmanuelle Moureaux,0.5335641,digipa-high-impact -Conrad Marca-Relli,0.5148334,digipa-med-impact -Gyula Batthyány,0.5332407,fineart -Francesco Raibolini,0.53314835,fineart -Apelles,0.5166026,fineart -Marat Latypov,0.45811993,fineart -Andrei Markin,0.5328752,fineart -Einar Hakonarson,0.5328311,digipa-high-impact -Beatrice Huntington,0.5328165,digipa-high-impact -Coppo di Marcovaldo,0.5327443,fineart -Gregorio Prestopino,0.53250784,fineart -A.D.M. Cooper,0.53244877,digipa-high-impact -Horatio McCulloch,0.53244334,digipa-high-impact -Wes Anderson,0.5318741,digipa-high-impact -Moebius,0.53178746,digipa-high-impact -Gerard Soest,0.53160626,fineart -Charles Ellison,0.53152347,digipa-high-impact -Wojciech Ostrycharz,0.5314213,fineart -Doug Chiang,0.5313724,fineart -Anne Savage,0.5310638,digipa-high-impact -Cor Melchers,0.53099334,fineart -Gordon Browne,0.5308195,digipa-high-impact -Augustus Earle,0.49196815,fineart -Carlos Francisco Chang Marín,0.5304734,fineart -Larry Elmore,0.53032553,fineart -Adolf Hölzel,0.5303149,fineart -David Ligare,0.5301894,fineart -Jan Luyken,0.52985555,fineart -Earle Bergey,0.5298525,fineart -David Ramsay Hay,0.52974963,digipa-high-impact -Alfred East,0.5296565,digipa-high-impact -A. R. Middleton Todd,0.50988734,fineart -Giorgio De Vincenzi,0.5291678,fineart -Hugh William Williams,0.5291014,digipa-high-impact -Erwin Bowien,0.52895796,digipa-high-impact -Victor Adame Minguez,0.5288686,fineart -Yoji Shinkawa,0.5287015,anime -Clara Weaver Parrish,0.5284487,digipa-high-impact -Albert Eckhout,0.5284096,fineart -Dorothy Coke,0.5282345,digipa-high-impact -Jerzy Duda-Gracz,0.5279943,digipa-high-impact -Byron Galvez,0.39178842,fareast -Alson S. Clark,0.5278568,digipa-high-impact -Adolf Ulric Wertmüller,0.5278296,digipa-high-impact -Bruce Coville,0.5277226,digipa-high-impact -Gong Kai,0.5276811,digipa-high-impact -Andréi Arinouchkine,0.52763486,digipa-high-impact -Florence Engelbach,0.5273161,digipa-high-impact -Brian Froud,0.5270276,fineart -Charles Thomson,0.5270127,digipa-high-impact -Bessie Wheeler,0.5269164,digipa-high-impact -Anton Lehmden,0.5268611,fineart -Emilia Wilk,0.5264961,fineart -Carl Eytel,0.52646196,digipa-high-impact -Alfred Janes,0.5264481,digipa-high-impact -Julie Bell,0.49962538,fineart -Eugenio de Arriba,0.52613926,digipa-high-impact -Samuel and Joseph Newsom,0.52595663,digipa-high-impact -Hans Falk,0.52588874,digipa-high-impact -Guillermo del Toro,0.52565175,digipa-high-impact -Félix Arauz,0.52555984,digipa-high-impact -Gyula Basch,0.52524436,digipa-high-impact -Haroon Mirza,0.5252279,digipa-high-impact -Du Jin,0.5249934,digipa-med-impact -Harry Shoulberg,0.5249456,digipa-med-impact -Arie Smit,0.5249027,fineart -Ahmed Karahisari,0.4259451,digipa-low-impact -Brian and Wendy Froud,0.5246335,fineart -E. William Gollings,0.52461207,digipa-med-impact -Bo Bartlett,0.51341593,digipa-med-impact -Hans Burgkmair,0.52416867,digipa-med-impact -David Macaulay,0.5241233,digipa-med-impact -Benedetto Caliari,0.52370214,digipa-med-impact -Eliott Lilly,0.5235398,digipa-med-impact -Vincent Tanguay,0.48578292,digipa-med-impact -Ada Hill Walker,0.52207166,fineart -Christopher Wood,0.49360397,digipa-med-impact -Kris Kuksi,0.43938053,digipa-low-impact -Chen Yifei,0.5217867,fineart -Margaux Valonia,0.5217782,digipa-med-impact -Antoni Pitxot,0.40582713,digipa-low-impact -Jhonen Vasquez,0.5216471,digipa-med-impact -Emilio Grau Sala,0.52156484,fineart -Henry B. Christian,0.52153796,fineart -Jacques Nathan-Garamond,0.52144086,digipa-med-impact -Eddie Mendoza,0.4949638,digipa-med-impact -Grzegorz Rutkowski,0.48906532,special -Beeple,0.40085253,digipa-low-impact -Giorgio Cavallon,0.5209209,digipa-med-impact -Godfrey Blow,0.52062386,digipa-med-impact -Gabriel Dawe,0.5204431,fineart -Emile Lahner,0.5202367,digipa-med-impact -Steve Dillon,0.5201676,digipa-med-impact -Lee Quinones,0.4626683,digipa-low-impact -Hale Woodruff,0.52000225,digipa-med-impact -Tom Hammick,0.5032626,digipa-med-impact -Hamilton Sloan,0.5197798,digipa-med-impact -Caesar Andrade Faini,0.51971483,digipa-med-impact -Sam Spratt,0.48991,digipa-med-impact -Chris Cold,0.4753577,fineart -Alejandro Obregón,0.5190562,digipa-med-impact -Dan Flavin,0.51901346,digipa-med-impact -Arthur Sarnoff,0.5189428,fineart -Elenore Abbott,0.5187141,digipa-med-impact -Andrea Kowch,0.51822996,digipa-med-impact -Demetrios Farmakopoulos,0.5181248,digipa-med-impact -Alexis Grimou,0.41958088,digipa-low-impact -Lesley Vance,0.5177536,digipa-med-impact -Gyula Aggházy,0.517747,fineart -Georgina Hunt,0.46105456,digipa-low-impact -Christian W. Staudinger,0.4684662,digipa-low-impact -Abraham Begeyn,0.5172538,digipa-med-impact -Charles Mozley,0.5171356,digipa-med-impact -Elias Ravanetti,0.38719344,digipa-low-impact -Herman van Swanevelt,0.5168748,digipa-med-impact -David Paton,0.4842217,digipa-med-impact -Hans Werner Schmidt,0.51671976,digipa-med-impact -Bob Ross,0.51628315,fineart -Sou Fujimoto,0.5162528,fareast -Balcomb Greene,0.5162045,digipa-med-impact -Glen Angus,0.51609933,digipa-med-impact -Buckminster Fuller,0.51607454,digipa-med-impact -Andrei Ryabushkin,0.5158933,fineart -Almeida Júnior,0.515856,digipa-med-impact -Tim White,0.4182697,digipa-low-impact -Hans Beat Wieland,0.51553553,digipa-med-impact -Jakub Różalski,0.5154904,digipa-med-impact -John Whitcomb,0.51523805,digipa-med-impact -Dorothy King,0.5150925,digipa-med-impact -Richard S. Johnson,0.51500344,fineart -Aniello Falcone,0.51475304,digipa-med-impact -Henning Jakob Henrik Lund,0.5147134,c -Robert M Cunningham,0.5144858,digipa-med-impact -Nick Knight,0.51447505,digipa-med-impact -David Chipperfield,0.51424,digipa-med-impact -Bartolomeo Cesi,0.5136737,digipa-med-impact -Bettina Heinen-Ayech,0.51334465,digipa-med-impact -Annabel Kidston,0.51327646,digipa-med-impact -Charles Schridde,0.51308405,digipa-med-impact -Samuel Earp,0.51305825,digipa-med-impact -Eugene Montgomery,0.5128343,digipa-med-impact -Alfred Parsons,0.5127445,digipa-med-impact -Anton Möller,0.5127209,digipa-med-impact -Craig Davison,0.499598,special -Cricorps Grégoire,0.51267076,fineart -Celia Fiennes,0.51266706,digipa-med-impact -Raymond Swanland,0.41350424,fineart -Howard Knotts,0.5122062,digipa-med-impact -Helmut Federle,0.51201206,digipa-med-impact -Tyler Edlin,0.44028252,digipa-high-impact -Elwood H. Smith,0.5119027,digipa-med-impact -Ralph Horsley,0.51142794,fineart -Alexander Ivanov,0.4539051,digipa-low-impact -Cedric Peyravernay,0.4200587,digipa-low-impact -Annabel Eyres,0.51136214,digipa-med-impact -Zack Snyder,0.51129746,digipa-med-impact -Gentile Bellini,0.511102,digipa-med-impact -Giovanni Pelliccioli,0.4868688,digipa-med-impact -Fikret Muallâ Saygı,0.510694,digipa-med-impact -Bauhaus,0.43454266,digipa-low-impact -Charles Williams,0.510406,digipa-med-impact -Georg Arnold-Graboné,0.5103381,digipa-med-impact -Fedot Sychkov,0.47935224,digipa-med-impact -Alberto Magnelli,0.5103212,digipa-med-impact -Aloysius O'Kelly,0.5102891,digipa-med-impact -Alexander McQueen,0.5101986,digipa-med-impact -Cam Sykes,0.510071,digipa-med-impact -George Lucas,0.510038,digipa-med-impact -Eglon van der Neer,0.5099339,digipa-med-impact -Christian August Lorentzen,0.50989646,digipa-med-impact -Eleanor Best,0.50966686,digipa-med-impact -Terry Redlin,0.474244,fineart -Ken Kelly,0.4304738,fineart -David Eugene Henry,0.48173362,fineart -Shin Jeongho,0.5092497,fareast -Flora Borsi,0.5091922,digipa-med-impact -Berndnaut Smilde,0.50864,digipa-med-impact -Art of Brom,0.45828784,fineart -Ernő Tibor,0.50851977,digipa-med-impact -Ancell Stronach,0.5084514,digipa-med-impact -Helen Thomas Dranga,0.45412368,digipa-low-impact -Anita Malfatti,0.5080986,digipa-med-impact -Arnold Brügger,0.5080749,digipa-med-impact -Edward Ben Avram,0.50778764,digipa-med-impact -Antonio Ciseri,0.5073538,fineart -Alyssa Monks,0.50734174,digipa-med-impact -Chen Zhen,0.5071876,digipa-med-impact -Francis Helps,0.50707847,digipa-med-impact -Georg Karl Pfahler,0.50700235,digipa-med-impact -Henry Woods,0.506811,digipa-med-impact -Barbara Greg,0.50674164,digipa-med-impact -Guan Daosheng,0.506712,fareast -Guy Billout,0.5064906,digipa-med-impact -Basuki Abdullah,0.50613165,digipa-med-impact -Thomas Visscher,0.5059943,digipa-med-impact -Edward Simmons,0.50598735,digipa-med-impact -Arabella Rankin,0.50572735,digipa-med-impact -Lady Pink,0.5056634,digipa-high-impact -Christopher Williams,0.5052288,digipa-med-impact -Fuyuko Matsui,0.5051116,fareast -Edward Baird,0.5049874,digipa-med-impact -Georges Stein,0.5049069,digipa-med-impact -Alex Alemany,0.43974748,digipa-low-impact -Emanuel Schongut,0.5047326,digipa-med-impact -Hans Bol,0.5045265,digipa-med-impact -Kurzgesagt,0.5043725,digipa-med-impact -Harald Giersing,0.50410193,digipa-med-impact -Antonín Slavíček,0.5040368,fineart -Carl Rahl,0.5040115,digipa-med-impact -Etienne Delessert,0.5037818,fineart -Americo Makk,0.5034161,digipa-med-impact -Fernand Pelez,0.5027561,digipa-med-impact -Alexey Merinov,0.4469615,digipa-low-impact -Caspar Netscher,0.5019529,digipa-med-impact -Walt Disney,0.50178146,digipa-med-impact -Qian Xuan,0.50150526,fareast -Geoffrey Dyer,0.50120556,digipa-med-impact -Andre Norton,0.5007602,digipa-med-impact -Daphne McClure,0.5007391,digipa-med-impact -Dieric Bouts,0.5005882,fineart -Aguri Uchida,0.5005107,fareast -Hugo Scheiber,0.50004864,digipa-med-impact -Kenne Gregoire,0.46421963,digipa-low-impact -Wolfgang Tillmans,0.4999767,fineart -Carl-Henning Pedersen,0.4998986,digipa-med-impact -Alison Debenham,0.4998683,digipa-med-impact -Eppo Doeve,0.49975222,digipa-med-impact -Christen Købke,0.49961317,digipa-med-impact -Aron Demetz,0.49895018,digipa-med-impact -Alesso Baldovinetti,0.49849576,digipa-med-impact -Jimmy Lawlor,0.4475271,fineart -Carl Walter Liner,0.49826378,fineart -Gwenny Griffiths,0.45598924,digipa-low-impact -David Cooke Gibson,0.4976222,digipa-med-impact -Howard Butterworth,0.4974621,digipa-med-impact -Bob Thompson,0.49743804,fineart -Enguerrand Quarton,0.49711192,fineart -Abdel Hadi Al Gazzar,0.49631482,digipa-med-impact -Gu Zhengyi,0.49629828,digipa-med-impact -Aleksander Kotsis,0.4953621,digipa-med-impact -Alexander Sharpe Ross,0.49519226,digipa-med-impact -Carlos Enríquez Gómez,0.49494863,digipa-med-impact -Abed Abdi,0.4948855,digipa-med-impact -Elaine Duillo,0.49474388,digipa-med-impact -Anne Said,0.49473995,digipa-med-impact -Istvan Banyai,0.4947369,digipa-med-impact -Bouchta El Hayani,0.49455142,digipa-med-impact -Chinwe Chukwuogo-Roy,0.49445248,n -George Claessen,0.49412063,digipa-med-impact -Axel Törneman,0.49401706,digipa-med-impact -Avigdor Arikha,0.49384058,digipa-med-impact -Gloria Stoll Karn,0.4937976,digipa-med-impact -Alfredo Volpi,0.49367586,digipa-med-impact -Raffaello Sanizo,0.49365884,digipa-med-impact -Jeff Easley,0.49344411,digipa-med-impact -Aileen Eagleton,0.49318358,digipa-med-impact -Gaetano Sabatini,0.49307147,digipa-med-impact -Bertalan Pór,0.4930132,digipa-med-impact -Alfred Jensen,0.49291304,digipa-med-impact -Huang Guangjian,0.49286693,fareast -Emil Ferris,0.49282396,digipa-med-impact -Derek Chittock,0.492694,digipa-med-impact -Alonso Vázquez,0.49205148,digipa-med-impact -Kelly Sue Deconnick,0.4919476,digipa-med-impact -Clive Madgwick,0.4749857,fineart -Edward George Handel Lucas,0.49166748,digipa-med-impact -Dorothea Braby,0.49161923,digipa-med-impact -Sangyeob Park,0.49150884,fareast -Heinz Edelman,0.49140438,digipa-med-impact -Mark Seliger,0.4912073,digipa-med-impact -Camilo Egas,0.4586727,digipa-low-impact -Craig Mullins,0.49085408,fineart -Dong Kingman,0.49063343,digipa-med-impact -Douglas Robertson Bisset,0.49031347,digipa-med-impact -Blek Le Rat,0.49008566,digipa-med-impact -Anton Ažbe,0.48984748,fineart -Olafur Eliasson,0.48971075,digipa-med-impact -Elinor Proby Adams,0.48967826,digipa-med-impact -Cándido López,0.48915705,digipa-med-impact -D. Howard Hitchcock,0.48902267,digipa-med-impact -Cheng Jiasui,0.48889247,fareast -Jean Nouvel,0.4888183,digipa-med-impact -Bill Gekas,0.48848945,digipa-med-impact -Hermione Hammond,0.48845994,digipa-med-impact -Fernando Gerassi,0.48841453,digipa-med-impact -Frank Barrington Craig,0.4883762,digipa-med-impact -A. B. Jackson,0.4883623,digipa-med-impact -Bernie D’Andrea,0.48813275,digipa-med-impact -Clarice Beckett,0.487809,digipa-med-impact -Dosso Dossi,0.48775777,digipa-med-impact -Donald Roller Wilson,0.48767656,digipa-med-impact -Ernest William Christmas,0.4876317,digipa-med-impact -Aleksandr Gerasimov,0.48736423,digipa-med-impact -Edward Clark,0.48703307,digipa-med-impact -Georg Schrimpf,0.48697302,digipa-med-impact -John Wilhelm,0.48696536,digipa-med-impact -Aries Moross,0.4863676,digipa-med-impact -Bill Lewis,0.48635158,digipa-med-impact -Huang Ji,0.48611963,fareast -F. Scott Hess,0.43634564,fineart -Gao Qipei,0.4860631,fareast -Albert Tucker,0.4854299,digipa-med-impact -Barbara Balmer,0.48528513,fineart -Anne Ryan,0.48511976,digipa-med-impact -Helen Edwards,0.48484707,digipa-med-impact -Alexander Bogen,0.48421195,digipa-med-impact -David Annand,0.48418126,digipa-med-impact -Du Qiong,0.48414314,fareast -Fred Cress,0.4837878,digipa-med-impact -David B. Mattingly,0.48370445,digipa-med-impact -Hristofor Žefarović,0.4837008,digipa-med-impact -Wim Wenders,0.44484183,digipa-low-impact -Alexander Fedosav,0.48360944,digipa-med-impact -Anne Rigney,0.48357943,digipa-med-impact -Bertalan Karlovszky,0.48338628,digipa-med-impact -George Frederick Harris,0.4833259,fineart -Toshiharu Mizutani,0.48315164,fareast -David McClellan,0.39739317,digipa-low-impact -Eugeen Van Mieghem,0.48270774,digipa-med-impact -Alexei Harlamoff,0.48255378,digipa-med-impact -Jeff Legg,0.48249072,digipa-med-impact -Elizabeth Murray,0.48227608,digipa-med-impact -Hugo Heyrman,0.48213717,digipa-med-impact -Adrian Paul Allinson,0.48211843,digipa-med-impact -Altoon Sultan,0.4820177,digipa-med-impact -Alice Mason,0.48188528,fareast -Harriet Powers,0.48181778,digipa-med-impact -Aaron Bohrod,0.48175076,digipa-med-impact -Chris Saunders,0.41429797,digipa-low-impact -Clara Miller Burd,0.47797233,digipa-med-impact -David G. Sorensen,0.38101727,digipa-low-impact -Iwan Baan,0.4806739,digipa-med-impact -Anatoly Metlan,0.48020265,digipa-med-impact -Alfons von Czibulka,0.4801954,digipa-med-impact -Amedee Ozenfant,0.47950014,digipa-med-impact -Valerie Hegarty,0.47947168,digipa-med-impact -Hugo Anton Fisher,0.4793551,digipa-med-impact -Antonio Roybal,0.4792729,digipa-med-impact -Cui Zizhong,0.47902682,fareast -F Scott Hess,0.42582104,fineart -Julien Delval,0.47888556,digipa-med-impact -Marcin Jakubowski,0.4788583,digipa-med-impact -Anne Stokes,0.4786997,digipa-med-impact -David Palumbo,0.47632077,fineart -Hallsteinn Sigurðsson,0.47858906,digipa-med-impact -Mike Campau,0.47850558,digipa-med-impact -Giuseppe Avanzi,0.47846943,digipa-med-impact -Harry Morley,0.47836518,digipa-med-impact -Constance-Anne Parker,0.47832203,digipa-med-impact -Albert Keller,0.47825447,digipa-med-impact -Daniel Chodowiecki,0.47825167,digipa-med-impact -Alasdair Grant Taylor,0.47802624,digipa-med-impact -Maria Pascual Alberich,0.4779718,fineart -Rebeca Saray,0.41697127,digipa-low-impact -Ernő Bánk,0.47753686,digipa-med-impact -Shaddy Safadi,0.47724134,digipa-med-impact -André Castro,0.4771826,digipa-med-impact -Amiet Cuno,0.41975892,digipa-low-impact -Adi Granov,0.40670198,fineart -Allen Williams,0.47675848,digipa-med-impact -Anna Haifisch,0.47672725,digipa-med-impact -Clovis Trouille,0.47669724,digipa-med-impact -Jane Graverol,0.47655866,digipa-med-impact -Conroy Maddox,0.47645602,digipa-med-impact -Božidar Jakac,0.4763106,digipa-med-impact -George Morrison,0.47533786,digipa-med-impact -Douglas Bourgeois,0.47527707,digipa-med-impact -Cao Zhibai,0.47476804,fareast -Bradley Walker Tomlin,0.47462896,digipa-low-impact -Dave Dorman,0.46852386,fineart -Stevan Dohanos,0.47452107,fineart -John Howe,0.44144905,fineart -Fanny McIan,0.47406268,digipa-low-impact -Bholekar Srihari,0.47387534,digipa-low-impact -Giovanni Lanfranco,0.4737344,digipa-low-impact -Fred Marcellino,0.47346023,digipa-low-impact -Clyde Caldwell,0.47305286,fineart -Haukur Halldórsson,0.47275954,digipa-low-impact -Huang Gongwang,0.47269204,fareast -Brothers Grimm,0.47249007,digipa-low-impact -Ollie Hoff,0.47240657,digipa-low-impact -RHADS,0.4722166,digipa-low-impact -Constance Gordon-Cumming,0.47219282,digipa-low-impact -Anne Mccaffrey,0.4719924,digipa-low-impact -Henry Heerup,0.47190166,digipa-low-impact -Adrian Smith,0.4716923,digipa-high-impact -Harold Elliott,0.4714101,digipa-low-impact -Eric Peterson,0.47106332,digipa-low-impact -David Garner,0.47106326,digipa-low-impact -Edward Hicks,0.4708863,digipa-low-impact -Alfred Krupa,0.47052455,digipa-low-impact -Breyten Breytenbach,0.4699338,digipa-low-impact -Douglas Shuler,0.4695691,digipa-low-impact -Elaine Hamilton,0.46941522,digipa-low-impact -Kapwani Kiwanga,0.46917036,digipa-low-impact -Dan Scott,0.46897763,digipa-low-impact -Allan Brooks,0.46882123,digipa-low-impact -Ian Fairweather,0.46878594,digipa-low-impact -Arlington Nelson Lindenmuth,0.4683814,digipa-low-impact -Russell Ayto,0.4681503,digipa-low-impact -Allan Linder,0.46812692,digipa-low-impact -Bohumil Kubista,0.4679809,digipa-low-impact -Christopher Jin Baron,0.4677839,digipa-low-impact -Eero Snellman,0.46777654,digipa-low-impact -Christabel Dennison,0.4677633,digipa-low-impact -Amelia Peláez,0.46764764,digipa-low-impact -James Gurney,0.46740666,digipa-low-impact -Carles Delclaux Is,0.46734855,digipa-low-impact -George Papazov,0.42420334,digipa-low-impact -Mark Brooks,0.4672415,fineart -Anne Dunn,0.46722376,digipa-low-impact -Klaus Wittmann,0.4670704,fineart -Arvid Nyholm,0.46697336,digipa-low-impact -Georg Scholz,0.46674117,digipa-low-impact -David Spriggs,0.46671993,digipa-low-impact -Ernest Morgan,0.4665036,digipa-low-impact -Ella Guru,0.46619284,digipa-low-impact -Helen Berman,0.46614346,digipa-low-impact -Gen Paul,0.4658785,digipa-low-impact -Auseklis Ozols,0.46569023,digipa-low-impact -Amelia Robertson Hill,0.4654411,fineart -Jim Lee,0.46544096,digipa-low-impact -Anson Maddocks,0.46539295,digipa-low-impact -Chen Hong,0.46516004,fareast -Haddon Sundblom,0.46490777,digipa-low-impact -Eva Švankmajerová,0.46454152,digipa-low-impact -Antonio Cavallucci,0.4645282,digipa-low-impact -Herve Groussin,0.40050638,digipa-low-impact -Gwen Barnard,0.46400994,digipa-low-impact -Grace English,0.4638674,digipa-low-impact -Carl Critchlow,0.4636,digipa-low-impact -Ayshia Taşkın,0.463412,digipa-low-impact -Alison Watt,0.43141022,digipa-low-impact -Andre de Krayewski,0.4628024,digipa-low-impact -Hamish MacDonald,0.462645,digipa-low-impact -Ni Chuanjing,0.46254826,fareast -Frank Mason,0.46254665,digipa-low-impact -Steve Henderson,0.43113405,fineart -Eileen Aldridge,0.46210572,digipa-low-impact -Brad Rigney,0.28446302,digipa-low-impact -Ching Yeh,0.46177,fareast -Bertram Brooker,0.46176457,digipa-low-impact -Henry Bright,0.46150023,digipa-low-impact -Claire Dalby,0.46117848,digipa-low-impact -Brian Despain,0.41538632,digipa-low-impact -Anna Maria Barbara Abesch,0.4611045,digipa-low-impact -Bernardo Daddi,0.46088326,digipa-low-impact -Abraham Mintchine,0.46088243,digipa-high-impact -Alexander Carse,0.46078917,digipa-low-impact -Doc Hammer,0.46075988,digipa-low-impact -Yuumei,0.46072406,digipa-low-impact -Teophilus Tetteh,0.46064255,n -Bess Hamiti,0.46062252,digipa-low-impact -Ceferí Olivé,0.46058378,digipa-low-impact -Enrique Grau,0.46046937,digipa-low-impact -Eleanor Hughes,0.46007007,digipa-low-impact -Elizabeth Charleston,0.46001568,digipa-low-impact -Félix Ziem,0.45987016,digipa-low-impact -Eugeniusz Zak,0.45985222,digipa-low-impact -Dain Yoon,0.45977795,fareast -Gong Xian,0.4595083,digipa-low-impact -Flavia Blois,0.45950204,digipa-low-impact -Frederik Vermehren,0.45949826,digipa-low-impact -Gang Se-hwang,0.45937777,digipa-low-impact -Bjørn Wiinblad,0.45934483,digipa-low-impact -Alex Horley-Orlandelli,0.42623433,digipa-low-impact -Dr. Atl,0.459287,digipa-low-impact -Hu Jieqing,0.45889485,fareast -Amédée Ozenfant,0.4585215,digipa-low-impact -Warren Ellis,0.4584044,digipa-low-impact -Helen Dahm,0.45804346,digipa-low-impact -Anne Geddes,0.45785287,digipa-low-impact -Bikash Bhattacharjee,0.45775396,digipa-low-impact -Phil Foglio,0.457582,digipa-low-impact -Evelyn Abelson,0.4574563,digipa-low-impact -Alan Moore,0.4573369,digipa-low-impact -Josh Kao,0.45725146,fareast -Bertil Nilsson,0.45724383,digipa-low-impact -Hristofor Zhefarovich,0.457089,fineart -Edward Bailey,0.45659882,digipa-low-impact -Christopher Moeller,0.45648077,digipa-low-impact -Dóra Keresztes,0.4558745,fineart -Cory Arcangel,0.4558071,digipa-low-impact -Aleksander Kobzdej,0.45552525,digipa-low-impact -Tim Burton,0.45541722,digipa-high-impact -Chen Jiru,0.4553378,fareast -George Passantino,0.4552104,digipa-low-impact -Fuller Potter,0.4552072,digipa-low-impact -Warwick Globe,0.45516664,digipa-low-impact -Heinz Anger,0.45466962,digipa-low-impact -Elias Goldberg,0.45416242,digipa-low-impact -tokyogenso,0.45406622,fareast -Zeen Chin,0.45404464,digipa-low-impact -Albert Koetsier,0.45385844,fineart -Giuseppe Camuncoli,0.45377725,digipa-low-impact -Elsie Vera Cole,0.45377362,digipa-low-impact -Andreas Franke,0.4300047,digipa-low-impact -Constantine Andreou,0.4533816,digipa-low-impact -Elisabeth Collins,0.45337808,digipa-low-impact -Ted Nasmith,0.45302224,fineart -Antônio Parreiras,0.45269623,digipa-low-impact -Gwilym Prichard,0.45256525,digipa-low-impact -Fang Congyi,0.45240825,fareast -Huang Ding,0.45233482,fareast -Hans von Bartels,0.45200723,digipa-low-impact -Peter Elson,0.4121406,fineart -Fan Kuan,0.4513034,digipa-low-impact -Dean Roger,0.45112592,digipa-low-impact -Bernat Sanjuan,0.45074993,fareast -Fletcher Martin,0.45055175,digipa-low-impact -Gentile Tondino,0.45043385,digipa-low-impact -Ei-Q,0.45038772,digipa-low-impact -Chen Lin,0.45035738,fareast -Ted Wallace,0.4500007,digipa-low-impact -"Cornelisz Hendriksz Vroom, the Younger",0.4499252,digipa-low-impact -Alpo Jaakola,0.44981295,digipa-low-impact -Clark Voorhees,0.4495309,digipa-low-impact -Cleve Gray,0.449188,digipa-low-impact -Wolf Kahn,0.4489858,digipa-low-impact -Choi Buk,0.44892842,fareast -Frank Tinsley,0.4480373,digipa-low-impact -George Bell,0.44779524,digipa-low-impact -Fiona Stephenson,0.44761062,fineart -Carlos Trillo Name,0.4470371,digipa-low-impact -Jamie McKelvie,0.44696707,digipa-low-impact -Dennis Flanders,0.44673377,digipa-low-impact -Dulah Marie Evans,0.44662604,digipa-low-impact -Hans Schwarz,0.4463275,digipa-low-impact -Steve McCurry,0.44620228,digipa-low-impact -Bedwyr Williams,0.44616276,digipa-low-impact -Anton Graff,0.38569996,digipa-low-impact -Leticia Gillett,0.44578317,digipa-low-impact -Rafał Olbiński,0.44561762,digipa-low-impact -Artgerm,0.44555497,fineart -Adrienn Henczné Deák,0.445518,digipa-low-impact -Gu Hongzhong,0.4454906,fareast -Matt Groening,0.44518438,digipa-low-impact -Sue Bryce,0.4447164,digipa-low-impact -Armin Baumgarten,0.444061,digipa-low-impact -Araceli Gilbert,0.44399196,digipa-low-impact -Carey Morris,0.44388965,digipa-low-impact -Ignat Bednarik,0.4438085,digipa-low-impact -Frank Buchser,0.44373792,digipa-low-impact -Ben Zoeller,0.44368798,digipa-low-impact -Adam Szentpétery,0.4434548,fineart -Gene Davis,0.44343877,digipa-low-impact -Fei Danxu,0.4433627,fareast -Andrei Kolkoutine,0.44328922,digipa-low-impact -Bruce Onobrakpeya,0.42588046,n -Christoph Amberger,0.38912287,digipa-low-impact -"Fred Mitchell,",0.4432277,digipa-low-impact -Klaus Burgle,0.44295216,digipa-low-impact -Carl Hoppe,0.44270635,digipa-low-impact -Caroline Gotch,0.44263047,digipa-low-impact -Hans Mertens,0.44260004,digipa-low-impact -Mandy Disher,0.44219893,fineart -Sarah Lucas,0.4420507,digipa-low-impact -Sydney Edmunds,0.44198513,digipa-low-impact -Amos Ferguson,0.4418735,digipa-low-impact -Alton Tobey,0.4416385,digipa-low-impact -Clifford Ross,0.44139367,digipa-low-impact -Henric Trenk,0.4412782,digipa-low-impact -Claire Hummel,0.44119984,digipa-low-impact -Norman Foster,0.4411899,digipa-low-impact -Carmen Saldana,0.44076762,digipa-low-impact -Michael Whelan,0.4372847,digipa-low-impact -Carlos Berlanga,0.440354,digipa-low-impact -Gilles Beloeil,0.43997732,digipa-low-impact -Ashley Wood,0.4398396,digipa-low-impact -David Allan,0.43969798,digipa-low-impact -Mark Lovett,0.43922082,digipa-low-impact -Jed Henry,0.43882954,digipa-low-impact -Adam Bruce Thomson,0.43847767,digipa-low-impact -Horst Antes,0.4384303,digipa-low-impact -Fritz Glarner,0.43787453,digipa-low-impact -Harold McCauley,0.43760818,digipa-low-impact -Estuardo Maldonado,0.437594,digipa-low-impact -Dai Jin,0.4375449,fareast -Fabien Charuau,0.43688047,digipa-low-impact -Chica Macnab,0.4365166,digipa-low-impact -Jim Burns,0.3975072,digipa-low-impact -Santiago Calatrava,0.43651623,digipa-low-impact -Robert Maguire,0.40926617,digipa-low-impact -Cliff Childs,0.43611953,digipa-low-impact -Charles Martin,0.43582463,fareast -Elbridge Ayer Burbank,0.43572164,digipa-low-impact -Anita Kunz,0.4356005,digipa-low-impact -Colin Geller,0.43559563,digipa-low-impact -Allen Tupper True,0.43556124,digipa-low-impact -Jef Wu,0.43555313,digipa-low-impact -Jon McCoy,0.4147122,digipa-low-impact -Cedric Seaut,0.43521535,digipa-low-impact -Emily Shanks,0.43519047,digipa-low-impact -Andrew Whem,0.43512022,digipa-low-impact -Ibrahim Kodra,0.43471518,digipa-low-impact -Harrington Mann,0.4345901,digipa-low-impact -Jerry Siegel,0.43458986,digipa-low-impact -Howard Kanovitz,0.4345178,digipa-low-impact -Cicely Hey,0.43449926,digipa-low-impact -Ben Thompson,0.43436068,digipa-low-impact -Joe Bowler,0.43413073,digipa-low-impact -Lori Earley,0.43389612,digipa-low-impact -Arent Arentsz,0.43373522,digipa-low-impact -David Bailly,0.43371305,digipa-low-impact -Hans Arnold,0.4335214,digipa-low-impact -Constance Copeman,0.4334836,digipa-low-impact -Brent Heighton,0.4333118,fineart -Eric Taylor,0.43312082,digipa-low-impact -Aleksander Gine,0.4326849,digipa-low-impact -Alexander Johnston,0.4326589,digipa-low-impact -David Park,0.43235332,digipa-low-impact -Balázs Diószegi,0.432244,digipa-low-impact -Ed Binkley,0.43222216,digipa-low-impact -Eric Dinyer,0.4321258,digipa-low-impact -Susan Luo,0.43198025,fareast -Cedric Seaut (Keos Masons),0.4317356,digipa-low-impact -Lorena Alvarez Gómez,0.431683,digipa-low-impact -Fred Ludekens,0.431662,digipa-low-impact -David Begbie,0.4316218,digipa-low-impact -Ai Xuan,0.43150818,fareast -Felix-Kelly,0.43132153,digipa-low-impact -Antonín Chittussi,0.431248,digipa-low-impact -Ammi Phillips,0.43095884,digipa-low-impact -Elke Vogelsang,0.43092483,digipa-low-impact -Fathi Hassan,0.43090487,digipa-low-impact -Angela Sung,0.391746,fareast -Clément Serveau,0.43050706,digipa-low-impact -Dong Yuan,0.4303865,fareast -Hew Lorimer,0.43035403,digipa-low-impact -David Finch,0.29487437,digipa-low-impact -Bill Durgin,0.4300932,digipa-low-impact -Alexander Robertson,0.4300743,digipa-low-impact diff --git a/extensions-builtin/LDSR/ldsr_model_arch.py b/extensions-builtin/LDSR/ldsr_model_arch.py index 0ad49f4e..bc11cc6e 100644 --- a/extensions-builtin/LDSR/ldsr_model_arch.py +++ b/extensions-builtin/LDSR/ldsr_model_arch.py @@ -1,7 +1,6 @@ import os import gc import time -import warnings import numpy as np import torch @@ -15,8 +14,6 @@ from ldm.models.diffusion.ddim import DDIMSampler from ldm.util import instantiate_from_config, ismap from modules import shared, sd_hijack -warnings.filterwarnings("ignore", category=UserWarning) - cached_ldsr_model: torch.nn.Module = None diff --git a/extensions-builtin/Lora/extra_networks_lora.py b/extensions-builtin/Lora/extra_networks_lora.py new file mode 100644 index 00000000..8f2e753e --- /dev/null +++ b/extensions-builtin/Lora/extra_networks_lora.py @@ -0,0 +1,20 @@ +from modules import extra_networks +import lora + +class ExtraNetworkLora(extra_networks.ExtraNetwork): + def __init__(self): + super().__init__('lora') + + def activate(self, p, params_list): + names = [] + multipliers = [] + for params in params_list: + assert len(params.items) > 0 + + names.append(params.items[0]) + multipliers.append(float(params.items[1]) if len(params.items) > 1 else 1.0) + + lora.load_loras(names, multipliers) + + def deactivate(self, p): + pass diff --git a/extensions-builtin/Lora/lora.py b/extensions-builtin/Lora/lora.py new file mode 100644 index 00000000..da1797dc --- /dev/null +++ b/extensions-builtin/Lora/lora.py @@ -0,0 +1,199 @@ +import glob +import os +import re +import torch + +from modules import shared, devices, sd_models + +re_digits = re.compile(r"\d+") +re_unet_down_blocks = re.compile(r"lora_unet_down_blocks_(\d+)_attentions_(\d+)_(.+)") +re_unet_mid_blocks = re.compile(r"lora_unet_mid_block_attentions_(\d+)_(.+)") +re_unet_up_blocks = re.compile(r"lora_unet_up_blocks_(\d+)_attentions_(\d+)_(.+)") +re_text_block = re.compile(r"lora_te_text_model_encoder_layers_(\d+)_(.+)") + + +def convert_diffusers_name_to_compvis(key): + def match(match_list, regex): + r = re.match(regex, key) + if not r: + return False + + match_list.clear() + match_list.extend([int(x) if re.match(re_digits, x) else x for x in r.groups()]) + return True + + m = [] + + if match(m, re_unet_down_blocks): + return f"diffusion_model_input_blocks_{1 + m[0] * 3 + m[1]}_1_{m[2]}" + + if match(m, re_unet_mid_blocks): + return f"diffusion_model_middle_block_1_{m[1]}" + + if match(m, re_unet_up_blocks): + return f"diffusion_model_output_blocks_{m[0] * 3 + m[1]}_1_{m[2]}" + + if match(m, re_text_block): + return f"transformer_text_model_encoder_layers_{m[0]}_{m[1]}" + + return key + + +class LoraOnDisk: + def __init__(self, name, filename): + self.name = name + self.filename = filename + + +class LoraModule: + def __init__(self, name): + self.name = name + self.multiplier = 1.0 + self.modules = {} + self.mtime = None + + +class LoraUpDownModule: + def __init__(self): + self.up = None + self.down = None + + +def assign_lora_names_to_compvis_modules(sd_model): + lora_layer_mapping = {} + + for name, module in shared.sd_model.cond_stage_model.wrapped.named_modules(): + lora_name = name.replace(".", "_") + lora_layer_mapping[lora_name] = module + module.lora_layer_name = lora_name + + for name, module in shared.sd_model.model.named_modules(): + lora_name = name.replace(".", "_") + lora_layer_mapping[lora_name] = module + module.lora_layer_name = lora_name + + sd_model.lora_layer_mapping = lora_layer_mapping + + +def load_lora(name, filename): + lora = LoraModule(name) + lora.mtime = os.path.getmtime(filename) + + sd = sd_models.read_state_dict(filename) + + keys_failed_to_match = [] + + for key_diffusers, weight in sd.items(): + fullkey = convert_diffusers_name_to_compvis(key_diffusers) + key, lora_key = fullkey.split(".", 1) + + sd_module = shared.sd_model.lora_layer_mapping.get(key, None) + if sd_module is None: + keys_failed_to_match.append(key_diffusers) + continue + + if type(sd_module) == torch.nn.Linear: + module = torch.nn.Linear(weight.shape[1], weight.shape[0], bias=False) + elif type(sd_module) == torch.nn.Conv2d: + module = torch.nn.Conv2d(weight.shape[1], weight.shape[0], (1, 1), bias=False) + else: + assert False, f'Lora layer {key_diffusers} matched a layer with unsupported type: {type(sd_module).__name__}' + + with torch.no_grad(): + module.weight.copy_(weight) + + module.to(device=devices.device, dtype=devices.dtype) + + lora_module = lora.modules.get(key, None) + if lora_module is None: + lora_module = LoraUpDownModule() + lora.modules[key] = lora_module + + if lora_key == "lora_up.weight": + lora_module.up = module + elif lora_key == "lora_down.weight": + lora_module.down = module + else: + assert False, f'Bad Lora layer name: {key_diffusers} - must end in lora_up.weight or lora_down.weight' + + if len(keys_failed_to_match) > 0: + print(f"Failed to match keys when loading Lora {filename}: {keys_failed_to_match}") + + return lora + + +def load_loras(names, multipliers=None): + already_loaded = {} + + for lora in loaded_loras: + if lora.name in names: + already_loaded[lora.name] = lora + + loaded_loras.clear() + + loras_on_disk = [available_loras.get(name, None) for name in names] + if any([x is None for x in loras_on_disk]): + list_available_loras() + + loras_on_disk = [available_loras.get(name, None) for name in names] + + for i, name in enumerate(names): + lora = already_loaded.get(name, None) + + lora_on_disk = loras_on_disk[i] + if lora_on_disk is not None: + if lora is None or os.path.getmtime(lora_on_disk.filename) > lora.mtime: + lora = load_lora(name, lora_on_disk.filename) + + if lora is None: + print(f"Couldn't find Lora with name {name}") + continue + + lora.multiplier = multipliers[i] if multipliers else 1.0 + loaded_loras.append(lora) + + +def lora_forward(module, input, res): + if len(loaded_loras) == 0: + return res + + lora_layer_name = getattr(module, 'lora_layer_name', None) + for lora in loaded_loras: + module = lora.modules.get(lora_layer_name, None) + if module is not None: + res = res + module.up(module.down(input)) * lora.multiplier + + return res + + +def lora_Linear_forward(self, input): + return lora_forward(self, input, torch.nn.Linear_forward_before_lora(self, input)) + + +def lora_Conv2d_forward(self, input): + return lora_forward(self, input, torch.nn.Conv2d_forward_before_lora(self, input)) + + +def list_available_loras(): + available_loras.clear() + + os.makedirs(shared.cmd_opts.lora_dir, exist_ok=True) + + candidates = \ + glob.glob(os.path.join(shared.cmd_opts.lora_dir, '**/*.pt'), recursive=True) + \ + glob.glob(os.path.join(shared.cmd_opts.lora_dir, '**/*.safetensors'), recursive=True) + \ + glob.glob(os.path.join(shared.cmd_opts.lora_dir, '**/*.ckpt'), recursive=True) + + for filename in sorted(candidates): + if os.path.isdir(filename): + continue + + name = os.path.splitext(os.path.basename(filename))[0] + + available_loras[name] = LoraOnDisk(name, filename) + + +available_loras = {} +loaded_loras = [] + +list_available_loras() diff --git a/extensions-builtin/Lora/preload.py b/extensions-builtin/Lora/preload.py new file mode 100644 index 00000000..863dc5c0 --- /dev/null +++ b/extensions-builtin/Lora/preload.py @@ -0,0 +1,6 @@ +import os +from modules import paths + + +def preload(parser): + parser.add_argument("--lora-dir", type=str, help="Path to directory with Lora networks.", default=os.path.join(paths.models_path, 'Lora')) diff --git a/extensions-builtin/Lora/scripts/lora_script.py b/extensions-builtin/Lora/scripts/lora_script.py new file mode 100644 index 00000000..60b9eb64 --- /dev/null +++ b/extensions-builtin/Lora/scripts/lora_script.py @@ -0,0 +1,30 @@ +import torch + +import lora +import extra_networks_lora +import ui_extra_networks_lora +from modules import script_callbacks, ui_extra_networks, extra_networks + + +def unload(): + torch.nn.Linear.forward = torch.nn.Linear_forward_before_lora + torch.nn.Conv2d.forward = torch.nn.Conv2d_forward_before_lora + + +def before_ui(): + ui_extra_networks.register_page(ui_extra_networks_lora.ExtraNetworksPageLora()) + extra_networks.register_extra_network(extra_networks_lora.ExtraNetworkLora()) + + +if not hasattr(torch.nn, 'Linear_forward_before_lora'): + torch.nn.Linear_forward_before_lora = torch.nn.Linear.forward + +if not hasattr(torch.nn, 'Conv2d_forward_before_lora'): + torch.nn.Conv2d_forward_before_lora = torch.nn.Conv2d.forward + +torch.nn.Linear.forward = lora.lora_Linear_forward +torch.nn.Conv2d.forward = lora.lora_Conv2d_forward + +script_callbacks.on_model_loaded(lora.assign_lora_names_to_compvis_modules) +script_callbacks.on_script_unloaded(unload) +script_callbacks.on_before_ui(before_ui) diff --git a/extensions-builtin/Lora/ui_extra_networks_lora.py b/extensions-builtin/Lora/ui_extra_networks_lora.py new file mode 100644 index 00000000..54a80d36 --- /dev/null +++ b/extensions-builtin/Lora/ui_extra_networks_lora.py @@ -0,0 +1,36 @@ +import json +import os +import lora + +from modules import shared, ui_extra_networks + + +class ExtraNetworksPageLora(ui_extra_networks.ExtraNetworksPage): + def __init__(self): + super().__init__('Lora') + + def refresh(self): + lora.list_available_loras() + + def list_items(self): + for name, lora_on_disk in lora.available_loras.items(): + path, ext = os.path.splitext(lora_on_disk.filename) + previews = [path + ".png", path + ".preview.png"] + + preview = None + for file in previews: + if os.path.isfile(file): + preview = "./file=" + file.replace('\\', '/') + "?mtime=" + str(os.path.getmtime(file)) + break + + yield { + "name": name, + "filename": path, + "preview": preview, + "prompt": json.dumps(f""), + "local_preview": path + ".png", + } + + def allowed_directories_for_previews(self): + return [shared.cmd_opts.lora_dir] + diff --git a/extensions-builtin/prompt-bracket-checker/javascript/prompt-bracket-checker.js b/extensions-builtin/prompt-bracket-checker/javascript/prompt-bracket-checker.js index eccfb0f9..4a85c8eb 100644 --- a/extensions-builtin/prompt-bracket-checker/javascript/prompt-bracket-checker.js +++ b/extensions-builtin/prompt-bracket-checker/javascript/prompt-bracket-checker.js @@ -4,16 +4,10 @@ // Counts open and closed brackets (round, square, curly) in the prompt and negative prompt text boxes in the txt2img and img2img tabs. // If there's a mismatch, the keyword counter turns red and if you hover on it, a tooltip tells you what's wrong. -function checkBrackets(evt) { - textArea = evt.target; - tabName = evt.target.parentElement.parentElement.id.split("_")[0]; - counterElt = document.querySelector('gradio-app').shadowRoot.querySelector('#' + tabName + '_token_counter'); - - promptName = evt.target.parentElement.parentElement.id.includes('neg') ? ' negative' : ''; - - errorStringParen = '(' + tabName + promptName + ' prompt) - Different number of opening and closing parentheses detected.\n'; - errorStringSquare = '[' + tabName + promptName + ' prompt] - Different number of opening and closing square brackets detected.\n'; - errorStringCurly = '{' + tabName + promptName + ' prompt} - Different number of opening and closing curly brackets detected.\n'; +function checkBrackets(evt, textArea, counterElt) { + errorStringParen = '(...) - Different number of opening and closing parentheses detected.\n'; + errorStringSquare = '[...] - Different number of opening and closing square brackets detected.\n'; + errorStringCurly = '{...} - Different number of opening and closing curly brackets detected.\n'; openBracketRegExp = /\(/g; closeBracketRegExp = /\)/g; @@ -86,22 +80,31 @@ function checkBrackets(evt) { } if(counterElt.title != '') { - counterElt.style = 'color: #FF5555;'; + counterElt.classList.add('error'); } else { - counterElt.style = ''; + counterElt.classList.remove('error'); } } +function setupBracketChecking(id_prompt, id_counter){ + var textarea = gradioApp().querySelector("#" + id_prompt + " > label > textarea"); + var counter = gradioApp().getElementById(id_counter) + textarea.addEventListener("input", function(evt){ + checkBrackets(evt, textarea, counter) + }); +} + var shadowRootLoaded = setInterval(function() { - var shadowTextArea = document.querySelector('gradio-app').shadowRoot.querySelectorAll('#txt2img_prompt > label > textarea'); - if(shadowTextArea.length < 1) { - return false; - } + var shadowRoot = document.querySelector('gradio-app').shadowRoot; + if(! shadowRoot) return false; - clearInterval(shadowRootLoaded); + var shadowTextArea = shadowRoot.querySelectorAll('#txt2img_prompt > label > textarea'); + if(shadowTextArea.length < 1) return false; - document.querySelector('gradio-app').shadowRoot.querySelector('#txt2img_prompt').onkeyup = checkBrackets; - document.querySelector('gradio-app').shadowRoot.querySelector('#txt2img_neg_prompt').onkeyup = checkBrackets; - document.querySelector('gradio-app').shadowRoot.querySelector('#img2img_prompt').onkeyup = checkBrackets; - document.querySelector('gradio-app').shadowRoot.querySelector('#img2img_neg_prompt').onkeyup = checkBrackets; + clearInterval(shadowRootLoaded); + + setupBracketChecking('txt2img_prompt', 'txt2img_token_counter') + setupBracketChecking('txt2img_neg_prompt', 'txt2img_negative_token_counter') + setupBracketChecking('img2img_prompt', 'imgimg_token_counter') + setupBracketChecking('img2img_neg_prompt', 'img2img_negative_token_counter') }, 1000); diff --git a/extensions-builtin/roll-artist/scripts/roll-artist.py b/extensions-builtin/roll-artist/scripts/roll-artist.py deleted file mode 100644 index c3bc1fd0..00000000 --- a/extensions-builtin/roll-artist/scripts/roll-artist.py +++ /dev/null @@ -1,50 +0,0 @@ -import random - -from modules import script_callbacks, shared -import gradio as gr - -art_symbol = '\U0001f3a8' # 🎨 -global_prompt = None -related_ids = {"txt2img_prompt", "txt2img_clear_prompt", "img2img_prompt", "img2img_clear_prompt" } - - -def roll_artist(prompt): - allowed_cats = set([x for x in shared.artist_db.categories() if len(shared.opts.random_artist_categories)==0 or x in shared.opts.random_artist_categories]) - artist = random.choice([x for x in shared.artist_db.artists if x.category in allowed_cats]) - - return prompt + ", " + artist.name if prompt != '' else artist.name - - -def add_roll_button(prompt): - roll = gr.Button(value=art_symbol, elem_id="roll", visible=len(shared.artist_db.artists) > 0) - - roll.click( - fn=roll_artist, - _js="update_txt2img_tokens", - inputs=[ - prompt, - ], - outputs=[ - prompt, - ] - ) - - -def after_component(component, **kwargs): - global global_prompt - - elem_id = kwargs.get('elem_id', None) - if elem_id not in related_ids: - return - - if elem_id == "txt2img_prompt": - global_prompt = component - elif elem_id == "txt2img_clear_prompt": - add_roll_button(global_prompt) - elif elem_id == "img2img_prompt": - global_prompt = component - elif elem_id == "img2img_clear_prompt": - add_roll_button(global_prompt) - - -script_callbacks.on_after_component(after_component) diff --git a/html/card-no-preview.png b/html/card-no-preview.png new file mode 100644 index 00000000..e2beb269 Binary files /dev/null and b/html/card-no-preview.png differ diff --git a/html/extra-networks-card.html b/html/extra-networks-card.html new file mode 100644 index 00000000..1bdf1d27 --- /dev/null +++ b/html/extra-networks-card.html @@ -0,0 +1,11 @@ +
+
+
+ +
+ {name} +
+
+ diff --git a/html/extra-networks-no-cards.html b/html/extra-networks-no-cards.html new file mode 100644 index 00000000..389358d6 --- /dev/null +++ b/html/extra-networks-no-cards.html @@ -0,0 +1,8 @@ +
+

Nothing here. Add some content to the following directories:

+ +
    +{dirs} +
+
+ diff --git a/javascript/aspectRatioOverlay.js b/javascript/aspectRatioOverlay.js index 66f26a22..0f164b82 100644 --- a/javascript/aspectRatioOverlay.js +++ b/javascript/aspectRatioOverlay.js @@ -21,11 +21,16 @@ function dimensionChange(e, is_width, is_height){ var targetElement = null; var tabIndex = get_tab_index('mode_img2img') - if(tabIndex == 0){ + if(tabIndex == 0){ // img2img targetElement = gradioApp().querySelector('div[data-testid=image] img'); - } else if(tabIndex == 1){ + } else if(tabIndex == 1){ //Sketch + targetElement = gradioApp().querySelector('#img2img_sketch div[data-testid=image] img'); + } else if(tabIndex == 2){ // Inpaint targetElement = gradioApp().querySelector('#img2maskimg div[data-testid=image] img'); + } else if(tabIndex == 3){ // Inpaint sketch + targetElement = gradioApp().querySelector('#inpaint_sketch div[data-testid=image] img'); } + if(targetElement){ diff --git a/javascript/edit-attention.js b/javascript/edit-attention.js index b947cbec..619bb1fa 100644 --- a/javascript/edit-attention.js +++ b/javascript/edit-attention.js @@ -1,75 +1,96 @@ -addEventListener('keydown', (event) => { +function keyupEditAttention(event){ let target = event.originalTarget || event.composedPath()[0]; - if (!target.matches("#toprow textarea.gr-text-input[placeholder]")) return; + if (!target.matches("[id*='_toprow'] textarea.gr-text-input[placeholder]")) return; if (! (event.metaKey || event.ctrlKey)) return; - - let plus = "ArrowUp" - let minus = "ArrowDown" - if (event.key != plus && event.key != minus) return; + let isPlus = event.key == "ArrowUp" + let isMinus = event.key == "ArrowDown" + if (!isPlus && !isMinus) return; let selectionStart = target.selectionStart; let selectionEnd = target.selectionEnd; - // If the user hasn't selected anything, let's select their current parenthesis block - if (selectionStart === selectionEnd) { + let text = target.value; + + function selectCurrentParenthesisBlock(OPEN, CLOSE){ + if (selectionStart !== selectionEnd) return false; + // Find opening parenthesis around current cursor - const before = target.value.substring(0, selectionStart); - let beforeParen = before.lastIndexOf("("); - if (beforeParen == -1) return; - let beforeParenClose = before.lastIndexOf(")"); + const before = text.substring(0, selectionStart); + let beforeParen = before.lastIndexOf(OPEN); + if (beforeParen == -1) return false; + let beforeParenClose = before.lastIndexOf(CLOSE); while (beforeParenClose !== -1 && beforeParenClose > beforeParen) { - beforeParen = before.lastIndexOf("(", beforeParen - 1); - beforeParenClose = before.lastIndexOf(")", beforeParenClose - 1); + beforeParen = before.lastIndexOf(OPEN, beforeParen - 1); + beforeParenClose = before.lastIndexOf(CLOSE, beforeParenClose - 1); } // Find closing parenthesis around current cursor - const after = target.value.substring(selectionStart); - let afterParen = after.indexOf(")"); - if (afterParen == -1) return; - let afterParenOpen = after.indexOf("("); + const after = text.substring(selectionStart); + let afterParen = after.indexOf(CLOSE); + if (afterParen == -1) return false; + let afterParenOpen = after.indexOf(OPEN); while (afterParenOpen !== -1 && afterParen > afterParenOpen) { - afterParen = after.indexOf(")", afterParen + 1); - afterParenOpen = after.indexOf("(", afterParenOpen + 1); + afterParen = after.indexOf(CLOSE, afterParen + 1); + afterParenOpen = after.indexOf(OPEN, afterParenOpen + 1); } - if (beforeParen === -1 || afterParen === -1) return; + if (beforeParen === -1 || afterParen === -1) return false; // Set the selection to the text between the parenthesis - const parenContent = target.value.substring(beforeParen + 1, selectionStart + afterParen); + const parenContent = text.substring(beforeParen + 1, selectionStart + afterParen); const lastColon = parenContent.lastIndexOf(":"); selectionStart = beforeParen + 1; selectionEnd = selectionStart + lastColon; target.setSelectionRange(selectionStart, selectionEnd); - } + return true; + } + + // If the user hasn't selected anything, let's select their current parenthesis block + if(! selectCurrentParenthesisBlock('<', '>')){ + selectCurrentParenthesisBlock('(', ')') + } event.preventDefault(); - if (selectionStart == 0 || target.value[selectionStart - 1] != "(") { - target.value = target.value.slice(0, selectionStart) + - "(" + target.value.slice(selectionStart, selectionEnd) + ":1.0)" + - target.value.slice(selectionEnd); + closeCharacter = ')' + delta = opts.keyedit_precision_attention - target.focus(); - target.selectionStart = selectionStart + 1; - target.selectionEnd = selectionEnd + 1; + if (selectionStart > 0 && text[selectionStart - 1] == '<'){ + closeCharacter = '>' + delta = opts.keyedit_precision_extra + } else if (selectionStart == 0 || text[selectionStart - 1] != "(") { - } else { - end = target.value.slice(selectionEnd + 1).indexOf(")") + 1; - weight = parseFloat(target.value.slice(selectionEnd + 1, selectionEnd + 1 + end)); - if (isNaN(weight)) return; - if (event.key == minus) weight -= 0.1; - if (event.key == plus) weight += 0.1; + // do not include spaces at the end + while(selectionEnd > selectionStart && text[selectionEnd-1] == ' '){ + selectionEnd -= 1; + } + if(selectionStart == selectionEnd){ + return + } - weight = parseFloat(weight.toPrecision(12)); + text = text.slice(0, selectionStart) + "(" + text.slice(selectionStart, selectionEnd) + ":1.0)" + text.slice(selectionEnd); - target.value = target.value.slice(0, selectionEnd + 1) + - weight + - target.value.slice(selectionEnd + 1 + end - 1); + selectionStart += 1; + selectionEnd += 1; + } - target.focus(); - target.selectionStart = selectionStart; - target.selectionEnd = selectionEnd; - } - // Since we've modified a Gradio Textbox component manually, we need to simulate an `input` DOM event to ensure its - // internal Svelte data binding remains in sync. - target.dispatchEvent(new Event("input", { bubbles: true })); -}); + end = text.slice(selectionEnd + 1).indexOf(closeCharacter) + 1; + weight = parseFloat(text.slice(selectionEnd + 1, selectionEnd + 1 + end)); + if (isNaN(weight)) return; + + weight += isPlus ? delta : -delta; + weight = parseFloat(weight.toPrecision(12)); + if(String(weight).length == 1) weight += ".0" + + text = text.slice(0, selectionEnd + 1) + weight + text.slice(selectionEnd + 1 + end - 1); + + target.focus(); + target.value = text; + target.selectionStart = selectionStart; + target.selectionEnd = selectionEnd; + + updateInput(target) +} + +addEventListener('keydown', (event) => { + keyupEditAttention(event); +}); \ No newline at end of file diff --git a/javascript/extensions.js b/javascript/extensions.js index 59179ca6..ac6e35b9 100644 --- a/javascript/extensions.js +++ b/javascript/extensions.js @@ -29,7 +29,7 @@ function install_extension_from_index(button, url){ textarea = gradioApp().querySelector('#extension_to_install textarea') textarea.value = url - textarea.dispatchEvent(new Event("input", { bubbles: true })) + updateInput(textarea) gradioApp().querySelector('#install_extension_button').click() } diff --git a/javascript/extraNetworks.js b/javascript/extraNetworks.js new file mode 100644 index 00000000..c5a9adb3 --- /dev/null +++ b/javascript/extraNetworks.js @@ -0,0 +1,69 @@ + +function setupExtraNetworksForTab(tabname){ + gradioApp().querySelector('#'+tabname+'_extra_tabs').classList.add('extra-networks') + + var tabs = gradioApp().querySelector('#'+tabname+'_extra_tabs > div') + var search = gradioApp().querySelector('#'+tabname+'_extra_search textarea') + var refresh = gradioApp().getElementById(tabname+'_extra_refresh') + var close = gradioApp().getElementById(tabname+'_extra_close') + + search.classList.add('search') + tabs.appendChild(search) + tabs.appendChild(refresh) + tabs.appendChild(close) + + search.addEventListener("input", function(evt){ + searchTerm = search.value.toLowerCase() + + gradioApp().querySelectorAll('#'+tabname+'_extra_tabs div.card').forEach(function(elem){ + text = elem.querySelector('.name').textContent.toLowerCase() + elem.style.display = text.indexOf(searchTerm) == -1 ? "none" : "" + }) + }); +} + +var activePromptTextarea = {}; + +function setupExtraNetworks(){ + setupExtraNetworksForTab('txt2img') + setupExtraNetworksForTab('img2img') + + function registerPrompt(tabname, id){ + var textarea = gradioApp().querySelector("#" + id + " > label > textarea"); + + if (! activePromptTextarea[tabname]){ + activePromptTextarea[tabname] = textarea + } + + textarea.addEventListener("focus", function(){ + activePromptTextarea[tabname] = textarea; + }); + } + + registerPrompt('txt2img', 'txt2img_prompt') + registerPrompt('txt2img', 'txt2img_neg_prompt') + registerPrompt('img2img', 'img2img_prompt') + registerPrompt('img2img', 'img2img_neg_prompt') +} + +onUiLoaded(setupExtraNetworks) + +function cardClicked(tabname, textToAdd, allowNegativePrompt){ + var textarea = allowNegativePrompt ? activePromptTextarea[tabname] : gradioApp().querySelector("#" + tabname + "_prompt > label > textarea") + + textarea.value = textarea.value + " " + textToAdd + updateInput(textarea) +} + +function saveCardPreview(event, tabname, filename){ + var textarea = gradioApp().querySelector("#" + tabname + '_preview_filename > label > textarea') + var button = gradioApp().getElementById(tabname + '_save_preview') + + textarea.value = filename + updateInput(textarea) + + button.click() + + event.stopPropagation() + event.preventDefault() +} diff --git a/javascript/hints.js b/javascript/hints.js index 244bfde2..3cf10e20 100644 --- a/javascript/hints.js +++ b/javascript/hints.js @@ -14,12 +14,14 @@ titles = { "Seed": "A value that determines the output of random number generator - if you create an image with same parameters and seed as another image, you'll get the same result", "\u{1f3b2}\ufe0f": "Set seed to -1, which will cause a new random number to be used every time", "\u267b\ufe0f": "Reuse seed from last generation, mostly useful if it was randomed", - "\u{1f3a8}": "Add a random artist to the prompt.", "\u2199\ufe0f": "Read generation parameters from prompt or last generation if prompt is empty into user interface.", "\u{1f4c2}": "Open images output directory", "\u{1f4be}": "Save style", "\U0001F5D1": "Clear prompt", "\u{1f4cb}": "Apply selected styles to current prompt", + "\u{1f4d2}": "Paste available values into the field", + "\u{1f3b4}": "Show extra networks", + "Inpaint a part of image": "Draw a mask over an image, and the script will regenerate the masked area with content according to prompt", "SD upscale": "Upscale image normally, split result into tiles, improve each tile using img2img, merge whole image back", @@ -91,6 +93,7 @@ titles = { "Weighted sum": "Result = A * (1 - M) + B * M", "Add difference": "Result = A + (B - C) * M", + "No interpolation": "Result = A", "Initialization text": "If the number of tokens is more than the number of vectors, some may be skipped.\nLeave the textbox empty to start with zeroed out vectors", "Learning rate": "How fast should training go. Low values will take longer to train, high values may fail to converge (not generate accurate results) and/or may break the embedding (This has happened if you see Loss: nan in the training info textbox. If this happens, you need to manually restore your embedding from an older not-broken backup).\n\nYou can set a single numeric value, or multiple learning rates using the syntax:\n\n rate_1:max_steps_1, rate_2:max_steps_2, ...\n\nEG: 0.005:100, 1e-3:1000, 1e-5\n\nWill train with rate of 0.005 for first 100 steps, then 1e-3 until 1000 steps, then 1e-5 for all remaining steps.", @@ -104,7 +107,10 @@ titles = { "Hires steps": "Number of sampling steps for upscaled picture. If 0, uses same as for original.", "Upscale by": "Adjusts the size of the image by multiplying the original width and height by the selected value. Ignored if either Resize width to or Resize height to are non-zero.", "Resize width to": "Resizes image to this width. If 0, width is inferred from either of two nearby sliders.", - "Resize height to": "Resizes image to this height. If 0, height is inferred from either of two nearby sliders." + "Resize height to": "Resizes image to this height. If 0, height is inferred from either of two nearby sliders.", + "Multiplier for extra networks": "When adding extra network such as Hypernetwork or Lora to prompt, use this multiplier for it.", + "Discard weights with matching name": "Regular expression; if weights's name matches it, the weights is not written to the resulting checkpoint. Use ^model_ema to discard EMA weights.", + "Extra networks tab order": "Comma-separated list of tab names; tabs listed here will appear in the extra networks UI first and in order lsited." } diff --git a/javascript/hires_fix.js b/javascript/hires_fix.js index 07fba549..0629475f 100644 --- a/javascript/hires_fix.js +++ b/javascript/hires_fix.js @@ -1,6 +1,5 @@ function setInactive(elem, inactive){ - console.log(elem) if(inactive){ elem.classList.add('inactive') } else{ @@ -9,8 +8,6 @@ function setInactive(elem, inactive){ } function onCalcResolutionHires(enable, width, height, hr_scale, hr_resize_x, hr_resize_y){ - console.log(enable, width, height, hr_scale, hr_resize_x, hr_resize_y) - hrUpscaleBy = gradioApp().getElementById('txt2img_hr_scale') hrResizeX = gradioApp().getElementById('txt2img_hr_resize_x') hrResizeY = gradioApp().getElementById('txt2img_hr_resize_y') diff --git a/javascript/imageviewer.js b/javascript/imageviewer.js index 1f29ad7b..aac2ee82 100644 --- a/javascript/imageviewer.js +++ b/javascript/imageviewer.js @@ -148,7 +148,15 @@ function showGalleryImage() { if(e && e.parentElement.tagName == 'DIV'){ e.style.cursor='pointer' e.style.userSelect='none' - e.addEventListener('mousedown', function (evt) { + + var isFirefox = isFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1 + + // For Firefox, listening on click first switched to next image then shows the lightbox. + // If you know how to fix this without switching to mousedown event, please. + // For other browsers the event is click to make it possiblr to drag picture. + var event = isFirefox ? 'mousedown' : 'click' + + e.addEventListener(event, function (evt) { if(!opts.js_modal_lightbox || evt.button != 0) return; modalZoomSet(gradioApp().getElementById('modalImage'), opts.js_modal_lightbox_initially_zoomed) evt.preventDefault() diff --git a/javascript/localization.js b/javascript/localization.js index f92d2d24..1a5a1dbb 100644 --- a/javascript/localization.js +++ b/javascript/localization.js @@ -10,10 +10,8 @@ ignore_ids_for_localization={ modelmerger_tertiary_model_name: 'OPTION', train_embedding: 'OPTION', train_hypernetwork: 'OPTION', - txt2img_style_index: 'OPTION', - txt2img_style2_index: 'OPTION', - img2img_style_index: 'OPTION', - img2img_style2_index: 'OPTION', + txt2img_styles: 'OPTION', + img2img_styles: 'OPTION', setting_random_artist_categories: 'SPAN', setting_face_restoration_model: 'SPAN', setting_realesrgan_enabled_models: 'SPAN', diff --git a/javascript/progressbar.js b/javascript/progressbar.js index d6323ed9..ff6d757b 100644 --- a/javascript/progressbar.js +++ b/javascript/progressbar.js @@ -1,82 +1,25 @@ // code related to showing and updating progressbar shown as the image is being made -global_progressbars = {} + + galleries = {} +storedGallerySelections = {} galleryObservers = {} -// this tracks launches of window.setTimeout for progressbar to prevent starting a new timeout when the previous is still running -timeoutIds = {} - -function check_progressbar(id_part, id_progressbar, id_progressbar_span, id_skip, id_interrupt, id_preview, id_gallery){ - // gradio 3.8's enlightened approach allows them to create two nested div elements inside each other with same id - // every time you use gr.HTML(elem_id='xxx'), so we handle this here - var progressbar = gradioApp().querySelector("#"+id_progressbar+" #"+id_progressbar) - var progressbarParent - if(progressbar){ - progressbarParent = gradioApp().querySelector("#"+id_progressbar) - } else{ - progressbar = gradioApp().getElementById(id_progressbar) - progressbarParent = null - } - - var skip = id_skip ? gradioApp().getElementById(id_skip) : null - var interrupt = gradioApp().getElementById(id_interrupt) - - if(opts.show_progress_in_title && progressbar && progressbar.offsetParent){ - if(progressbar.innerText){ - let newtitle = '[' + progressbar.innerText.trim() + '] Stable Diffusion'; - if(document.title != newtitle){ - document.title = newtitle; - } - }else{ - let newtitle = 'Stable Diffusion' - if(document.title != newtitle){ - document.title = newtitle; - } - } - } - - if(progressbar!= null && progressbar != global_progressbars[id_progressbar]){ - global_progressbars[id_progressbar] = progressbar - - var mutationObserver = new MutationObserver(function(m){ - if(timeoutIds[id_part]) return; - - preview = gradioApp().getElementById(id_preview) - gallery = gradioApp().getElementById(id_gallery) - - if(preview != null && gallery != null){ - preview.style.width = gallery.clientWidth + "px" - preview.style.height = gallery.clientHeight + "px" - if(progressbarParent) progressbar.style.width = progressbarParent.clientWidth + "px" - - //only watch gallery if there is a generation process going on - check_gallery(id_gallery); - - var progressDiv = gradioApp().querySelectorAll('#' + id_progressbar_span).length > 0; - if(progressDiv){ - timeoutIds[id_part] = window.setTimeout(function() { - timeoutIds[id_part] = null - requestMoreProgress(id_part, id_progressbar_span, id_skip, id_interrupt) - }, 500) - } else{ - if (skip) { - skip.style.display = "none" - } - interrupt.style.display = "none" - - //disconnect observer once generation finished, so user can close selected image if they want - if (galleryObservers[id_gallery]) { - galleryObservers[id_gallery].disconnect(); - galleries[id_gallery] = null; - } - } - } - - }); - mutationObserver.observe( progressbar, { childList:true, subtree:true }) - } +function rememberGallerySelection(id_gallery){ + storedGallerySelections[id_gallery] = getGallerySelectedIndex(id_gallery) } +function getGallerySelectedIndex(id_gallery){ + let galleryButtons = gradioApp().querySelectorAll('#'+id_gallery+' .gallery-item') + let galleryBtnSelected = gradioApp().querySelector('#'+id_gallery+' .gallery-item.\\!ring-2') + + let currentlySelectedIndex = -1 + galleryButtons.forEach(function(v, i){ if(v==galleryBtnSelected) { currentlySelectedIndex = i } }) + + return currentlySelectedIndex +} + +// this is a workaround for https://github.com/gradio-app/gradio/issues/2984 function check_gallery(id_gallery){ let gallery = gradioApp().getElementById(id_gallery) // if gallery has no change, no need to setting up observer again. @@ -85,10 +28,16 @@ function check_gallery(id_gallery){ if(galleryObservers[id_gallery]){ galleryObservers[id_gallery].disconnect(); } - let prevSelectedIndex = selected_gallery_index(); + + storedGallerySelections[id_gallery] = -1 + galleryObservers[id_gallery] = new MutationObserver(function (){ let galleryButtons = gradioApp().querySelectorAll('#'+id_gallery+' .gallery-item') let galleryBtnSelected = gradioApp().querySelector('#'+id_gallery+' .gallery-item.\\!ring-2') + let currentlySelectedIndex = getGallerySelectedIndex(id_gallery) + prevSelectedIndex = storedGallerySelections[id_gallery] + storedGallerySelections[id_gallery] = -1 + if (prevSelectedIndex !== -1 && galleryButtons.length>prevSelectedIndex && !galleryBtnSelected) { // automatically re-open previously selected index (if exists) activeElement = gradioApp().activeElement; @@ -120,30 +69,175 @@ function check_gallery(id_gallery){ } onUiUpdate(function(){ - check_progressbar('txt2img', 'txt2img_progressbar', 'txt2img_progress_span', 'txt2img_skip', 'txt2img_interrupt', 'txt2img_preview', 'txt2img_gallery') - check_progressbar('img2img', 'img2img_progressbar', 'img2img_progress_span', 'img2img_skip', 'img2img_interrupt', 'img2img_preview', 'img2img_gallery') - check_progressbar('ti', 'ti_progressbar', 'ti_progress_span', '', 'ti_interrupt', 'ti_preview', 'ti_gallery') + check_gallery('txt2img_gallery') + check_gallery('img2img_gallery') }) -function requestMoreProgress(id_part, id_progressbar_span, id_skip, id_interrupt){ - btn = gradioApp().getElementById(id_part+"_check_progress"); - if(btn==null) return; - - btn.click(); - var progressDiv = gradioApp().querySelectorAll('#' + id_progressbar_span).length > 0; - var skip = id_skip ? gradioApp().getElementById(id_skip) : null - var interrupt = gradioApp().getElementById(id_interrupt) - if(progressDiv && interrupt){ - if (skip) { - skip.style.display = "block" +function request(url, data, handler, errorHandler){ + var xhr = new XMLHttpRequest(); + var url = url; + xhr.open("POST", url, true); + xhr.setRequestHeader("Content-Type", "application/json"); + xhr.onreadystatechange = function () { + if (xhr.readyState === 4) { + if (xhr.status === 200) { + try { + var js = JSON.parse(xhr.responseText); + handler(js) + } catch (error) { + console.error(error); + errorHandler() + } + } else{ + errorHandler() + } } - interrupt.style.display = "block" + }; + var js = JSON.stringify(data); + xhr.send(js); +} + +function pad2(x){ + return x<10 ? '0'+x : x +} + +function formatTime(secs){ + if(secs > 3600){ + return pad2(Math.floor(secs/60/60)) + ":" + pad2(Math.floor(secs/60)%60) + ":" + pad2(Math.floor(secs)%60) + } else if(secs > 60){ + return pad2(Math.floor(secs/60)) + ":" + pad2(Math.floor(secs)%60) + } else{ + return Math.floor(secs) + "s" } } -function requestProgress(id_part){ - btn = gradioApp().getElementById(id_part+"_check_progress_initial"); - if(btn==null) return; +function setTitle(progress){ + var title = 'Stable Diffusion' - btn.click(); + if(opts.show_progress_in_title && progress){ + title = '[' + progress.trim() + '] ' + title; + } + + if(document.title != title){ + document.title = title; + } +} + + +function randomId(){ + return "task(" + Math.random().toString(36).slice(2, 7) + Math.random().toString(36).slice(2, 7) + Math.random().toString(36).slice(2, 7)+")" +} + +// starts sending progress requests to "/internal/progress" uri, creating progressbar above progressbarContainer element and +// preview inside gallery element. Cleans up all created stuff when the task is over and calls atEnd. +// calls onProgress every time there is a progress update +function requestProgress(id_task, progressbarContainer, gallery, atEnd, onProgress){ + var dateStart = new Date() + var wasEverActive = false + var parentProgressbar = progressbarContainer.parentNode + var parentGallery = gallery ? gallery.parentNode : null + + var divProgress = document.createElement('div') + divProgress.className='progressDiv' + divProgress.style.display = opts.show_progressbar ? "" : "none" + var divInner = document.createElement('div') + divInner.className='progress' + + divProgress.appendChild(divInner) + parentProgressbar.insertBefore(divProgress, progressbarContainer) + + if(parentGallery){ + var livePreview = document.createElement('div') + livePreview.className='livePreview' + parentGallery.insertBefore(livePreview, gallery) + } + + var removeProgressBar = function(){ + setTitle("") + parentProgressbar.removeChild(divProgress) + if(parentGallery) parentGallery.removeChild(livePreview) + atEnd() + } + + var fun = function(id_task, id_live_preview){ + request("./internal/progress", {"id_task": id_task, "id_live_preview": id_live_preview}, function(res){ + if(res.completed){ + removeProgressBar() + return + } + + var rect = progressbarContainer.getBoundingClientRect() + + if(rect.width){ + divProgress.style.width = rect.width + "px"; + } + + progressText = "" + + divInner.style.width = ((res.progress || 0) * 100.0) + '%' + divInner.style.background = res.progress ? "" : "transparent" + + if(res.progress > 0){ + progressText = ((res.progress || 0) * 100.0).toFixed(0) + '%' + } + + if(res.eta){ + progressText += " ETA: " + formatTime(res.eta) + } + + + setTitle(progressText) + + if(res.textinfo && res.textinfo.indexOf("\n") == -1){ + progressText = res.textinfo + " " + progressText + } + + divInner.textContent = progressText + + var elapsedFromStart = (new Date() - dateStart) / 1000 + + if(res.active) wasEverActive = true; + + if(! res.active && wasEverActive){ + removeProgressBar() + return + } + + if(elapsedFromStart > 5 && !res.queued && !res.active){ + removeProgressBar() + return + } + + + if(res.live_preview && gallery){ + var rect = gallery.getBoundingClientRect() + if(rect.width){ + livePreview.style.width = rect.width + "px" + livePreview.style.height = rect.height + "px" + } + + var img = new Image(); + img.onload = function() { + livePreview.appendChild(img) + if(livePreview.childElementCount > 2){ + livePreview.removeChild(livePreview.firstElementChild) + } + } + img.src = res.live_preview; + } + + + if(onProgress){ + onProgress(res) + } + + setTimeout(() => { + fun(id_task, res.id_live_preview); + }, opts.live_preview_refresh_period || 500) + }, function(){ + removeProgressBar() + }) + } + + fun(id_task, 0) } diff --git a/javascript/textualInversion.js b/javascript/textualInversion.js index 8061be08..0354b860 100644 --- a/javascript/textualInversion.js +++ b/javascript/textualInversion.js @@ -1,8 +1,17 @@ + function start_training_textual_inversion(){ - requestProgress('ti') gradioApp().querySelector('#ti_error').innerHTML='' - return args_to_array(arguments) + var id = randomId() + requestProgress(id, gradioApp().getElementById('ti_output'), gradioApp().getElementById('ti_gallery'), function(){}, function(progress){ + gradioApp().getElementById('ti_progress').innerHTML = progress.textinfo + }) + + var res = args_to_array(arguments) + + res[0] = id + + return res } diff --git a/javascript/ui.js b/javascript/ui.js index 1e04a8f4..77256e15 100644 --- a/javascript/ui.js +++ b/javascript/ui.js @@ -45,10 +45,27 @@ function switch_to_txt2img(){ return args_to_array(arguments); } -function switch_to_img2img(){ +function switch_to_img2img_tab(no){ gradioApp().querySelector('#tabs').querySelectorAll('button')[1].click(); - gradioApp().getElementById('mode_img2img').querySelectorAll('button')[0].click(); + gradioApp().getElementById('mode_img2img').querySelectorAll('button')[no].click(); +} +function switch_to_img2img(){ + switch_to_img2img_tab(0); + return args_to_array(arguments); +} +function switch_to_sketch(){ + switch_to_img2img_tab(1); + return args_to_array(arguments); +} + +function switch_to_inpaint(){ + switch_to_img2img_tab(2); + return args_to_array(arguments); +} + +function switch_to_inpaint_sketch(){ + switch_to_img2img_tab(3); return args_to_array(arguments); } @@ -92,6 +109,13 @@ function get_extras_tab_index(){ return [get_tab_index('mode_extras'), get_tab_index('extras_resize_mode'), ...args] } +function get_img2img_tab_index() { + let res = args_to_array(arguments) + res.splice(-2) + res[0] = get_tab_index('mode_img2img') + return res +} + function create_submit_args(args){ res = [] for(var i=0;i label > textarea"); - txt2img_textarea?.addEventListener("input", () => update_token_counter("txt2img_token_button")); - } - if (!img2img_textarea) { - img2img_textarea = gradioApp().querySelector("#img2img_prompt > label > textarea"); - img2img_textarea?.addEventListener("input", () => update_token_counter("img2img_token_button")); - } + function registerTextarea(id, id_counter, id_button){ + var prompt = gradioApp().getElementById(id) + var counter = gradioApp().getElementById(id_counter) + var textarea = gradioApp().querySelector("#" + id + " > label > textarea"); + + if(counter.parentElement == prompt.parentElement){ + return + } + + + prompt.parentElement.insertBefore(counter, prompt) + counter.classList.add("token-counter") + prompt.parentElement.style.position = "relative" + + textarea.addEventListener("input", function(){ + update_token_counter(id_button); + }); + } + + registerTextarea('txt2img_prompt', 'txt2img_token_counter', 'txt2img_token_button') + registerTextarea('txt2img_neg_prompt', 'txt2img_negative_token_counter', 'txt2img_negative_token_button') + registerTextarea('img2img_prompt', 'img2img_token_counter', 'img2img_token_button') + registerTextarea('img2img_neg_prompt', 'img2img_negative_token_counter', 'img2img_negative_token_button') show_all_pages = gradioApp().getElementById('settings_show_all_pages') settings_tabs = gradioApp().querySelector('#settings div') @@ -195,7 +264,6 @@ onUiUpdate(function(){ } }) - onOptionsChanged(function(){ elem = gradioApp().getElementById('sd_checkpoint_hash') sd_checkpoint_hash = opts.sd_checkpoint_hash || "" @@ -238,3 +306,11 @@ function restart_reload(){ return [] } + +// Simulate an `input` DOM event for Gradio Textbox component. Needed after you edit its contents in javascript, otherwise your edits +// will only visible on web page and not sent to python. +function updateInput(target){ + let e = new Event("input", { bubbles: true }) + Object.defineProperty(e, "target", {value: target}) + target.dispatchEvent(e); +} diff --git a/launch.py b/launch.py index bcbb792c..5afb2956 100644 --- a/launch.py +++ b/launch.py @@ -14,6 +14,7 @@ python = sys.executable git = os.environ.get('GIT', "git") index_url = os.environ.get('INDEX_URL', "") stored_commit_hash = None +skip_install = False def commit_hash(): @@ -89,6 +90,9 @@ def run_python(code, desc=None, errdesc=None): def run_pip(args, desc=None): + if skip_install: + return + index_url_line = f' --index-url {index_url}' if index_url != '' else '' return run(f'"{python}" -m pip {args} --prefer-binary{index_url_line}', desc=f"Installing {desc}", errdesc=f"Couldn't install {desc}") @@ -173,6 +177,8 @@ def run_extensions_installers(settings_file): def prepare_environment(): + global skip_install + torch_command = os.environ.get('TORCH_COMMAND', "pip install torch==1.12.1+cu113 torchvision==0.13.1+cu113 --extra-index-url https://download.pytorch.org/whl/cu113") requirements_file = os.environ.get('REQS_FILE', "requirements_versions.txt") commandline_args = os.environ.get('COMMANDLINE_ARGS', "") @@ -206,6 +212,7 @@ def prepare_environment(): sys.argv, reinstall_xformers = extract_arg(sys.argv, '--reinstall-xformers') sys.argv, update_check = extract_arg(sys.argv, '--update-check') sys.argv, run_tests, test_dir = extract_opt(sys.argv, '--tests') + sys.argv, skip_install = extract_arg(sys.argv, '--skip-install') xformers = '--xformers' in sys.argv ngrok = '--ngrok' in sys.argv @@ -279,6 +286,8 @@ def tests(test_dir): sys.argv.append("./test/test_files/empty.pt") if "--skip-torch-cuda-test" not in sys.argv: sys.argv.append("--skip-torch-cuda-test") + if "--disable-nan-check" not in sys.argv: + sys.argv.append("--disable-nan-check") print(f"Launching Web UI in another process for testing with arguments: {' '.join(sys.argv[1:])}") diff --git a/modules/api/api.py b/modules/api/api.py index 9814bbc2..f2e9e884 100644 --- a/modules/api/api.py +++ b/modules/api/api.py @@ -126,8 +126,6 @@ class Api: self.add_api_route("/sdapi/v1/face-restorers", self.get_face_restorers, methods=["GET"], response_model=List[FaceRestorerItem]) self.add_api_route("/sdapi/v1/realesrgan-models", self.get_realesrgan_models, methods=["GET"], response_model=List[RealesrganItem]) self.add_api_route("/sdapi/v1/prompt-styles", self.get_prompt_styles, methods=["GET"], response_model=List[PromptStyleItem]) - self.add_api_route("/sdapi/v1/artist-categories", self.get_artists_categories, methods=["GET"], response_model=List[str]) - self.add_api_route("/sdapi/v1/artists", self.get_artists, methods=["GET"], response_model=List[ArtistItem]) self.add_api_route("/sdapi/v1/embeddings", self.get_embeddings, methods=["GET"], response_model=EmbeddingsResponse) self.add_api_route("/sdapi/v1/refresh-checkpoints", self.refresh_checkpoints, methods=["POST"]) self.add_api_route("/sdapi/v1/create/embedding", self.create_embedding, methods=["POST"], response_model=CreateResponse) @@ -390,12 +388,6 @@ class Api: return styleList - def get_artists_categories(self): - return shared.artist_db.cats - - def get_artists(self): - return [{"name":x[0], "score":x[1], "category":x[2]} for x in shared.artist_db.artists] - def get_embeddings(self): db = sd_hijack.model_hijack.embedding_db @@ -480,7 +472,7 @@ class Api: def train_hypernetwork(self, args: dict): try: shared.state.begin() - initial_hypernetwork = shared.loaded_hypernetwork + shared.loaded_hypernetworks = [] apply_optimizations = shared.opts.training_xattention_optimizations error = None filename = '' @@ -491,16 +483,15 @@ class Api: except Exception as e: error = e finally: - shared.loaded_hypernetwork = initial_hypernetwork shared.sd_model.cond_stage_model.to(devices.device) shared.sd_model.first_stage_model.to(devices.device) if not apply_optimizations: sd_hijack.apply_optimizations() shared.state.end() - return TrainResponse(info = "train embedding complete: filename: {filename} error: {error}".format(filename = filename, error = error)) + return TrainResponse(info="train embedding complete: filename: {filename} error: {error}".format(filename=filename, error=error)) except AssertionError as msg: shared.state.end() - return TrainResponse(info = "train embedding error: {error}".format(error = error)) + return TrainResponse(info="train embedding error: {error}".format(error=error)) def get_memory(self): try: diff --git a/modules/artists.py b/modules/artists.py deleted file mode 100644 index 3612758b..00000000 --- a/modules/artists.py +++ /dev/null @@ -1,25 +0,0 @@ -import os.path -import csv -from collections import namedtuple - -Artist = namedtuple("Artist", ['name', 'weight', 'category']) - - -class ArtistsDatabase: - def __init__(self, filename): - self.cats = set() - self.artists = [] - - if not os.path.exists(filename): - return - - with open(filename, "r", newline='', encoding="utf8") as file: - reader = csv.DictReader(file) - - for row in reader: - artist = Artist(row["artist"], float(row["score"]), row["category"]) - self.artists.append(artist) - self.cats.add(artist.category) - - def categories(self): - return sorted(self.cats) diff --git a/modules/call_queue.py b/modules/call_queue.py index 4cd49533..92097c15 100644 --- a/modules/call_queue.py +++ b/modules/call_queue.py @@ -4,7 +4,7 @@ import threading import traceback import time -from modules import shared +from modules import shared, progress queue_lock = threading.Lock() @@ -22,12 +22,23 @@ def wrap_queued_call(func): def wrap_gradio_gpu_call(func, extra_outputs=None): def f(*args, **kwargs): - shared.state.begin() + # if the first argument is a string that says "task(...)", it is treated as a job id + if len(args) > 0 and type(args[0]) == str and args[0][0:5] == "task(" and args[0][-1] == ")": + id_task = args[0] + progress.add_task_to_queue(id_task) + else: + id_task = None with queue_lock: - res = func(*args, **kwargs) + shared.state.begin() + progress.start_task(id_task) - shared.state.end() + try: + res = func(*args, **kwargs) + finally: + progress.finish_task(id_task) + + shared.state.end() return res diff --git a/modules/devices.py b/modules/devices.py index caeb0276..524ec7af 100644 --- a/modules/devices.py +++ b/modules/devices.py @@ -106,6 +106,36 @@ def autocast(disable=False): return torch.autocast("cuda") +class NansException(Exception): + pass + + +def test_for_nans(x, where): + from modules import shared + + if shared.cmd_opts.disable_nan_check: + return + + if not torch.all(torch.isnan(x)).item(): + return + + if where == "unet": + message = "A tensor with all NaNs was produced in Unet." + + if not shared.cmd_opts.no_half: + message += " This could be either because there's not enough precision to represent the picture, or because your video card does not support half type. Try using --no-half commandline argument to fix this." + + elif where == "vae": + message = "A tensor with all NaNs was produced in VAE." + + if not shared.cmd_opts.no_half and not shared.cmd_opts.no_half_vae: + message += " This could be because there's not enough precision to represent the picture. Try adding --no-half-vae commandline argument to fix this." + else: + message = "A tensor with all NaNs was produced." + + raise NansException(message) + + # MPS workaround for https://github.com/pytorch/pytorch/issues/79383 orig_tensor_to = torch.Tensor.to def tensor_to_fix(self, *args, **kwargs): @@ -139,8 +169,10 @@ orig_Tensor_cumsum = torch.Tensor.cumsum def cumsum_fix(input, cumsum_func, *args, **kwargs): if input.device.type == 'mps': output_dtype = kwargs.get('dtype', input.dtype) - if any(output_dtype == broken_dtype for broken_dtype in [torch.bool, torch.int8, torch.int16, torch.int64]): + if output_dtype == torch.int64: return cumsum_func(input.cpu(), *args, **kwargs).to(input.device) + elif cumsum_needs_bool_fix and output_dtype == torch.bool or cumsum_needs_int_fix and (output_dtype == torch.int8 or output_dtype == torch.int16): + return cumsum_func(input.to(torch.int32), *args, **kwargs).to(torch.int64) return cumsum_func(input, *args, **kwargs) @@ -151,8 +183,10 @@ if has_mps(): torch.nn.functional.layer_norm = layer_norm_fix torch.Tensor.numpy = numpy_fix elif version.parse(torch.__version__) > version.parse("1.13.1"): - if not torch.Tensor([1,2]).to(torch.device("mps")).equal(torch.Tensor([1,1]).to(torch.device("mps")).cumsum(0, dtype=torch.int16)): - torch.cumsum = lambda input, *args, **kwargs: ( cumsum_fix(input, orig_cumsum, *args, **kwargs) ) - torch.Tensor.cumsum = lambda self, *args, **kwargs: ( cumsum_fix(self, orig_Tensor_cumsum, *args, **kwargs) ) + cumsum_needs_int_fix = not torch.Tensor([1,2]).to(torch.device("mps")).equal(torch.ShortTensor([1,1]).to(torch.device("mps")).cumsum(0)) + cumsum_needs_bool_fix = not torch.BoolTensor([True,True]).to(device=torch.device("mps"), dtype=torch.int64).equal(torch.BoolTensor([True,False]).to(torch.device("mps")).cumsum(0)) + torch.cumsum = lambda input, *args, **kwargs: ( cumsum_fix(input, orig_cumsum, *args, **kwargs) ) + torch.Tensor.cumsum = lambda self, *args, **kwargs: ( cumsum_fix(self, orig_Tensor_cumsum, *args, **kwargs) ) orig_narrow = torch.narrow torch.narrow = lambda *args, **kwargs: ( orig_narrow(*args, **kwargs).clone() ) + diff --git a/modules/errors.py b/modules/errors.py index a668c014..a10e8708 100644 --- a/modules/errors.py +++ b/modules/errors.py @@ -19,7 +19,7 @@ def display(e: Exception, task): message = str(e) if "copying a param with shape torch.Size([640, 1024]) from checkpoint, the shape in current model is torch.Size([640, 768])" in message: print_error_explanation(""" -The most likely cause of this is you are trying to load Stable Diffusion 2.0 model without specifying its connfig file. +The most likely cause of this is you are trying to load Stable Diffusion 2.0 model without specifying its config file. See https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Features#stable-diffusion-20 for how to solve this. """) diff --git a/modules/extra_networks.py b/modules/extra_networks.py new file mode 100644 index 00000000..1978673d --- /dev/null +++ b/modules/extra_networks.py @@ -0,0 +1,147 @@ +import re +from collections import defaultdict + +from modules import errors + +extra_network_registry = {} + + +def initialize(): + extra_network_registry.clear() + + +def register_extra_network(extra_network): + extra_network_registry[extra_network.name] = extra_network + + +class ExtraNetworkParams: + def __init__(self, items=None): + self.items = items or [] + + +class ExtraNetwork: + def __init__(self, name): + self.name = name + + def activate(self, p, params_list): + """ + Called by processing on every run. Whatever the extra network is meant to do should be activated here. + Passes arguments related to this extra network in params_list. + User passes arguments by specifying this in his prompt: + + + + Where name matches the name of this ExtraNetwork object, and arg1:arg2:arg3 are any natural number of text arguments + separated by colon. + + Even if the user does not mention this ExtraNetwork in his prompt, the call will stil be made, with empty params_list - + in this case, all effects of this extra networks should be disabled. + + Can be called multiple times before deactivate() - each new call should override the previous call completely. + + For example, if this ExtraNetwork's name is 'hypernet' and user's prompt is: + + > "1girl, " + + params_list will be: + + [ + ExtraNetworkParams(items=["agm", "1.1"]), + ExtraNetworkParams(items=["ray"]) + ] + + """ + raise NotImplementedError + + def deactivate(self, p): + """ + Called at the end of processing for housekeeping. No need to do anything here. + """ + + raise NotImplementedError + + +def activate(p, extra_network_data): + """call activate for extra networks in extra_network_data in specified order, then call + activate for all remaining registered networks with an empty argument list""" + + for extra_network_name, extra_network_args in extra_network_data.items(): + extra_network = extra_network_registry.get(extra_network_name, None) + if extra_network is None: + print(f"Skipping unknown extra network: {extra_network_name}") + continue + + try: + extra_network.activate(p, extra_network_args) + except Exception as e: + errors.display(e, f"activating extra network {extra_network_name} with arguments {extra_network_args}") + + for extra_network_name, extra_network in extra_network_registry.items(): + args = extra_network_data.get(extra_network_name, None) + if args is not None: + continue + + try: + extra_network.activate(p, []) + except Exception as e: + errors.display(e, f"activating extra network {extra_network_name}") + + +def deactivate(p, extra_network_data): + """call deactivate for extra networks in extra_network_data in specified order, then call + deactivate for all remaining registered networks""" + + for extra_network_name, extra_network_args in extra_network_data.items(): + extra_network = extra_network_registry.get(extra_network_name, None) + if extra_network is None: + continue + + try: + extra_network.deactivate(p) + except Exception as e: + errors.display(e, f"deactivating extra network {extra_network_name}") + + for extra_network_name, extra_network in extra_network_registry.items(): + args = extra_network_data.get(extra_network_name, None) + if args is not None: + continue + + try: + extra_network.deactivate(p) + except Exception as e: + errors.display(e, f"deactivating unmentioned extra network {extra_network_name}") + + +re_extra_net = re.compile(r"<(\w+):([^>]+)>") + + +def parse_prompt(prompt): + res = defaultdict(list) + + def found(m): + name = m.group(1) + args = m.group(2) + + res[name].append(ExtraNetworkParams(items=args.split(":"))) + + return "" + + prompt = re.sub(re_extra_net, found, prompt) + + return prompt, res + + +def parse_prompts(prompts): + res = [] + extra_data = None + + for prompt in prompts: + updated_prompt, parsed_extra_data = parse_prompt(prompt) + + if extra_data is None: + extra_data = parsed_extra_data + + res.append(updated_prompt) + + return res, extra_data + diff --git a/modules/extra_networks_hypernet.py b/modules/extra_networks_hypernet.py new file mode 100644 index 00000000..ff279a1f --- /dev/null +++ b/modules/extra_networks_hypernet.py @@ -0,0 +1,21 @@ +from modules import extra_networks +from modules.hypernetworks import hypernetwork + + +class ExtraNetworkHypernet(extra_networks.ExtraNetwork): + def __init__(self): + super().__init__('hypernet') + + def activate(self, p, params_list): + names = [] + multipliers = [] + for params in params_list: + assert len(params.items) > 0 + + names.append(params.items[0]) + multipliers.append(float(params.items[1]) if len(params.items) > 1 else 1.0) + + hypernetwork.load_hypernetworks(names, multipliers) + + def deactivate(self, p): + pass diff --git a/modules/extras.py b/modules/extras.py index a03d558e..385430dc 100644 --- a/modules/extras.py +++ b/modules/extras.py @@ -1,6 +1,7 @@ from __future__ import annotations import math import os +import re import sys import traceback import shutil @@ -15,7 +16,7 @@ from typing import Callable, List, OrderedDict, Tuple from functools import partial from dataclasses import dataclass -from modules import processing, shared, images, devices, sd_models, sd_samplers +from modules import processing, shared, images, devices, sd_models, sd_samplers, sd_vae from modules.shared import opts import modules.gfpgan_model from modules.ui import plaintext_to_html @@ -251,7 +252,8 @@ def run_pnginfo(image): def create_config(ckpt_result, config_source, a, b, c): def config(x): - return sd_models.find_checkpoint_config(x) if x else None + res = sd_models.find_checkpoint_config(x) if x else None + return res if res != shared.sd_default_config else None if config_source == 0: cfg = config(a) or config(b) or config(c) @@ -274,10 +276,25 @@ def create_config(ckpt_result, config_source, a, b, c): shutil.copyfile(cfg, checkpoint_filename) -def run_modelmerger(primary_model_name, secondary_model_name, tertiary_model_name, interp_method, multiplier, save_as_half, custom_name, checkpoint_format, config_source): +checkpoint_dict_skip_on_merge = ["cond_stage_model.transformer.text_model.embeddings.position_ids"] + + +def to_half(tensor, enable): + if enable and tensor.dtype == torch.float: + return tensor.half() + + return tensor + + +def run_modelmerger(id_task, primary_model_name, secondary_model_name, tertiary_model_name, interp_method, multiplier, save_as_half, custom_name, checkpoint_format, config_source, bake_in_vae, discard_weights): shared.state.begin() shared.state.job = 'model-merge' + def fail(message): + shared.state.textinfo = message + shared.state.end() + return [*[gr.update() for _ in range(4)], message] + def weighted_sum(theta0, theta1, alpha): return ((1 - alpha) * theta0) + (alpha * theta1) @@ -287,51 +304,96 @@ def run_modelmerger(primary_model_name, secondary_model_name, tertiary_model_nam def add_difference(theta0, theta1_2_diff, alpha): return theta0 + (alpha * theta1_2_diff) - primary_model_info = sd_models.checkpoints_list[primary_model_name] - secondary_model_info = sd_models.checkpoints_list[secondary_model_name] - tertiary_model_info = sd_models.checkpoints_list.get(tertiary_model_name, None) - result_is_inpainting_model = False + def filename_weighted_sum(): + a = primary_model_info.model_name + b = secondary_model_info.model_name + Ma = round(1 - multiplier, 2) + Mb = round(multiplier, 2) + + return f"{Ma}({a}) + {Mb}({b})" + + def filename_add_difference(): + a = primary_model_info.model_name + b = secondary_model_info.model_name + c = tertiary_model_info.model_name + M = round(multiplier, 2) + + return f"{a} + {M}({b} - {c})" + + def filename_nothing(): + return primary_model_info.model_name theta_funcs = { - "Weighted sum": (None, weighted_sum), - "Add difference": (get_difference, add_difference), + "Weighted sum": (filename_weighted_sum, None, weighted_sum), + "Add difference": (filename_add_difference, get_difference, add_difference), + "No interpolation": (filename_nothing, None, None), } - theta_func1, theta_func2 = theta_funcs[interp_method] + filename_generator, theta_func1, theta_func2 = theta_funcs[interp_method] + shared.state.job_count = (1 if theta_func1 else 0) + (1 if theta_func2 else 0) - if theta_func1 and not tertiary_model_info: - shared.state.textinfo = "Failed: Interpolation method requires a tertiary model." - shared.state.end() - return ["Failed: Interpolation method requires a tertiary model."] + [gr.Dropdown.update(choices=sd_models.checkpoint_tiles()) for _ in range(4)] + if not primary_model_name: + return fail("Failed: Merging requires a primary model.") - shared.state.textinfo = f"Loading {secondary_model_info.filename}..." - print(f"Loading {secondary_model_info.filename}...") - theta_1 = sd_models.read_state_dict(secondary_model_info.filename, map_location='cpu') + primary_model_info = sd_models.checkpoints_list[primary_model_name] + + if theta_func2 and not secondary_model_name: + return fail("Failed: Merging requires a secondary model.") + + secondary_model_info = sd_models.checkpoints_list[secondary_model_name] if theta_func2 else None + + if theta_func1 and not tertiary_model_name: + return fail(f"Failed: Interpolation method ({interp_method}) requires a tertiary model.") + + tertiary_model_info = sd_models.checkpoints_list[tertiary_model_name] if theta_func1 else None + + result_is_inpainting_model = False + + if theta_func2: + shared.state.textinfo = f"Loading B" + print(f"Loading {secondary_model_info.filename}...") + theta_1 = sd_models.read_state_dict(secondary_model_info.filename, map_location='cpu') + else: + theta_1 = None if theta_func1: + shared.state.textinfo = f"Loading C" print(f"Loading {tertiary_model_info.filename}...") theta_2 = sd_models.read_state_dict(tertiary_model_info.filename, map_location='cpu') + shared.state.textinfo = 'Merging B and C' + shared.state.sampling_steps = len(theta_1.keys()) for key in tqdm.tqdm(theta_1.keys()): + if key in checkpoint_dict_skip_on_merge: + continue + if 'model' in key: if key in theta_2: t2 = theta_2.get(key, torch.zeros_like(theta_1[key])) theta_1[key] = theta_func1(theta_1[key], t2) else: theta_1[key] = torch.zeros_like(theta_1[key]) + + shared.state.sampling_step += 1 del theta_2 + shared.state.nextjob() + shared.state.textinfo = f"Loading {primary_model_info.filename}..." print(f"Loading {primary_model_info.filename}...") theta_0 = sd_models.read_state_dict(primary_model_info.filename, map_location='cpu') print("Merging...") - + shared.state.textinfo = 'Merging A and B' + shared.state.sampling_steps = len(theta_0.keys()) for key in tqdm.tqdm(theta_0.keys()): - if 'model' in key and key in theta_1: + if theta_1 and 'model' in key and key in theta_1: + + if key in checkpoint_dict_skip_on_merge: + continue + a = theta_0[key] b = theta_1[key] - shared.state.textinfo = f'Merging layer {key}' # this enables merging an inpainting model (A) with another one (B); # where normal model would have 4 channels, for latenst space, inpainting model would # have another 4 channels for unmasked picture's latent space, plus one channel for mask, for a total of 9 @@ -346,32 +408,45 @@ def run_modelmerger(primary_model_name, secondary_model_name, tertiary_model_nam else: theta_0[key] = theta_func2(a, b, multiplier) - if save_as_half: - theta_0[key] = theta_0[key].half() + theta_0[key] = to_half(theta_0[key], save_as_half) + + shared.state.sampling_step += 1 - # I believe this part should be discarded, but I'll leave it for now until I am sure - for key in theta_1.keys(): - if 'model' in key and key not in theta_0: - theta_0[key] = theta_1[key] - if save_as_half: - theta_0[key] = theta_0[key].half() del theta_1 + bake_in_vae_filename = sd_vae.vae_dict.get(bake_in_vae, None) + if bake_in_vae_filename is not None: + print(f"Baking in VAE from {bake_in_vae_filename}") + shared.state.textinfo = 'Baking in VAE' + vae_dict = sd_vae.load_vae_dict(bake_in_vae_filename, map_location='cpu') + + for key in vae_dict.keys(): + theta_0_key = 'first_stage_model.' + key + if theta_0_key in theta_0: + theta_0[theta_0_key] = to_half(vae_dict[key], save_as_half) + + del vae_dict + + if save_as_half and not theta_func2: + for key in theta_0.keys(): + theta_0[key] = to_half(theta_0[key], save_as_half) + + if discard_weights: + regex = re.compile(discard_weights) + for key in list(theta_0): + if re.search(regex, key): + theta_0.pop(key, None) + ckpt_dir = shared.cmd_opts.ckpt_dir or sd_models.model_path - filename = \ - primary_model_info.model_name + '_' + str(round(1-multiplier, 2)) + '-' + \ - secondary_model_info.model_name + '_' + str(round(multiplier, 2)) + '-' + \ - interp_method.replace(" ", "_") + \ - '-merged.' + \ - ("inpainting." if result_is_inpainting_model else "") + \ - checkpoint_format - - filename = filename if custom_name == '' else (custom_name + '.' + checkpoint_format) + filename = filename_generator() if custom_name == '' else custom_name + filename += ".inpainting" if result_is_inpainting_model else "" + filename += "." + checkpoint_format output_modelname = os.path.join(ckpt_dir, filename) - shared.state.textinfo = f"Saving to {output_modelname}..." + shared.state.nextjob() + shared.state.textinfo = "Saving" print(f"Saving to {output_modelname}...") _, extension = os.path.splitext(output_modelname) @@ -384,8 +459,8 @@ def run_modelmerger(primary_model_name, secondary_model_name, tertiary_model_nam create_config(output_modelname, config_source, primary_model_info, secondary_model_info, tertiary_model_info) - print("Checkpoint saved.") - shared.state.textinfo = "Checkpoint saved to " + output_modelname + print(f"Checkpoint saved to {output_modelname}.") + shared.state.textinfo = "Checkpoint saved" shared.state.end() - return ["Checkpoint saved to " + output_modelname] + [gr.Dropdown.update(choices=sd_models.checkpoint_tiles()) for _ in range(4)] + return [*[gr.Dropdown.update(choices=sd_models.checkpoint_tiles()) for _ in range(4)], "Checkpoint saved to " + output_modelname] diff --git a/modules/generation_parameters_copypaste.py b/modules/generation_parameters_copypaste.py index 593d99ef..46e12dc6 100644 --- a/modules/generation_parameters_copypaste.py +++ b/modules/generation_parameters_copypaste.py @@ -37,6 +37,9 @@ def quote(text): def image_from_url_text(filedata): + if filedata is None: + return None + if type(filedata) == list and len(filedata) > 0 and type(filedata[0]) == dict and filedata[0].get("is_file", False): filedata = filedata[0] @@ -76,8 +79,6 @@ def integrate_settings_paste_fields(component_dict): from modules import ui settings_map = { - 'sd_hypernetwork': 'Hypernet', - 'sd_hypernetwork_strength': 'Hypernet strength', 'CLIP_stop_at_last_layers': 'Clip skip', 'inpainting_mask_weight': 'Conditional mask weight', 'sd_model_checkpoint': 'Model hash', @@ -272,13 +273,9 @@ Steps: 20, Sampler: Euler a, CFG scale: 7, Seed: 965400086, Size: 512x512, Model if "Clip skip" not in res: res["Clip skip"] = "1" - if "Hypernet strength" not in res: - res["Hypernet strength"] = "1" - - if "Hypernet" in res: - hypernet_name = res["Hypernet"] - hypernet_hash = res.get("Hypernet hash", None) - res["Hypernet"] = find_hypernetwork_key(hypernet_name, hypernet_hash) + hypernet = res.get("Hypernet", None) + if hypernet is not None: + res["Prompt"] += f"""""" if "Hires resize-1" not in res: res["Hires resize-1"] = 0 diff --git a/modules/hashes.py b/modules/hashes.py index 14231771..b85a7580 100644 --- a/modules/hashes.py +++ b/modules/hashes.py @@ -34,9 +34,10 @@ def cache(subsection): def calculate_sha256(filename): hash_sha256 = hashlib.sha256() + blksize = 1024 * 1024 with open(filename, "rb") as f: - for chunk in iter(lambda: f.read(4096), b""): + for chunk in iter(lambda: f.read(blksize), b""): hash_sha256.update(chunk) return hash_sha256.hexdigest() diff --git a/modules/hypernetworks/hypernetwork.py b/modules/hypernetworks/hypernetwork.py index 3aebefa8..503534e2 100644 --- a/modules/hypernetworks/hypernetwork.py +++ b/modules/hypernetworks/hypernetwork.py @@ -12,7 +12,7 @@ import torch import tqdm from einops import rearrange, repeat from ldm.util import default -from modules import devices, processing, sd_models, shared, sd_samplers, hashes +from modules import devices, processing, sd_models, shared, sd_samplers, hashes, sd_hijack_checkpoint from modules.textual_inversion import textual_inversion, logging from modules.textual_inversion.learn_schedule import LearnRateScheduler from torch import einsum @@ -25,7 +25,6 @@ from statistics import stdev, mean optimizer_dict = {optim_name : cls_obj for optim_name, cls_obj in inspect.getmembers(torch.optim, inspect.isclass) if optim_name != "Optimizer"} class HypernetworkModule(torch.nn.Module): - multiplier = 1.0 activation_dict = { "linear": torch.nn.Identity, "relu": torch.nn.ReLU, @@ -41,6 +40,8 @@ class HypernetworkModule(torch.nn.Module): add_layer_norm=False, activate_output=False, dropout_structure=None): super().__init__() + self.multiplier = 1.0 + assert layer_structure is not None, "layer_structure must not be None" assert layer_structure[0] == 1, "Multiplier Sequence should start with size 1!" assert layer_structure[-1] == 1, "Multiplier Sequence should end with size 1!" @@ -115,7 +116,7 @@ class HypernetworkModule(torch.nn.Module): state_dict[to] = x def forward(self, x): - return x + self.linear(x) * (HypernetworkModule.multiplier if not self.training else 1) + return x + self.linear(x) * (self.multiplier if not self.training else 1) def trainables(self): layer_structure = [] @@ -125,9 +126,6 @@ class HypernetworkModule(torch.nn.Module): return layer_structure -def apply_strength(value=None): - HypernetworkModule.multiplier = value if value is not None else shared.opts.sd_hypernetwork_strength - #param layer_structure : sequence used for length, use_dropout : controlling boolean, last_layer_dropout : for compatibility check. def parse_dropout_structure(layer_structure, use_dropout, last_layer_dropout): if layer_structure is None: @@ -192,6 +190,20 @@ class Hypernetwork: for param in layer.parameters(): param.requires_grad = mode + def to(self, device): + for k, layers in self.layers.items(): + for layer in layers: + layer.to(device) + + return self + + def set_multiplier(self, multiplier): + for k, layers in self.layers.items(): + for layer in layers: + layer.multiplier = multiplier + + return self + def eval(self): for k, layers in self.layers.items(): for layer in layers: @@ -269,11 +281,13 @@ class Hypernetwork: self.optimizer_state_dict = None if self.optimizer_state_dict: self.optimizer_name = optimizer_saved_dict.get('optimizer_name', 'AdamW') - print("Loaded existing optimizer from checkpoint") - print(f"Optimizer name is {self.optimizer_name}") + if shared.opts.print_hypernet_extra: + print("Loaded existing optimizer from checkpoint") + print(f"Optimizer name is {self.optimizer_name}") else: self.optimizer_name = "AdamW" - print("No saved optimizer exists in checkpoint") + if shared.opts.print_hypernet_extra: + print("No saved optimizer exists in checkpoint") for size, sd in state_dict.items(): if type(size) == int: @@ -306,23 +320,43 @@ def list_hypernetworks(path): return res -def load_hypernetwork(filename): - path = shared.hypernetworks.get(filename, None) - # Prevent any file named "None.pt" from being loaded. - if path is not None and filename != "None": - print(f"Loading hypernetwork {filename}") - try: - shared.loaded_hypernetwork = Hypernetwork() - shared.loaded_hypernetwork.load(path) +def load_hypernetwork(name): + path = shared.hypernetworks.get(name, None) - except Exception: - print(f"Error loading hypernetwork {path}", file=sys.stderr) - print(traceback.format_exc(), file=sys.stderr) - else: - if shared.loaded_hypernetwork is not None: - print("Unloading hypernetwork") + if path is None: + return None - shared.loaded_hypernetwork = None + hypernetwork = Hypernetwork() + + try: + hypernetwork.load(path) + except Exception: + print(f"Error loading hypernetwork {path}", file=sys.stderr) + print(traceback.format_exc(), file=sys.stderr) + return None + + return hypernetwork + + +def load_hypernetworks(names, multipliers=None): + already_loaded = {} + + for hypernetwork in shared.loaded_hypernetworks: + if hypernetwork.name in names: + already_loaded[hypernetwork.name] = hypernetwork + + shared.loaded_hypernetworks.clear() + + for i, name in enumerate(names): + hypernetwork = already_loaded.get(name, None) + if hypernetwork is None: + hypernetwork = load_hypernetwork(name) + + if hypernetwork is None: + continue + + hypernetwork.set_multiplier(multipliers[i] if multipliers else 1.0) + shared.loaded_hypernetworks.append(hypernetwork) def find_closest_hypernetwork_name(search: str): @@ -336,18 +370,27 @@ def find_closest_hypernetwork_name(search: str): return applicable[0] -def apply_hypernetwork(hypernetwork, context, layer=None): - hypernetwork_layers = (hypernetwork.layers if hypernetwork is not None else {}).get(context.shape[2], None) +def apply_single_hypernetwork(hypernetwork, context_k, context_v, layer=None): + hypernetwork_layers = (hypernetwork.layers if hypernetwork is not None else {}).get(context_k.shape[2], None) if hypernetwork_layers is None: - return context, context + return context_k, context_v if layer is not None: layer.hyper_k = hypernetwork_layers[0] layer.hyper_v = hypernetwork_layers[1] - context_k = hypernetwork_layers[0](context) - context_v = hypernetwork_layers[1](context) + context_k = hypernetwork_layers[0](context_k) + context_v = hypernetwork_layers[1](context_v) + return context_k, context_v + + +def apply_hypernetworks(hypernetworks, context, layer=None): + context_k = context + context_v = context + for hypernetwork in hypernetworks: + context_k, context_v = apply_single_hypernetwork(hypernetwork, context_k, context_v, layer) + return context_k, context_v @@ -357,7 +400,7 @@ def attention_CrossAttention_forward(self, x, context=None, mask=None): q = self.to_q(x) context = default(context, x) - context_k, context_v = apply_hypernetwork(shared.loaded_hypernetwork, context, self) + context_k, context_v = apply_hypernetworks(shared.loaded_hypernetworks, context, self) k = self.to_k(context_k) v = self.to_v(context_v) @@ -453,7 +496,7 @@ def create_hypernetwork(name, enable_sizes, overwrite_old, layer_structure=None, shared.reload_hypernetworks() -def train_hypernetwork(hypernetwork_name, learn_rate, batch_size, gradient_step, data_root, log_directory, training_width, training_height, varsize, steps, clip_grad_mode, clip_grad_value, shuffle_tags, tag_drop_out, latent_sampling_method, create_image_every, save_hypernetwork_every, template_filename, preview_from_txt2img, preview_prompt, preview_negative_prompt, preview_steps, preview_sampler_index, preview_cfg_scale, preview_seed, preview_width, preview_height): +def train_hypernetwork(id_task, hypernetwork_name, learn_rate, batch_size, gradient_step, data_root, log_directory, training_width, training_height, varsize, steps, clip_grad_mode, clip_grad_value, shuffle_tags, tag_drop_out, latent_sampling_method, create_image_every, save_hypernetwork_every, template_filename, preview_from_txt2img, preview_prompt, preview_negative_prompt, preview_steps, preview_sampler_index, preview_cfg_scale, preview_seed, preview_width, preview_height): # images allows training previews to have infotext. Importing it at the top causes a circular import problem. from modules import images @@ -464,8 +507,9 @@ def train_hypernetwork(hypernetwork_name, learn_rate, batch_size, gradient_step, template_file = template_file.path path = shared.hypernetworks.get(hypernetwork_name, None) - shared.loaded_hypernetwork = Hypernetwork() - shared.loaded_hypernetwork.load(path) + hypernetwork = Hypernetwork() + hypernetwork.load(path) + shared.loaded_hypernetworks = [hypernetwork] shared.state.job = "train-hypernetwork" shared.state.textinfo = "Initializing hypernetwork training..." @@ -489,7 +533,6 @@ def train_hypernetwork(hypernetwork_name, learn_rate, batch_size, gradient_step, else: images_dir = None - hypernetwork = shared.loaded_hypernetwork checkpoint = sd_models.select_checkpoint() initial_step = hypernetwork.step or 0 @@ -561,6 +604,7 @@ def train_hypernetwork(hypernetwork_name, learn_rate, batch_size, gradient_step, _loss_step = 0 #internal # size = len(ds.indexes) # loss_dict = defaultdict(lambda : deque(maxlen = 1024)) + loss_logging = deque(maxlen=len(ds) * 3) # this should be configurable parameter, this is 3 * epoch(dataset size) # losses = torch.zeros((size,)) # previous_mean_losses = [0] # previous_mean_loss = 0 @@ -574,6 +618,8 @@ def train_hypernetwork(hypernetwork_name, learn_rate, batch_size, gradient_step, pbar = tqdm.tqdm(total=steps - initial_step) try: + sd_hijack_checkpoint.add() + for i in range((steps-initial_step) * gradient_step): if scheduler.finished: break @@ -610,7 +656,7 @@ def train_hypernetwork(hypernetwork_name, learn_rate, batch_size, gradient_step, # go back until we reach gradient accumulation steps if (j + 1) % gradient_step != 0: continue - + loss_logging.append(_loss_step) if clip_grad: clip_grad(weights, clip_grad_sched.learn_rate) @@ -629,7 +675,6 @@ def train_hypernetwork(hypernetwork_name, learn_rate, batch_size, gradient_step, description = f"Training hypernetwork [Epoch {epoch_num}: {epoch_step+1}/{steps_per_epoch}]loss: {loss_step:.7f}" pbar.set_description(description) - shared.state.textinfo = description if hypernetwork_dir is not None and steps_done % save_hypernetwork_every == 0: # Before saving, change name to match current checkpoint. hypernetwork_name_every = f'{hypernetwork_name}-{steps_done}' @@ -645,7 +690,7 @@ def train_hypernetwork(hypernetwork_name, learn_rate, batch_size, gradient_step, if shared.opts.training_enable_tensorboard: epoch_num = hypernetwork.step // len(ds) epoch_step = hypernetwork.step - (epoch_num * len(ds)) + 1 - + mean_loss = sum(loss_logging) / len(loss_logging) textual_inversion.tensorboard_add(tensorboard_writer, loss=mean_loss, global_step=hypernetwork.step, step=epoch_step, learn_rate=scheduler.learn_rate, epoch_num=epoch_num) textual_inversion.write_loss(log_directory, "hypernetwork_loss.csv", hypernetwork.step, steps_per_epoch, { @@ -670,6 +715,8 @@ def train_hypernetwork(hypernetwork_name, learn_rate, batch_size, gradient_step, do_not_save_samples=True, ) + p.disable_extra_networks = True + if preview_from_txt2img: p.prompt = preview_prompt p.negative_prompt = preview_negative_prompt @@ -689,9 +736,6 @@ def train_hypernetwork(hypernetwork_name, learn_rate, batch_size, gradient_step, processed = processing.process_images(p) image = processed.images[0] if len(processed.images) > 0 else None - - if shared.opts.training_enable_tensorboard and shared.opts.training_tensorboard_save_images: - textual_inversion.tensorboard_add_image(tensorboard_writer, f"Validation at epoch {epoch_num}", image, hypernetwork.step) if unload: shared.sd_model.cond_stage_model.to(devices.cpu) @@ -701,7 +745,11 @@ def train_hypernetwork(hypernetwork_name, learn_rate, batch_size, gradient_step, torch.cuda.set_rng_state_all(cuda_rng_state) hypernetwork.train() if image is not None: - shared.state.current_image = image + shared.state.assign_current_image(image) + if shared.opts.training_enable_tensorboard and shared.opts.training_tensorboard_save_images: + textual_inversion.tensorboard_add_image(tensorboard_writer, + f"Validation at epoch {epoch_num}", image, + hypernetwork.step) last_saved_image, last_text_info = images.save_image(image, images_dir, "", p.seed, p.prompt, shared.opts.samples_format, processed.infotexts[0], p=p, forced_filename=forced_filename, save_to_dirs=False) last_saved_image += f", prompt: {preview_text}" @@ -723,6 +771,9 @@ Last saved image: {html.escape(last_saved_image)}
pbar.close() hypernetwork.eval() #report_statistics(loss_dict) + sd_hijack_checkpoint.remove() + + filename = os.path.join(shared.cmd_opts.hypernetwork_dir, f'{hypernetwork_name}.pt') hypernetwork.optimizer_name = optimizer_name diff --git a/modules/hypernetworks/ui.py b/modules/hypernetworks/ui.py index 81e3f519..76599f5a 100644 --- a/modules/hypernetworks/ui.py +++ b/modules/hypernetworks/ui.py @@ -9,6 +9,7 @@ from modules import devices, sd_hijack, shared not_available = ["hardswish", "multiheadattention"] keys = list(x for x in modules.hypernetworks.hypernetwork.HypernetworkModule.activation_dict.keys() if x not in not_available) + def create_hypernetwork(name, enable_sizes, overwrite_old, layer_structure=None, activation_func=None, weight_init=None, add_layer_norm=False, use_dropout=False, dropout_structure=None): filename = modules.hypernetworks.hypernetwork.create_hypernetwork(name, enable_sizes, overwrite_old, layer_structure, activation_func, weight_init, add_layer_norm, use_dropout, dropout_structure) @@ -16,8 +17,7 @@ def create_hypernetwork(name, enable_sizes, overwrite_old, layer_structure=None, def train_hypernetwork(*args): - - initial_hypernetwork = shared.loaded_hypernetwork + shared.loaded_hypernetworks = [] assert not shared.cmd_opts.lowvram, 'Training models with lowvram is not possible' @@ -34,7 +34,6 @@ Hypernetwork saved to {html.escape(filename)} except Exception: raise finally: - shared.loaded_hypernetwork = initial_hypernetwork shared.sd_model.cond_stage_model.to(devices.device) shared.sd_model.first_stage_model.to(devices.device) sd_hijack.apply_optimizations() diff --git a/modules/images.py b/modules/images.py index c3a5fc8b..3b1c5f34 100644 --- a/modules/images.py +++ b/modules/images.py @@ -605,8 +605,9 @@ def read_info_from_image(image): except ValueError: exif_comment = exif_comment.decode('utf8', errors="ignore") - items['exif comment'] = exif_comment - geninfo = exif_comment + if exif_comment: + items['exif comment'] = exif_comment + geninfo = exif_comment for field in ['jfif', 'jfif_version', 'jfif_unit', 'jfif_density', 'dpi', 'exif', 'loop', 'background', 'timestamp', 'duration']: diff --git a/modules/img2img.py b/modules/img2img.py index f62783c6..2168c8e2 100644 --- a/modules/img2img.py +++ b/modules/img2img.py @@ -59,7 +59,7 @@ def process_batch(p, input_dir, output_dir, args): processed_image.save(os.path.join(output_dir, filename)) -def img2img(mode: int, prompt: str, negative_prompt: str, prompt_style: str, prompt_style2: str, init_img, sketch, init_img_with_mask, inpaint_color_sketch, inpaint_color_sketch_orig, init_img_inpaint, init_mask_inpaint, steps: int, sampler_index: int, mask_blur: int, mask_alpha: float, inpainting_fill: int, restore_faces: bool, tiling: bool, n_iter: int, batch_size: int, cfg_scale: float, denoising_strength: float, seed: int, subseed: int, subseed_strength: float, seed_resize_from_h: int, seed_resize_from_w: int, seed_enable_extras: bool, height: int, width: int, resize_mode: int, inpaint_full_res: bool, inpaint_full_res_padding: int, inpainting_mask_invert: int, img2img_batch_input_dir: str, img2img_batch_output_dir: str, *args): +def img2img(id_task: str, mode: int, prompt: str, negative_prompt: str, prompt_styles, init_img, sketch, init_img_with_mask, inpaint_color_sketch, inpaint_color_sketch_orig, init_img_inpaint, init_mask_inpaint, steps: int, sampler_index: int, mask_blur: int, mask_alpha: float, inpainting_fill: int, restore_faces: bool, tiling: bool, n_iter: int, batch_size: int, cfg_scale: float, denoising_strength: float, seed: int, subseed: int, subseed_strength: float, seed_resize_from_h: int, seed_resize_from_w: int, seed_enable_extras: bool, height: int, width: int, resize_mode: int, inpaint_full_res: bool, inpaint_full_res_padding: int, inpainting_mask_invert: int, img2img_batch_input_dir: str, img2img_batch_output_dir: str, *args): is_batch = mode == 5 if mode == 0: # img2img @@ -101,7 +101,7 @@ def img2img(mode: int, prompt: str, negative_prompt: str, prompt_style: str, pro outpath_grids=opts.outdir_grids or opts.outdir_img2img_grids, prompt=prompt, negative_prompt=negative_prompt, - styles=[prompt_style, prompt_style2], + styles=prompt_styles, seed=seed, subseed=subseed, subseed_strength=subseed_strength, diff --git a/modules/interrogate.py b/modules/interrogate.py index 738d8ff7..19938cbb 100644 --- a/modules/interrogate.py +++ b/modules/interrogate.py @@ -5,12 +5,13 @@ from collections import namedtuple import re import torch +import torch.hub from torchvision import transforms from torchvision.transforms.functional import InterpolationMode import modules.shared as shared -from modules import devices, paths, lowvram, modelloader +from modules import devices, paths, lowvram, modelloader, errors blip_image_eval_size = 384 clip_model_name = 'ViT-L/14' @@ -20,27 +21,59 @@ Category = namedtuple("Category", ["name", "topn", "items"]) re_topn = re.compile(r"\.top(\d+)\.") +def download_default_clip_interrogate_categories(content_dir): + print("Downloading CLIP categories...") + + tmpdir = content_dir + "_tmp" + try: + os.makedirs(tmpdir) + + torch.hub.download_url_to_file("https://raw.githubusercontent.com/pharmapsychotic/clip-interrogator/main/clip_interrogator/data/artists.txt", os.path.join(tmpdir, "artists.txt")) + torch.hub.download_url_to_file("https://raw.githubusercontent.com/pharmapsychotic/clip-interrogator/main/clip_interrogator/data/flavors.txt", os.path.join(tmpdir, "flavors.top3.txt")) + torch.hub.download_url_to_file("https://raw.githubusercontent.com/pharmapsychotic/clip-interrogator/main/clip_interrogator/data/mediums.txt", os.path.join(tmpdir, "mediums.txt")) + torch.hub.download_url_to_file("https://raw.githubusercontent.com/pharmapsychotic/clip-interrogator/main/clip_interrogator/data/movements.txt", os.path.join(tmpdir, "movements.txt")) + + os.rename(tmpdir, content_dir) + + except Exception as e: + errors.display(e, "downloading default CLIP interrogate categories") + finally: + if os.path.exists(tmpdir): + os.remove(tmpdir) + + class InterrogateModels: blip_model = None clip_model = None clip_preprocess = None - categories = None dtype = None running_on_cpu = None def __init__(self, content_dir): - self.categories = [] + self.loaded_categories = None + self.content_dir = content_dir self.running_on_cpu = devices.device_interrogate == torch.device("cpu") - if os.path.exists(content_dir): - for filename in os.listdir(content_dir): + def categories(self): + if self.loaded_categories is not None: + return self.loaded_categories + + self.loaded_categories = [] + + if not os.path.exists(self.content_dir): + download_default_clip_interrogate_categories(self.content_dir) + + if os.path.exists(self.content_dir): + for filename in os.listdir(self.content_dir): m = re_topn.search(filename) topn = 1 if m is None else int(m.group(1)) - with open(os.path.join(content_dir, filename), "r", encoding="utf8") as file: + with open(os.path.join(self.content_dir, filename), "r", encoding="utf8") as file: lines = [x.strip() for x in file.readlines()] - self.categories.append(Category(name=filename, topn=topn, items=lines)) + self.loaded_categories.append(Category(name=filename, topn=topn, items=lines)) + + return self.loaded_categories def load_blip_model(self): import models.blip @@ -139,7 +172,6 @@ class InterrogateModels: shared.state.begin() shared.state.job = 'interrogate' try: - if shared.cmd_opts.lowvram or shared.cmd_opts.medvram: lowvram.send_everything_to_cpu() devices.torch_gc() @@ -159,12 +191,7 @@ class InterrogateModels: image_features /= image_features.norm(dim=-1, keepdim=True) - if shared.opts.interrogate_use_builtin_artists: - artist = self.rank(image_features, ["by " + artist.name for artist in shared.artist_db.artists])[0] - - res += ", " + artist[0] - - for name, topn, items in self.categories: + for name, topn, items in self.categories(): matches = self.rank(image_features, items, top_count=topn) for match, score in matches: if shared.opts.interrogate_return_ranks: diff --git a/modules/processing.py b/modules/processing.py index 849f6b19..bc541e2f 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -13,7 +13,7 @@ from skimage import exposure from typing import Any, Dict, List, Optional import modules.sd_hijack -from modules import devices, prompt_parser, masking, sd_samplers, lowvram, generation_parameters_copypaste, script_callbacks +from modules import devices, prompt_parser, masking, sd_samplers, lowvram, generation_parameters_copypaste, script_callbacks, extra_networks from modules.sd_hijack import model_hijack from modules.shared import opts, cmd_opts, state import modules.shared as shared @@ -94,7 +94,7 @@ def txt2img_image_conditioning(sd_model, x, width, height): return image_conditioning -class StableDiffusionProcessing(): +class StableDiffusionProcessing: """ The first set of paramaters: sd_models -> do_not_reload_embeddings represent the minimum required to create a StableDiffusionProcessing """ @@ -102,7 +102,6 @@ class StableDiffusionProcessing(): if sampler_index is not None: print("sampler_index argument for StableDiffusionProcessing does not do anything; use sampler_name", file=sys.stderr) - self.sd_model = sd_model self.outpath_samples: str = outpath_samples self.outpath_grids: str = outpath_grids self.prompt: str = prompt @@ -141,6 +140,7 @@ class StableDiffusionProcessing(): self.override_settings = {k: v for k, v in (override_settings or {}).items() if k not in shared.restricted_opts} self.override_settings_restore_afterwards = override_settings_restore_afterwards self.is_using_inpainting_conditioning = False + self.disable_extra_networks = False if not seed_enable_extras: self.subseed = -1 @@ -156,6 +156,10 @@ class StableDiffusionProcessing(): self.all_subseeds = None self.iteration = 0 + @property + def sd_model(self): + return shared.sd_model + def txt2img_image_conditioning(self, x, width=None, height=None): self.is_using_inpainting_conditioning = self.sd_model.model.conditioning_key in {'hybrid', 'concat'} @@ -236,7 +240,6 @@ class StableDiffusionProcessing(): raise NotImplementedError() def close(self): - self.sd_model = None self.sampler = None @@ -436,9 +439,6 @@ def create_infotext(p, all_prompts, all_seeds, all_subseeds, comments=None, iter "Size": f"{p.width}x{p.height}", "Model hash": getattr(p, 'sd_model_hash', None if not opts.add_model_hash_to_info or not shared.sd_model.sd_model_hash else shared.sd_model.sd_model_hash), "Model": (None if not opts.add_model_name_to_info or not shared.sd_model.sd_checkpoint_info.model_name else shared.sd_model.sd_checkpoint_info.model_name.replace(',', '').replace(':', '')), - "Hypernet": (None if shared.loaded_hypernetwork is None else shared.loaded_hypernetwork.name), - "Hypernet hash": (None if shared.loaded_hypernetwork is None else shared.loaded_hypernetwork.shorthash()), - "Hypernet strength": (None if shared.loaded_hypernetwork is None or shared.opts.sd_hypernetwork_strength >= 1 else shared.opts.sd_hypernetwork_strength), "Batch size": (None if p.batch_size < 2 else p.batch_size), "Batch pos": (None if p.batch_size < 2 else position_in_batch), "Variation seed": (None if p.subseed_strength == 0 else all_subseeds[index]), @@ -466,15 +466,12 @@ def process_images(p: StableDiffusionProcessing) -> Processed: try: for k, v in p.override_settings.items(): setattr(opts, k, v) - if k == 'sd_hypernetwork': - shared.reload_hypernetworks() # make onchange call for changing hypernet if k == 'sd_model_checkpoint': - sd_models.reload_model_weights() # make onchange call for changing SD model - p.sd_model = shared.sd_model + sd_models.reload_model_weights() if k == 'sd_vae': - sd_vae.reload_vae_weights() # make onchange call for changing VAE + sd_vae.reload_vae_weights() res = process_images_inner(p) @@ -483,9 +480,11 @@ def process_images(p: StableDiffusionProcessing) -> Processed: if p.override_settings_restore_afterwards: for k, v in stored_opts.items(): setattr(opts, k, v) - if k == 'sd_hypernetwork': shared.reload_hypernetworks() - if k == 'sd_model_checkpoint': sd_models.reload_model_weights() - if k == 'sd_vae': sd_vae.reload_vae_weights() + if k == 'sd_model_checkpoint': + sd_models.reload_model_weights() + + if k == 'sd_vae': + sd_vae.reload_vae_weights() return res @@ -534,13 +533,11 @@ def process_images_inner(p: StableDiffusionProcessing) -> Processed: if os.path.exists(cmd_opts.embeddings_dir) and not p.do_not_reload_embeddings: model_hijack.embedding_db.load_textual_inversion_embeddings() + _, extra_network_data = extra_networks.parse_prompts(p.all_prompts[0:1]) + if p.scripts is not None: p.scripts.process(p) - with open(os.path.join(shared.script_path, "params.txt"), "w", encoding="utf8") as file: - processed = Processed(p, [], p.seed, "") - file.write(processed.infotext(p, 0)) - infotexts = [] output_images = [] @@ -571,6 +568,13 @@ def process_images_inner(p: StableDiffusionProcessing) -> Processed: with devices.autocast(): p.init(p.all_prompts, p.all_seeds, p.all_subseeds) + if not p.disable_extra_networks: + extra_networks.activate(p, extra_network_data) + + with open(os.path.join(shared.script_path, "params.txt"), "w", encoding="utf8") as file: + processed = Processed(p, [], p.seed, "") + file.write(processed.infotext(p, 0)) + if state.job_count == -1: state.job_count = p.n_iter @@ -591,6 +595,8 @@ def process_images_inner(p: StableDiffusionProcessing) -> Processed: if len(prompts) == 0: break + prompts, _ = extra_networks.parse_prompts(prompts) + if p.scripts is not None: p.scripts.process_batch(p, batch_number=n, prompts=prompts, seeds=seeds, subseeds=subseeds) @@ -608,6 +614,9 @@ def process_images_inner(p: StableDiffusionProcessing) -> Processed: samples_ddim = p.sample(conditioning=c, unconditional_conditioning=uc, seeds=seeds, subseeds=subseeds, subseed_strength=p.subseed_strength, prompts=prompts) x_samples_ddim = [decode_first_stage(p.sd_model, samples_ddim[i:i+1].to(dtype=devices.dtype_vae))[0].cpu() for i in range(samples_ddim.size(0))] + for x in x_samples_ddim: + devices.test_for_nans(x, "vae") + x_samples_ddim = torch.stack(x_samples_ddim).float() x_samples_ddim = torch.clamp((x_samples_ddim + 1.0) / 2.0, min=0.0, max=1.0) @@ -677,6 +686,9 @@ def process_images_inner(p: StableDiffusionProcessing) -> Processed: if opts.grid_save: images.save_image(grid, p.outpath_grids, "grid", p.all_seeds[0], p.all_prompts[0], opts.grid_format, info=infotext(), short_filename=not opts.grid_extended_filename, p=p, grid=True) + if not p.disable_extra_networks: + extra_networks.deactivate(p, extra_network_data) + devices.torch_gc() res = Processed(p, output_images, p.all_seeds[0], infotext(), comments="".join(["\n\n" + x for x in comments]), subseed=p.all_subseeds[0], index_of_first_image=index_of_first_image, infotexts=infotexts) @@ -853,7 +865,8 @@ class StableDiffusionProcessingTxt2Img(StableDiffusionProcessing): shared.state.nextjob() - self.sampler = sd_samplers.create_sampler(self.sampler_name, self.sd_model) + img2img_sampler_name = self.sampler_name if self.sampler_name != 'PLMS' else 'DDIM' # PLMS does not support img2img so we just silently switch ot DDIM + self.sampler = sd_samplers.create_sampler(img2img_sampler_name, self.sd_model) samples = samples[:, :, self.truncate_y//2:samples.shape[2]-(self.truncate_y+1)//2, self.truncate_x//2:samples.shape[3]-(self.truncate_x+1)//2] diff --git a/modules/progress.py b/modules/progress.py new file mode 100644 index 00000000..c69ecf3d --- /dev/null +++ b/modules/progress.py @@ -0,0 +1,99 @@ +import base64 +import io +import time + +import gradio as gr +from pydantic import BaseModel, Field + +from modules.shared import opts + +import modules.shared as shared + + +current_task = None +pending_tasks = {} +finished_tasks = [] + + +def start_task(id_task): + global current_task + + current_task = id_task + pending_tasks.pop(id_task, None) + + +def finish_task(id_task): + global current_task + + if current_task == id_task: + current_task = None + + finished_tasks.append(id_task) + if len(finished_tasks) > 16: + finished_tasks.pop(0) + + +def add_task_to_queue(id_job): + pending_tasks[id_job] = time.time() + + +class ProgressRequest(BaseModel): + id_task: str = Field(default=None, title="Task ID", description="id of the task to get progress for") + id_live_preview: int = Field(default=-1, title="Live preview image ID", description="id of last received last preview image") + + +class ProgressResponse(BaseModel): + active: bool = Field(title="Whether the task is being worked on right now") + queued: bool = Field(title="Whether the task is in queue") + completed: bool = Field(title="Whether the task has already finished") + progress: float = Field(default=None, title="Progress", description="The progress with a range of 0 to 1") + eta: float = Field(default=None, title="ETA in secs") + live_preview: str = Field(default=None, title="Live preview image", description="Current live preview; a data: uri") + id_live_preview: int = Field(default=None, title="Live preview image ID", description="Send this together with next request to prevent receiving same image") + textinfo: str = Field(default=None, title="Info text", description="Info text used by WebUI.") + + +def setup_progress_api(app): + return app.add_api_route("/internal/progress", progressapi, methods=["POST"], response_model=ProgressResponse) + + +def progressapi(req: ProgressRequest): + active = req.id_task == current_task + queued = req.id_task in pending_tasks + completed = req.id_task in finished_tasks + + if not active: + return ProgressResponse(active=active, queued=queued, completed=completed, id_live_preview=-1, textinfo="In queue..." if queued else "Waiting...") + + progress = 0 + + job_count, job_no = shared.state.job_count, shared.state.job_no + sampling_steps, sampling_step = shared.state.sampling_steps, shared.state.sampling_step + + if job_count > 0: + progress += job_no / job_count + if sampling_steps > 0 and job_count > 0: + progress += 1 / job_count * sampling_step / sampling_steps + + progress = min(progress, 1) + + elapsed_since_start = time.time() - shared.state.time_start + predicted_duration = elapsed_since_start / progress if progress > 0 else None + eta = predicted_duration - elapsed_since_start if predicted_duration is not None else None + + id_live_preview = req.id_live_preview + shared.state.set_current_image() + if opts.live_previews_enable and shared.state.id_live_preview != req.id_live_preview: + image = shared.state.current_image + if image is not None: + buffered = io.BytesIO() + image.save(buffered, format="png") + live_preview = 'data:image/png;base64,' + base64.b64encode(buffered.getvalue()).decode("ascii") + id_live_preview = shared.state.id_live_preview + else: + live_preview = None + else: + live_preview = None + + return ProgressResponse(active=active, queued=queued, completed=completed, progress=progress, eta=eta, live_preview=live_preview, id_live_preview=id_live_preview, textinfo=shared.state.textinfo) + diff --git a/modules/prompt_parser.py b/modules/prompt_parser.py index 870218db..69665372 100644 --- a/modules/prompt_parser.py +++ b/modules/prompt_parser.py @@ -274,6 +274,7 @@ re_attention = re.compile(r""" : """, re.X) +re_break = re.compile(r"\s*\bBREAK\b\s*", re.S) def parse_prompt_attention(text): """ @@ -339,7 +340,11 @@ def parse_prompt_attention(text): elif text == ']' and len(square_brackets) > 0: multiply_range(square_brackets.pop(), square_bracket_multiplier) else: - res.append([text, 1.0]) + parts = re.split(re_break, text) + for i, part in enumerate(parts): + if i > 0: + res.append(["BREAK", -1]) + res.append([part, 1.0]) for pos in round_brackets: multiply_range(pos, round_bracket_multiplier) diff --git a/modules/realesrgan_model.py b/modules/realesrgan_model.py index 3ac0b97a..47f70251 100644 --- a/modules/realesrgan_model.py +++ b/modules/realesrgan_model.py @@ -38,13 +38,13 @@ class UpscalerRealESRGAN(Upscaler): return img info = self.load_model(path) - if not os.path.exists(info.data_path): + if not os.path.exists(info.local_data_path): print("Unable to load RealESRGAN model: %s" % info.name) return img upsampler = RealESRGANer( scale=info.scale, - model_path=info.data_path, + model_path=info.local_data_path, model=info.model(), half=not cmd_opts.no_half, tile=opts.ESRGAN_tile, @@ -58,17 +58,13 @@ class UpscalerRealESRGAN(Upscaler): def load_model(self, path): try: - info = None - for scaler in self.scalers: - if scaler.data_path == path: - info = scaler + info = next(iter([scaler for scaler in self.scalers if scaler.data_path == path]), None) if info is None: print(f"Unable to find model info: {path}") return None - model_file = load_file_from_url(url=info.data_path, model_dir=self.model_path, progress=True) - info.data_path = model_file + info.local_data_path = load_file_from_url(url=info.data_path, model_dir=self.model_path, progress=True) return info except Exception as e: print(f"Error making Real-ESRGAN models list: {e}", file=sys.stderr) diff --git a/modules/script_callbacks.py b/modules/script_callbacks.py index a9e19236..4bb45ec7 100644 --- a/modules/script_callbacks.py +++ b/modules/script_callbacks.py @@ -73,6 +73,7 @@ callback_map = dict( callbacks_image_grid=[], callbacks_infotext_pasted=[], callbacks_script_unloaded=[], + callbacks_before_ui=[], ) @@ -189,6 +190,14 @@ def script_unloaded_callback(): report_exception(c, 'script_unloaded') +def before_ui_callback(): + for c in reversed(callback_map['callbacks_before_ui']): + try: + c.callback() + except Exception: + report_exception(c, 'before_ui') + + def add_callback(callbacks, fun): stack = [x for x in inspect.stack() if x.filename != __file__] filename = stack[0].filename if len(stack) > 0 else 'unknown file' @@ -313,3 +322,9 @@ def on_script_unloaded(callback): the script did should be reverted here""" add_callback(callback_map['callbacks_script_unloaded'], callback) + + +def on_before_ui(callback): + """register a function to be called before the UI is created.""" + + add_callback(callback_map['callbacks_before_ui'], callback) diff --git a/modules/sd_disable_initialization.py b/modules/sd_disable_initialization.py index c72d8efc..e90aa9fe 100644 --- a/modules/sd_disable_initialization.py +++ b/modules/sd_disable_initialization.py @@ -41,7 +41,9 @@ class DisableInitialization: return self.create_model_and_transforms(*args, pretrained=None, **kwargs) def CLIPTextModel_from_pretrained(pretrained_model_name_or_path, *model_args, **kwargs): - return self.CLIPTextModel_from_pretrained(None, *model_args, config=pretrained_model_name_or_path, state_dict={}, **kwargs) + res = self.CLIPTextModel_from_pretrained(None, *model_args, config=pretrained_model_name_or_path, state_dict={}, **kwargs) + res.name_or_path = pretrained_model_name_or_path + return res def transformers_modeling_utils_load_pretrained_model(*args, **kwargs): args = args[0:3] + ('/', ) + args[4:] # resolved_archive_file; must set it to something to prevent what seems to be a bug diff --git a/modules/sd_hijack.py b/modules/sd_hijack.py index 6b0d95af..f9652d21 100644 --- a/modules/sd_hijack.py +++ b/modules/sd_hijack.py @@ -70,9 +70,10 @@ def undo_optimizations(): def fix_checkpoint(): - ldm.modules.attention.BasicTransformerBlock.forward = sd_hijack_checkpoint.BasicTransformerBlock_forward - ldm.modules.diffusionmodules.openaimodel.ResBlock.forward = sd_hijack_checkpoint.ResBlock_forward - ldm.modules.diffusionmodules.openaimodel.AttentionBlock.forward = sd_hijack_checkpoint.AttentionBlock_forward + """checkpoints are now added and removed in embedding/hypernet code, since torch doesn't want + checkpoints to be added when not training (there's a warning)""" + + pass class StableDiffusionModelHijack: @@ -106,8 +107,6 @@ class StableDiffusionModelHijack: self.optimization_method = apply_optimizations() self.clip = m.cond_stage_model - - fix_checkpoint() def flatten(el): flattened = [flatten(children) for children in el.children()] diff --git a/modules/sd_hijack_checkpoint.py b/modules/sd_hijack_checkpoint.py index 5712972f..2604d969 100644 --- a/modules/sd_hijack_checkpoint.py +++ b/modules/sd_hijack_checkpoint.py @@ -1,10 +1,46 @@ from torch.utils.checkpoint import checkpoint +import ldm.modules.attention +import ldm.modules.diffusionmodules.openaimodel + + def BasicTransformerBlock_forward(self, x, context=None): return checkpoint(self._forward, x, context) + def AttentionBlock_forward(self, x): return checkpoint(self._forward, x) + def ResBlock_forward(self, x, emb): - return checkpoint(self._forward, x, emb) \ No newline at end of file + return checkpoint(self._forward, x, emb) + + +stored = [] + + +def add(): + if len(stored) != 0: + return + + stored.extend([ + ldm.modules.attention.BasicTransformerBlock.forward, + ldm.modules.diffusionmodules.openaimodel.ResBlock.forward, + ldm.modules.diffusionmodules.openaimodel.AttentionBlock.forward + ]) + + ldm.modules.attention.BasicTransformerBlock.forward = BasicTransformerBlock_forward + ldm.modules.diffusionmodules.openaimodel.ResBlock.forward = ResBlock_forward + ldm.modules.diffusionmodules.openaimodel.AttentionBlock.forward = AttentionBlock_forward + + +def remove(): + if len(stored) == 0: + return + + ldm.modules.attention.BasicTransformerBlock.forward = stored[0] + ldm.modules.diffusionmodules.openaimodel.ResBlock.forward = stored[1] + ldm.modules.diffusionmodules.openaimodel.AttentionBlock.forward = stored[2] + + stored.clear() + diff --git a/modules/sd_hijack_clip.py b/modules/sd_hijack_clip.py index 852afc66..9fa5c5c5 100644 --- a/modules/sd_hijack_clip.py +++ b/modules/sd_hijack_clip.py @@ -96,13 +96,18 @@ class FrozenCLIPEmbedderWithCustomWordsBase(torch.nn.Module): token_count = 0 last_comma = -1 - def next_chunk(): - """puts current chunk into the list of results and produces the next one - empty""" + def next_chunk(is_last=False): + """puts current chunk into the list of results and produces the next one - empty; + if is_last is true, tokens tokens at the end won't add to token_count""" nonlocal token_count nonlocal last_comma nonlocal chunk - token_count += len(chunk.tokens) + if is_last: + token_count += len(chunk.tokens) + else: + token_count += self.chunk_length + to_add = self.chunk_length - len(chunk.tokens) if to_add > 0: chunk.tokens += [self.id_end] * to_add @@ -116,6 +121,10 @@ class FrozenCLIPEmbedderWithCustomWordsBase(torch.nn.Module): chunk = PromptChunk() for tokens, (text, weight) in zip(tokenized, parsed): + if text == 'BREAK' and weight == -1: + next_chunk() + continue + position = 0 while position < len(tokens): token = tokens[position] @@ -159,7 +168,7 @@ class FrozenCLIPEmbedderWithCustomWordsBase(torch.nn.Module): position += embedding_length_in_tokens if len(chunk.tokens) > 0 or len(chunks) == 0: - next_chunk() + next_chunk(is_last=True) return chunks, token_count diff --git a/modules/sd_hijack_optimizations.py b/modules/sd_hijack_optimizations.py index cdc63ed7..4fa54329 100644 --- a/modules/sd_hijack_optimizations.py +++ b/modules/sd_hijack_optimizations.py @@ -44,7 +44,7 @@ def split_cross_attention_forward_v1(self, x, context=None, mask=None): q_in = self.to_q(x) context = default(context, x) - context_k, context_v = hypernetwork.apply_hypernetwork(shared.loaded_hypernetwork, context) + context_k, context_v = hypernetwork.apply_hypernetworks(shared.loaded_hypernetworks, context) k_in = self.to_k(context_k) v_in = self.to_v(context_v) del context, context_k, context_v, x @@ -78,7 +78,7 @@ def split_cross_attention_forward(self, x, context=None, mask=None): q_in = self.to_q(x) context = default(context, x) - context_k, context_v = hypernetwork.apply_hypernetwork(shared.loaded_hypernetwork, context) + context_k, context_v = hypernetwork.apply_hypernetworks(shared.loaded_hypernetworks, context) k_in = self.to_k(context_k) v_in = self.to_v(context_v) @@ -203,7 +203,7 @@ def split_cross_attention_forward_invokeAI(self, x, context=None, mask=None): q = self.to_q(x) context = default(context, x) - context_k, context_v = hypernetwork.apply_hypernetwork(shared.loaded_hypernetwork, context) + context_k, context_v = hypernetwork.apply_hypernetworks(shared.loaded_hypernetworks, context) k = self.to_k(context_k) * self.scale v = self.to_v(context_v) del context, context_k, context_v, x @@ -225,7 +225,7 @@ def sub_quad_attention_forward(self, x, context=None, mask=None): q = self.to_q(x) context = default(context, x) - context_k, context_v = hypernetwork.apply_hypernetwork(shared.loaded_hypernetwork, context) + context_k, context_v = hypernetwork.apply_hypernetworks(shared.loaded_hypernetworks, context) k = self.to_k(context_k) v = self.to_v(context_v) del context, context_k, context_v, x @@ -284,7 +284,7 @@ def xformers_attention_forward(self, x, context=None, mask=None): q_in = self.to_q(x) context = default(context, x) - context_k, context_v = hypernetwork.apply_hypernetwork(shared.loaded_hypernetwork, context) + context_k, context_v = hypernetwork.apply_hypernetworks(shared.loaded_hypernetworks, context) k_in = self.to_k(context_k) v_in = self.to_v(context_v) diff --git a/modules/sd_models.py b/modules/sd_models.py index 6a681cef..12083848 100644 --- a/modules/sd_models.py +++ b/modules/sd_models.py @@ -41,14 +41,16 @@ class CheckpointInfo: if name.startswith("\\") or name.startswith("/"): name = name[1:] - self.title = name + self.name = name self.model_name = os.path.splitext(name.replace("/", "_").replace("\\", "_"))[0] self.hash = model_hash(filename) - self.sha256 = hashes.sha256_from_cache(self.filename, "checkpoint/" + self.title) + self.sha256 = hashes.sha256_from_cache(self.filename, "checkpoint/" + name) self.shorthash = self.sha256[0:10] if self.sha256 else None - self.ids = [self.hash, self.model_name, self.title, f'{name} [{self.hash}]'] + ([self.shorthash, self.sha256] if self.shorthash else []) + self.title = name if self.shorthash is None else f'{name} [{self.shorthash}]' + + self.ids = [self.hash, self.model_name, self.title, name, f'{name} [{self.hash}]'] + ([self.shorthash, self.sha256, f'{self.name} [{self.shorthash}]'] if self.shorthash else []) def register(self): checkpoints_list[self.title] = self @@ -56,13 +58,15 @@ class CheckpointInfo: checkpoint_alisases[id] = self def calculate_shorthash(self): - self.sha256 = hashes.sha256(self.filename, "checkpoint/" + self.title) + self.sha256 = hashes.sha256(self.filename, "checkpoint/" + self.name) self.shorthash = self.sha256[0:10] if self.shorthash not in self.ids: self.ids += [self.shorthash, self.sha256] self.register() + self.title = f'{self.name} [{self.shorthash}]' + return self.shorthash @@ -225,7 +229,10 @@ def read_state_dict(checkpoint_file, print_global_state=False, map_location=None def load_model_weights(model, checkpoint_info: CheckpointInfo): + title = checkpoint_info.title sd_model_hash = checkpoint_info.calculate_shorthash() + if checkpoint_info.title != title: + shared.opts.data["sd_model_checkpoint"] = checkpoint_info.title cache_enabled = shared.opts.sd_checkpoint_cache > 0 diff --git a/modules/sd_samplers.py b/modules/sd_samplers.py index 7616fded..6261d1f7 100644 --- a/modules/sd_samplers.py +++ b/modules/sd_samplers.py @@ -140,7 +140,7 @@ def store_latent(decoded): if opts.live_previews_enable and opts.show_progress_every_n_steps > 0 and shared.state.sampling_step % opts.show_progress_every_n_steps == 0: if not shared.parallel_processing_allowed: - shared.state.current_image = sample_to_image(decoded) + shared.state.assign_current_image(sample_to_image(decoded)) class InterruptedException(BaseException): @@ -351,6 +351,8 @@ class CFGDenoiser(torch.nn.Module): x_out[-uncond.shape[0]:] = self.inner_model(x_in[-uncond.shape[0]:], sigma_in[-uncond.shape[0]:], cond={"c_crossattn": [uncond], "c_concat": [image_cond_in[-uncond.shape[0]:]]}) + devices.test_for_nans(x_out, "unet") + if opts.live_preview_content == "Prompt": store_latent(x_out[0:uncond.shape[0]]) elif opts.live_preview_content == "Negative prompt": diff --git a/modules/sd_vae.py b/modules/sd_vae.py index add5cecf..4ce238b8 100644 --- a/modules/sd_vae.py +++ b/modules/sd_vae.py @@ -72,6 +72,13 @@ def refresh_vae_list(): os.path.join(shared.cmd_opts.ckpt_dir, '**/*.vae.safetensors'), ] + if shared.cmd_opts.vae_dir is not None and os.path.isdir(shared.cmd_opts.vae_dir): + paths += [ + os.path.join(shared.cmd_opts.vae_dir, '**/*.ckpt'), + os.path.join(shared.cmd_opts.vae_dir, '**/*.pt'), + os.path.join(shared.cmd_opts.vae_dir, '**/*.safetensors'), + ] + candidates = [] for path in paths: candidates += glob.iglob(path, recursive=True) @@ -94,8 +101,10 @@ def resolve_vae(checkpoint_file): if shared.cmd_opts.vae_path is not None: return shared.cmd_opts.vae_path, 'from commandline argument' + is_automatic = shared.opts.sd_vae in {"Automatic", "auto"} # "auto" for people with old config + vae_near_checkpoint = find_vae_near_checkpoint(checkpoint_file) - if vae_near_checkpoint is not None and (shared.opts.sd_vae_as_default or shared.opts.sd_vae == "Automatic"): + if vae_near_checkpoint is not None and (shared.opts.sd_vae_as_default or is_automatic): return vae_near_checkpoint, 'found near the checkpoint' if shared.opts.sd_vae == "None": @@ -105,12 +114,18 @@ def resolve_vae(checkpoint_file): if vae_from_options is not None: return vae_from_options, 'specified in settings' - if shared.opts.sd_vae != "Automatic": + if not is_automatic: print(f"Couldn't find VAE named {shared.opts.sd_vae}; using None instead") return None, None +def load_vae_dict(filename, map_location): + vae_ckpt = sd_models.read_state_dict(filename, map_location=map_location) + vae_dict_1 = {k: v for k, v in vae_ckpt.items() if k[0:4] != "loss" and k not in vae_ignore_keys} + return vae_dict_1 + + def load_vae(model, vae_file=None, vae_source="from unknown source"): global vae_dict, loaded_vae_file # save_settings = False @@ -128,8 +143,7 @@ def load_vae(model, vae_file=None, vae_source="from unknown source"): print(f"Loading VAE weights {vae_source}: {vae_file}") store_base_vae(model) - vae_ckpt = sd_models.read_state_dict(vae_file, map_location=shared.weight_load_location) - vae_dict_1 = {k: v for k, v in vae_ckpt.items() if k[0:4] != "loss" and k not in vae_ignore_keys} + vae_dict_1 = load_vae_dict(vae_file, map_location=shared.weight_load_location) _load_vae_dict(model, vae_dict_1) if cache_enabled: diff --git a/modules/sd_vae_approx.py b/modules/sd_vae_approx.py index 0a58542d..0027343a 100644 --- a/modules/sd_vae_approx.py +++ b/modules/sd_vae_approx.py @@ -36,7 +36,7 @@ def model(): if sd_vae_approx_model is None: sd_vae_approx_model = VAEApprox() - sd_vae_approx_model.load_state_dict(torch.load(os.path.join(paths.models_path, "VAE-approx", "model.pt"))) + sd_vae_approx_model.load_state_dict(torch.load(os.path.join(paths.models_path, "VAE-approx", "model.pt"), map_location='cpu' if devices.device.type != 'cuda' else None)) sd_vae_approx_model.eval() sd_vae_approx_model.to(devices.device, devices.dtype) diff --git a/modules/shared.py b/modules/shared.py index 9756adea..cd78e50a 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -9,7 +9,6 @@ from PIL import Image import gradio as gr import tqdm -import modules.artists import modules.interrogate import modules.memmon import modules.styles @@ -20,12 +19,15 @@ from modules.paths import models_path, script_path, sd_path demo = None +sd_default_config = os.path.join(script_path, "configs/v1-inference.yaml") sd_model_file = os.path.join(script_path, 'model.ckpt') default_sd_model_file = sd_model_file + parser = argparse.ArgumentParser() -parser.add_argument("--config", type=str, default=os.path.join(script_path, "configs/v1-inference.yaml"), help="path to config which constructs model",) +parser.add_argument("--config", type=str, default=sd_default_config, help="path to config which constructs model",) parser.add_argument("--ckpt", type=str, default=sd_model_file, help="path to checkpoint of stable diffusion model; if specified, this checkpoint will be added to the list of checkpoints and loaded",) parser.add_argument("--ckpt-dir", type=str, default=None, help="Path to directory with stable diffusion checkpoints") +parser.add_argument("--vae-dir", type=str, default=None, help="Path to directory with VAE files") parser.add_argument("--gfpgan-dir", type=str, help="GFPGAN directory", default=('./src/gfpgan' if os.path.exists('./src/gfpgan') else './GFPGAN')) parser.add_argument("--gfpgan-model", type=str, help="GFPGAN model file name", default=None) parser.add_argument("--no-half", action='store_true', help="do not switch the model to 16-bit floats") @@ -64,6 +66,7 @@ parser.add_argument("--sub-quad-chunk-threshold", type=int, help="the percentage parser.add_argument("--opt-split-attention-invokeai", action='store_true', help="force-enables InvokeAI's cross-attention layer optimization. By default, it's on when cuda is unavailable.") parser.add_argument("--opt-split-attention-v1", action='store_true', help="enable older version of split attention optimization that does not consume all the VRAM it can find") parser.add_argument("--disable-opt-split-attention", action='store_true', help="force-disables cross-attention layer optimization") +parser.add_argument("--disable-nan-check", action='store_true', help="do not check if produced images/latent spaces have nans; useful for running without a checkpoint in CI") parser.add_argument("--use-cpu", nargs='+', help="use CPU as torch device for specified modules", default=[], type=str.lower) parser.add_argument("--listen", action='store_true', help="launch gradio with 0.0.0.0 as server name, allowing to respond to network requests") parser.add_argument("--port", type=int, help="launch gradio with given server port, you need root/admin rights for ports < 1024, defaults to 7860 if available", default=None) @@ -97,6 +100,8 @@ parser.add_argument("--cors-allow-origins-regex", type=str, help="Allowed CORS o parser.add_argument("--tls-keyfile", type=str, help="Partially enables TLS, requires --tls-certfile to fully function", default=None) parser.add_argument("--tls-certfile", type=str, help="Partially enables TLS, requires --tls-keyfile to fully function", default=None) parser.add_argument("--server-name", type=str, help="Sets hostname of server", default=None) +parser.add_argument("--gradio-queue", action='store_true', help="Uses gradio queue; experimental option; breaks restart UI button") + script_loading.preload_extensions(extensions.extensions_dir, parser) script_loading.preload_extensions(extensions.extensions_builtin_dir, parser) @@ -116,6 +121,7 @@ restricted_opts = { } ui_reorder_categories = [ + "inpaint", "sampler", "dimensions", "cfg", @@ -141,7 +147,7 @@ config_filename = cmd_opts.ui_settings_file os.makedirs(cmd_opts.hypernetwork_dir, exist_ok=True) hypernetworks = {} -loaded_hypernetwork = None +loaded_hypernetworks = [] def reload_hypernetworks(): @@ -149,7 +155,6 @@ def reload_hypernetworks(): global hypernetworks hypernetworks = hypernetwork.list_hypernetworks(cmd_opts.hypernetwork_dir) - hypernetwork.load_hypernetwork(opts.sd_hypernetwork) class State: @@ -165,9 +170,11 @@ class State: current_latent = None current_image = None current_image_sampling_step = 0 + id_live_preview = 0 textinfo = None time_start = None need_restart = False + server_start = None def skip(self): self.skipped = True @@ -206,6 +213,7 @@ class State: self.current_latent = None self.current_image = None self.current_image_sampling_step = 0 + self.id_live_preview = 0 self.skipped = False self.interrupted = False self.textinfo = None @@ -219,12 +227,12 @@ class State: devices.torch_gc() - """sets self.current_image from self.current_latent if enough sampling steps have been made after the last call to this""" def set_current_image(self): + """sets self.current_image from self.current_latent if enough sampling steps have been made after the last call to this""" if not parallel_processing_allowed: return - if self.sampling_step - self.current_image_sampling_step >= opts.show_progress_every_n_steps and opts.live_previews_enable: + if self.sampling_step - self.current_image_sampling_step >= opts.show_progress_every_n_steps and opts.live_previews_enable and opts.show_progress_every_n_steps != -1: self.do_set_current_image() def do_set_current_image(self): @@ -233,16 +241,19 @@ class State: import modules.sd_samplers if opts.show_progress_grid: - self.current_image = modules.sd_samplers.samples_to_image_grid(self.current_latent) + self.assign_current_image(modules.sd_samplers.samples_to_image_grid(self.current_latent)) else: - self.current_image = modules.sd_samplers.sample_to_image(self.current_latent) + self.assign_current_image(modules.sd_samplers.sample_to_image(self.current_latent)) self.current_image_sampling_step = self.sampling_step + def assign_current_image(self, image): + self.current_image = image + self.id_live_preview += 1 + state = State() - -artist_db = modules.artists.ArtistsDatabase(os.path.join(script_path, 'artists.csv')) +state.server_start = time.time() styles_filename = cmd_opts.styles_file prompt_styles = modules.styles.StyleDatabase(styles_filename) @@ -358,6 +369,7 @@ options_templates.update(options_section(('face-restoration', "Face restoration" })) options_templates.update(options_section(('system', "System"), { + "show_warnings": OptionInfo(False, "Show warnings in console."), "memmon_poll_rate": OptionInfo(8, "VRAM usage polls per second during generation. Set to 0 to disable.", gr.Slider, {"minimum": 0, "maximum": 40, "step": 1}), "samples_log_stdout": OptionInfo(False, "Always print all generation info to standard output"), "multiple_tqdm": OptionInfo(True, "Add a second progress bar to the console that shows progress for an entire job."), @@ -384,11 +396,9 @@ options_templates.update(options_section(('sd', "Stable Diffusion"), { "sd_checkpoint_cache": OptionInfo(0, "Checkpoints to cache in RAM", gr.Slider, {"minimum": 0, "maximum": 10, "step": 1}), "sd_vae_checkpoint_cache": OptionInfo(0, "VAE Checkpoints to cache in RAM", gr.Slider, {"minimum": 0, "maximum": 10, "step": 1}), "sd_vae": OptionInfo("Automatic", "SD VAE", gr.Dropdown, lambda: {"choices": ["Automatic", "None"] + list(sd_vae.vae_dict)}, refresh=sd_vae.refresh_vae_list), - "sd_vae_as_default": OptionInfo(False, "Ignore selected VAE for stable diffusion checkpoints that have their own .vae.pt next to them"), - "sd_hypernetwork": OptionInfo("None", "Hypernetwork", gr.Dropdown, lambda: {"choices": ["None"] + [x for x in hypernetworks.keys()]}, refresh=reload_hypernetworks), - "sd_hypernetwork_strength": OptionInfo(1.0, "Hypernetwork strength", gr.Slider, {"minimum": 0.0, "maximum": 1.0, "step": 0.001}), + "sd_vae_as_default": OptionInfo(True, "Ignore selected VAE for stable diffusion checkpoints that have their own .vae.pt next to them"), "inpainting_mask_weight": OptionInfo(1.0, "Inpainting conditioning mask strength", gr.Slider, {"minimum": 0.0, "maximum": 1.0, "step": 0.01}), - "initial_noise_multiplier": OptionInfo(1.0, "Noise multiplier for img2img", gr.Slider, {"minimum": 0.5, "maximum": 1.5, "step": 0.01 }), + "initial_noise_multiplier": OptionInfo(1.0, "Noise multiplier for img2img", gr.Slider, {"minimum": 0.5, "maximum": 1.5, "step": 0.01}), "img2img_color_correction": OptionInfo(False, "Apply color correction to img2img results to match original colors."), "img2img_fix_steps": OptionInfo(False, "With img2img, do exactly the amount of steps the slider specifies (normally you'd do less with less denoising)."), "img2img_background_color": OptionInfo("#ffffff", "With img2img, fill image's transparent parts with this color.", ui_components.FormColorPicker, {}), @@ -396,8 +406,8 @@ options_templates.update(options_section(('sd', "Stable Diffusion"), { "enable_emphasis": OptionInfo(True, "Emphasis: use (text) to make model pay more attention to text and [text] to make it pay less attention"), "enable_batch_seeds": OptionInfo(True, "Make K-diffusion samplers produce same images in a batch as when making a single image"), "comma_padding_backtrack": OptionInfo(20, "Increase coherency by padding from the last comma within n tokens when using more than 75 tokens", gr.Slider, {"minimum": 0, "maximum": 74, "step": 1 }), - 'CLIP_stop_at_last_layers': OptionInfo(1, "Clip skip", gr.Slider, {"minimum": 1, "maximum": 12, "step": 1}), - "random_artist_categories": OptionInfo([], "Allowed categories for random artists selection when using the Roll button", gr.CheckboxGroup, {"choices": artist_db.categories()}), + "CLIP_stop_at_last_layers": OptionInfo(1, "Clip skip", gr.Slider, {"minimum": 1, "maximum": 12, "step": 1}), + "extra_networks_default_multiplier": OptionInfo(1.0, "Multiplier for extra networks", gr.Slider, {"minimum": 0.0, "maximum": 1.0, "step": 0.01}), })) options_templates.update(options_section(('compatibility', "Compatibility"), { @@ -408,7 +418,6 @@ options_templates.update(options_section(('compatibility', "Compatibility"), { options_templates.update(options_section(('interrogate', "Interrogate Options"), { "interrogate_keep_models_in_memory": OptionInfo(False, "Interrogate: keep models in VRAM"), - "interrogate_use_builtin_artists": OptionInfo(True, "Interrogate: use artists from artists.csv"), "interrogate_return_ranks": OptionInfo(False, "Interrogate: include ranks of model tags matches in results (Has no effect on caption-based interrogators)."), "interrogate_clip_num_beams": OptionInfo(1, "Interrogate: num_beams for BLIP", gr.Slider, {"minimum": 1, "maximum": 16, "step": 1}), "interrogate_clip_min_length": OptionInfo(24, "Interrogate: minimum description length (excluding artists, etc..)", gr.Slider, {"minimum": 1, "maximum": 128, "step": 1}), @@ -422,8 +431,6 @@ options_templates.update(options_section(('interrogate', "Interrogate Options"), })) options_templates.update(options_section(('ui', "User interface"), { - "show_progressbar": OptionInfo(True, "Show progressbar"), - "show_progress_grid": OptionInfo(True, "Show previews of all images generated in a batch as a grid"), "return_grid": OptionInfo(True, "Show grid in results for web"), "do_not_show_images": OptionInfo(False, "Do not show any images in results for web"), "add_model_hash_to_info": OptionInfo(True, "Add model hash to generation information"), @@ -436,17 +443,23 @@ options_templates.update(options_section(('ui', "User interface"), { "js_modal_lightbox_initially_zoomed": OptionInfo(True, "Show images zoomed in by default in full page image viewer"), "show_progress_in_title": OptionInfo(True, "Show generation progress in window title."), "samplers_in_dropdown": OptionInfo(True, "Use dropdown for sampler selection instead of radio group"), - "dimensions_and_batch_together": OptionInfo(True, "Show Witdth/Height and Batch sliders in same row"), - 'quicksettings': OptionInfo("sd_model_checkpoint", "Quicksettings list"), - 'ui_reorder': OptionInfo(", ".join(ui_reorder_categories), "txt2img/img2img UI item order"), - 'localization': OptionInfo("None", "Localization (requires restart)", gr.Dropdown, lambda: {"choices": ["None"] + list(localization.localizations.keys())}, refresh=lambda: localization.list_localizations(cmd_opts.localizations_dir)), + "dimensions_and_batch_together": OptionInfo(True, "Show Width/Height and Batch sliders in same row"), + "keyedit_precision_attention": OptionInfo(0.1, "Ctrl+up/down precision when editing (attention:1.1)", gr.Slider, {"minimum": 0.01, "maximum": 0.2, "step": 0.001}), + "keyedit_precision_extra": OptionInfo(0.05, "Ctrl+up/down precision when editing ", gr.Slider, {"minimum": 0.01, "maximum": 0.2, "step": 0.001}), + "quicksettings": OptionInfo("sd_model_checkpoint", "Quicksettings list"), + "ui_reorder": OptionInfo(", ".join(ui_reorder_categories), "txt2img/img2img UI item order"), + "ui_extra_networks_tab_reorder": OptionInfo("", "Extra networks tab order"), + "localization": OptionInfo("None", "Localization (requires restart)", gr.Dropdown, lambda: {"choices": ["None"] + list(localization.localizations.keys())}, refresh=lambda: localization.list_localizations(cmd_opts.localizations_dir)), })) options_templates.update(options_section(('ui', "Live previews"), { + "show_progressbar": OptionInfo(True, "Show progressbar"), "live_previews_enable": OptionInfo(True, "Show live previews of the created image"), + "show_progress_grid": OptionInfo(True, "Show previews of all images generated in a batch as a grid"), "show_progress_every_n_steps": OptionInfo(10, "Show new live preview image every N sampling steps. Set to -1 to show after completion of batch.", gr.Slider, {"minimum": -1, "maximum": 32, "step": 1}), "show_progress_type": OptionInfo("Approx NN", "Image creation progress preview mode", gr.Radio, {"choices": ["Full", "Approx NN", "Approx cheap"]}), "live_preview_content": OptionInfo("Prompt", "Live preview subject", gr.Radio, {"choices": ["Combined", "Prompt", "Negative prompt"]}), + "live_preview_refresh_period": OptionInfo(1000, "Progressbar/preview update period, in milliseconds") })) options_templates.update(options_section(('sampler-params', "Sampler parameters"), { @@ -646,3 +659,17 @@ mem_mon.start() def listfiles(dirname): filenames = [os.path.join(dirname, x) for x in sorted(os.listdir(dirname)) if not x.startswith(".")] return [file for file in filenames if os.path.isfile(file)] + + +def html_path(filename): + return os.path.join(script_path, "html", filename) + + +def html(filename): + path = html_path(filename) + + if os.path.exists(path): + with open(path, encoding="utf8") as file: + return file.read() + + return "" diff --git a/modules/styles.py b/modules/styles.py index ce6e71ca..990d5623 100644 --- a/modules/styles.py +++ b/modules/styles.py @@ -40,12 +40,18 @@ def apply_styles_to_prompt(prompt, styles): class StyleDatabase: def __init__(self, path: str): self.no_style = PromptStyle("None", "", "") - self.styles = {"None": self.no_style} + self.styles = {} + self.path = path - if not os.path.exists(path): + self.reload() + + def reload(self): + self.styles.clear() + + if not os.path.exists(self.path): return - with open(path, "r", encoding="utf-8-sig", newline='') as file: + with open(self.path, "r", encoding="utf-8-sig", newline='') as file: reader = csv.DictReader(file) for row in reader: # Support loading old CSV format with "name, text"-columns diff --git a/modules/textual_inversion/logging.py b/modules/textual_inversion/logging.py index 31e50b64..734a4b6f 100644 --- a/modules/textual_inversion/logging.py +++ b/modules/textual_inversion/logging.py @@ -2,7 +2,7 @@ import datetime import json import os -saved_params_shared = {"model_name", "model_hash", "initial_step", "num_of_dataset_images", "learn_rate", "batch_size", "clip_grad_mode", "clip_grad_value", "gradient_step", "data_root", "log_directory", "training_width", "training_height", "steps", "create_image_every", "template_file"} +saved_params_shared = {"model_name", "model_hash", "initial_step", "num_of_dataset_images", "learn_rate", "batch_size", "clip_grad_mode", "clip_grad_value", "gradient_step", "data_root", "log_directory", "training_width", "training_height", "steps", "create_image_every", "template_file", "gradient_step", "latent_sampling_method"} saved_params_ti = {"embedding_name", "num_vectors_per_token", "save_embedding_every", "save_image_with_stored_embedding"} saved_params_hypernet = {"hypernetwork_name", "layer_structure", "activation_func", "weight_init", "add_layer_norm", "use_dropout", "save_hypernetwork_every"} saved_params_all = saved_params_shared | saved_params_ti | saved_params_hypernet diff --git a/modules/textual_inversion/preprocess.py b/modules/textual_inversion/preprocess.py index 3c1042ad..c0ac11d3 100644 --- a/modules/textual_inversion/preprocess.py +++ b/modules/textual_inversion/preprocess.py @@ -12,7 +12,7 @@ from modules.shared import opts, cmd_opts from modules.textual_inversion import autocrop -def preprocess(process_src, process_dst, process_width, process_height, preprocess_txt_action, process_flip, process_split, process_caption, process_caption_deepbooru=False, split_threshold=0.5, overlap_ratio=0.2, process_focal_crop=False, process_focal_crop_face_weight=0.9, process_focal_crop_entropy_weight=0.3, process_focal_crop_edges_weight=0.5, process_focal_crop_debug=False): +def preprocess(id_task, process_src, process_dst, process_width, process_height, preprocess_txt_action, process_flip, process_split, process_caption, process_caption_deepbooru=False, split_threshold=0.5, overlap_ratio=0.2, process_focal_crop=False, process_focal_crop_face_weight=0.9, process_focal_crop_entropy_weight=0.3, process_focal_crop_edges_weight=0.5, process_focal_crop_debug=False, process_multicrop=None, process_multicrop_mindim=None, process_multicrop_maxdim=None, process_multicrop_minarea=None, process_multicrop_maxarea=None, process_multicrop_objective=None, process_multicrop_threshold=None): try: if process_caption: shared.interrogator.load() @@ -20,7 +20,7 @@ def preprocess(process_src, process_dst, process_width, process_height, preproce if process_caption_deepbooru: deepbooru.model.start() - preprocess_work(process_src, process_dst, process_width, process_height, preprocess_txt_action, process_flip, process_split, process_caption, process_caption_deepbooru, split_threshold, overlap_ratio, process_focal_crop, process_focal_crop_face_weight, process_focal_crop_entropy_weight, process_focal_crop_edges_weight, process_focal_crop_debug) + preprocess_work(process_src, process_dst, process_width, process_height, preprocess_txt_action, process_flip, process_split, process_caption, process_caption_deepbooru, split_threshold, overlap_ratio, process_focal_crop, process_focal_crop_face_weight, process_focal_crop_entropy_weight, process_focal_crop_edges_weight, process_focal_crop_debug, process_multicrop, process_multicrop_mindim, process_multicrop_maxdim, process_multicrop_minarea, process_multicrop_maxarea, process_multicrop_objective, process_multicrop_threshold) finally: @@ -109,8 +109,30 @@ def split_pic(image, inverse_xy, width, height, overlap_ratio): splitted = image.crop((0, y, to_w, y + to_h)) yield splitted +# not using torchvision.transforms.CenterCrop because it doesn't allow float regions +def center_crop(image: Image, w: int, h: int): + iw, ih = image.size + if ih / h < iw / w: + sw = w * ih / h + box = (iw - sw) / 2, 0, iw - (iw - sw) / 2, ih + else: + sh = h * iw / w + box = 0, (ih - sh) / 2, iw, ih - (ih - sh) / 2 + return image.resize((w, h), Image.Resampling.LANCZOS, box) -def preprocess_work(process_src, process_dst, process_width, process_height, preprocess_txt_action, process_flip, process_split, process_caption, process_caption_deepbooru=False, split_threshold=0.5, overlap_ratio=0.2, process_focal_crop=False, process_focal_crop_face_weight=0.9, process_focal_crop_entropy_weight=0.3, process_focal_crop_edges_weight=0.5, process_focal_crop_debug=False): + +def multicrop_pic(image: Image, mindim, maxdim, minarea, maxarea, objective, threshold): + iw, ih = image.size + err = lambda w, h: 1-(lambda x: x if x < 1 else 1/x)(iw/ih/(w/h)) + wh = max(((w, h) for w in range(mindim, maxdim+1, 64) for h in range(mindim, maxdim+1, 64) + if minarea <= w * h <= maxarea and err(w, h) <= threshold), + key= lambda wh: (wh[0]*wh[1], -err(*wh))[::1 if objective=='Maximize area' else -1], + default=None + ) + return wh and center_crop(image, *wh) + + +def preprocess_work(process_src, process_dst, process_width, process_height, preprocess_txt_action, process_flip, process_split, process_caption, process_caption_deepbooru=False, split_threshold=0.5, overlap_ratio=0.2, process_focal_crop=False, process_focal_crop_face_weight=0.9, process_focal_crop_entropy_weight=0.3, process_focal_crop_edges_weight=0.5, process_focal_crop_debug=False, process_multicrop=None, process_multicrop_mindim=None, process_multicrop_maxdim=None, process_multicrop_minarea=None, process_multicrop_maxarea=None, process_multicrop_objective=None, process_multicrop_threshold=None): width = process_width height = process_height src = os.path.abspath(process_src) @@ -194,6 +216,14 @@ def preprocess_work(process_src, process_dst, process_width, process_height, pre save_pic(focal, index, params, existing_caption=existing_caption) process_default_resize = False + if process_multicrop: + cropped = multicrop_pic(img, process_multicrop_mindim, process_multicrop_maxdim, process_multicrop_minarea, process_multicrop_maxarea, process_multicrop_objective, process_multicrop_threshold) + if cropped is not None: + save_pic(cropped, index, params, existing_caption=existing_caption) + else: + print(f"skipped {img.width}x{img.height} image {filename} (can't find suitable size within error threshold)") + process_default_resize = False + if process_default_resize: img = images.resize_image(1, img, width, height) save_pic(img, index, params, existing_caption=existing_caption) diff --git a/modules/textual_inversion/textual_inversion.py b/modules/textual_inversion/textual_inversion.py index 63935878..4e90f690 100644 --- a/modules/textual_inversion/textual_inversion.py +++ b/modules/textual_inversion/textual_inversion.py @@ -15,7 +15,7 @@ import numpy as np from PIL import Image, PngImagePlugin from torch.utils.tensorboard import SummaryWriter -from modules import shared, devices, sd_hijack, processing, sd_models, images, sd_samplers +from modules import shared, devices, sd_hijack, processing, sd_models, images, sd_samplers, sd_hijack_checkpoint import modules.textual_inversion.dataset from modules.textual_inversion.learn_schedule import LearnRateScheduler @@ -50,6 +50,7 @@ class Embedding: self.sd_checkpoint = None self.sd_checkpoint_name = None self.optimizer_state_dict = None + self.filename = None def save(self, filename): embedding_data = { @@ -182,6 +183,7 @@ class EmbeddingDatabase: embedding.sd_checkpoint_name = data.get('sd_checkpoint_name', None) embedding.vectors = vec.shape[0] embedding.shape = vec.shape[-1] + embedding.filename = path if self.expected_shape == -1 or self.expected_shape == embedding.shape: self.register_embedding(embedding, shared.sd_model) @@ -345,7 +347,7 @@ def validate_train_inputs(model_name, learn_rate, batch_size, gradient_step, dat assert log_directory, "Log directory is empty" -def train_embedding(embedding_name, learn_rate, batch_size, gradient_step, data_root, log_directory, training_width, training_height, varsize, steps, clip_grad_mode, clip_grad_value, shuffle_tags, tag_drop_out, latent_sampling_method, create_image_every, save_embedding_every, template_filename, save_image_with_stored_embedding, preview_from_txt2img, preview_prompt, preview_negative_prompt, preview_steps, preview_sampler_index, preview_cfg_scale, preview_seed, preview_width, preview_height): +def train_embedding(id_task, embedding_name, learn_rate, batch_size, gradient_step, data_root, log_directory, training_width, training_height, varsize, steps, clip_grad_mode, clip_grad_value, shuffle_tags, tag_drop_out, latent_sampling_method, create_image_every, save_embedding_every, template_filename, save_image_with_stored_embedding, preview_from_txt2img, preview_prompt, preview_negative_prompt, preview_steps, preview_sampler_index, preview_cfg_scale, preview_seed, preview_width, preview_height): save_embedding_every = save_embedding_every or 0 create_image_every = create_image_every or 0 template_file = textual_inversion_templates.get(template_filename, None) @@ -452,6 +454,8 @@ def train_embedding(embedding_name, learn_rate, batch_size, gradient_step, data_ pbar = tqdm.tqdm(total=steps - initial_step) try: + sd_hijack_checkpoint.add() + for i in range((steps-initial_step) * gradient_step): if scheduler.finished: break @@ -510,7 +514,6 @@ def train_embedding(embedding_name, learn_rate, batch_size, gradient_step, data_ description = f"Training textual inversion [Epoch {epoch_num}: {epoch_step+1}/{steps_per_epoch}] loss: {loss_step:.7f}" pbar.set_description(description) - shared.state.textinfo = description if embedding_dir is not None and steps_done % save_embedding_every == 0: # Before saving, change name to match current checkpoint. embedding_name_every = f'{embedding_name}-{steps_done}' @@ -560,7 +563,8 @@ def train_embedding(embedding_name, learn_rate, batch_size, gradient_step, data_ shared.sd_model.first_stage_model.to(devices.cpu) if image is not None: - shared.state.current_image = image + shared.state.assign_current_image(image) + last_saved_image, last_text_info = images.save_image(image, images_dir, "", p.seed, p.prompt, shared.opts.samples_format, processed.infotexts[0], p=p, forced_filename=forced_filename, save_to_dirs=False) last_saved_image += f", prompt: {preview_text}" @@ -617,9 +621,11 @@ Last saved image: {html.escape(last_saved_image)}
pbar.close() shared.sd_model.first_stage_model.to(devices.device) shared.parallel_processing_allowed = old_parallel_processing_allowed + sd_hijack_checkpoint.remove() return embedding, filename + def save_embedding(embedding, optimizer, checkpoint, embedding_name, filename, remove_cached_checksum=True): old_embedding_name = embedding.name old_sd_checkpoint = embedding.sd_checkpoint if hasattr(embedding, "sd_checkpoint") else None diff --git a/modules/txt2img.py b/modules/txt2img.py index 38b5f591..e945fd69 100644 --- a/modules/txt2img.py +++ b/modules/txt2img.py @@ -8,13 +8,13 @@ import modules.processing as processing from modules.ui import plaintext_to_html -def txt2img(prompt: str, negative_prompt: str, prompt_style: str, prompt_style2: str, steps: int, sampler_index: int, restore_faces: bool, tiling: bool, n_iter: int, batch_size: int, cfg_scale: float, seed: int, subseed: int, subseed_strength: float, seed_resize_from_h: int, seed_resize_from_w: int, seed_enable_extras: bool, height: int, width: int, enable_hr: bool, denoising_strength: float, hr_scale: float, hr_upscaler: str, hr_second_pass_steps: int, hr_resize_x: int, hr_resize_y: int, *args): +def txt2img(id_task: str, prompt: str, negative_prompt: str, prompt_styles, steps: int, sampler_index: int, restore_faces: bool, tiling: bool, n_iter: int, batch_size: int, cfg_scale: float, seed: int, subseed: int, subseed_strength: float, seed_resize_from_h: int, seed_resize_from_w: int, seed_enable_extras: bool, height: int, width: int, enable_hr: bool, denoising_strength: float, hr_scale: float, hr_upscaler: str, hr_second_pass_steps: int, hr_resize_x: int, hr_resize_y: int, *args): p = StableDiffusionProcessingTxt2Img( sd_model=shared.sd_model, outpath_samples=opts.outdir_samples or opts.outdir_txt2img_samples, outpath_grids=opts.outdir_grids or opts.outdir_txt2img_grids, prompt=prompt, - styles=[prompt_style, prompt_style2], + styles=prompt_styles, negative_prompt=negative_prompt, seed=seed, subseed=subseed, diff --git a/modules/ui.py b/modules/ui.py index 2625ae32..eb4b7e6b 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -11,6 +11,7 @@ import tempfile import time import traceback from functools import partial, reduce +import warnings import gradio as gr import gradio.routes @@ -19,7 +20,7 @@ import numpy as np from PIL import Image, PngImagePlugin from modules.call_queue import wrap_gradio_gpu_call, wrap_queued_call, wrap_gradio_call -from modules import sd_hijack, sd_models, localization, script_callbacks, ui_extensions, deepbooru +from modules import sd_hijack, sd_models, localization, script_callbacks, ui_extensions, deepbooru, sd_vae, extra_networks from modules.ui_components import FormRow, FormGroup, ToolButton, FormHTML from modules.paths import script_path @@ -41,6 +42,8 @@ from modules.textual_inversion import textual_inversion import modules.hypernetworks.ui from modules.generation_parameters_copypaste import image_from_url_text +warnings.filterwarnings("default" if opts.show_warnings else "ignore", category=UserWarning) + # this is a fix for Windows users. Without it, javascript files will be served with text/html content-type and the browser will not show any UI mimetypes.init() mimetypes.add_type('application/javascript', '.js') @@ -72,6 +75,7 @@ css_hide_progressbar = """ .wrap .m-12::before { content:"Loading..." } .wrap .z-20 svg { display:none!important; } .wrap .z-20::before { content:"Loading..." } +.wrap.cover-bg .z-20::before { content:"" } .progress-bar { display:none!important; } .meta-text { display:none!important; } .meta-text-center { display:none!important; } @@ -87,6 +91,7 @@ refresh_symbol = '\U0001f504' # 🔄 save_style_symbol = '\U0001f4be' # 💾 apply_style_symbol = '\U0001f4cb' # 📋 clear_prompt_symbol = '\U0001F5D1' # 🗑️ +extra_networks_symbol = '\U0001F3B4' # 🎴 def plaintext_to_html(text): @@ -180,7 +185,7 @@ def add_style(name: str, prompt: str, negative_prompt: str): # reserialize all styles every time we save them shared.prompt_styles.save_styles(shared.styles_filename) - return [gr.Dropdown.update(visible=True, choices=list(shared.prompt_styles.styles)) for _ in range(4)] + return [gr.Dropdown.update(visible=True, choices=list(shared.prompt_styles.styles)) for _ in range(2)] def calc_resolution_hires(enable, width, height, hr_scale, hr_resize_x, hr_resize_y): @@ -197,22 +202,44 @@ def calc_resolution_hires(enable, width, height, hr_scale, hr_resize_x, hr_resiz return f"resize: from {p.width}x{p.height} to {p.hr_resize_x or p.hr_upscale_to_x}x{p.hr_resize_y or p.hr_upscale_to_y}" -def apply_styles(prompt, prompt_neg, style1_name, style2_name): - prompt = shared.prompt_styles.apply_styles_to_prompt(prompt, [style1_name, style2_name]) - prompt_neg = shared.prompt_styles.apply_negative_styles_to_prompt(prompt_neg, [style1_name, style2_name]) +def apply_styles(prompt, prompt_neg, styles): + prompt = shared.prompt_styles.apply_styles_to_prompt(prompt, styles) + prompt_neg = shared.prompt_styles.apply_negative_styles_to_prompt(prompt_neg, styles) - return [gr.Textbox.update(value=prompt), gr.Textbox.update(value=prompt_neg), gr.Dropdown.update(value="None"), gr.Dropdown.update(value="None")] + return [gr.Textbox.update(value=prompt), gr.Textbox.update(value=prompt_neg), gr.Dropdown.update(value=[])] + + +def process_interrogate(interrogation_function, mode, ii_input_dir, ii_output_dir, *ii_singles): + if mode in {0, 1, 3, 4}: + return [interrogation_function(ii_singles[mode]), None] + elif mode == 2: + return [interrogation_function(ii_singles[mode]["image"]), None] + elif mode == 5: + assert not shared.cmd_opts.hide_ui_dir_config, "Launched with --hide-ui-dir-config, batch img2img disabled" + images = shared.listfiles(ii_input_dir) + print(f"Will process {len(images)} images.") + if ii_output_dir != "": + os.makedirs(ii_output_dir, exist_ok=True) + else: + ii_output_dir = ii_input_dir + + for image in images: + img = Image.open(image) + filename = os.path.basename(image) + left, _ = os.path.splitext(filename) + print(interrogation_function(img), file=open(os.path.join(ii_output_dir, left + ".txt"), 'a')) + + return [gr.update(), None] def interrogate(image): prompt = shared.interrogator.interrogate(image.convert("RGB")) - - return gr_show(True) if prompt is None else prompt + return gr.update() if prompt is None else prompt def interrogate_deepbooru(image): prompt = deepbooru.model.tag(image) - return gr_show(True) if prompt is None else prompt + return gr.update() if prompt is None else prompt def create_seed_inputs(target_interface): @@ -299,6 +326,8 @@ def connect_reuse_seed(seed: gr.Number, reuse_seed: gr.Button, generation_info: def update_token_counter(text, steps): try: + text, _ = extra_networks.parse_prompt(text) + _, prompt_flat_list, _ = prompt_parser.get_multicond_prompt_list([text]) prompt_schedules = prompt_parser.get_learned_conditioning_prompt_schedules(prompt_flat_list, steps) @@ -310,43 +339,23 @@ def update_token_counter(text, steps): flat_prompts = reduce(lambda list1, list2: list1+list2, prompt_schedules) prompts = [prompt_text for step, prompt_text in flat_prompts] token_count, max_length = max([model_hijack.get_prompt_lengths(prompt) for prompt in prompts], key=lambda args: args[0]) - style_class = ' class="red"' if (token_count > max_length) else "" - return f"{token_count}/{max_length}" + return f"{token_count}/{max_length}" def create_toprow(is_img2img): id_part = "img2img" if is_img2img else "txt2img" - with gr.Row(elem_id="toprow"): - with gr.Column(scale=6): + with gr.Row(elem_id=f"{id_part}_toprow", variant="compact"): + with gr.Column(elem_id=f"{id_part}_prompt_container", scale=6): with gr.Row(): with gr.Column(scale=80): with gr.Row(): - prompt = gr.Textbox(label="Prompt", elem_id=f"{id_part}_prompt", show_label=False, lines=2, - placeholder="Prompt (press Ctrl+Enter or Alt+Enter to generate)" - ) + prompt = gr.Textbox(label="Prompt", elem_id=f"{id_part}_prompt", show_label=False, lines=3, placeholder="Prompt (press Ctrl+Enter or Alt+Enter to generate)") with gr.Row(): with gr.Column(scale=80): with gr.Row(): - negative_prompt = gr.Textbox(label="Negative prompt", elem_id=f"{id_part}_neg_prompt", show_label=False, lines=2, - placeholder="Negative prompt (press Ctrl+Enter or Alt+Enter to generate)" - ) - - with gr.Column(scale=1, elem_id="roll_col"): - paste = gr.Button(value=paste_symbol, elem_id="paste") - save_style = gr.Button(value=save_style_symbol, elem_id="style_create") - prompt_style_apply = gr.Button(value=apply_style_symbol, elem_id="style_apply") - clear_prompt_button = gr.Button(value=clear_prompt_symbol, elem_id=f"{id_part}_clear_prompt") - token_counter = gr.HTML(value="", elem_id=f"{id_part}_token_counter") - token_button = gr.Button(visible=False, elem_id=f"{id_part}_token_button") - - clear_prompt_button.click( - fn=lambda *x: x, - _js="confirm_clear_prompt", - inputs=[prompt, negative_prompt], - outputs=[prompt, negative_prompt], - ) + negative_prompt = gr.Textbox(label="Negative prompt", elem_id=f"{id_part}_neg_prompt", show_label=False, lines=2, placeholder="Negative prompt (press Ctrl+Enter or Alt+Enter to generate)") button_interrogate = None button_deepbooru = None @@ -355,10 +364,10 @@ def create_toprow(is_img2img): button_interrogate = gr.Button('Interrogate\nCLIP', elem_id="interrogate") button_deepbooru = gr.Button('Interrogate\nDeepBooru', elem_id="deepbooru") - with gr.Column(scale=1): - with gr.Row(): - skip = gr.Button('Skip', elem_id=f"{id_part}_skip") + with gr.Column(scale=1, elem_id=f"{id_part}_actions_column"): + with gr.Row(elem_id=f"{id_part}_generate_box"): interrupt = gr.Button('Interrupt', elem_id=f"{id_part}_interrupt") + skip = gr.Button('Skip', elem_id=f"{id_part}_skip") submit = gr.Button('Generate', elem_id=f"{id_part}_generate", variant='primary') skip.click( @@ -373,20 +382,34 @@ def create_toprow(is_img2img): outputs=[], ) - with gr.Row(): - with gr.Column(scale=1, elem_id="style_pos_col"): - prompt_style = gr.Dropdown(label="Style 1", elem_id=f"{id_part}_style_index", choices=[k for k, v in shared.prompt_styles.styles.items()], value=next(iter(shared.prompt_styles.styles.keys()))) + with gr.Row(elem_id=f"{id_part}_tools"): + paste = ToolButton(value=paste_symbol, elem_id="paste") + clear_prompt_button = ToolButton(value=clear_prompt_symbol, elem_id=f"{id_part}_clear_prompt") + extra_networks_button = ToolButton(value=extra_networks_symbol, elem_id=f"{id_part}_extra_networks") + prompt_style_apply = ToolButton(value=apply_style_symbol, elem_id=f"{id_part}_style_apply") + save_style = ToolButton(value=save_style_symbol, elem_id=f"{id_part}_style_create") - with gr.Column(scale=1, elem_id="style_neg_col"): - prompt_style2 = gr.Dropdown(label="Style 2", elem_id=f"{id_part}_style2_index", choices=[k for k, v in shared.prompt_styles.styles.items()], value=next(iter(shared.prompt_styles.styles.keys()))) + token_counter = gr.HTML(value="", elem_id=f"{id_part}_token_counter") + token_button = gr.Button(visible=False, elem_id=f"{id_part}_token_button") + negative_token_counter = gr.HTML(value="", elem_id=f"{id_part}_negative_token_counter") + negative_token_button = gr.Button(visible=False, elem_id=f"{id_part}_negative_token_button") - return prompt, prompt_style, negative_prompt, prompt_style2, submit, button_interrogate, button_deepbooru, prompt_style_apply, save_style, paste, token_counter, token_button + clear_prompt_button.click( + fn=lambda *x: x, + _js="confirm_clear_prompt", + inputs=[prompt, negative_prompt], + outputs=[prompt, negative_prompt], + ) + + with gr.Row(elem_id=f"{id_part}_styles_row"): + prompt_styles = gr.Dropdown(label="Styles", elem_id=f"{id_part}_styles", choices=[k for k, v in shared.prompt_styles.styles.items()], value=[], multiselect=True) + create_refresh_button(prompt_styles, shared.prompt_styles.reload, lambda: {"choices": [k for k, v in shared.prompt_styles.styles.items()]}, f"refresh_{id_part}_styles") + + return prompt, prompt_styles, negative_prompt, submit, button_interrogate, button_deepbooru, prompt_style_apply, save_style, paste, extra_networks_button, token_counter, token_button, negative_token_counter, negative_token_button def setup_progressbar(*args, **kwargs): - import modules.ui_progress - - modules.ui_progress.setup_progressbar(*args, **kwargs) + pass def apply_setting(key, value): @@ -419,20 +442,19 @@ def apply_setting(key, value): opts.data_labels[key].onchange() opts.save(shared.config_filename) - return value + return getattr(opts, key) -def update_generation_info(args): - generation_info, html_info, img_index = args +def update_generation_info(generation_info, html_info, img_index): try: generation_info = json.loads(generation_info) if img_index < 0 or img_index >= len(generation_info["infotexts"]): - return html_info - return plaintext_to_html(generation_info["infotexts"][img_index]) + return html_info, gr.update() + return plaintext_to_html(generation_info["infotexts"][img_index]), gr.update() except Exception: pass # if the json parse or anything else fails, just return the old html_info - return html_info + return html_info, gr.update() def create_refresh_button(refresh_component, refresh_method, refreshed_args, elem_id): @@ -479,8 +501,8 @@ Requested path was: {f} else: sp.Popen(["xdg-open", path]) - with gr.Column(variant='panel'): - with gr.Group(): + with gr.Column(variant='panel', elem_id=f"{tabname}_results"): + with gr.Group(elem_id=f"{tabname}_gallery_container"): result_gallery = gr.Gallery(label='Output', show_label=False, elem_id=f"{tabname}_gallery").style(grid=4) generation_info = None @@ -513,10 +535,9 @@ Requested path was: {f} generation_info_button = gr.Button(visible=False, elem_id=f"{tabname}_generation_info_button") generation_info_button.click( fn=update_generation_info, - _js="(x, y) => [x, y, selected_gallery_index()]", - inputs=[generation_info, html_info], - outputs=[html_info], - preprocess=False + _js="function(x, y, z){ return [x, y, selected_gallery_index()] }", + inputs=[generation_info, html_info, html_info], + outputs=[html_info, html_info], ) save.click( @@ -531,7 +552,8 @@ Requested path was: {f} outputs=[ download_files, html_log, - ] + ], + show_progress=False, ) save_zip.click( @@ -572,12 +594,22 @@ def create_sampler_and_steps_selection(choices, tabname): def ordered_ui_categories(): - user_order = {x.strip(): i for i, x in enumerate(shared.opts.ui_reorder.split(","))} + user_order = {x.strip(): i * 2 + 1 for i, x in enumerate(shared.opts.ui_reorder.split(","))} - for i, category in sorted(enumerate(shared.ui_reorder_categories), key=lambda x: user_order.get(x[1], x[0] + 1000)): + for i, category in sorted(enumerate(shared.ui_reorder_categories), key=lambda x: user_order.get(x[1], x[0] * 2 + 0)): yield category +def get_value_for_setting(key): + value = getattr(opts, key) + + info = opts.data_labels[key] + args = info.component_args() if callable(info.component_args) else info.component_args or {} + args = {k: v for k, v in args.items() if k not in {'precision'}} + + return gr.update(value=value, **args) + + def create_ui(): import modules.img2img import modules.txt2img @@ -590,22 +622,17 @@ def create_ui(): modules.scripts.scripts_txt2img.initialize_scripts(is_img2img=False) with gr.Blocks(analytics_enabled=False) as txt2img_interface: - txt2img_prompt, txt2img_prompt_style, txt2img_negative_prompt, txt2img_prompt_style2, submit, _, _,txt2img_prompt_style_apply, txt2img_save_style, txt2img_paste, token_counter, token_button = create_toprow(is_img2img=False) + txt2img_prompt, txt2img_prompt_styles, txt2img_negative_prompt, submit, _, _, txt2img_prompt_style_apply, txt2img_save_style, txt2img_paste, extra_networks_button, token_counter, token_button, negative_token_counter, negative_token_button = create_toprow(is_img2img=False) dummy_component = gr.Label(visible=False) - txt_prompt_img = gr.File(label="", elem_id="txt2img_prompt_image", file_count="single", type="bytes", visible=False) + txt_prompt_img = gr.File(label="", elem_id="txt2img_prompt_image", file_count="single", type="binary", visible=False) - with gr.Row(elem_id='txt2img_progress_row'): - with gr.Column(scale=1): - pass - - with gr.Column(scale=1): - progressbar = gr.HTML(elem_id="txt2img_progressbar") - txt2img_preview = gr.Image(elem_id='txt2img_preview', visible=False) - setup_progressbar(progressbar, txt2img_preview, 'txt2img') + with FormRow(variant='compact', elem_id="txt2img_extra_networks", visible=False) as extra_networks: + from modules import ui_extra_networks + extra_networks_ui = ui_extra_networks.create_ui(extra_networks, extra_networks_button, 'txt2img') with gr.Row().style(equal_height=False): - with gr.Column(variant='panel', elem_id="txt2img_settings"): + with gr.Column(variant='compact', elem_id="txt2img_settings"): for category in ordered_ui_categories(): if category == "sampler": steps, sampler_index = create_sampler_and_steps_selection(samplers, "txt2img") @@ -628,7 +655,7 @@ def create_ui(): seed, reuse_seed, subseed, reuse_subseed, subseed_strength, seed_resize_from_h, seed_resize_from_w, seed_checkbox = create_seed_inputs('txt2img') elif category == "checkboxes": - with FormRow(elem_id="txt2img_checkboxes"): + with FormRow(elem_id="txt2img_checkboxes", variant="compact"): restore_faces = gr.Checkbox(label='Restore faces', value=False, visible=len(shared.face_restorers) > 1, elem_id="txt2img_restore_faces") tiling = gr.Checkbox(label='Tiling', value=False, elem_id="txt2img_tiling") enable_hr = gr.Checkbox(label='Hires. fix', value=False, elem_id="txt2img_enable_hr") @@ -636,12 +663,12 @@ def create_ui(): elif category == "hires_fix": with FormGroup(visible=False, elem_id="txt2img_hires_fix") as hr_options: - with FormRow(elem_id="txt2img_hires_fix_row1"): + with FormRow(elem_id="txt2img_hires_fix_row1", variant="compact"): hr_upscaler = gr.Dropdown(label="Upscaler", elem_id="txt2img_hr_upscaler", choices=[*shared.latent_upscale_modes, *[x.name for x in shared.sd_upscalers]], value=shared.latent_upscale_default_mode) hr_second_pass_steps = gr.Slider(minimum=0, maximum=150, step=1, label='Hires steps', value=0, elem_id="txt2img_hires_steps") denoising_strength = gr.Slider(minimum=0.0, maximum=1.0, step=0.01, label='Denoising strength', value=0.7, elem_id="txt2img_denoising_strength") - with FormRow(elem_id="txt2img_hires_fix_row2"): + with FormRow(elem_id="txt2img_hires_fix_row2", variant="compact"): hr_scale = gr.Slider(minimum=1.0, maximum=4.0, step=0.05, label="Upscale by", value=2.0, elem_id="txt2img_hr_scale") hr_resize_x = gr.Slider(minimum=0, maximum=2048, step=8, label="Resize width to", value=0, elem_id="txt2img_hr_resize_x") hr_resize_y = gr.Slider(minimum=0, maximum=2048, step=8, label="Resize height to", value=0, elem_id="txt2img_hr_resize_y") @@ -682,10 +709,10 @@ def create_ui(): fn=wrap_gradio_gpu_call(modules.txt2img.txt2img, extra_outputs=[None, '', '']), _js="submit", inputs=[ + dummy_component, txt2img_prompt, txt2img_negative_prompt, - txt2img_prompt_style, - txt2img_prompt_style2, + txt2img_prompt_styles, steps, sampler_index, restore_faces, @@ -775,39 +802,57 @@ def create_ui(): ] token_button.click(fn=wrap_queued_call(update_token_counter), inputs=[txt2img_prompt, steps], outputs=[token_counter]) + negative_token_button.click(fn=wrap_queued_call(update_token_counter), inputs=[txt2img_negative_prompt, steps], outputs=[negative_token_counter]) + + ui_extra_networks.setup_ui(extra_networks_ui, txt2img_gallery) modules.scripts.scripts_current = modules.scripts.scripts_img2img modules.scripts.scripts_img2img.initialize_scripts(is_img2img=True) with gr.Blocks(analytics_enabled=False) as img2img_interface: - img2img_prompt, img2img_prompt_style, img2img_negative_prompt, img2img_prompt_style2, submit, img2img_interrogate, img2img_deepbooru, img2img_prompt_style_apply, img2img_save_style, img2img_paste,token_counter, token_button = create_toprow(is_img2img=True) + img2img_prompt, img2img_prompt_styles, img2img_negative_prompt, submit, img2img_interrogate, img2img_deepbooru, img2img_prompt_style_apply, img2img_save_style, img2img_paste, extra_networks_button, token_counter, token_button, negative_token_counter, negative_token_button = create_toprow(is_img2img=True) - with gr.Row(elem_id='img2img_progress_row'): - img2img_prompt_img = gr.File(label="", elem_id="img2img_prompt_image", file_count="single", type="bytes", visible=False) + img2img_prompt_img = gr.File(label="", elem_id="img2img_prompt_image", file_count="single", type="binary", visible=False) - with gr.Column(scale=1): - pass - - with gr.Column(scale=1): - progressbar = gr.HTML(elem_id="img2img_progressbar") - img2img_preview = gr.Image(elem_id='img2img_preview', visible=False) - setup_progressbar(progressbar, img2img_preview, 'img2img') + with FormRow(variant='compact', elem_id="img2img_extra_networks", visible=False) as extra_networks: + from modules import ui_extra_networks + extra_networks_ui_img2img = ui_extra_networks.create_ui(extra_networks, extra_networks_button, 'img2img') with FormRow().style(equal_height=False): - with gr.Column(variant='panel', elem_id="img2img_settings"): + with gr.Column(variant='compact', elem_id="img2img_settings"): + copy_image_buttons = [] + copy_image_destinations = {} + + def add_copy_image_controls(tab_name, elem): + with gr.Row(variant="compact", elem_id=f"img2img_copy_to_{tab_name}"): + gr.HTML("Copy image to: ", elem_id=f"img2img_label_copy_to_{tab_name}") + + for title, name in zip(['img2img', 'sketch', 'inpaint', 'inpaint sketch'], ['img2img', 'sketch', 'inpaint', 'inpaint_sketch']): + if name == tab_name: + gr.Button(title, interactive=False) + copy_image_destinations[name] = elem + continue + + button = gr.Button(title) + copy_image_buttons.append((button, name, elem)) + with gr.Tabs(elem_id="mode_img2img"): with gr.TabItem('img2img', id='img2img', elem_id="img2img_img2img_tab") as tab_img2img: init_img = gr.Image(label="Image for img2img", elem_id="img2img_image", show_label=False, source="upload", interactive=True, type="pil", tool="editor", image_mode="RGBA").style(height=480) + add_copy_image_controls('img2img', init_img) with gr.TabItem('Sketch', id='img2img_sketch', elem_id="img2img_img2img_sketch_tab") as tab_sketch: sketch = gr.Image(label="Image for img2img", elem_id="img2img_sketch", show_label=False, source="upload", interactive=True, type="pil", tool="color-sketch", image_mode="RGBA").style(height=480) + add_copy_image_controls('sketch', sketch) with gr.TabItem('Inpaint', id='inpaint', elem_id="img2img_inpaint_tab") as tab_inpaint: init_img_with_mask = gr.Image(label="Image for inpainting with mask", show_label=False, elem_id="img2maskimg", source="upload", interactive=True, type="pil", tool="sketch", image_mode="RGBA").style(height=480) + add_copy_image_controls('inpaint', init_img_with_mask) with gr.TabItem('Inpaint sketch', id='inpaint_sketch', elem_id="img2img_inpaint_sketch_tab") as tab_inpaint_color: inpaint_color_sketch = gr.Image(label="Color sketch inpainting", show_label=False, elem_id="inpaint_sketch", source="upload", interactive=True, type="pil", tool="color-sketch", image_mode="RGBA").style(height=480) inpaint_color_sketch_orig = gr.State(None) + add_copy_image_controls('inpaint_sketch', inpaint_color_sketch) def update_orig(image, state): if image is not None: @@ -824,36 +869,27 @@ def create_ui(): with gr.TabItem('Batch', id='batch', elem_id="img2img_batch_tab") as tab_batch: hidden = '
Disabled when launched with --hide-ui-dir-config.' if shared.cmd_opts.hide_ui_dir_config else '' - gr.HTML(f"

Process images in a directory on the same machine where the server is running.
Use an empty output directory to save pictures normally instead of writing to the output directory.{hidden}

") + gr.HTML(f"

Process images in a directory on the same machine where the server is running.
Use an empty output directory to save pictures normally instead of writing to the output directory.{hidden}

") img2img_batch_input_dir = gr.Textbox(label="Input directory", **shared.hide_dirs, elem_id="img2img_batch_input_dir") img2img_batch_output_dir = gr.Textbox(label="Output directory", **shared.hide_dirs, elem_id="img2img_batch_output_dir") - with FormGroup(elem_id="inpaint_controls", visible=False) as inpaint_controls: - with FormRow(): - mask_blur = gr.Slider(label='Mask blur', minimum=0, maximum=64, step=1, value=4, elem_id="img2img_mask_blur") - mask_alpha = gr.Slider(label="Mask transparency", visible=False, elem_id="img2img_mask_alpha") + def copy_image(img): + if isinstance(img, dict) and 'image' in img: + return img['image'] - with FormRow(): - inpainting_mask_invert = gr.Radio(label='Mask mode', choices=['Inpaint masked', 'Inpaint not masked'], value='Inpaint masked', type="index", elem_id="img2img_mask_mode") + return img - with FormRow(): - inpainting_fill = gr.Radio(label='Masked content', choices=['fill', 'original', 'latent noise', 'latent nothing'], value='original', type="index", elem_id="img2img_inpainting_fill") - - with FormRow(): - with gr.Column(): - inpaint_full_res = gr.Radio(label="Inpaint area", choices=["Whole picture", "Only masked"], type="index", value="Whole picture", elem_id="img2img_inpaint_full_res") - - with gr.Column(scale=4): - inpaint_full_res_padding = gr.Slider(label='Only masked padding, pixels', minimum=0, maximum=256, step=4, value=32, elem_id="img2img_inpaint_full_res_padding") - - def select_img2img_tab(tab): - return gr.update(visible=tab in [2, 3, 4]), gr.update(visible=tab == 3), - - for i, elem in enumerate([tab_img2img, tab_sketch, tab_inpaint, tab_inpaint_color, tab_inpaint_upload, tab_batch]): - elem.select( - fn=lambda tab=i: select_img2img_tab(tab), + for button, name, elem in copy_image_buttons: + button.click( + fn=copy_image, + inputs=[elem], + outputs=[copy_image_destinations[name]], + ) + button.click( + fn=lambda: None, + _js="switch_to_"+name.replace(" ", "_"), inputs=[], - outputs=[inpaint_controls, mask_alpha], + outputs=[], ) with FormRow(): @@ -897,6 +933,35 @@ def create_ui(): with FormGroup(elem_id="img2img_script_container"): custom_inputs = modules.scripts.scripts_img2img.setup_ui() + elif category == "inpaint": + with FormGroup(elem_id="inpaint_controls", visible=False) as inpaint_controls: + with FormRow(): + mask_blur = gr.Slider(label='Mask blur', minimum=0, maximum=64, step=1, value=4, elem_id="img2img_mask_blur") + mask_alpha = gr.Slider(label="Mask transparency", visible=False, elem_id="img2img_mask_alpha") + + with FormRow(): + inpainting_mask_invert = gr.Radio(label='Mask mode', choices=['Inpaint masked', 'Inpaint not masked'], value='Inpaint masked', type="index", elem_id="img2img_mask_mode") + + with FormRow(): + inpainting_fill = gr.Radio(label='Masked content', choices=['fill', 'original', 'latent noise', 'latent nothing'], value='original', type="index", elem_id="img2img_inpainting_fill") + + with FormRow(): + with gr.Column(): + inpaint_full_res = gr.Radio(label="Inpaint area", choices=["Whole picture", "Only masked"], type="index", value="Whole picture", elem_id="img2img_inpaint_full_res") + + with gr.Column(scale=4): + inpaint_full_res_padding = gr.Slider(label='Only masked padding, pixels', minimum=0, maximum=256, step=4, value=32, elem_id="img2img_inpaint_full_res_padding") + + def select_img2img_tab(tab): + return gr.update(visible=tab in [2, 3, 4]), gr.update(visible=tab == 3), + + for i, elem in enumerate([tab_img2img, tab_sketch, tab_inpaint, tab_inpaint_color, tab_inpaint_upload, tab_batch]): + elem.select( + fn=lambda tab=i: select_img2img_tab(tab), + inputs=[], + outputs=[inpaint_controls, mask_alpha], + ) + img2img_gallery, generation_info, html_info, html_log = create_output_panel("img2img", opts.outdir_img2img_samples) parameters_copypaste.bind_buttons({"img2img": img2img_paste}, None, img2img_prompt) @@ -918,11 +983,11 @@ def create_ui(): fn=wrap_gradio_gpu_call(modules.img2img.img2img, extra_outputs=[None, '', '']), _js="submit_img2img", inputs=[ + dummy_component, dummy_component, img2img_prompt, img2img_negative_prompt, - img2img_prompt_style, - img2img_prompt_style2, + img2img_prompt_styles, init_img, sketch, init_img_with_mask, @@ -961,23 +1026,36 @@ def create_ui(): show_progress=False, ) + interrogate_args = dict( + _js="get_img2img_tab_index", + inputs=[ + dummy_component, + img2img_batch_input_dir, + img2img_batch_output_dir, + init_img, + sketch, + init_img_with_mask, + inpaint_color_sketch, + init_img_inpaint, + ], + outputs=[img2img_prompt, dummy_component], + ) + img2img_prompt.submit(**img2img_args) submit.click(**img2img_args) img2img_interrogate.click( - fn=interrogate, - inputs=[init_img], - outputs=[img2img_prompt], + fn=lambda *args: process_interrogate(interrogate, *args), + **interrogate_args, ) img2img_deepbooru.click( - fn=interrogate_deepbooru, - inputs=[init_img], - outputs=[img2img_prompt], + fn=lambda *args: process_interrogate(interrogate_deepbooru, *args), + **interrogate_args, ) prompts = [(txt2img_prompt, txt2img_negative_prompt), (img2img_prompt, img2img_negative_prompt)] - style_dropdowns = [(txt2img_prompt_style, txt2img_prompt_style2), (img2img_prompt_style, img2img_prompt_style2)] + style_dropdowns = [txt2img_prompt_styles, img2img_prompt_styles] style_js_funcs = ["update_txt2img_tokens", "update_img2img_tokens"] for button, (prompt, negative_prompt) in zip([txt2img_save_style, img2img_save_style], prompts): @@ -987,18 +1065,21 @@ def create_ui(): # Have to pass empty dummy component here, because the JavaScript and Python function have to accept # the same number of parameters, but we only know the style-name after the JavaScript prompt inputs=[dummy_component, prompt, negative_prompt], - outputs=[txt2img_prompt_style, img2img_prompt_style, txt2img_prompt_style2, img2img_prompt_style2], + outputs=[txt2img_prompt_styles, img2img_prompt_styles], ) - for button, (prompt, negative_prompt), (style1, style2), js_func in zip([txt2img_prompt_style_apply, img2img_prompt_style_apply], prompts, style_dropdowns, style_js_funcs): + for button, (prompt, negative_prompt), styles, js_func in zip([txt2img_prompt_style_apply, img2img_prompt_style_apply], prompts, style_dropdowns, style_js_funcs): button.click( fn=apply_styles, _js=js_func, - inputs=[prompt, negative_prompt, style1, style2], - outputs=[prompt, negative_prompt, style1, style2], + inputs=[prompt, negative_prompt, styles], + outputs=[prompt, negative_prompt, styles], ) token_button.click(fn=update_token_counter, inputs=[img2img_prompt, steps], outputs=[token_counter]) + negative_token_button.click(fn=wrap_queued_call(update_token_counter), inputs=[txt2img_negative_prompt, steps], outputs=[negative_token_counter]) + + ui_extra_networks.setup_ui(extra_networks_ui_img2img, img2img_gallery) img2img_paste_fields = [ (img2img_prompt, "Prompt"), @@ -1026,7 +1107,7 @@ def create_ui(): with gr.Blocks(analytics_enabled=False) as extras_interface: with gr.Row().style(equal_height=False): - with gr.Column(variant='panel'): + with gr.Column(variant='compact'): with gr.Tabs(elem_id="mode_extras"): with gr.TabItem('Single Image', elem_id="extras_single_tab"): extras_image = gr.Image(label="Source", source="upload", interactive=True, type="pil", elem_id="extras_image") @@ -1125,12 +1206,21 @@ def create_ui(): outputs=[html, generation_info, html2], ) + def update_interp_description(value): + interp_description_css = "

{}

" + interp_descriptions = { + "No interpolation": interp_description_css.format("No interpolation will be used. Requires one model; A. Allows for format conversion and VAE baking."), + "Weighted sum": interp_description_css.format("A weighted sum will be used for interpolation. Requires two models; A and B. The result is calculated as A * (1 - M) + B * M"), + "Add difference": interp_description_css.format("The difference between the last two models will be added to the first. Requires three models; A, B and C. The result is calculated as A + (B - C) * M") + } + return interp_descriptions[value] + with gr.Blocks(analytics_enabled=False) as modelmerger_interface: with gr.Row().style(equal_height=False): - with gr.Column(variant='panel'): - gr.HTML(value="

A merger of the two checkpoints will be generated in your checkpoint directory.

") + with gr.Column(variant='compact'): + interp_description = gr.HTML(value=update_interp_description("Weighted sum"), elem_id="modelmerger_interp_description") - with FormRow(): + with FormRow(elem_id="modelmerger_models"): primary_model_name = gr.Dropdown(modules.sd_models.checkpoint_tiles(), elem_id="modelmerger_primary_model_name", label="Primary model (A)") create_refresh_button(primary_model_name, modules.sd_models.list_models, lambda: {"choices": modules.sd_models.checkpoint_tiles()}, "refresh_checkpoint_A") @@ -1142,24 +1232,37 @@ def create_ui(): custom_name = gr.Textbox(label="Custom Name (Optional)", elem_id="modelmerger_custom_name") interp_amount = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='Multiplier (M) - set to 0 to get model A', value=0.3, elem_id="modelmerger_interp_amount") - interp_method = gr.Radio(choices=["Weighted sum", "Add difference"], value="Weighted sum", label="Interpolation Method", elem_id="modelmerger_interp_method") + interp_method = gr.Radio(choices=["No interpolation", "Weighted sum", "Add difference"], value="Weighted sum", label="Interpolation Method", elem_id="modelmerger_interp_method") + interp_method.change(fn=update_interp_description, inputs=[interp_method], outputs=[interp_description]) with FormRow(): checkpoint_format = gr.Radio(choices=["ckpt", "safetensors"], value="ckpt", label="Checkpoint format", elem_id="modelmerger_checkpoint_format") save_as_half = gr.Checkbox(value=False, label="Save as float16", elem_id="modelmerger_save_as_half") - config_source = gr.Radio(choices=["A, B or C", "B", "C", "Don't"], value="A, B or C", label="Copy config from", type="index", elem_id="modelmerger_config_method") + with FormRow(): + with gr.Column(): + config_source = gr.Radio(choices=["A, B or C", "B", "C", "Don't"], value="A, B or C", label="Copy config from", type="index", elem_id="modelmerger_config_method") - modelmerger_merge = gr.Button(elem_id="modelmerger_merge", value="Merge", variant='primary') + with gr.Column(): + with FormRow(): + bake_in_vae = gr.Dropdown(choices=["None"] + list(sd_vae.vae_dict), value="None", label="Bake in VAE", elem_id="modelmerger_bake_in_vae") + create_refresh_button(bake_in_vae, sd_vae.refresh_vae_list, lambda: {"choices": ["None"] + list(sd_vae.vae_dict)}, "modelmerger_refresh_bake_in_vae") - with gr.Column(variant='panel'): - submit_result = gr.Textbox(elem_id="modelmerger_result", show_label=False) + with FormRow(): + discard_weights = gr.Textbox(value="", label="Discard weights with matching name", elem_id="modelmerger_discard_weights") + + with gr.Row(): + modelmerger_merge = gr.Button(elem_id="modelmerger_merge", value="Merge", variant='primary') + + with gr.Column(variant='compact', elem_id="modelmerger_results_container"): + with gr.Group(elem_id="modelmerger_results_panel"): + modelmerger_result = gr.HTML(elem_id="modelmerger_result", show_label=False) with gr.Blocks(analytics_enabled=False) as train_interface: with gr.Row().style(equal_height=False): gr.HTML(value="

See wiki for detailed explanation.

") - with gr.Row().style(equal_height=False): + with gr.Row(variant="compact").style(equal_height=False): with gr.Tabs(elem_id="train_tabs"): with gr.Tab(label="Create embedding"): @@ -1204,6 +1307,7 @@ def create_ui(): process_flip = gr.Checkbox(label='Create flipped copies', elem_id="train_process_flip") process_split = gr.Checkbox(label='Split oversized images', elem_id="train_process_split") process_focal_crop = gr.Checkbox(label='Auto focal point crop', elem_id="train_process_focal_crop") + process_multicrop = gr.Checkbox(label='Auto-sized crop', elem_id="train_process_multicrop") process_caption = gr.Checkbox(label='Use BLIP for caption', elem_id="train_process_caption") process_caption_deepbooru = gr.Checkbox(label='Use deepbooru for caption', visible=True, elem_id="train_process_caption_deepbooru") @@ -1216,7 +1320,19 @@ def create_ui(): process_focal_crop_entropy_weight = gr.Slider(label='Focal point entropy weight', value=0.15, minimum=0.0, maximum=1.0, step=0.05, elem_id="train_process_focal_crop_entropy_weight") process_focal_crop_edges_weight = gr.Slider(label='Focal point edges weight', value=0.5, minimum=0.0, maximum=1.0, step=0.05, elem_id="train_process_focal_crop_edges_weight") process_focal_crop_debug = gr.Checkbox(label='Create debug image', elem_id="train_process_focal_crop_debug") - + + with gr.Column(visible=False) as process_multicrop_col: + gr.Markdown('Each image is center-cropped with an automatically chosen width and height.') + with gr.Row(): + process_multicrop_mindim = gr.Slider(minimum=64, maximum=2048, step=8, label="Dimension lower bound", value=384, elem_id="train_process_multicrop_mindim") + process_multicrop_maxdim = gr.Slider(minimum=64, maximum=2048, step=8, label="Dimension upper bound", value=768, elem_id="train_process_multicrop_maxdim") + with gr.Row(): + process_multicrop_minarea = gr.Slider(minimum=64*64, maximum=2048*2048, step=1, label="Area lower bound", value=64*64, elem_id="train_process_multicrop_minarea") + process_multicrop_maxarea = gr.Slider(minimum=64*64, maximum=2048*2048, step=1, label="Area upper bound", value=640*640, elem_id="train_process_multicrop_maxarea") + with gr.Row(): + process_multicrop_objective = gr.Radio(["Maximize area", "Minimize error"], value="Maximize area", label="Resizing objective", elem_id="train_process_multicrop_objective") + process_multicrop_threshold = gr.Slider(minimum=0, maximum=1, step=0.01, label="Error threshold", value=0.1, elem_id="train_process_multicrop_threshold") + with gr.Row(): with gr.Column(scale=3): gr.HTML(value="") @@ -1238,6 +1354,12 @@ def create_ui(): outputs=[process_focal_crop_row], ) + process_multicrop.change( + fn=lambda show: gr_show(show), + inputs=[process_multicrop], + outputs=[process_multicrop_col], + ) + def get_textual_inversion_template_names(): return sorted([x for x in textual_inversion.textual_inversion_templates]) @@ -1295,15 +1417,11 @@ def create_ui(): script_callbacks.ui_train_tabs_callback(params) - with gr.Column(): - progressbar = gr.HTML(elem_id="ti_progressbar") + with gr.Column(elem_id='ti_gallery_container'): ti_output = gr.Text(elem_id="ti_output", value="", show_label=False) - ti_gallery = gr.Gallery(label='Output', show_label=False, elem_id='ti_gallery').style(grid=4) - ti_preview = gr.Image(elem_id='ti_preview', visible=False) ti_progress = gr.HTML(elem_id="ti_progress", value="") ti_outcome = gr.HTML(elem_id="ti_error", value="") - setup_progressbar(progressbar, ti_preview, 'ti', textinfo=ti_progress) create_embedding.click( fn=modules.textual_inversion.ui.create_embedding, @@ -1344,6 +1462,7 @@ def create_ui(): fn=wrap_gradio_gpu_call(modules.textual_inversion.ui.preprocess, extra_outputs=[gr.update()]), _js="start_training_textual_inversion", inputs=[ + dummy_component, process_src, process_dst, process_width, @@ -1360,6 +1479,13 @@ def create_ui(): process_focal_crop_entropy_weight, process_focal_crop_edges_weight, process_focal_crop_debug, + process_multicrop, + process_multicrop_mindim, + process_multicrop_maxdim, + process_multicrop_minarea, + process_multicrop_maxarea, + process_multicrop_objective, + process_multicrop_threshold, ], outputs=[ ti_output, @@ -1371,6 +1497,7 @@ def create_ui(): fn=wrap_gradio_gpu_call(modules.textual_inversion.ui.train_embedding, extra_outputs=[gr.update()]), _js="start_training_textual_inversion", inputs=[ + dummy_component, train_embedding_name, embedding_learn_rate, batch_size, @@ -1403,6 +1530,7 @@ def create_ui(): fn=wrap_gradio_gpu_call(modules.hypernetworks.ui.train_hypernetwork, extra_outputs=[gr.update()]), _js="start_training_textual_inversion", inputs=[ + dummy_component, train_hypernetwork_name, hypernetwork_learn_rate, batch_size, @@ -1511,7 +1639,7 @@ def create_ui(): opts.save(shared.config_filename) - return gr.update(value=value), opts.dumpjson() + return get_value_for_setting(key), opts.dumpjson() with gr.Blocks(analytics_enabled=False) as settings_interface: with gr.Row(): @@ -1529,6 +1657,7 @@ def create_ui(): previous_section = None current_tab = None + current_row = None with gr.Tabs(elem_id="settings"): for i, (k, item) in enumerate(opts.data_labels.items()): section_must_be_skipped = item.section[0] is None @@ -1537,10 +1666,14 @@ def create_ui(): elem_id, text = item.section if current_tab is not None: + current_row.__exit__() current_tab.__exit__() + gr.Group() current_tab = gr.TabItem(elem_id="settings_{}".format(elem_id), label=text) current_tab.__enter__() + current_row = gr.Column(variant='compact') + current_row.__enter__() previous_section = item.section @@ -1555,6 +1688,7 @@ def create_ui(): components.append(component) if current_tab is not None: + current_row.__exit__() current_tab.__exit__() with gr.TabItem("Actions"): @@ -1562,10 +1696,8 @@ def create_ui(): download_localization = gr.Button(value='Download localization template', elem_id="download_localization") reload_script_bodies = gr.Button(value='Reload custom script bodies (No ui updates, No restart)', variant='secondary', elem_id="settings_reload_script_bodies") - if os.path.exists("html/licenses.html"): - with open("html/licenses.html", encoding="utf8") as file: - with gr.TabItem("Licenses"): - gr.HTML(file.read(), elem_id="licenses") + with gr.TabItem("Licenses"): + gr.HTML(shared.html("licenses.html"), elem_id="licenses") gr.Button(value="Show all pages", elem_id="settings_show_all_pages") @@ -1636,7 +1768,7 @@ def create_ui(): interfaces += [(extensions_interface, "Extensions", "extensions")] with gr.Blocks(css=css, analytics_enabled=False, title="Stable Diffusion") as demo: - with gr.Row(elem_id="quicksettings"): + with gr.Row(elem_id="quicksettings", variant="compact"): for i, k, item in sorted(quicksettings_list, key=lambda x: quicksettings_names.get(x[1], x[0])): component = create_setting_component(k, is_quicksettings=True) component_dict[k] = component @@ -1652,11 +1784,9 @@ def create_ui(): if os.path.exists(os.path.join(script_path, "notification.mp3")): audio_notification = gr.Audio(interactive=False, value=os.path.join(script_path, "notification.mp3"), elem_id="audio_notification", visible=False) - if os.path.exists("html/footer.html"): - with open("html/footer.html", encoding="utf8") as file: - footer = file.read() - footer = footer.format(versions=versions_html()) - gr.HTML(footer, elem_id="footer") + footer = shared.html("footer.html") + footer = footer.format(versions=versions_html()) + gr.HTML(footer, elem_id="footer") text_settings = gr.Textbox(elem_id="settings_json", value=lambda: opts.dumpjson(), visible=False) settings_submit.click( @@ -1677,7 +1807,7 @@ def create_ui(): component_keys = [k for k in opts.data_labels.keys() if k in component_dict] def get_settings_values(): - return [getattr(opts, key) for key in component_keys] + return [get_value_for_setting(key) for key in component_keys] demo.load( fn=get_settings_values, @@ -1692,12 +1822,15 @@ def create_ui(): print("Error loading/saving model file:", file=sys.stderr) print(traceback.format_exc(), file=sys.stderr) modules.sd_models.list_models() # to remove the potentially missing models from the list - return [f"Error merging checkpoints: {e}"] + [gr.Dropdown.update(choices=modules.sd_models.checkpoint_tiles()) for _ in range(4)] + return [*[gr.Dropdown.update(choices=modules.sd_models.checkpoint_tiles()) for _ in range(4)], f"Error merging checkpoints: {e}"] return results + modelmerger_merge.click(fn=lambda: '', inputs=[], outputs=[modelmerger_result]) modelmerger_merge.click( - fn=modelmerger, + fn=wrap_gradio_gpu_call(modelmerger, extra_outputs=lambda: [gr.update() for _ in range(4)]), + _js='modelmerger', inputs=[ + dummy_component, primary_model_name, secondary_model_name, tertiary_model_name, @@ -1707,13 +1840,15 @@ def create_ui(): custom_name, checkpoint_format, config_source, + bake_in_vae, + discard_weights, ], outputs=[ - submit_result, primary_model_name, secondary_model_name, tertiary_model_name, component_dict['sd_model_checkpoint'], + modelmerger_result, ] ) @@ -1745,7 +1880,10 @@ def create_ui(): if saved_value is None: ui_settings[key] = getattr(obj, field) elif condition and not condition(saved_value): - print(f'Warning: Bad ui setting value: {key}: {saved_value}; Default value "{getattr(obj, field)}" will be used instead.') + pass + + # this warning is generally not useful; + # print(f'Warning: Bad ui setting value: {key}: {saved_value}; Default value "{getattr(obj, field)}" will be used instead.') else: setattr(obj, field, saved_value) if init_field is not None: @@ -1773,7 +1911,13 @@ def create_ui(): apply_field(x, 'value') if type(x) == gr.Dropdown: - apply_field(x, 'value', lambda val: val in x.choices, getattr(x, 'init_field', None)) + def check_dropdown(val): + if getattr(x, 'multiselect', False): + return all([value in x.choices for value in val]) + else: + return val in x.choices + + apply_field(x, 'value', check_dropdown, getattr(x, 'init_field', None)) visit(txt2img_interface, loadsave, "txt2img") visit(img2img_interface, loadsave, "img2img") @@ -1785,28 +1929,27 @@ def create_ui(): with open(ui_config_file, "w", encoding="utf8") as file: json.dump(ui_settings, file, indent=4) + # Required as a workaround for change() event not triggering when loading values from ui-config.json + interp_description.value = update_interp_description(interp_method.value) + return demo def reload_javascript(): - with open(os.path.join(script_path, "script.js"), "r", encoding="utf8") as jsfile: - javascript = f'' - - scripts_list = modules.scripts.list_scripts("javascript", ".js") - - for basedir, filename, path in scripts_list: - with open(path, "r", encoding="utf8") as jsfile: - javascript += f"\n" + head = f'\n' + inline = f"{localization.localization_js(shared.opts.localization)};" if cmd_opts.theme is not None: - javascript += f"\n\n" + inline += f"set_theme('{cmd_opts.theme}');" - javascript += f"\n" + head += f'\n' + + for script in modules.scripts.list_scripts("javascript", ".js"): + head += f'\n' def template_response(*args, **kwargs): res = shared.GradioTemplateResponseOriginal(*args, **kwargs) - res.body = res.body.replace( - b'', f'{javascript}'.encode("utf8")) + res.body = res.body.replace(b'', f'{head}'.encode("utf8")) res.init_headers() return res diff --git a/modules/ui_components.py b/modules/ui_components.py index 97acff06..46324425 100644 --- a/modules/ui_components.py +++ b/modules/ui_components.py @@ -11,6 +11,16 @@ class ToolButton(gr.Button, gr.components.FormComponent): return "button" +class ToolButtonTop(gr.Button, gr.components.FormComponent): + """Small button with single emoji as text, with extra margin at top, fits inside gradio forms""" + + def __init__(self, **kwargs): + super().__init__(variant="tool-top", **kwargs) + + def get_block_name(self): + return "button" + + class FormRow(gr.Row, gr.components.FormComponent): """Same as gr.Row but fits inside gradio forms""" diff --git a/modules/ui_extra_networks.py b/modules/ui_extra_networks.py new file mode 100644 index 00000000..af2b8071 --- /dev/null +++ b/modules/ui_extra_networks.py @@ -0,0 +1,171 @@ +import os.path + +from modules import shared +import gradio as gr +import json + +from modules.generation_parameters_copypaste import image_from_url_text + +extra_pages = [] + + +def register_page(page): + """registers extra networks page for the UI; recommend doing it in on_before_ui() callback for extensions""" + + extra_pages.append(page) + + +class ExtraNetworksPage: + def __init__(self, title): + self.title = title + self.name = title.lower() + self.card_page = shared.html("extra-networks-card.html") + self.allow_negative_prompt = False + + def refresh(self): + pass + + def create_html(self, tabname): + items_html = '' + + for item in self.list_items(): + items_html += self.create_html_for_item(item, tabname) + + if items_html == '': + dirs = "".join([f"
  • {x}
  • " for x in self.allowed_directories_for_previews()]) + items_html = shared.html("extra-networks-no-cards.html").format(dirs=dirs) + + res = f""" +
    +{items_html} +
    +""" + + return res + + def list_items(self): + raise NotImplementedError() + + def allowed_directories_for_previews(self): + return [] + + def create_html_for_item(self, item, tabname): + preview = item.get("preview", None) + + args = { + "preview_html": "style='background-image: url(" + json.dumps(preview) + ")'" if preview else '', + "prompt": item["prompt"], + "tabname": json.dumps(tabname), + "local_preview": json.dumps(item["local_preview"]), + "name": item["name"], + "allow_negative_prompt": "true" if self.allow_negative_prompt else "false", + } + + return self.card_page.format(**args) + + +def intialize(): + extra_pages.clear() + + +class ExtraNetworksUi: + def __init__(self): + self.pages = None + self.stored_extra_pages = None + + self.button_save_preview = None + self.preview_target_filename = None + + self.tabname = None + + +def pages_in_preferred_order(pages): + tab_order = [x.lower().strip() for x in shared.opts.ui_extra_networks_tab_reorder.split(",")] + + def tab_name_score(name): + name = name.lower() + for i, possible_match in enumerate(tab_order): + if possible_match in name: + return i + + return len(pages) + + tab_scores = {page.name: (tab_name_score(page.name), original_index) for original_index, page in enumerate(pages)} + + return sorted(pages, key=lambda x: tab_scores[x.name]) + + +def create_ui(container, button, tabname): + ui = ExtraNetworksUi() + ui.pages = [] + ui.stored_extra_pages = pages_in_preferred_order(extra_pages.copy()) + ui.tabname = tabname + + with gr.Tabs(elem_id=tabname+"_extra_tabs") as tabs: + for page in ui.stored_extra_pages: + with gr.Tab(page.title): + page_elem = gr.HTML(page.create_html(ui.tabname)) + ui.pages.append(page_elem) + + filter = gr.Textbox('', show_label=False, elem_id=tabname+"_extra_search", placeholder="Search...", visible=False) + button_refresh = gr.Button('Refresh', elem_id=tabname+"_extra_refresh") + button_close = gr.Button('Close', elem_id=tabname+"_extra_close") + + ui.button_save_preview = gr.Button('Save preview', elem_id=tabname+"_save_preview", visible=False) + ui.preview_target_filename = gr.Textbox('Preview save filename', elem_id=tabname+"_preview_filename", visible=False) + + button.click(fn=lambda: gr.update(visible=True), inputs=[], outputs=[container]) + button_close.click(fn=lambda: gr.update(visible=False), inputs=[], outputs=[container]) + + def refresh(): + res = [] + + for pg in ui.stored_extra_pages: + pg.refresh() + res.append(pg.create_html(ui.tabname)) + + return res + + button_refresh.click(fn=refresh, inputs=[], outputs=ui.pages) + + return ui + + +def path_is_parent(parent_path, child_path): + parent_path = os.path.abspath(parent_path) + child_path = os.path.abspath(child_path) + + return os.path.commonpath([parent_path]) == os.path.commonpath([parent_path, child_path]) + + +def setup_ui(ui, gallery): + def save_preview(index, images, filename): + if len(images) == 0: + print("There is no image in gallery to save as a preview.") + return [page.create_html(ui.tabname) for page in ui.stored_extra_pages] + + index = int(index) + index = 0 if index < 0 else index + index = len(images) - 1 if index >= len(images) else index + + img_info = images[index if index >= 0 else 0] + image = image_from_url_text(img_info) + + is_allowed = False + for extra_page in ui.stored_extra_pages: + if any([path_is_parent(x, filename) for x in extra_page.allowed_directories_for_previews()]): + is_allowed = True + break + + assert is_allowed, f'writing to {filename} is not allowed' + + image.save(filename) + + return [page.create_html(ui.tabname) for page in ui.stored_extra_pages] + + ui.button_save_preview.click( + fn=save_preview, + _js="function(x, y, z){console.log(x, y, z); return [selected_gallery_index(), y, z]}", + inputs=[ui.preview_target_filename, gallery, ui.preview_target_filename], + outputs=[*ui.pages] + ) diff --git a/modules/ui_extra_networks_hypernets.py b/modules/ui_extra_networks_hypernets.py new file mode 100644 index 00000000..65d000cf --- /dev/null +++ b/modules/ui_extra_networks_hypernets.py @@ -0,0 +1,35 @@ +import json +import os + +from modules import shared, ui_extra_networks + + +class ExtraNetworksPageHypernetworks(ui_extra_networks.ExtraNetworksPage): + def __init__(self): + super().__init__('Hypernetworks') + + def refresh(self): + shared.reload_hypernetworks() + + def list_items(self): + for name, path in shared.hypernetworks.items(): + path, ext = os.path.splitext(path) + previews = [path + ".png", path + ".preview.png"] + + preview = None + for file in previews: + if os.path.isfile(file): + preview = "./file=" + file.replace('\\', '/') + "?mtime=" + str(os.path.getmtime(file)) + break + + yield { + "name": name, + "filename": path, + "preview": preview, + "prompt": json.dumps(f""), + "local_preview": path + ".png", + } + + def allowed_directories_for_previews(self): + return [shared.cmd_opts.hypernetwork_dir] + diff --git a/modules/ui_extra_networks_textual_inversion.py b/modules/ui_extra_networks_textual_inversion.py new file mode 100644 index 00000000..dbd23d2d --- /dev/null +++ b/modules/ui_extra_networks_textual_inversion.py @@ -0,0 +1,33 @@ +import json +import os + +from modules import ui_extra_networks, sd_hijack + + +class ExtraNetworksPageTextualInversion(ui_extra_networks.ExtraNetworksPage): + def __init__(self): + super().__init__('Textual Inversion') + self.allow_negative_prompt = True + + def refresh(self): + sd_hijack.model_hijack.embedding_db.load_textual_inversion_embeddings(force_reload=True) + + def list_items(self): + for embedding in sd_hijack.model_hijack.embedding_db.word_embeddings.values(): + path, ext = os.path.splitext(embedding.filename) + preview_file = path + ".preview.png" + + preview = None + if os.path.isfile(preview_file): + preview = "./file=" + preview_file.replace('\\', '/') + "?mtime=" + str(os.path.getmtime(preview_file)) + + yield { + "name": embedding.name, + "filename": embedding.filename, + "preview": preview, + "prompt": json.dumps(embedding.name), + "local_preview": path + ".preview.png", + } + + def allowed_directories_for_previews(self): + return list(sd_hijack.model_hijack.embedding_db.embedding_dirs) diff --git a/modules/ui_progress.py b/modules/ui_progress.py deleted file mode 100644 index 7cd312e4..00000000 --- a/modules/ui_progress.py +++ /dev/null @@ -1,101 +0,0 @@ -import time - -import gradio as gr - -from modules.shared import opts - -import modules.shared as shared - - -def calc_time_left(progress, threshold, label, force_display, show_eta): - if progress == 0: - return "" - else: - time_since_start = time.time() - shared.state.time_start - eta = (time_since_start/progress) - eta_relative = eta-time_since_start - if (eta_relative > threshold and show_eta) or force_display: - if eta_relative > 3600: - return label + time.strftime('%H:%M:%S', time.gmtime(eta_relative)) - elif eta_relative > 60: - return label + time.strftime('%M:%S', time.gmtime(eta_relative)) - else: - return label + time.strftime('%Ss', time.gmtime(eta_relative)) - else: - return "" - - -def check_progress_call(id_part): - if shared.state.job_count == 0: - return "", gr.update(visible=False), gr.update(visible=False), gr.update(visible=False) - - progress = 0 - - if shared.state.job_count > 0: - progress += shared.state.job_no / shared.state.job_count - if shared.state.sampling_steps > 0: - progress += 1 / shared.state.job_count * shared.state.sampling_step / shared.state.sampling_steps - - # Show progress percentage and time left at the same moment, and base it also on steps done - show_eta = progress >= 0.01 or shared.state.sampling_step >= 10 - - time_left = calc_time_left(progress, 1, " ETA: ", shared.state.time_left_force_display, show_eta) - if time_left != "": - shared.state.time_left_force_display = True - - progress = min(progress, 1) - - progressbar = "" - if opts.show_progressbar: - progressbar = f"""
    {" " * 2 + str(int(progress*100))+"%" + time_left if show_eta else ""}
    """ - - image = gr.update(visible=False) - preview_visibility = gr.update(visible=False) - - if opts.live_previews_enable: - shared.state.set_current_image() - image = shared.state.current_image - - if image is None: - image = gr.update(value=None) - else: - preview_visibility = gr.update(visible=True) - - if shared.state.textinfo is not None: - textinfo_result = gr.HTML.update(value=shared.state.textinfo, visible=True) - else: - textinfo_result = gr.update(visible=False) - - return f"

    {progressbar}

    ", preview_visibility, image, textinfo_result - - -def check_progress_call_initial(id_part): - shared.state.job_count = -1 - shared.state.current_latent = None - shared.state.current_image = None - shared.state.textinfo = None - shared.state.time_start = time.time() - shared.state.time_left_force_display = False - - return check_progress_call(id_part) - - -def setup_progressbar(progressbar, preview, id_part, textinfo=None): - if textinfo is None: - textinfo = gr.HTML(visible=False) - - check_progress = gr.Button('Check progress', elem_id=f"{id_part}_check_progress", visible=False) - check_progress.click( - fn=lambda: check_progress_call(id_part), - show_progress=False, - inputs=[], - outputs=[progressbar, preview, preview, textinfo], - ) - - check_progress_initial = gr.Button('Check progress (first)', elem_id=f"{id_part}_check_progress_initial", visible=False) - check_progress_initial.click( - fn=lambda: check_progress_call_initial(id_part), - show_progress=False, - inputs=[], - outputs=[progressbar, preview, preview, textinfo], - ) diff --git a/modules/upscaler.py b/modules/upscaler.py index 231680cb..a5bf5acb 100644 --- a/modules/upscaler.py +++ b/modules/upscaler.py @@ -95,6 +95,7 @@ class UpscalerData: def __init__(self, name: str, path: str, upscaler: Upscaler = None, scale: int = 4, model=None): self.name = name self.data_path = path + self.local_data_path = path self.scaler = upscaler self.scale = scale self.model = model diff --git a/requirements.txt b/requirements.txt index e1dbf8e5..ef5e3472 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,7 +5,7 @@ fairscale==0.4.4 fonts font-roboto gfpgan -gradio==3.15.0 +gradio==3.16.2 invisible-watermark numpy omegaconf diff --git a/requirements_versions.txt b/requirements_versions.txt index d2899292..f97ad765 100644 --- a/requirements_versions.txt +++ b/requirements_versions.txt @@ -3,7 +3,7 @@ transformers==4.19.2 accelerate==0.12.0 basicsr==1.4.2 gfpgan==1.3.8 -gradio==3.15.0 +gradio==3.16.2 numpy==1.23.3 Pillow==9.4.0 realesrgan==0.3.0 diff --git a/script.js b/script.js index 3345e32b..97e0bfcf 100644 --- a/script.js +++ b/script.js @@ -13,6 +13,7 @@ function get_uiCurrentTabContent() { } uiUpdateCallbacks = [] +uiLoadedCallbacks = [] uiTabChangeCallbacks = [] optionsChangedCallbacks = [] let uiCurrentTab = null @@ -20,6 +21,9 @@ let uiCurrentTab = null function onUiUpdate(callback){ uiUpdateCallbacks.push(callback) } +function onUiLoaded(callback){ + uiLoadedCallbacks.push(callback) +} function onUiTabChange(callback){ uiTabChangeCallbacks.push(callback) } @@ -38,8 +42,15 @@ function executeCallbacks(queue, m) { queue.forEach(function(x){runCallback(x, m)}) } +var executedOnLoaded = false; + document.addEventListener("DOMContentLoaded", function() { var mutationObserver = new MutationObserver(function(m){ + if(!executedOnLoaded && gradioApp().querySelector('#txt2img_prompt')){ + executedOnLoaded = true; + executeCallbacks(uiLoadedCallbacks); + } + executeCallbacks(uiUpdateCallbacks, m); const newTab = get_uiCurrentTab(); if ( newTab && ( newTab !== uiCurrentTab ) ) { @@ -53,7 +64,7 @@ document.addEventListener("DOMContentLoaded", function() { /** * Add a ctrl+enter as a shortcut to start a generation */ - document.addEventListener('keydown', function(e) { +document.addEventListener('keydown', function(e) { var handled = false; if (e.key !== undefined) { if((e.key == "Enter" && (e.metaKey || e.ctrlKey || e.altKey))) handled = true; diff --git a/scripts/prompts_from_file.py b/scripts/prompts_from_file.py index f3e711d7..76dc5778 100644 --- a/scripts/prompts_from_file.py +++ b/scripts/prompts_from_file.py @@ -116,7 +116,7 @@ class Script(scripts.Script): checkbox_iterate_batch = gr.Checkbox(label="Use same random seed for all lines", value=False, elem_id=self.elem_id("checkbox_iterate_batch")) prompt_txt = gr.Textbox(label="List of prompt inputs", lines=1, elem_id=self.elem_id("prompt_txt")) - file = gr.File(label="Upload prompt inputs", type='bytes', elem_id=self.elem_id("file")) + file = gr.File(label="Upload prompt inputs", type='binary', elem_id=self.elem_id("file")) file.change(fn=load_prompt_file, inputs=[file], outputs=[file, prompt_txt, prompt_txt]) diff --git a/scripts/xy_grid.py b/scripts/xy_grid.py index bd3087d4..98254c64 100644 --- a/scripts/xy_grid.py +++ b/scripts/xy_grid.py @@ -10,8 +10,7 @@ import numpy as np import modules.scripts as scripts import gradio as gr -from modules import images, paths, sd_samplers, processing -from modules.hypernetworks import hypernetwork +from modules import images, paths, sd_samplers, processing, sd_models, sd_vae from modules.processing import process_images, Processed, StableDiffusionProcessingTxt2Img from modules.shared import opts, cmd_opts, state import modules.shared as shared @@ -22,6 +21,10 @@ import glob import os import re +from modules.ui_components import ToolButton + +fill_values_symbol = "\U0001f4d2" # 📒 + def apply_field(field): def fun(p, x, xs): @@ -82,7 +85,6 @@ def apply_checkpoint(p, x, xs): if info is None: raise RuntimeError(f"Unknown checkpoint: {x}") modules.sd_models.reload_model_weights(shared.sd_model, info) - p.sd_model = shared.sd_model def confirm_checkpoints(p, xs): @@ -91,28 +93,6 @@ def confirm_checkpoints(p, xs): raise RuntimeError(f"Unknown checkpoint: {x}") -def apply_hypernetwork(p, x, xs): - if x.lower() in ["", "none"]: - name = None - else: - name = hypernetwork.find_closest_hypernetwork_name(x) - if not name: - raise RuntimeError(f"Unknown hypernetwork: {x}") - hypernetwork.load_hypernetwork(name) - - -def apply_hypernetwork_strength(p, x, xs): - hypernetwork.apply_strength(x) - - -def confirm_hypernetworks(p, xs): - for x in xs: - if x.lower() in ["", "none"]: - continue - if not hypernetwork.find_closest_hypernetwork_name(x): - raise RuntimeError(f"Unknown hypernetwork: {x}") - - def apply_clip_skip(p, x, xs): opts.data["CLIP_stop_at_last_layers"] = x @@ -175,80 +155,109 @@ def str_permutations(x): """dummy function for specifying it in AxisOption's type when you want to get a list of permutations""" return x -AxisOption = namedtuple("AxisOption", ["label", "type", "apply", "format_value", "confirm"]) -AxisOptionImg2Img = namedtuple("AxisOptionImg2Img", ["label", "type", "apply", "format_value", "confirm"]) + +class AxisOption: + def __init__(self, label, type, apply, format_value=format_value_add_label, confirm=None, cost=0.0, choices=None): + self.label = label + self.type = type + self.apply = apply + self.format_value = format_value + self.confirm = confirm + self.cost = cost + self.choices = choices + + +class AxisOptionImg2Img(AxisOption): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.is_img2img = True + +class AxisOptionTxt2Img(AxisOption): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.is_img2img = False axis_options = [ - AxisOption("Nothing", str, do_nothing, format_nothing, None), - AxisOption("Seed", int, apply_field("seed"), format_value_add_label, None), - AxisOption("Var. seed", int, apply_field("subseed"), format_value_add_label, None), - AxisOption("Var. strength", float, apply_field("subseed_strength"), format_value_add_label, None), - AxisOption("Steps", int, apply_field("steps"), format_value_add_label, None), - AxisOption("CFG Scale", float, apply_field("cfg_scale"), format_value_add_label, None), - AxisOption("Prompt S/R", str, apply_prompt, format_value, None), - AxisOption("Prompt order", str_permutations, apply_order, format_value_join_list, None), - AxisOption("Sampler", str, apply_sampler, format_value, confirm_samplers), - AxisOption("Checkpoint name", str, apply_checkpoint, format_value, confirm_checkpoints), - AxisOption("Hypernetwork", str, apply_hypernetwork, format_value, confirm_hypernetworks), - AxisOption("Hypernet str.", float, apply_hypernetwork_strength, format_value_add_label, None), - AxisOption("Sigma Churn", float, apply_field("s_churn"), format_value_add_label, None), - AxisOption("Sigma min", float, apply_field("s_tmin"), format_value_add_label, None), - AxisOption("Sigma max", float, apply_field("s_tmax"), format_value_add_label, None), - AxisOption("Sigma noise", float, apply_field("s_noise"), format_value_add_label, None), - AxisOption("Eta", float, apply_field("eta"), format_value_add_label, None), - AxisOption("Clip skip", int, apply_clip_skip, format_value_add_label, None), - AxisOption("Denoising", float, apply_field("denoising_strength"), format_value_add_label, None), - AxisOption("Hires upscaler", str, apply_field("hr_upscaler"), format_value_add_label, None), - AxisOption("Cond. Image Mask Weight", float, apply_field("inpainting_mask_weight"), format_value_add_label, None), - AxisOption("VAE", str, apply_vae, format_value_add_label, None), - AxisOption("Styles", str, apply_styles, format_value_add_label, None), + AxisOption("Nothing", str, do_nothing, format_value=format_nothing), + AxisOption("Seed", int, apply_field("seed")), + AxisOption("Var. seed", int, apply_field("subseed")), + AxisOption("Var. strength", float, apply_field("subseed_strength")), + AxisOption("Steps", int, apply_field("steps")), + AxisOption("CFG Scale", float, apply_field("cfg_scale")), + AxisOption("Prompt S/R", str, apply_prompt, format_value=format_value), + AxisOption("Prompt order", str_permutations, apply_order, format_value=format_value_join_list), + AxisOptionTxt2Img("Sampler", str, apply_sampler, format_value=format_value, confirm=confirm_samplers, choices=lambda: [x.name for x in sd_samplers.samplers]), + AxisOptionImg2Img("Sampler", str, apply_sampler, format_value=format_value, confirm=confirm_samplers, choices=lambda: [x.name for x in sd_samplers.samplers_for_img2img]), + AxisOption("Checkpoint name", str, apply_checkpoint, format_value=format_value, confirm=confirm_checkpoints, cost=1.0, choices=lambda: list(sd_models.checkpoints_list)), + AxisOption("Sigma Churn", float, apply_field("s_churn")), + AxisOption("Sigma min", float, apply_field("s_tmin")), + AxisOption("Sigma max", float, apply_field("s_tmax")), + AxisOption("Sigma noise", float, apply_field("s_noise")), + AxisOption("Eta", float, apply_field("eta")), + AxisOption("Clip skip", int, apply_clip_skip), + AxisOption("Denoising", float, apply_field("denoising_strength")), + AxisOptionTxt2Img("Hires upscaler", str, apply_field("hr_upscaler"), choices=lambda: [*shared.latent_upscale_modes, *[x.name for x in shared.sd_upscalers]]), + AxisOptionImg2Img("Cond. Image Mask Weight", float, apply_field("inpainting_mask_weight")), + AxisOption("VAE", str, apply_vae, cost=0.7, choices=lambda: list(sd_vae.vae_dict)), + AxisOption("Styles", str, apply_styles, choices=lambda: list(shared.prompt_styles.styles)), ] -def draw_xy_grid(p, xs, ys, x_labels, y_labels, cell, draw_legend, include_lone_images): +def draw_xy_grid(p, xs, ys, x_labels, y_labels, cell, draw_legend, include_lone_images, swap_axes_processing_order): ver_texts = [[images.GridAnnotation(y)] for y in y_labels] hor_texts = [[images.GridAnnotation(x)] for x in x_labels] # Temporary list of all the images that are generated to be populated into the grid. # Will be filled with empty images for any individual step that fails to process properly - image_cache = [] + image_cache = [None] * (len(xs) * len(ys)) processed_result = None cell_mode = "P" - cell_size = (1,1) + cell_size = (1, 1) state.job_count = len(xs) * len(ys) * p.n_iter - for iy, y in enumerate(ys): + def process_cell(x, y, ix, iy): + nonlocal image_cache, processed_result, cell_mode, cell_size + + state.job = f"{ix + iy * len(xs) + 1} out of {len(xs) * len(ys)}" + + processed: Processed = cell(x, y) + + try: + # this dereference will throw an exception if the image was not processed + # (this happens in cases such as if the user stops the process from the UI) + processed_image = processed.images[0] + + if processed_result is None: + # Use our first valid processed result as a template container to hold our full results + processed_result = copy(processed) + cell_mode = processed_image.mode + cell_size = processed_image.size + processed_result.images = [Image.new(cell_mode, cell_size)] + + image_cache[ix + iy * len(xs)] = processed_image + if include_lone_images: + processed_result.images.append(processed_image) + processed_result.all_prompts.append(processed.prompt) + processed_result.all_seeds.append(processed.seed) + processed_result.infotexts.append(processed.infotexts[0]) + except: + image_cache[ix + iy * len(xs)] = Image.new(cell_mode, cell_size) + + if swap_axes_processing_order: for ix, x in enumerate(xs): - state.job = f"{ix + iy * len(xs) + 1} out of {len(xs) * len(ys)}" - - processed:Processed = cell(x, y) - try: - # this dereference will throw an exception if the image was not processed - # (this happens in cases such as if the user stops the process from the UI) - processed_image = processed.images[0] - - if processed_result is None: - # Use our first valid processed result as a template container to hold our full results - processed_result = copy(processed) - cell_mode = processed_image.mode - cell_size = processed_image.size - processed_result.images = [Image.new(cell_mode, cell_size)] - - image_cache.append(processed_image) - if include_lone_images: - processed_result.images.append(processed_image) - processed_result.all_prompts.append(processed.prompt) - processed_result.all_seeds.append(processed.seed) - processed_result.infotexts.append(processed.infotexts[0]) - except: - image_cache.append(Image.new(cell_mode, cell_size)) + for iy, y in enumerate(ys): + process_cell(x, y, ix, iy) + else: + for iy, y in enumerate(ys): + for ix, x in enumerate(xs): + process_cell(x, y, ix, iy) if not processed_result: print("Unexpected error: draw_xy_grid failed to return even a single processed image") - return Processed() + return Processed(p, []) grid = images.image_grid(image_cache, rows=len(ys)) if draw_legend: @@ -262,18 +271,12 @@ def draw_xy_grid(p, xs, ys, x_labels, y_labels, cell, draw_legend, include_lone_ class SharedSettingsStackHelper(object): def __enter__(self): self.CLIP_stop_at_last_layers = opts.CLIP_stop_at_last_layers - self.hypernetwork = opts.sd_hypernetwork - self.model = shared.sd_model self.vae = opts.sd_vae def __exit__(self, exc_type, exc_value, tb): - modules.sd_models.reload_model_weights(self.model) - opts.data["sd_vae"] = self.vae - modules.sd_vae.reload_vae_weights(self.model) - - hypernetwork.load_hypernetwork(self.hypernetwork) - hypernetwork.apply_strength() + modules.sd_models.reload_model_weights() + modules.sd_vae.reload_vae_weights() opts.data["CLIP_stop_at_last_layers"] = self.CLIP_stop_at_last_layers @@ -290,19 +293,44 @@ class Script(scripts.Script): return "X/Y plot" def ui(self, is_img2img): - current_axis_options = [x for x in axis_options if type(x) == AxisOption or type(x) == AxisOptionImg2Img and is_img2img] + self.current_axis_options = [x for x in axis_options if type(x) == AxisOption or x.is_img2img == is_img2img] with gr.Row(): - x_type = gr.Dropdown(label="X type", choices=[x.label for x in current_axis_options], value=current_axis_options[1].label, type="index", elem_id=self.elem_id("x_type")) - x_values = gr.Textbox(label="X values", lines=1, elem_id=self.elem_id("x_values")) + with gr.Column(scale=19): + with gr.Row(): + x_type = gr.Dropdown(label="X type", choices=[x.label for x in self.current_axis_options], value=self.current_axis_options[1].label, type="index", elem_id=self.elem_id("x_type")) + x_values = gr.Textbox(label="X values", lines=1, elem_id=self.elem_id("x_values")) + fill_x_button = ToolButton(value=fill_values_symbol, elem_id="xy_grid_fill_x_tool_button", visible=False) - with gr.Row(): - y_type = gr.Dropdown(label="Y type", choices=[x.label for x in current_axis_options], value=current_axis_options[0].label, type="index", elem_id=self.elem_id("y_type")) - y_values = gr.Textbox(label="Y values", lines=1, elem_id=self.elem_id("y_values")) - - draw_legend = gr.Checkbox(label='Draw legend', value=True, elem_id=self.elem_id("draw_legend")) - include_lone_images = gr.Checkbox(label='Include Separate Images', value=False, elem_id=self.elem_id("include_lone_images")) - no_fixed_seeds = gr.Checkbox(label='Keep -1 for seeds', value=False, elem_id=self.elem_id("no_fixed_seeds")) + with gr.Row(): + y_type = gr.Dropdown(label="Y type", choices=[x.label for x in self.current_axis_options], value=self.current_axis_options[0].label, type="index", elem_id=self.elem_id("y_type")) + y_values = gr.Textbox(label="Y values", lines=1, elem_id=self.elem_id("y_values")) + fill_y_button = ToolButton(value=fill_values_symbol, elem_id="xy_grid_fill_y_tool_button", visible=False) + + with gr.Row(variant="compact"): + draw_legend = gr.Checkbox(label='Draw legend', value=True, elem_id=self.elem_id("draw_legend")) + include_lone_images = gr.Checkbox(label='Include Separate Images', value=False, elem_id=self.elem_id("include_lone_images")) + no_fixed_seeds = gr.Checkbox(label='Keep -1 for seeds', value=False, elem_id=self.elem_id("no_fixed_seeds")) + swap_axes_button = gr.Button(value="Swap axes", elem_id="xy_grid_swap_axes_button") + + def swap_axes(x_type, x_values, y_type, y_values): + return self.current_axis_options[y_type].label, y_values, self.current_axis_options[x_type].label, x_values + + swap_args = [x_type, x_values, y_type, y_values] + swap_axes_button.click(swap_axes, inputs=swap_args, outputs=swap_args) + + def fill(x_type): + axis = self.current_axis_options[x_type] + return ", ".join(axis.choices()) if axis.choices else gr.update() + + fill_x_button.click(fn=fill, inputs=[x_type], outputs=[x_values]) + fill_y_button.click(fn=fill, inputs=[y_type], outputs=[y_values]) + + def select_axis(x_type): + return gr.Button.update(visible=self.current_axis_options[x_type].choices is not None) + + x_type.change(fn=select_axis, inputs=[x_type], outputs=[fill_x_button]) + y_type.change(fn=select_axis, inputs=[y_type], outputs=[fill_y_button]) return [x_type, x_values, y_type, y_values, draw_legend, include_lone_images, no_fixed_seeds] @@ -374,10 +402,10 @@ class Script(scripts.Script): return valslist - x_opt = axis_options[x_type] + x_opt = self.current_axis_options[x_type] xs = process_axis(x_opt, x_values) - y_opt = axis_options[y_type] + y_opt = self.current_axis_options[y_type] ys = process_axis(y_opt, y_values) def fix_axis_seeds(axis_opt, axis_list): @@ -405,7 +433,15 @@ class Script(scripts.Script): grid_infotext = [None] + # If one of the axes is very slow to change between (like SD model + # checkpoint), then make sure it is in the outer iteration of the nested + # `for` loop. + swap_axes_processing_order = x_opt.cost > y_opt.cost + def cell(x, y): + if shared.state.interrupted: + return Processed(p, [], p.seed, "") + pc = copy(p) x_opt.apply(pc, x, xs) y_opt.apply(pc, y, ys) @@ -440,7 +476,8 @@ class Script(scripts.Script): y_labels=[y_opt.format_value(p, y_opt, y) for y in ys], cell=cell, draw_legend=draw_legend, - include_lone_images=include_lone_images + include_lone_images=include_lone_images, + swap_axes_processing_order=swap_axes_processing_order ) if opts.grid_save: diff --git a/style.css b/style.css index ffd6307f..507acec1 100644 --- a/style.css +++ b/style.css @@ -2,12 +2,26 @@ max-width: 100%; } -#txt2img_token_counter { - height: 0px; +.token-counter{ + position: absolute; + display: inline-block; + right: 2em; + min-width: 0 !important; + width: auto; + z-index: 100; } -#img2img_token_counter { - height: 0px; +.token-counter.error span{ + box-shadow: 0 0 0.0 0.3em rgba(255,0,0,0.15), inset 0 0 0.6em rgba(255,0,0,0.075); + border: 2px solid rgba(255,0,0,0.4) !important; +} + +.token-counter div{ + display: inline; +} + +.token-counter span{ + padding: 0.1em 0.75em; } #sh{ @@ -20,7 +34,7 @@ padding-right: 0.25em; margin: 0.1em 0; opacity: 0%; - cursor: default; + cursor: default; } .output-html p {margin: 0 0.5em;} @@ -110,29 +124,22 @@ height: 100%; } -#roll_col{ - min-width: unset !important; - flex-grow: 0 !important; - padding: 0.4em 0; +#txt2img_actions_column, #img2img_actions_column{ + gap: 0; } -#roll_col > button { - min-width: 2em; - min-height: 2em; - max-width: 2em; - max-height: 2em; - flex-grow: 0; - padding-left: 0.25em; - padding-right: 0.25em; - margin: 0.1em 0; +#txt2img_tools, #img2img_tools{ + gap: 0.4em; } #interrogate_col{ min-width: 0 !important; max-width: 8em !important; + margin-right: 1em; + gap: 0; } #interrogate, #deepbooru{ - margin: 0em 0.25em 0.9em 0.25em; + margin: 0em 0.25em 0.5em 0.25em; min-width: 8em; max-width: 8em; } @@ -141,8 +148,25 @@ min-width: 8em !important; } -#txt2img_style_index, #txt2img_style2_index, #img2img_style_index, #img2img_style2_index{ - margin-top: 1em; +#txt2img_styles_row, #img2img_styles_row{ + gap: 0.25em; +} + +#txt2img_styles_row > button, #img2img_styles_row > button{ + margin: 0; +} + +#txt2img_styles, #img2img_styles{ + padding: 0; +} + +#txt2img_styles > label > div, #img2img_styles > label > div{ + min-height: 3.2em; +} + +#txt2img_styles ul, #img2img_styles ul{ + max-height: 35em; + z-index: 2000; } .gr-form{ @@ -154,12 +178,6 @@ margin-bottom: 0; } -#toprow div{ - border: none; - gap: 0; - background: transparent; -} - #resize_mode{ flex: 1.5; } @@ -221,7 +239,10 @@ fieldset span.text-gray-500, .gr-block.gr-box span.text-gray-500, label.block s .dark fieldset span.text-gray-500, .dark .gr-block.gr-box span.text-gray-500, .dark label.block span{ background-color: rgb(31, 41, 55); - box-shadow: 6px 0 6px 0px rgb(31, 41, 55), -6px 0 6px 0px rgb(31, 41, 55); + box-shadow: none; + border: 1px solid rgba(128, 128, 128, 0.1); + border-radius: 6px; + padding: 0.1em 0.5em; } #txt2img_column_batch, #img2img_column_batch{ @@ -286,45 +307,52 @@ input[type="range"]{ } /* more gradio's garbage cleanup */ -.min-h-\[4rem\] { - min-height: unset !important; -} - -#txt2img_progressbar, #img2img_progressbar, #ti_progressbar{ - position: absolute; - z-index: 1000; - right: 0; - padding-left: 5px; - padding-right: 5px; - display: block; -} - -#txt2img_progress_row, #img2img_progress_row{ - margin-bottom: 10px; - margin-top: -18px; -} +.min-h-\[4rem\] { min-height: unset !important; } +.min-h-\[6rem\] { min-height: unset !important; } .progressDiv{ - width: 100%; - height: 20px; - background: #b4c0cc; - border-radius: 8px; + position: absolute; + height: 20px; + top: -20px; + background: #b4c0cc; + border-radius: 3px !important; } .dark .progressDiv{ - background: #424c5b; + background: #424c5b; } .progressDiv .progress{ - width: 0%; - height: 20px; - background: #0060df; - color: white; - font-weight: bold; - line-height: 20px; - padding: 0 8px 0 0; - text-align: right; - border-radius: 8px; + width: 0%; + height: 20px; + background: #0060df; + color: white; + font-weight: bold; + line-height: 20px; + padding: 0 8px 0 0; + text-align: right; + border-radius: 3px; + overflow: visible; + white-space: nowrap; + padding: 0 0.5em; +} + +.livePreview{ + position: absolute; + z-index: 300; + background-color: white; + margin: -4px; +} + +.dark .livePreview{ + background-color: rgb(17 24 39 / var(--tw-bg-opacity)); +} + +.livePreview img{ + position: absolute; + object-fit: contain; + width: 100%; + height: 100%; } #lightboxModal{ @@ -371,7 +399,7 @@ input[type="range"]{ grid-area: tile; } -.modalClose, +.modalClose, .modalZoom, .modalTileImage { color: white; @@ -450,23 +478,25 @@ input[type="range"]{ display:none } -#txt2img_interrupt, #img2img_interrupt{ - position: absolute; - width: 50%; - height: 72px; - background: #b4c0cc; - border-radius: 0px; - display: none; +#txt2img_generate_box, #img2img_generate_box{ + position: relative; } +#txt2img_interrupt, #img2img_interrupt, #txt2img_skip, #img2img_skip{ + position: absolute; + width: 50%; + height: 100%; + background: #b4c0cc; + display: none; +} + +#txt2img_interrupt, #img2img_interrupt{ + left: 0; + border-radius: 0.5rem 0 0 0.5rem; +} #txt2img_skip, #img2img_skip{ - position: absolute; - width: 50%; - right: 0px; - height: 72px; - background: #b4c0cc; - border-radius: 0px; - display: none; + right: 0; + border-radius: 0 0.5rem 0.5rem 0; } .red { @@ -508,30 +538,21 @@ input[type="range"]{ gap: 0.4em; } -#quicksettings > div{ - border: none; - background: none; - flex: unset; - gap: 1em; -} - -#quicksettings > div > div{ - max-width: 32em; +#quicksettings > div, #quicksettings > fieldset{ + max-width: 24em; min-width: 24em; padding: 0; + border: none; + box-shadow: none; + background: none; } -#quicksettings > div > div > div > div > label > span { +#quicksettings > div > div > div > label > span { position: relative; margin-right: 9em; margin-bottom: -1em; } -#quicksettings > div > div > label > span { - position: relative; - margin-bottom: -1em; -} - canvas[key="mask"] { z-index: 12 !important; filter: invert(); @@ -617,13 +638,31 @@ canvas[key="mask"] { background-color: rgb(31 41 55 / var(--tw-bg-opacity)); } -.gr-button-tool{ +.gr-button-tool, .gr-button-tool-top{ max-width: 2.5em; min-width: 2.5em !important; height: 2.4em; - margin: 0.55em 0; } +.gr-button-tool{ + margin: 0.6em 0em 0.55em 0; +} + +.gr-button-tool-top, #settings .gr-button-tool{ + margin: 1.6em 0.7em 0.55em 0; +} + + +#modelmerger_results_container{ + margin-top: 1em; + overflow: visible; +} + +#modelmerger_models{ + gap: 0; +} + + #quicksettings .gr-button-tool{ margin: 0; } @@ -666,91 +705,161 @@ footer { font-weight: bold; } -#txt2img_checkboxes > div > div{ +#txt2img_checkboxes, #img2img_checkboxes{ + margin-bottom: 0.5em; + margin-left: 0em; +} +#txt2img_checkboxes > div, #img2img_checkboxes > div{ flex: 0; white-space: nowrap; min-width: auto; } +#txt2img_hires_fix{ + margin-left: -0.8em; +} .inactive{ opacity: 0.5; } -/* The following handles localization for right-to-left (RTL) languages like Arabic. -The rtl media type will only be activated by the logic in javascript/localization.js. -If you change anything above, you need to make sure it is RTL compliant by just running -your changes through converters like https://cssjanus.github.io/ or https://rtlcss.com/. -Then, you will need to add the RTL counterpart only if needed in the rtl section below.*/ -@media rtl { - /* this part was added manually */ - :host { - direction: rtl; - } - select, .file-preview, .gr-text-input, .output-html:has(.performance), #ti_progress { - direction: ltr; - } - #script_list > label > select, - #x_type > label > select, - #y_type > label > select { - direction: rtl; - } - .gr-radio, .gr-checkbox{ - margin-left: 0.25em; - } +[id*='_prompt_container']{ + gap: 0; +} + +[id*='_prompt_container'] > div{ + margin: -0.4em 0 0 0; +} + +.gr-compact { + border: none; +} + +.dark .gr-compact{ + background-color: rgb(31 41 55 / var(--tw-bg-opacity)); + margin-left: 0.8em; +} + +.gr-compact{ + overflow: visible; +} + +.gr-compact > *{ +} + +.gr-compact .gr-block, .gr-compact .gr-form{ + border: none; + box-shadow: none; +} + +.gr-compact .gr-box{ + border-radius: .5rem !important; + border-width: 1px !important; +} + +#mode_img2img > div > div{ + gap: 0 !important; +} + +[id*='img2img_copy_to_'] { + border: none; +} + +[id*='img2img_copy_to_'] > button { +} + +[id*='img2img_label_copy_to_'] { + font-size: 1.0em; + font-weight: bold; + text-align: center; + line-height: 2.4em; +} + +.extra-networks > div > [id *= '_extra_']{ + margin: 0.3em; +} + + + +#txt2img_extra_networks .search, #img2img_extra_networks .search{ + display: inline-block; + max-width: 16em; + margin: 0.3em; +} + +.extra-network-cards .nocards{ + margin: 1.25em 0.5em 0.5em 0.5em; +} + +.extra-network-cards .nocards h1{ + font-size: 1.5em; + margin-bottom: 1em; +} + +.extra-network-cards .nocards li{ + margin-left: 0.5em; +} + +.extra-network-cards .card{ + display: inline-block; + margin: 0.5em; + width: 16em; + height: 24em; + box-shadow: 0 0 5px rgba(128, 128, 128, 0.5); + border-radius: 0.2em; + position: relative; + + background-size: auto 100%; + background-position: center; + overflow: hidden; + cursor: pointer; + + background-image: url('./file=html/card-no-preview.png') +} + +.extra-network-cards .card:hover{ + box-shadow: 0 0 2px 0.3em rgba(0, 128, 255, 0.35); +} + +.extra-network-cards .card .actions .additional{ + display: none; +} + +.extra-network-cards .card .actions{ + position: absolute; + bottom: 0; + left: 0; + right: 0; + padding: 0.5em; + color: white; + background: rgba(0,0,0,0.5); + box-shadow: 0 0 0.25em 0.25em rgba(0,0,0,0.5); + text-shadow: 0 0 0.2em black; +} + +.extra-network-cards .card .actions:hover{ + box-shadow: 0 0 0.75em 0.75em rgba(0,0,0,0.5) !important; +} + +.extra-network-cards .card .actions .name{ + font-size: 1.7em; + font-weight: bold; + line-break: anywhere; +} + +.extra-network-cards .card .actions:hover .additional{ + display: block; +} + +.extra-network-cards .card ul{ + margin: 0.25em 0 0.75em 0.25em; + cursor: unset; +} + +.extra-network-cards .card ul a{ + cursor: pointer; +} + +.extra-network-cards .card ul a:hover{ + color: red; +} - /* automatically generated with few manual modifications */ - .performance .time { - margin-right: unset; - margin-left: 0; - } - .justify-center.overflow-x-scroll { - justify-content: right; - } - .justify-center.overflow-x-scroll button:first-of-type { - margin-left: unset; - margin-right: auto; - } - .justify-center.overflow-x-scroll button:last-of-type { - margin-right: unset; - margin-left: auto; - } - #settings fieldset span.text-gray-500, #settings .gr-block.gr-box span.text-gray-500, #settings label.block span{ - margin-right: unset; - margin-left: 8em; - } - #txt2img_progressbar, #img2img_progressbar, #ti_progressbar{ - right: unset; - left: 0; - } - .progressDiv .progress{ - padding: 0 0 0 8px; - text-align: left; - } - #lightboxModal{ - left: unset; - right: 0; - } - .modalPrev, .modalNext{ - border-radius: 3px 0 0 3px; - } - .modalNext { - right: unset; - left: 0; - border-radius: 0 3px 3px 0; - } - #imageARPreview{ - left:unset; - right:0px; - } - #txt2img_skip, #img2img_skip{ - right: unset; - left: 0px; - } - #context-menu{ - box-shadow:-1px 1px 2px #CE6400; - } - .gr-box > div > div > input.gr-text-input{ - right: unset; - left: 0.5em; - } -} \ No newline at end of file diff --git a/test/basic_features/utils_test.py b/test/basic_features/utils_test.py index 94e00253..0bfc28a0 100644 --- a/test/basic_features/utils_test.py +++ b/test/basic_features/utils_test.py @@ -12,8 +12,6 @@ class UtilsTests(unittest.TestCase): self.url_face_restorers = "http://localhost:7860/sdapi/v1/face-restorers" self.url_realesrgan_models = "http://localhost:7860/sdapi/v1/realesrgan-models" self.url_prompt_styles = "http://localhost:7860/sdapi/v1/prompt-styles" - self.url_artist_categories = "http://localhost:7860/sdapi/v1/artist-categories" - self.url_artists = "http://localhost:7860/sdapi/v1/artists" self.url_embeddings = "http://localhost:7860/sdapi/v1/embeddings" def test_options_get(self): @@ -56,15 +54,9 @@ class UtilsTests(unittest.TestCase): def test_prompt_styles(self): self.assertEqual(requests.get(self.url_prompt_styles).status_code, 200) - - def test_artist_categories(self): - self.assertEqual(requests.get(self.url_artist_categories).status_code, 200) - - def test_artists(self): - self.assertEqual(requests.get(self.url_artists).status_code, 200) def test_embeddings(self): - self.assertEqual(requests.get(self.url_artists).status_code, 200) + self.assertEqual(requests.get(self.url_embeddings).status_code, 200) if __name__ == "__main__": unittest.main() diff --git a/webui.py b/webui.py index 1fff80da..d235da74 100644 --- a/webui.py +++ b/webui.py @@ -9,16 +9,18 @@ from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware from fastapi.middleware.gzip import GZipMiddleware -from modules import import_hook, errors +from modules import import_hook, errors, extra_networks +from modules import extra_networks_hypernet, ui_extra_networks_hypernets, ui_extra_networks_textual_inversion from modules.call_queue import wrap_queued_call, queue_lock, wrap_gradio_gpu_call from modules.paths import script_path import torch + # Truncate version number of nightly/local build of PyTorch to not cause exceptions with CodeFormer or Safetensors if ".dev" in torch.__version__ or "+git" in torch.__version__: torch.__version__ = re.search(r'[\d.]+[\d]', torch.__version__).group(0) -from modules import shared, devices, sd_samplers, upscaler, extensions, localization, ui_tempdir +from modules import shared, devices, sd_samplers, upscaler, extensions, localization, ui_tempdir, ui_extra_networks import modules.codeformer_model as codeformer import modules.extras import modules.face_restoration @@ -34,6 +36,7 @@ import modules.sd_vae import modules.txt2img import modules.script_callbacks import modules.textual_inversion.textual_inversion +import modules.progress import modules.ui from modules import modelloader @@ -83,10 +86,17 @@ def initialize(): shared.opts.onchange("sd_model_checkpoint", wrap_queued_call(lambda: modules.sd_models.reload_model_weights())) shared.opts.onchange("sd_vae", wrap_queued_call(lambda: modules.sd_vae.reload_vae_weights()), call=False) shared.opts.onchange("sd_vae_as_default", wrap_queued_call(lambda: modules.sd_vae.reload_vae_weights()), call=False) - shared.opts.onchange("sd_hypernetwork", wrap_queued_call(lambda: shared.reload_hypernetworks())) - shared.opts.onchange("sd_hypernetwork_strength", modules.hypernetworks.hypernetwork.apply_strength) shared.opts.onchange("temp_dir", ui_tempdir.on_tmpdir_changed) + shared.reload_hypernetworks() + + ui_extra_networks.intialize() + ui_extra_networks.register_page(ui_extra_networks_textual_inversion.ExtraNetworksPageTextualInversion()) + ui_extra_networks.register_page(ui_extra_networks_hypernets.ExtraNetworksPageHypernetworks()) + + extra_networks.initialize() + extra_networks.register_extra_network(extra_networks_hypernet.ExtraNetworkHypernet()) + if cmd_opts.tls_keyfile is not None and cmd_opts.tls_keyfile is not None: try: @@ -155,9 +165,14 @@ def webui(): if shared.opts.clean_temp_dir_at_start: ui_tempdir.cleanup_tmpdr() + modules.script_callbacks.before_ui_callback() + shared.demo = modules.ui.create_ui() - app, local_url, share_url = shared.demo.queue(default_enabled=False).launch( + if cmd_opts.gradio_queue: + shared.demo.queue(64) + + app, local_url, share_url = shared.demo.launch( share=cmd_opts.share, server_name=server_name, server_port=cmd_opts.port, @@ -181,11 +196,12 @@ def webui(): app.add_middleware(GZipMiddleware, minimum_size=1000) + modules.progress.setup_progress_api(app) + if launch_api: create_api(app) modules.script_callbacks.app_started_callback(shared.demo, app) - modules.script_callbacks.app_started_callback(shared.demo, app) wait_on_server(shared.demo) print('Restarting UI...') @@ -207,6 +223,15 @@ def webui(): modules.sd_models.list_models() + shared.reload_hypernetworks() + + ui_extra_networks.intialize() + ui_extra_networks.register_page(ui_extra_networks_textual_inversion.ExtraNetworksPageTextualInversion()) + ui_extra_networks.register_page(ui_extra_networks_hypernets.ExtraNetworksPageHypernetworks()) + + extra_networks.initialize() + extra_networks.register_extra_network(extra_networks_hypernet.ExtraNetworkHypernet()) + if __name__ == "__main__": if cmd_opts.nowebui: diff --git a/webui.sh b/webui.sh index c4d6521d..8cdad22d 100755 --- a/webui.sh +++ b/webui.sh @@ -104,6 +104,23 @@ then fi # Check prerequisites +gpu_info=$(lspci 2>/dev/null | grep VGA) +case "$gpu_info" in + *"Navi 1"*|*"Navi 2"*) export HSA_OVERRIDE_GFX_VERSION=10.3.0 + ;; + *"Renoir"*) export HSA_OVERRIDE_GFX_VERSION=9.0.0 + printf "\n%s\n" "${delimiter}" + printf "Experimental support for Renoir: make sure to have at least 4GB of VRAM and 10GB of RAM or enable cpu mode: --use-cpu all --no-half" + printf "\n%s\n" "${delimiter}" + ;; + *) + ;; +esac +if echo "$gpu_info" | grep -q "AMD" && [[ -z "${TORCH_COMMAND}" ]] +then + export TORCH_COMMAND="pip install torch torchvision --extra-index-url https://download.pytorch.org/whl/rocm5.2" +fi + for preq in "${GIT}" "${python_cmd}" do if ! hash "${preq}" &>/dev/null @@ -164,6 +181,6 @@ then else printf "\n%s\n" "${delimiter}" printf "Launching launch.py..." - printf "\n%s\n" "${delimiter}" + printf "\n%s\n" "${delimiter}" exec "${python_cmd}" "${LAUNCH_SCRIPT}" "$@" fi