hysts HF staff valhalla commited on
Commit
8f873ac
1 Parent(s): bb7edb9

Merge sketch app

Browse files

Co-authored-by: Suraj Patil <[email protected]>

Files changed (5) hide show
  1. app.py +7 -139
  2. app_base.py +145 -0
  3. app_sketch.py +206 -0
  4. model.py +2 -4
  5. utils.py +11 -0
app.py CHANGED
@@ -1,13 +1,12 @@
1
  #!/usr/bin/env python
2
 
3
  import os
4
- import random
5
 
6
  import gradio as gr
7
- import numpy as np
8
- import PIL.Image
9
  import torch
10
 
 
 
11
  from model import ADAPTER_NAMES, Model
12
 
13
  DESCRIPTION = "# T2I-Adapter-SDXL"
@@ -15,45 +14,10 @@ DESCRIPTION = "# T2I-Adapter-SDXL"
15
  if not torch.cuda.is_available():
16
  DESCRIPTION += "\n<p>Running on CPU 🥶 This demo does not work on CPU.</p>"
17
 
18
- MAX_SEED = np.iinfo(np.int32).max
19
-
20
-
21
- def randomize_seed_fn(seed: int, randomize_seed: bool) -> int:
22
- if randomize_seed:
23
- seed = random.randint(0, MAX_SEED)
24
- return seed
25
-
26
 
27
  model = Model(ADAPTER_NAMES[0])
28
 
29
 
30
- def run(
31
- image: PIL.Image.Image,
32
- prompt: str,
33
- negative_prompt: str,
34
- adapter_name: str,
35
- num_inference_steps: int = 30,
36
- guidance_scale: float = 5.0,
37
- adapter_conditioning_scale: float = 1.0,
38
- cond_tau: float = 1.0,
39
- seed: int = 0,
40
- apply_preprocess: bool = True,
41
- progress=gr.Progress(track_tqdm=True),
42
- ) -> list[PIL.Image.Image]:
43
- return model.run(
44
- image=image,
45
- prompt=prompt,
46
- negative_prompt=negative_prompt,
47
- adapter_name=adapter_name,
48
- num_inference_steps=num_inference_steps,
49
- guidance_scale=guidance_scale,
50
- adapter_conditioning_scale=adapter_conditioning_scale,
51
- cond_tau=cond_tau,
52
- seed=seed,
53
- apply_preprocess=apply_preprocess,
54
- )
55
-
56
-
57
  with gr.Blocks(css="style.css") as demo:
58
  gr.Markdown(DESCRIPTION)
59
  gr.DuplicateButton(
@@ -61,107 +25,11 @@ with gr.Blocks(css="style.css") as demo:
61
  elem_id="duplicate-button",
62
  visible=os.getenv("SHOW_DUPLICATE_BUTTON") == "1",
63
  )
64
-
65
- with gr.Row():
66
- with gr.Column():
67
- with gr.Group():
68
- image = gr.Image(label="Input image", type="pil", height=600)
69
- prompt = gr.Textbox(label="Prompt")
70
- adapter_name = gr.Dropdown(label="Adapter", choices=ADAPTER_NAMES, value=ADAPTER_NAMES[0])
71
- run_button = gr.Button("Run")
72
- with gr.Accordion("Advanced options", open=False):
73
- apply_preprocess = gr.Checkbox(label="Apply preprocess", value=True)
74
- negative_prompt = gr.Textbox(
75
- label="Negative prompt",
76
- value="anime, cartoon, graphic, text, painting, crayon, graphite, abstract, glitch, deformed, mutated, ugly, disfigured",
77
- )
78
- num_inference_steps = gr.Slider(
79
- label="Number of steps",
80
- minimum=1,
81
- maximum=Model.MAX_NUM_INFERENCE_STEPS,
82
- step=1,
83
- value=30,
84
- )
85
- guidance_scale = gr.Slider(
86
- label="Guidance scale",
87
- minimum=0.1,
88
- maximum=30.0,
89
- step=0.1,
90
- value=5.0,
91
- )
92
- adapter_conditioning_scale = gr.Slider(
93
- label="Adapter Conditioning Scale",
94
- minimum=0.5,
95
- maximum=1,
96
- step=0.1,
97
- value=1.0,
98
- )
99
- cond_tau = gr.Slider(
100
- label="Fraction of timesteps for which adapter should be applied",
101
- minimum=0.5,
102
- maximum=1.0,
103
- step=0.1,
104
- value=1.0,
105
- )
106
- seed = gr.Slider(
107
- label="Seed",
108
- minimum=0,
109
- maximum=MAX_SEED,
110
- step=1,
111
- value=0,
112
- )
113
- randomize_seed = gr.Checkbox(label="Randomize seed", value=True)
114
- with gr.Column():
115
- result = gr.Gallery(label="Result", columns=2, height=600, object_fit="scale-down", show_label=False)
116
-
117
- inputs = [
118
- image,
119
- prompt,
120
- negative_prompt,
121
- adapter_name,
122
- num_inference_steps,
123
- guidance_scale,
124
- adapter_conditioning_scale,
125
- cond_tau,
126
- seed,
127
- apply_preprocess,
128
- ]
129
- prompt.submit(
130
- fn=randomize_seed_fn,
131
- inputs=[seed, randomize_seed],
132
- outputs=seed,
133
- queue=False,
134
- api_name=False,
135
- ).then(
136
- fn=run,
137
- inputs=inputs,
138
- outputs=result,
139
- api_name=False,
140
- )
141
- negative_prompt.submit(
142
- fn=randomize_seed_fn,
143
- inputs=[seed, randomize_seed],
144
- outputs=seed,
145
- queue=False,
146
- api_name=False,
147
- ).then(
148
- fn=run,
149
- inputs=inputs,
150
- outputs=result,
151
- api_name=False,
152
- )
153
- run_button.click(
154
- fn=randomize_seed_fn,
155
- inputs=[seed, randomize_seed],
156
- outputs=seed,
157
- queue=False,
158
- api_name=False,
159
- ).then(
160
- fn=run,
161
- inputs=inputs,
162
- outputs=result,
163
- api_name="run",
164
- )
165
 
166
  if __name__ == "__main__":
167
  demo.queue(max_size=20).launch()
 
1
  #!/usr/bin/env python
2
 
3
  import os
 
4
 
5
  import gradio as gr
 
 
6
  import torch
7
 
8
+ from app_base import create_demo as create_demo_base
9
+ from app_sketch import create_demo as create_demo_sketch
10
  from model import ADAPTER_NAMES, Model
11
 
12
  DESCRIPTION = "# T2I-Adapter-SDXL"
 
14
  if not torch.cuda.is_available():
15
  DESCRIPTION += "\n<p>Running on CPU 🥶 This demo does not work on CPU.</p>"
16
 
 
 
 
 
 
 
 
 
17
 
18
  model = Model(ADAPTER_NAMES[0])
19
 
20
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
  with gr.Blocks(css="style.css") as demo:
22
  gr.Markdown(DESCRIPTION)
23
  gr.DuplicateButton(
 
25
  elem_id="duplicate-button",
26
  visible=os.getenv("SHOW_DUPLICATE_BUTTON") == "1",
27
  )
28
+ with gr.Tabs():
29
+ with gr.Tab(label="Base"):
30
+ create_demo_base(model)
31
+ with gr.Tab(label="Sketch"):
32
+ create_demo_sketch(model)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
 
34
  if __name__ == "__main__":
35
  demo.queue(max_size=20).launch()
app_base.py ADDED
@@ -0,0 +1,145 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python
2
+
3
+ import gradio as gr
4
+ import PIL.Image
5
+
6
+ from model import ADAPTER_NAMES, Model
7
+ from utils import MAX_SEED, randomize_seed_fn
8
+
9
+
10
+ def create_demo(model: Model) -> gr.Blocks:
11
+ def run(
12
+ image: PIL.Image.Image,
13
+ prompt: str,
14
+ negative_prompt: str,
15
+ adapter_name: str,
16
+ num_inference_steps: int = 30,
17
+ guidance_scale: float = 5.0,
18
+ adapter_conditioning_scale: float = 1.0,
19
+ cond_tau: float = 1.0,
20
+ seed: int = 0,
21
+ apply_preprocess: bool = True,
22
+ progress=gr.Progress(track_tqdm=True),
23
+ ) -> list[PIL.Image.Image]:
24
+ return model.run(
25
+ image=image,
26
+ prompt=prompt,
27
+ negative_prompt=negative_prompt,
28
+ adapter_name=adapter_name,
29
+ num_inference_steps=num_inference_steps,
30
+ guidance_scale=guidance_scale,
31
+ adapter_conditioning_scale=adapter_conditioning_scale,
32
+ cond_tau=cond_tau,
33
+ seed=seed,
34
+ apply_preprocess=apply_preprocess,
35
+ )
36
+
37
+ with gr.Blocks() as demo:
38
+ with gr.Row():
39
+ with gr.Column():
40
+ with gr.Group():
41
+ image = gr.Image(label="Input image", type="pil", height=600)
42
+ prompt = gr.Textbox(label="Prompt")
43
+ adapter_name = gr.Dropdown(label="Adapter", choices=ADAPTER_NAMES, value=ADAPTER_NAMES[0])
44
+ run_button = gr.Button("Run")
45
+ with gr.Accordion("Advanced options", open=False):
46
+ apply_preprocess = gr.Checkbox(label="Apply preprocess", value=True)
47
+ negative_prompt = gr.Textbox(
48
+ label="Negative prompt",
49
+ value="anime, cartoon, graphic, text, painting, crayon, graphite, abstract, glitch, deformed, mutated, ugly, disfigured",
50
+ )
51
+ num_inference_steps = gr.Slider(
52
+ label="Number of steps",
53
+ minimum=1,
54
+ maximum=Model.MAX_NUM_INFERENCE_STEPS,
55
+ step=1,
56
+ value=30,
57
+ )
58
+ guidance_scale = gr.Slider(
59
+ label="Guidance scale",
60
+ minimum=0.1,
61
+ maximum=30.0,
62
+ step=0.1,
63
+ value=5.0,
64
+ )
65
+ adapter_conditioning_scale = gr.Slider(
66
+ label="Adapter Conditioning Scale",
67
+ minimum=0.5,
68
+ maximum=1,
69
+ step=0.1,
70
+ value=1.0,
71
+ )
72
+ cond_tau = gr.Slider(
73
+ label="Fraction of timesteps for which adapter should be applied",
74
+ minimum=0.5,
75
+ maximum=1.0,
76
+ step=0.1,
77
+ value=1.0,
78
+ )
79
+ seed = gr.Slider(
80
+ label="Seed",
81
+ minimum=0,
82
+ maximum=MAX_SEED,
83
+ step=1,
84
+ value=0,
85
+ )
86
+ randomize_seed = gr.Checkbox(label="Randomize seed", value=True)
87
+ with gr.Column():
88
+ result = gr.Gallery(label="Result", columns=2, height=600, object_fit="scale-down", show_label=False)
89
+
90
+ inputs = [
91
+ image,
92
+ prompt,
93
+ negative_prompt,
94
+ adapter_name,
95
+ num_inference_steps,
96
+ guidance_scale,
97
+ adapter_conditioning_scale,
98
+ cond_tau,
99
+ seed,
100
+ apply_preprocess,
101
+ ]
102
+ prompt.submit(
103
+ fn=randomize_seed_fn,
104
+ inputs=[seed, randomize_seed],
105
+ outputs=seed,
106
+ queue=False,
107
+ api_name=False,
108
+ ).then(
109
+ fn=run,
110
+ inputs=inputs,
111
+ outputs=result,
112
+ api_name=False,
113
+ )
114
+ negative_prompt.submit(
115
+ fn=randomize_seed_fn,
116
+ inputs=[seed, randomize_seed],
117
+ outputs=seed,
118
+ queue=False,
119
+ api_name=False,
120
+ ).then(
121
+ fn=run,
122
+ inputs=inputs,
123
+ outputs=result,
124
+ api_name=False,
125
+ )
126
+ run_button.click(
127
+ fn=randomize_seed_fn,
128
+ inputs=[seed, randomize_seed],
129
+ outputs=seed,
130
+ queue=False,
131
+ api_name=False,
132
+ ).then(
133
+ fn=run,
134
+ inputs=inputs,
135
+ outputs=result,
136
+ api_name="run",
137
+ )
138
+
139
+ return demo
140
+
141
+
142
+ if __name__ == "__main__":
143
+ model = Model(ADAPTER_NAMES[0])
144
+ demo = create_demo(model)
145
+ demo.queue(max_size=20).launch()
app_sketch.py ADDED
@@ -0,0 +1,206 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python
2
+
3
+ import gradio as gr
4
+ import PIL.Image
5
+ import torch
6
+ import torchvision.transforms.functional as TF
7
+
8
+ from model import Model
9
+ from utils import MAX_SEED, randomize_seed_fn
10
+
11
+ SKETCH_ADAPTER_NAME = "TencentARC/t2i-adapter-sketch-sdxl-1.0"
12
+
13
+ style_list = [
14
+ {
15
+ "name": "Cinematic",
16
+ "prompt": "cinematic still {prompt} . emotional, harmonious, vignette, highly detailed, high budget, bokeh, cinemascope, moody, epic, gorgeous, film grain, grainy",
17
+ "negative_prompt": "anime, cartoon, graphic, text, painting, crayon, graphite, abstract, glitch, deformed, mutated, ugly, disfigured",
18
+ },
19
+ {
20
+ "name": "3D Model",
21
+ "prompt": "professional 3d model {prompt} . octane render, highly detailed, volumetric, dramatic lighting",
22
+ "negative_prompt": "ugly, deformed, noisy, low poly, blurry, painting",
23
+ },
24
+ {
25
+ "name": "Anime",
26
+ "prompt": "anime artwork {prompt} . anime style, key visual, vibrant, studio anime, highly detailed",
27
+ "negative_prompt": "photo, deformed, black and white, realism, disfigured, low contrast",
28
+ },
29
+ {
30
+ "name": "Digital Art",
31
+ "prompt": "concept art {prompt} . digital artwork, illustrative, painterly, matte painting, highly detailed",
32
+ "negative_prompt": "photo, photorealistic, realism, ugly",
33
+ },
34
+ {
35
+ "name": "Photographic",
36
+ "prompt": "cinematic photo {prompt} . 35mm photograph, film, bokeh, professional, 4k, highly detailed",
37
+ "negative_prompt": "drawing, painting, crayon, sketch, graphite, impressionist, noisy, blurry, soft, deformed, ugly",
38
+ },
39
+ {
40
+ "name": "Pixel art",
41
+ "prompt": "pixel-art {prompt} . low-res, blocky, pixel art style, 8-bit graphics",
42
+ "negative_prompt": "sloppy, messy, blurry, noisy, highly detailed, ultra textured, photo, realistic",
43
+ },
44
+ {
45
+ "name": "Fantasy art",
46
+ "prompt": "ethereal fantasy concept art of {prompt} . magnificent, celestial, ethereal, painterly, epic, majestic, magical, fantasy art, cover art, dreamy",
47
+ "negative_prompt": "photographic, realistic, realism, 35mm film, dslr, cropped, frame, text, deformed, glitch, noise, noisy, off-center, deformed, cross-eyed, closed eyes, bad anatomy, ugly, disfigured, sloppy, duplicate, mutated, black and white",
48
+ },
49
+ ]
50
+
51
+ styles = {k["name"]: (k["prompt"], k["negative_prompt"]) for k in style_list}
52
+ default_style_name = "Photographic"
53
+ default_style = styles[default_style_name]
54
+ style_names = list(styles.keys())
55
+
56
+
57
+ def apply_style(style_name: str, positive: str, negative: str = "") -> tuple[str, str]:
58
+ p, n = styles.get(style_name, default_style)
59
+ return p.replace("{prompt}", positive), n + negative
60
+
61
+
62
+ def create_demo(model: Model) -> gr.Blocks:
63
+ def run(
64
+ image: PIL.Image.Image,
65
+ prompt: str,
66
+ negative_prompt: str,
67
+ style_name: str = default_style_name,
68
+ num_steps: int = 25,
69
+ guidance_scale: float = 5,
70
+ adapter_conditioning_scale: float = 0.8,
71
+ cond_tau: float = 0.8,
72
+ seed: int = 0,
73
+ progress=gr.Progress(track_tqdm=True),
74
+ ) -> PIL.Image.Image:
75
+ image = image.convert("RGB")
76
+ image = TF.to_tensor(image) > 0.5
77
+ image = TF.to_pil_image(image.to(torch.float32))
78
+
79
+ prompt, negative_prompt = apply_style(style_name, prompt, negative_prompt)
80
+
81
+ return model.run(
82
+ image=image,
83
+ prompt=prompt,
84
+ negative_prompt=negative_prompt,
85
+ adapter_name=SKETCH_ADAPTER_NAME,
86
+ num_inference_steps=num_steps,
87
+ guidance_scale=guidance_scale,
88
+ adapter_conditioning_scale=adapter_conditioning_scale,
89
+ cond_tau=cond_tau,
90
+ seed=seed,
91
+ apply_preprocess=False,
92
+ )[1]
93
+
94
+ with gr.Blocks() as demo:
95
+ with gr.Row():
96
+ with gr.Column():
97
+ with gr.Group():
98
+ image = gr.Image(
99
+ source="canvas",
100
+ tool="sketch",
101
+ type="pil",
102
+ image_mode="L",
103
+ invert_colors=True,
104
+ shape=(1024, 1024),
105
+ brush_radius=4,
106
+ height=600,
107
+ )
108
+ prompt = gr.Textbox(label="Prompt")
109
+ run_button = gr.Button("Run")
110
+ with gr.Accordion("Advanced options", open=False):
111
+ style = gr.Dropdown(choices=style_names, value=default_style_name, label="Style")
112
+ negative_prompt = gr.Textbox(label="Negative prompt")
113
+ num_steps = gr.Slider(
114
+ label="Number of steps",
115
+ minimum=1,
116
+ maximum=50,
117
+ step=1,
118
+ value=25,
119
+ )
120
+ guidance_scale = gr.Slider(
121
+ label="Guidance scale",
122
+ minimum=0.1,
123
+ maximum=10.0,
124
+ step=0.1,
125
+ value=5,
126
+ )
127
+ adapter_conditioning_scale = gr.Slider(
128
+ label="Adapter Conditioning Scale",
129
+ minimum=0.5,
130
+ maximum=1,
131
+ step=0.1,
132
+ value=0.8,
133
+ )
134
+ cond_tau = gr.Slider(
135
+ label="Fraction of timesteps for which adapter should be applied",
136
+ minimum=0.5,
137
+ maximum=1,
138
+ step=0.1,
139
+ value=0.8,
140
+ )
141
+ seed = gr.Slider(
142
+ label="Seed",
143
+ minimum=0,
144
+ maximum=MAX_SEED,
145
+ step=1,
146
+ value=0,
147
+ )
148
+ randomize_seed = gr.Checkbox(label="Randomize seed", value=True)
149
+ with gr.Column():
150
+ result = gr.Image(label="Result", height=600)
151
+
152
+ inputs = [
153
+ image,
154
+ prompt,
155
+ negative_prompt,
156
+ style,
157
+ num_steps,
158
+ guidance_scale,
159
+ adapter_conditioning_scale,
160
+ cond_tau,
161
+ seed,
162
+ ]
163
+ prompt.submit(
164
+ fn=randomize_seed_fn,
165
+ inputs=[seed, randomize_seed],
166
+ outputs=seed,
167
+ queue=False,
168
+ api_name=False,
169
+ ).then(
170
+ fn=run,
171
+ inputs=inputs,
172
+ outputs=result,
173
+ api_name=False,
174
+ )
175
+ negative_prompt.submit(
176
+ fn=randomize_seed_fn,
177
+ inputs=[seed, randomize_seed],
178
+ outputs=seed,
179
+ queue=False,
180
+ api_name=False,
181
+ ).then(
182
+ fn=run,
183
+ inputs=inputs,
184
+ outputs=result,
185
+ api_name=False,
186
+ )
187
+ run_button.click(
188
+ fn=randomize_seed_fn,
189
+ inputs=[seed, randomize_seed],
190
+ outputs=seed,
191
+ queue=False,
192
+ api_name=False,
193
+ ).then(
194
+ fn=run,
195
+ inputs=inputs,
196
+ outputs=result,
197
+ api_name=False,
198
+ )
199
+
200
+ return demo
201
+
202
+
203
+ if __name__ == "__main__":
204
+ model = Model(SKETCH_ADAPTER_NAME)
205
+ demo = create_demo(model)
206
+ demo.queue(max_size=20).launch()
model.py CHANGED
@@ -193,13 +193,11 @@ class Model:
193
  torch_dtype=torch.float16,
194
  varient="fp16",
195
  ).to(self.device)
196
- euler_a = EulerAncestralDiscreteScheduler.from_pretrained(model_id, subfolder="scheduler")
197
- vae = AutoencoderKL.from_pretrained("madebyollin/sdxl-vae-fp16-fix", torch_dtype=torch.float16)
198
  self.pipe = StableDiffusionXLAdapterPipeline.from_pretrained(
199
  model_id,
200
- vae=vae,
201
  adapter=adapter,
202
- scheduler=euler_a,
203
  torch_dtype=torch.float16,
204
  variant="fp16",
205
  ).to(self.device)
 
193
  torch_dtype=torch.float16,
194
  varient="fp16",
195
  ).to(self.device)
 
 
196
  self.pipe = StableDiffusionXLAdapterPipeline.from_pretrained(
197
  model_id,
198
+ vae=AutoencoderKL.from_pretrained("madebyollin/sdxl-vae-fp16-fix", torch_dtype=torch.float16),
199
  adapter=adapter,
200
+ scheduler=EulerAncestralDiscreteScheduler.from_pretrained(model_id, subfolder="scheduler"),
201
  torch_dtype=torch.float16,
202
  variant="fp16",
203
  ).to(self.device)
utils.py ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import random
2
+
3
+ import numpy as np
4
+
5
+ MAX_SEED = np.iinfo(np.int32).max
6
+
7
+
8
+ def randomize_seed_fn(seed: int, randomize_seed: bool) -> int:
9
+ if randomize_seed:
10
+ seed = random.randint(0, MAX_SEED)
11
+ return seed