Groundspout commited on
Commit
b860881
·
1 Parent(s): c4a2b08

Upload 4 files

Browse files
Files changed (4) hide show
  1. .gitignore +7 -0
  2. LICENSE +201 -0
  3. README.md +105 -12
  4. app.py +377 -0
.gitignore ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ __pycache__
2
+ deprecated
3
+ model
4
+ output
5
+ venv
6
+ v1-*inference.yaml
7
+ convert*
LICENSE ADDED
@@ -0,0 +1,201 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or
36
+ Object form, made available under the License, as indicated by a
37
+ copyright notice that is included in or attached to the work
38
+ (an example is provided in the Appendix below).
39
+
40
+ "Derivative Works" shall mean any work, whether in Source or Object
41
+ form, that is based on (or derived from) the Work and for which the
42
+ editorial revisions, annotations, elaborations, or other modifications
43
+ represent, as a whole, an original work of authorship. For the purposes
44
+ of this License, Derivative Works shall not include works that remain
45
+ separable from, or merely link (or bind by name) to the interfaces of,
46
+ the Work and Derivative Works thereof.
47
+
48
+ "Contribution" shall mean any work of authorship, including
49
+ the original version of the Work and any modifications or additions
50
+ to that Work or Derivative Works thereof, that is intentionally
51
+ submitted to Licensor for inclusion in the Work by the copyright owner
52
+ or by an individual or Legal Entity authorized to submit on behalf of
53
+ the copyright owner. For the purposes of this definition, "submitted"
54
+ means any form of electronic, verbal, or written communication sent
55
+ to the Licensor or its representatives, including but not limited to
56
+ communication on electronic mailing lists, source code control systems,
57
+ and issue tracking systems that are managed by, or on behalf of, the
58
+ Licensor for the purpose of discussing and improving the Work, but
59
+ excluding communication that is conspicuously marked or otherwise
60
+ designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+ "Contributor" shall mean Licensor and any individual or Legal Entity
63
+ on behalf of whom a Contribution has been received by Licensor and
64
+ subsequently incorporated within the Work.
65
+
66
+ 2. Grant of Copyright License. Subject to the terms and conditions of
67
+ this License, each Contributor hereby grants to You a perpetual,
68
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+ copyright license to reproduce, prepare Derivative Works of,
70
+ publicly display, publicly perform, sublicense, and distribute the
71
+ Work and such Derivative Works in Source or Object form.
72
+
73
+ 3. Grant of Patent License. Subject to the terms and conditions of
74
+ this License, each Contributor hereby grants to You a perpetual,
75
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+ (except as stated in this section) patent license to make, have made,
77
+ use, offer to sell, sell, import, and otherwise transfer the Work,
78
+ where such license applies only to those patent claims licensable
79
+ by such Contributor that are necessarily infringed by their
80
+ Contribution(s) alone or by combination of their Contribution(s)
81
+ with the Work to which such Contribution(s) was submitted. If You
82
+ institute patent litigation against any entity (including a
83
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+ or a Contribution incorporated within the Work constitutes direct
85
+ or contributory patent infringement, then any patent licenses
86
+ granted to You under this License for that Work shall terminate
87
+ as of the date such litigation is filed.
88
+
89
+ 4. Redistribution. You may reproduce and distribute copies of the
90
+ Work or Derivative Works thereof in any medium, with or without
91
+ modifications, and in Source or Object form, provided that You
92
+ meet the following conditions:
93
+
94
+ (a) You must give any other recipients of the Work or
95
+ Derivative Works a copy of this License; and
96
+
97
+ (b) You must cause any modified files to carry prominent notices
98
+ stating that You changed the files; and
99
+
100
+ (c) You must retain, in the Source form of any Derivative Works
101
+ that You distribute, all copyright, patent, trademark, and
102
+ attribution notices from the Source form of the Work,
103
+ excluding those notices that do not pertain to any part of
104
+ the Derivative Works; and
105
+
106
+ (d) If the Work includes a "NOTICE" text file as part of its
107
+ distribution, then any Derivative Works that You distribute must
108
+ include a readable copy of the attribution notices contained
109
+ within such NOTICE file, excluding those notices that do not
110
+ pertain to any part of the Derivative Works, in at least one
111
+ of the following places: within a NOTICE text file distributed
112
+ as part of the Derivative Works; within the Source form or
113
+ documentation, if provided along with the Derivative Works; or,
114
+ within a display generated by the Derivative Works, if and
115
+ wherever such third-party notices normally appear. The contents
116
+ of the NOTICE file are for informational purposes only and
117
+ do not modify the License. You may add Your own attribution
118
+ notices within Derivative Works that You distribute, alongside
119
+ or as an addendum to the NOTICE text from the Work, provided
120
+ that such additional attribution notices cannot be construed
121
+ as modifying the License.
122
+
123
+ You may add Your own copyright statement to Your modifications and
124
+ may provide additional or different license terms and conditions
125
+ for use, reproduction, or distribution of Your modifications, or
126
+ for any such Derivative Works as a whole, provided Your use,
127
+ reproduction, and distribution of the Work otherwise complies with
128
+ the conditions stated in this License.
129
+
130
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
131
+ any Contribution intentionally submitted for inclusion in the Work
132
+ by You to the Licensor shall be under the terms and conditions of
133
+ this License, without any additional terms or conditions.
134
+ Notwithstanding the above, nothing herein shall supersede or modify
135
+ the terms of any separate license agreement you may have executed
136
+ with Licensor regarding such Contributions.
137
+
138
+ 6. Trademarks. This License does not grant permission to use the trade
139
+ names, trademarks, service marks, or product names of the Licensor,
140
+ except as required for reasonable and customary use in describing the
141
+ origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+ 7. Disclaimer of Warranty. Unless required by applicable law or
144
+ agreed to in writing, Licensor provides the Work (and each
145
+ Contributor provides its Contributions) on an "AS IS" BASIS,
146
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+ implied, including, without limitation, any warranties or conditions
148
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+ PARTICULAR PURPOSE. You are solely responsible for determining the
150
+ appropriateness of using or redistributing the Work and assume any
151
+ risks associated with Your exercise of permissions under this License.
152
+
153
+ 8. Limitation of Liability. In no event and under no legal theory,
154
+ whether in tort (including negligence), contract, or otherwise,
155
+ unless required by applicable law (such as deliberate and grossly
156
+ negligent acts) or agreed to in writing, shall any Contributor be
157
+ liable to You for damages, including any direct, indirect, special,
158
+ incidental, or consequential damages of any character arising as a
159
+ result of this License or out of the use or inability to use the
160
+ Work (including but not limited to damages for loss of goodwill,
161
+ work stoppage, computer failure or malfunction, or any and all
162
+ other commercial damages or losses), even if such Contributor
163
+ has been advised of the possibility of such damages.
164
+
165
+ 9. Accepting Warranty or Additional Liability. While redistributing
166
+ the Work or Derivative Works thereof, You may choose to offer,
167
+ and charge a fee for, acceptance of support, warranty, indemnity,
168
+ or other liability obligations and/or rights consistent with this
169
+ License. However, in accepting such obligations, You may act only
170
+ on Your own behalf and on Your sole responsibility, not on behalf
171
+ of any other Contributor, and only if You agree to indemnify,
172
+ defend, and hold each Contributor harmless for any liability
173
+ incurred by, or claims asserted against, such Contributor by reason
174
+ of your accepting any such warranty or additional liability.
175
+
176
+ END OF TERMS AND CONDITIONS
177
+
178
+ APPENDIX: How to apply the Apache License to your work.
179
+
180
+ To apply the Apache License to your work, attach the following
181
+ boilerplate notice, with the fields enclosed by brackets "[]"
182
+ replaced with your own identifying information. (Don't include
183
+ the brackets!) The text should be enclosed in the appropriate
184
+ comment syntax for the file format. We also recommend that a
185
+ file or class name and description of purpose be included on the
186
+ same "printed page" as the copyright notice for easier
187
+ identification within third-party archives.
188
+
189
+ Copyright [yyyy] [name of copyright owner]
190
+
191
+ Licensed under the Apache License, Version 2.0 (the "License");
192
+ you may not use this file except in compliance with the License.
193
+ You may obtain a copy of the License at
194
+
195
+ http://www.apache.org/licenses/LICENSE-2.0
196
+
197
+ Unless required by applicable law or agreed to in writing, software
198
+ distributed under the License is distributed on an "AS IS" BASIS,
199
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200
+ See the License for the specific language governing permissions and
201
+ limitations under the License.
README.md CHANGED
@@ -1,12 +1,105 @@
1
- ---
2
- title: Ljnhsdf
3
- emoji: 🔥
4
- colorFrom: yellow
5
- colorTo: blue
6
- sdk: gradio
7
- sdk_version: 3.35.2
8
- app_file: app.py
9
- pinned: false
10
- ---
11
-
12
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Stable Diffusion ONNX UI
2
+
3
+ * [First installation](#first-installation)
4
+ * [How to add models](#how-to-add-models)
5
+ * [Run](#run)
6
+ * [Updating](#updating)
7
+
8
+ Dead simple gui with support for latest [Diffusers (v0.12.0)](https://github.com/huggingface/diffusers/) on Windows with AMD graphic cards (or CPU, thanks to ONNX and DirectML) with [Stable Diffusion 2.1](https://huggingface.co/stabilityai/stable-diffusion-2-1) or any other model, even inpainting finetuned ones.
9
+
10
+ Supported schedulers: DDIM, LMS, PNDM, Euler.
11
+
12
+ Built with Gradio.
13
+
14
+ ![image](./screenshots/app.png)
15
+
16
+ ![image](./screenshots/inpainting.png)
17
+
18
+ ## First installation
19
+
20
+ Prerequisites
21
+
22
+ * [Python 3.10](https://www.python.org/downloads/)
23
+ * [Git for windows](https://git-scm.com/download/win)
24
+ * An [huggingface.co](https://huggingface.co) account
25
+ * For a better experience, the [latest version of Powershell](https://github.com/PowerShell/PowerShell/releases)
26
+
27
+ From an empty folder:
28
+
29
+ ```ps1
30
+ python -m venv venv
31
+ .\venv\Scripts\activate
32
+ python -m pip install --upgrade pip
33
+ pip install wheel wget
34
+ pip install git+https://github.com/huggingface/diffusers.git
35
+ pip install transformers onnxruntime onnx gradio torch ftfy spacy scipy OmegaConf accelerate
36
+ pip install onnxruntime-directml --force-reinstall
37
+ pip install protobuf==3.20.2
38
+ python -m wget https://raw.githubusercontent.com/JbPasquier/stable-diffusion-onnx-ui/main/app.py
39
+ python -m wget https://raw.githubusercontent.com/huggingface/diffusers/main/scripts/convert_original_stable_diffusion_to_diffusers.py -o convert_original_stable_diffusion_to_diffusers.py
40
+ python -m wget https://raw.githubusercontent.com/huggingface/diffusers/main/scripts/convert_stable_diffusion_checkpoint_to_onnx.py -o convert_stable_diffusion_checkpoint_to_onnx.py
41
+ python -m wget https://raw.githubusercontent.com/runwayml/stable-diffusion/main/configs/stable-diffusion/v1-inference.yaml -o v1-inference.yaml
42
+ python -m wget https://raw.githubusercontent.com/runwayml/stable-diffusion/main/configs/stable-diffusion/v1-inpainting-inference.yaml -o v1-inpainting-inference.yaml
43
+ mkdir model
44
+ ```
45
+
46
+ ## How to add models
47
+
48
+ ### Stable Diffusion
49
+
50
+ ```ps1
51
+ python convert_stable_diffusion_checkpoint_to_onnx.py --model_path="stabilityai/stable-diffusion-2-1" --output_path="model/stable_diffusion_onnx"
52
+ ```
53
+
54
+ ### Stable Diffusion Inpainting
55
+
56
+ ```ps1
57
+ python convert_stable_diffusion_checkpoint_to_onnx.py --model_path="stabilityai/stable-diffusion-2-inpainting" --output_path="model/stable_diffusion_inpainting_onnx"
58
+ ```
59
+
60
+ ### Other from Hugging Face
61
+
62
+ ```ps1
63
+ python convert_stable_diffusion_checkpoint_to_onnx.py --model_path="nitrosocke/Nitro-Diffusion" --output_path="model/nitro_diffusion_onnx"
64
+ ```
65
+
66
+ ### Other from somewhere else
67
+
68
+ Replace `some_file.ckpt` with the path to your ckpt one.
69
+
70
+ ```ps1
71
+ python convert_original_stable_diffusion_to_diffusers.py --checkpoint_path="./some_file.ckpt" --dump_path="./some_file"
72
+ python convert_stable_diffusion_checkpoint_to_onnx.py --model_path="./some_file" --output_path="model/some_onnx"
73
+ ```
74
+
75
+ ## Run
76
+
77
+ ```ps1
78
+ # Ensure that you are in the virtualenv
79
+ .\venv\Scripts\activate
80
+
81
+ # Your computer only
82
+ python app.py
83
+
84
+ # Local network
85
+ python app.py --local
86
+
87
+ # The whole internet
88
+ python app.py --share
89
+
90
+ # Use CPU instead of AMD GPU
91
+ python app.py --cpu-only
92
+ ```
93
+
94
+ Notice that inpainting provide way better results with a proper model like [stable-diffusion-inpainting](https://huggingface.co/stabilityai/stable-diffusion-2-inpainting)
95
+
96
+ ## Updating
97
+
98
+ Remove `venv` folder and `*.py` files and restart the [First installation](#first-installation) process.
99
+
100
+ ## Credits
101
+
102
+ Inspired by:
103
+
104
+ * [azuritecoin/OnnxDiffusersUI](https://github.com/azuritecoin/OnnxDiffusersUI)
105
+ * [averad/256c507baa3dcc9464203dc14610d674](https://gist.github.com/averad/256c507baa3dcc9464203dc14610d674)
app.py ADDED
@@ -0,0 +1,377 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import argparse
2
+ import gc
3
+ import os
4
+ import re
5
+ import time
6
+ from datetime import datetime
7
+ from pathlib import Path
8
+ from typing import Tuple
9
+
10
+ from diffusers import OnnxStableDiffusionPipeline, OnnxStableDiffusionImg2ImgPipeline
11
+ from diffusers import OnnxStableDiffusionInpaintPipeline, OnnxStableDiffusionInpaintPipelineLegacy
12
+ from diffusers import DDIMScheduler, LMSDiscreteScheduler, PNDMScheduler, EulerDiscreteScheduler
13
+ from diffusers import __version__ as _df_version
14
+ import gradio as gr
15
+ import numpy as np
16
+ from packaging import version
17
+ import PIL
18
+
19
+
20
+
21
+ def get_latents_from_seed(seed: int, batch_size: int, height: int, width: int) -> np.ndarray:
22
+ latents_shape = (batch_size, 4, height // 8, width // 8)
23
+ rng = np.random.default_rng(seed)
24
+ image_latents = rng.standard_normal(latents_shape).astype(np.float32)
25
+ return image_latents
26
+
27
+
28
+ def run_diffusers(
29
+ prompt: str,
30
+ neg_prompt: str,
31
+ init_image: PIL.Image.Image,
32
+ iteration_count: int,
33
+ batch_size: int,
34
+ steps: int,
35
+ guidance_scale: float,
36
+ height: int,
37
+ width: int,
38
+ eta: float,
39
+ denoise_strength: float,
40
+ seed: str,
41
+ mask_image: PIL.Image.Image
42
+ ) -> Tuple[list, str]:
43
+ global model_name
44
+ global current_pipe
45
+ global pipe
46
+
47
+ prompt.strip("\n")
48
+ neg_prompt.strip("\n")
49
+
50
+ if seed == "":
51
+ rng = np.random.default_rng()
52
+ seed = rng.integers(np.iinfo(np.uint32).max)
53
+ else:
54
+ try:
55
+ seed = int(seed) & np.iinfo(np.uint32).max
56
+ except ValueError:
57
+ seed = hash(seed) & np.iinfo(np.uint32).max
58
+ seeds = np.array([seed], dtype=np.uint32)
59
+ if iteration_count > 1:
60
+ seed_seq = np.random.SeedSequence(seed)
61
+ seeds = np.concatenate((seeds, seed_seq.generate_state(iteration_count - 1)))
62
+
63
+ output_path = "output"
64
+ os.makedirs(output_path, exist_ok=True)
65
+
66
+ sched_name = str(pipe.scheduler._class_name)
67
+ prompts = [prompt]*batch_size
68
+ neg_prompts = [neg_prompt]*batch_size if neg_prompt != "" else None
69
+ images = []
70
+ time_taken = 0
71
+ output_base_path = Path("./output")
72
+ for i in range(iteration_count):
73
+ dt_obj = datetime.now()
74
+ dt_cust = dt_obj.strftime("%Y-%m-%d_%H-%M-%S")
75
+ image_name = dt_cust + "_" + str(seed) + ".png"
76
+ text_name = dt_cust + "_" + str(seed) + "_info.txt"
77
+ image_path = output_base_path / image_name
78
+ text_path = output_base_path / text_name
79
+ info = f"Prompt: {prompt}\nNegative prompt: {neg_prompt}\nSeed: {seeds[i]}\n" + \
80
+ f"Scheduler: {sched_name}\nScale: {guidance_scale}\nHeight: {height}\nWidth: {width}\nETA: {eta}\n" + \
81
+ f"Model: {model_name}\nIteration size: {iteration_count}\nBatch size: {batch_size}\nSteps: {steps}"
82
+ if (current_pipe == "img2img" or current_pipe == "inpaint" ):
83
+ info = info + f" denoise: {denoise_strength}"
84
+ with open(text_path, 'w', encoding='utf-8') as f:
85
+ f.write(info)
86
+
87
+ if current_pipe == "txt2img":
88
+ # Generate our own latents so that we can provide a seed.
89
+ latents = get_latents_from_seed(seeds[i], batch_size, height, width)
90
+
91
+ start = time.time()
92
+ batch_images = pipe(
93
+ prompts, negative_prompt=neg_prompts, height=height, width=width, num_inference_steps=steps,
94
+ guidance_scale=guidance_scale, eta=eta, latents=latents).images
95
+ finish = time.time()
96
+ elif current_pipe == "img2img":
97
+ # NOTE: at this time there's no good way of setting the seed for the random noise added by the scheduler
98
+ # np.random.seed(seeds[i])
99
+ start = time.time()
100
+ batch_images = pipe(
101
+ prompts, negative_prompt=neg_prompts, init_image=init_image, height=height, width=width,
102
+ num_inference_steps=steps, guidance_scale=guidance_scale, eta=eta, strength=denoise_strength,
103
+ num_images_per_prompt=batch_size).images
104
+ finish = time.time()
105
+ elif current_pipe == "inpaint":
106
+ start = time.time()
107
+ # NOTE: legacy require init_image but inpainting use image
108
+ batch_images = pipe(
109
+ prompts, negative_prompt=neg_prompts, image=init_image, mask_image=mask_image, height=height, width=width,
110
+ num_inference_steps=steps, guidance_scale=guidance_scale, eta=eta, strength=denoise_strength,
111
+ num_images_per_prompt=batch_size, init_image=init_image).images
112
+ finish = time.time()
113
+
114
+ short_prompt = prompt.strip("<>:\"/\\|?*\n\t")
115
+ short_prompt = short_prompt[:99] if len(short_prompt) > 100 else short_prompt
116
+ for j in range(batch_size):
117
+ batch_images[j].save(image_path)
118
+
119
+ images.extend(batch_images)
120
+ time_taken = time_taken + (finish - start)
121
+
122
+ time_taken = time_taken / 60.0
123
+ if iteration_count > 1:
124
+ status = f"Run took {time_taken:.1f} minutes " + \
125
+ f"to generate {iteration_count} iterations with batch size of {batch_size}. seeds: " + \
126
+ np.array2string(seeds, separator=",")
127
+ else:
128
+ status = f"Run took {time_taken:.1f} minutes to generate a batch size of " + \
129
+ f"{batch_size}. seed: {seeds[0]}"
130
+
131
+ return images, status
132
+
133
+
134
+ def clear_click():
135
+ return {
136
+ prompt: "", neg_prompt: "", image: None, mask: None, mask_mode: "Draw mask", sch: "Euler", iter: 1, batch: 1,
137
+ drawn_mask: None, steps: 25, guid: 11, height: 512, width: 512, eta: 0.0, denoise: 0.8, seed: ""}
138
+
139
+
140
+ def generate_click(
141
+ model_drop, prompt, neg_prompt, sch, iter, batch, steps, guid, height, width, eta,
142
+ seed, image, denoise, mask, pipeline, mask_mode, drawn_mask
143
+ ):
144
+ global model_name
145
+ global provider
146
+ global current_pipe
147
+ global scheduler
148
+ global pipe
149
+
150
+ # reset scheduler and pipeline if model is different
151
+ if model_name != model_drop:
152
+ model_name = model_drop
153
+ scheduler = None
154
+ pipe = None
155
+ model_path = os.path.join("model", model_name)
156
+
157
+ if sch == "PNDM" and type(scheduler) is not PNDMScheduler:
158
+ scheduler = PNDMScheduler.from_pretrained(model_path, subfolder="scheduler")
159
+ elif sch == "LMS" and type(scheduler) is not LMSDiscreteScheduler:
160
+ scheduler = LMSDiscreteScheduler.from_pretrained(model_path, subfolder="scheduler")
161
+ elif sch == "DDIM" and type(scheduler) is not DDIMScheduler:
162
+ scheduler = DDIMScheduler.from_pretrained(model_path, subfolder="scheduler")
163
+ elif sch == "Euler" and type(scheduler) is not EulerDiscreteScheduler:
164
+ scheduler = EulerDiscreteScheduler.from_pretrained(model_path, subfolder="scheduler")
165
+
166
+ # select which pipeline depending on current tab
167
+ if pipeline == "TEXT2IMG":
168
+ if current_pipe != "txt2img" or pipe is None:
169
+ pipe = OnnxStableDiffusionPipeline.from_pretrained(
170
+ model_path, provider=provider, scheduler=scheduler)
171
+ gc.collect()
172
+ current_pipe = "txt2img"
173
+
174
+ if type(pipe.scheduler) is not type(scheduler):
175
+ pipe.scheduler = scheduler
176
+
177
+ return run_diffusers(
178
+ prompt, neg_prompt, None, iter, batch, steps, guid, height, width, eta, 0,
179
+ seed, None)
180
+ elif pipeline == "IMG2IMG":
181
+ if current_pipe != "img2img" or pipe is None:
182
+ pipe = OnnxStableDiffusionImg2ImgPipeline.from_pretrained(
183
+ model_path, provider=provider, scheduler=scheduler)
184
+ gc.collect()
185
+ current_pipe = "img2img"
186
+
187
+ if type(pipe.scheduler) is not type(scheduler):
188
+ pipe.scheduler = scheduler
189
+
190
+ # input image resizing
191
+ input_image = image.convert("RGB")
192
+ input_width, input_height = input_image.size
193
+ if height / width > input_height / input_width:
194
+ adjust_width = int(input_width * height / input_height)
195
+ input_image = input_image.resize((adjust_width, height))
196
+ left = (adjust_width - width) // 2
197
+ right = left + width
198
+ input_image = input_image.crop((left, 0, right, height))
199
+ else:
200
+ adjust_height = int(input_height * width / input_width)
201
+ input_image = input_image.resize((width, adjust_height))
202
+ top = (adjust_height - height) // 2
203
+ bottom = top + height
204
+ input_image = input_image.crop((0, top, width, bottom))
205
+
206
+ return run_diffusers(
207
+ prompt, neg_prompt, input_image, iter, batch, steps, guid, height, width, eta,
208
+ denoise, seed, None)
209
+ elif pipeline == "Inpainting":
210
+ if current_pipe != "inpaint" or pipe is None:
211
+ # >=0.8.0: Model name must ends with "inpainting" to use the proper pipeline
212
+ # This allows usage of Legacy pipeline for models not finetuned for inpainting
213
+ # see huggingface/diffusers!51
214
+ if not model_name.endswith("inpainting"):
215
+ pipe = OnnxStableDiffusionInpaintPipelineLegacy.from_pretrained(
216
+ model_path, provider=provider, scheduler=scheduler)
217
+ else:
218
+ # on >=0.7.0 & <0.8.0 or model finetuned for inpainting
219
+ pipe = OnnxStableDiffusionInpaintPipeline.from_pretrained(
220
+ model_path, provider=provider, scheduler=scheduler)
221
+ gc.collect()
222
+ current_pipe = "inpaint"
223
+
224
+ if type(pipe.scheduler) is not type(scheduler):
225
+ pipe.scheduler = scheduler
226
+
227
+ if mask_mode == "Upload mask":
228
+ input_image = image.convert("RGB")
229
+
230
+ # input mask resizing
231
+ input_mask = mask.convert("RGB")
232
+ input_mask_width, input_mask_height = input_mask.size
233
+ if height / width > input_mask_height / input_mask_width:
234
+ adjust_mask_width = int(input_mask_width * height / input_mask_height)
235
+ input_mask = input_mask.resize((adjust_mask_width, height))
236
+ mask_left = (adjust_mask_width - width) // 2
237
+ mask_right = mask_left + width
238
+ input_mask = input_mask.crop((mask_left, 0, mask_right, height))
239
+ else:
240
+ adjust_height = int(input_mask_height * width / input_mask_width)
241
+ input_mask = input_mask.resize((width, adjust_height))
242
+ top = (adjust_height - height) // 2
243
+ bottom = top + height
244
+ input_mask = input_mask.crop((0, top, width, bottom))
245
+ else:
246
+ input_image = drawn_mask['image'].convert('RGB')
247
+ input_mask = drawn_mask['mask']
248
+
249
+ # input image resizing
250
+ input_width, input_height = input_image.size
251
+ if height / width > input_height / input_width:
252
+ adjust_width = int(input_width * height / input_height)
253
+ input_image = input_image.resize((adjust_width, height))
254
+ left = (adjust_width - width) // 2
255
+ right = left + width
256
+ input_image = input_image.crop((left, 0, right, height))
257
+ else:
258
+ adjust_height = int(input_height * width / input_width)
259
+ input_image = input_image.resize((width, adjust_height))
260
+ top = (adjust_height - height) // 2
261
+ bottom = top + height
262
+ input_image = input_image.crop((0, top, width, bottom))
263
+
264
+
265
+ return run_diffusers(
266
+ prompt, neg_prompt, input_image, iter, batch, steps, guid, height, width, eta,
267
+ denoise, seed, input_mask)
268
+
269
+
270
+ def choose_sch(sched_name: str):
271
+ if sched_name == "DDIM":
272
+ return gr.update(visible=True)
273
+ else:
274
+ return gr.update(visible=False)
275
+
276
+ def choose_pipeline(pipeline: str, mask_mode: str):
277
+ if(pipeline == "TEXT2IMG"):
278
+ return (gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), gr.update(visible=False))
279
+ if(pipeline == "IMG2IMG"):
280
+ return (gr.update(visible=True), gr.update(visible=False), gr.update(visible=True), gr.update(visible=False), gr.update(visible=False))
281
+ if(pipeline == "Inpainting"):
282
+ if mask_mode == "Draw mask":
283
+ return (gr.update(visible=False), gr.update(visible=False), gr.update(visible=True), gr.update(visible=True), gr.update(visible=True))
284
+ else:
285
+ return (gr.update(visible=True), gr.update(visible=True), gr.update(visible=True), gr.update(visible=True), gr.update(visible=False))
286
+
287
+ def choose_mask_mode(mask_mode):
288
+ if mask_mode == "Draw mask":
289
+ return [gr.update(visible=False), gr.update(visible=False), gr.update(visible=True)]
290
+ else:
291
+ return [gr.update(visible=True), gr.update(visible=True), gr.update(visible=False)]
292
+
293
+ def size_512_lock(size):
294
+ if size != 512:
295
+ return gr.update(interactive=False)
296
+ return gr.update(interactive=True)
297
+
298
+ if __name__ == "__main__":
299
+ parser = argparse.ArgumentParser(description="Gradio interface for ONNX based Stable Diffusion")
300
+ parser.add_argument("--cpu-only", action="store_true", default=False, help="Run ONNX with CPU")
301
+ parser.add_argument("--local", action="store_true", default=False, help="Open to local network")
302
+ parser.add_argument("--public", action="store_true", default=False, help="Create a publicly shareable link for the interface")
303
+ args = parser.parse_args()
304
+
305
+ # variables for ONNX pipelines
306
+ model_name = None
307
+ provider = "CPUExecutionProvider" if args.cpu_only else "DmlExecutionProvider"
308
+ current_pipe = "txt2img"
309
+
310
+ # diffusers objects
311
+ scheduler = None
312
+ pipe = None
313
+
314
+ # search the model folder
315
+ model_dir = "model"
316
+ model_list = []
317
+ with os.scandir(model_dir) as scan_it:
318
+ for entry in scan_it:
319
+ if entry.is_dir():
320
+ model_list.append(entry.name)
321
+ default_model = model_list[0] if len(model_list) > 0 else None
322
+
323
+ # create gradio block
324
+ title = "Stable Diffusion " + str(version.parse(_df_version))
325
+ possibilities = ['TEXT2IMG', 'IMG2IMG', 'Inpainting']
326
+
327
+ with gr.Blocks(title=title) as app:
328
+ with gr.Row():
329
+ with gr.Column(scale=1, min_width=600):
330
+ with gr.Column(variant='panel'):
331
+ with gr.Row():
332
+ model_drop = gr.Dropdown(model_list, value=default_model, label="Model", interactive=True)
333
+ pipeline = gr.Radio(possibilities, value="TEXT2IMG", label="Pipeline")
334
+ sch = gr.Radio(["DDIM", "LMS", "PNDM", "Euler"], value="Euler", label="Scheduler")
335
+ eta = gr.Slider(0, 1, value=0.0, step=0.01, label="DDIM eta", visible=False)
336
+ seed = gr.Textbox(value="", max_lines=1, label="Seed")
337
+ with gr.Column():
338
+ mask_mode = gr.Radio(label="Mask mode", show_label=False, choices=["Draw mask", "Upload mask"], value="Draw mask", visible=False)
339
+ image = gr.Image(label="Input image", type="pil", visible=False)
340
+ mask = gr.Image(label="Input mask", type="pil", visible=False)
341
+ drawn_mask = gr.Image(label="Input image and mask", source="upload", tool="sketch", type="pil", visible=False)
342
+ prompt = gr.Textbox(value="", lines=2, label="Prompt")
343
+ neg_prompt = gr.Textbox(value="", lines=2, label="Negative prompt")
344
+ steps = gr.Slider(1, 150, value=25, step=1, label="Steps")
345
+ guid = gr.Slider(0, 20, value=11, step=0.5, label="Guidance")
346
+ with gr.Column():
347
+ height = gr.Slider(16, 1920, value=512, step=8, label="Height")
348
+ width = gr.Slider(16, 1920, value=512, step=8, label="Width")
349
+ denoise = gr.Slider(0, 1, value=0.8, step=0.01, label="Denoise strength", visible=False)
350
+ with gr.Column():
351
+ iter = gr.Slider(1, 24, value=1, step=1, label="Iteration count")
352
+ batch = gr.Slider(1, 4, value=1, step=1, label="Batch size")
353
+ with gr.Column(scale=1, min_width=600):
354
+ with gr.Row():
355
+ gen_btn = gr.Button("Generate", variant="primary")
356
+ clear_btn = gr.Button("Clear", variant="secondary")
357
+ with gr.Row(variant='panel'):
358
+ image_out = gr.Gallery(value=None, label="Images")
359
+ status_out = gr.Textbox(value="", label="Status")
360
+
361
+ # config components
362
+ all_inputs = [
363
+ model_drop, prompt, neg_prompt, sch, iter, batch, steps, guid, height, width,
364
+ eta, seed, image, denoise, mask, pipeline, mask_mode, drawn_mask]
365
+ clear_btn.click(fn=clear_click, inputs=None, outputs=all_inputs, queue=False)
366
+ gen_btn.click(fn=generate_click, inputs=all_inputs, outputs=[image_out, status_out])
367
+
368
+ height.change(fn=size_512_lock, inputs=height, outputs=width)
369
+ width.change(fn=size_512_lock, inputs=width, outputs=height)
370
+ mask_mode.change(fn=choose_mask_mode, inputs=mask_mode, outputs=[image, mask, drawn_mask])
371
+ pipeline.change(fn=choose_pipeline, inputs=[pipeline, mask_mode], outputs=[image, mask, denoise, mask_mode, drawn_mask])
372
+ sch.change(fn=choose_sch, inputs=sch, outputs=eta)
373
+
374
+ image_out.style(grid=2)
375
+
376
+ app.queue(concurrency_count=1, api_open=False)
377
+ app.launch(inbrowser=True, server_name="0.0.0.0" if args.local else "127.0.0.1", show_api=False, quiet=True, share=args.public) # open to local network: server_name="0.0.0.0"