Sijuade commited on
Commit
27d1e65
1 Parent(s): 919446f

Upload 3 files

Browse files
Files changed (3) hide show
  1. app.py +48 -0
  2. requirements.txt +7 -0
  3. utils.py +265 -0
app.py ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ from utils import *
3
+
4
+
5
+ with gr.Blocks() as interface:
6
+ gr.HTML(value=HTML_TEMPLATE, show_label=False)
7
+ with gr.Row():
8
+ text_input = gr.Textbox(
9
+ label="Enter your prompt",
10
+ placeholder="A powerful mysterious sorceress..........",
11
+ )
12
+ concept_dropdown = gr.Dropdown(
13
+ label="Select a Concept",
14
+ choices=["Midjourney", "Dream", "Moebius", "Marc Allante", "Wlop"],
15
+ value='Dream'
16
+ )
17
+
18
+ method_dropdown = gr.Dropdown(
19
+ label="Select Guidance Method",
20
+ choices=["Elastic", "Symmetry", "Saturation", "Blue"],
21
+ value='Elastic'
22
+ )
23
+
24
+ seed_slider = gr.Slider(
25
+ label="Random Seed",
26
+ minimum=0,
27
+ maximum=1000,
28
+ step=1,
29
+ value=42
30
+ )
31
+ inputs = [text_input, concept_dropdown, method_dropdown, seed_slider]
32
+
33
+ with gr.Row():
34
+ outputs = gr.Gallery(
35
+ label="Generated Art", show_label=True,
36
+ columns=[2], rows=[1], object_fit="contain"
37
+ )
38
+
39
+ with gr.Row():
40
+ button = gr.Button("Generate Art")
41
+ button.click(generate_art, inputs=inputs, outputs=outputs)
42
+
43
+ with gr.Row():
44
+ gr.Examples(examples=get_examples(), inputs=inputs, outputs=outputs, fn=generate_art, cache_examples=True)
45
+
46
+
47
+ if __name__ == "__main__":
48
+ interface.launch(enable_queue=True)
requirements.txt ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ torch
2
+ torchvision
3
+ pillow
4
+ numpy
5
+ pandas
6
+ transformers
7
+ diffusers
utils.py ADDED
@@ -0,0 +1,265 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import PIL
2
+ import torch
3
+ import numpy as np
4
+ from PIL import Image
5
+ from tqdm import tqdm
6
+ import torch.nn.functional as F
7
+ import torchvision.transforms as T
8
+ from diffusers import LMSDiscreteScheduler, DiffusionPipeline
9
+
10
+ # configurations
11
+ torch_device = "cuda" if torch.cuda.is_available() else "mps" if torch.backends.mps.is_available() else "cpu"
12
+ height, width = 64, 64
13
+ guidance_scale = 8
14
+ blue_loss_scale = 200
15
+ num_inference_steps = 50
16
+
17
+ elastic_transformer = T.ElasticTransform(alpha=550.0, sigma=5.0)
18
+
19
+
20
+
21
+ pretrained_model_name_or_path = "segmind/tiny-sd"
22
+ pipe = DiffusionPipeline.from_pretrained(
23
+ pretrained_model_name_or_path,
24
+ low_cpu_mem_usage = True
25
+ ).to(torch_device)
26
+
27
+
28
+ pipe.load_textual_inversion("sd-concepts-library/dreams")
29
+ pipe.load_textual_inversion("sd-concepts-library/midjourney-style")
30
+ pipe.load_textual_inversion("sd-concepts-library/moebius")
31
+ pipe.load_textual_inversion("sd-concepts-library/style-of-marc-allante")
32
+ pipe.load_textual_inversion("sd-concepts-library/wlop-style")
33
+
34
+
35
+ concepts_mapping = {
36
+ "Dream": '<meeg>', "Midjourney":'<midjourney-style>',
37
+ "Marc Allante": '<Marc_Allante>', "Moebius": '<moebius>',
38
+ "Wlop": '<wlop-style>'
39
+ }
40
+
41
+
42
+ def image_loss(images, method='elastic'):
43
+
44
+ # elastic loss
45
+ if method == 'elastic':
46
+ transformed_imgs = elastic_transformer(images)
47
+ error = torch.abs(transformed_imgs - images).mean()
48
+
49
+ # symmetry loss - Flip the image along the width
50
+ elif method == "symmetry":
51
+ flipped_image = torch.flip(images, [3])
52
+ error = F.mse_loss(images, flipped_image)
53
+
54
+ # saturation loss
55
+ elif method == 'saturation':
56
+ transformed_imgs = T.functional.adjust_saturation(images,saturation_factor = 10)
57
+ error = torch.abs(transformed_imgs - images).mean()
58
+
59
+ # blue loss
60
+ elif method == 'blue':
61
+ error = torch.abs(images[:,2] - 0.9).mean() # [:,2] -> all images in batch, only the blue channel
62
+
63
+ return error
64
+
65
+
66
+ HTML_TEMPLATE = """
67
+ <style>
68
+ body {
69
+ background: linear-gradient(135deg, #f5f7fa, #c3cfe2);
70
+ }
71
+ #app-header {
72
+ text-align: center;
73
+ background: rgba(255, 255, 255, 0.8); /* Semi-transparent white */
74
+ padding: 20px;
75
+ border-radius: 10px;
76
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
77
+ position: relative; /* To position the artifacts */
78
+ }
79
+ #app-header h1 {
80
+ color: #4CAF50;
81
+ font-size: 2em;
82
+ margin-bottom: 10px;
83
+ }
84
+ .concept {
85
+ position: relative;
86
+ transition: transform 0.3s;
87
+ }
88
+ .concept:hover {
89
+ transform: scale(1.1);
90
+ }
91
+ .concept img {
92
+ width: 100px;
93
+ border-radius: 10px;
94
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
95
+ }
96
+ .concept-description {
97
+ position: absolute;
98
+ bottom: -30px;
99
+ left: 50%;
100
+ transform: translateX(-50%);
101
+ background-color: #4CAF50;
102
+ color: white;
103
+ padding: 5px 10px;
104
+ border-radius: 5px;
105
+ opacity: 0;
106
+ transition: opacity 0.3s;
107
+ }
108
+ .concept:hover .concept-description {
109
+ opacity: 1;
110
+ }
111
+ /* Artifacts */
112
+ .artifact {
113
+ position: absolute;
114
+ background: rgba(76, 175, 80, 0.1); /* Semi-transparent green */
115
+ border-radius: 50%; /* Make it circular */
116
+ }
117
+ .artifact.large {
118
+ width: 300px;
119
+ height: 300px;
120
+ top: -50px;
121
+ left: -150px;
122
+ }
123
+ .artifact.medium {
124
+ width: 200px;
125
+ height: 200px;
126
+ bottom: -50px;
127
+ right: -100px;
128
+ }
129
+ .artifact.small {
130
+ width: 100px;
131
+ height: 100px;
132
+ top: 50%;
133
+ left: 50%;
134
+ transform: translate(-50%, -50%);
135
+ }
136
+ </style>
137
+ <div id="app-header">
138
+ <!-- Artifacts -->
139
+ <div class="artifact large"></div>
140
+ <div class="artifact medium"></div>
141
+ <div class="artifact small"></div>
142
+ <!-- Content -->
143
+ <h1>Art Generator</h1>
144
+ <p>Generate new art in five different styles by providing a prompt.</p>
145
+ <div style="display: flex; justify-content: center; gap: 20px; margin-top: 20px;">
146
+ <div class="concept">
147
+ <img src="https://github.com/Delve-ERAV1/S20/assets/11761529/30ac92f8-fc62-4aab-9221-043865c6fe7c" alt="Midjourney">
148
+ <div class="concept-description">Midjourney Style</div>
149
+ </div>
150
+ <div class="concept">
151
+ <img src="https://github.com/Delve-ERAV1/S20/assets/11761529/54c9a61e-df9f-4054-835b-ec2c6ba5916c" alt="Dreams">
152
+ <div class="concept-description">Dreams Style</div>
153
+ </div>
154
+ <div class="concept">
155
+ <img src="https://github.com/Delve-ERAV1/S20/assets/11761529/2f37e402-15d1-4a74-ba85-bb1566da930e" alt="Moebius">
156
+ <div class="concept-description">Moebius Style</div>
157
+ </div>
158
+ <div class="concept">
159
+ <img src="https://github.com/Delve-ERAV1/S20/assets/11761529/f838e767-ac20-4996-b5be-65c61b365ce0" alt="Allante">
160
+ <div class="concept-description">Hong Kong born artist inspired by western and eastern influences</div>
161
+ </div>
162
+ <div class="concept">
163
+ <img src="https://github.com/Delve-ERAV1/S20/assets/11761529/9958140a-1b62-4972-83ca-85b023e3863f" alt="Wlop">
164
+ <div class="concept-description">WLOP (Born 1987) is known for Digital Art (NFTs)</div>
165
+ </div>
166
+ </div>
167
+ </div>
168
+ """
169
+
170
+
171
+ def get_examples():
172
+ examples = [
173
+ ['A powerful man in dreadlocks', 'Dream', 'Symmetry', 45],
174
+ ['World Peace', 'Marc Allante', 'Saturation', 147],
175
+ ['Storm trooper in the desert, dramatic lighting, high-detail', 'Moebius', 'Elastic', 28],
176
+ ['Delicious Italian pizza on a table, a window in the background overlooking a city skyline', 'Wlop', 'Blue', 50],
177
+ ]
178
+ return(examples)
179
+
180
+
181
+ def latents_to_pil(latents):
182
+ # bath of latents -> list of images
183
+ latents = (1 / 0.18215) * latents
184
+ with torch.no_grad():
185
+ image = pipe.vae.decode(latents).sample
186
+ image = (image / 2 + 0.5).clamp(0, 1) # 0 to 1
187
+ image = image.detach().cpu().permute(0, 2, 3, 1).numpy()
188
+ image = (image * 255).round().astype("uint8")
189
+ return Image.fromarray(image[0])
190
+
191
+
192
+ def generate_art(prompt, concept, method, seed):
193
+
194
+ prompt = f"{prompt} in the style of {concepts_mapping[concept]}"
195
+ img_no_loss = latents_to_pil(generate_image(prompt, method, seed))
196
+ img_loss = latents_to_pil(generate_image(prompt, method, seed, loss_apply=True))
197
+ return([img_no_loss, img_loss])
198
+
199
+
200
+ def generate_image(prompt, method, seed, loss_apply=False):
201
+
202
+ generator = torch.manual_seed(seed)
203
+ batch_size = 1
204
+ method = method.lower()
205
+
206
+ # scheduler
207
+ scheduler = LMSDiscreteScheduler(beta_start = 0.00085, beta_end = 0.012, beta_schedule = "scaled_linear", num_train_timesteps = 1000)
208
+ scheduler.set_timesteps(50)
209
+ scheduler.timesteps = scheduler.timesteps.to(torch.float32)
210
+
211
+ # text embeddings of the prompt
212
+ text_input = pipe.tokenizer([prompt], padding='max_length', max_length = pipe.tokenizer.model_max_length, truncation= True, return_tensors="pt")
213
+ input_ids = text_input.input_ids.to(torch_device)
214
+
215
+ with torch.no_grad():
216
+ text_embeddings = pipe.text_encoder(text_input.input_ids.to(torch_device))[0]
217
+
218
+ max_length = text_input.input_ids.shape[-1]
219
+ uncond_input = pipe.tokenizer(
220
+ [""] * 1, padding="max_length", max_length= max_length, return_tensors="pt"
221
+ )
222
+
223
+ with torch.no_grad():
224
+ uncond_embeddings = pipe.text_encoder(uncond_input.input_ids.to(torch_device))[0]
225
+
226
+ text_embeddings = torch.cat([uncond_embeddings,text_embeddings])
227
+
228
+ # random latent
229
+ latents = torch.randn(
230
+ (batch_size, pipe.unet.config.in_channels, height// 8, width //8),
231
+ generator = generator,
232
+ )
233
+
234
+
235
+ latents = latents.to(torch_device)
236
+ latents = latents * scheduler.init_noise_sigma
237
+
238
+ for i, t in tqdm(enumerate(scheduler.timesteps), total = len(scheduler.timesteps)):
239
+
240
+ latent_model_input = torch.cat([latents] * 2)
241
+ sigma = scheduler.sigmas[i]
242
+ latent_model_input = scheduler.scale_model_input(latent_model_input, t)
243
+
244
+ with torch.no_grad():
245
+ noise_pred = pipe.unet(latent_model_input, t, encoder_hidden_states=text_embeddings)["sample"]
246
+
247
+ noise_pred_uncond, noise_pred_text = noise_pred.chunk(2)
248
+ noise_pred = noise_pred_uncond + guidance_scale * (noise_pred_text - noise_pred_uncond)
249
+
250
+ if loss_apply and i%5 == 0:
251
+
252
+ latents = latents.detach().requires_grad_()
253
+ latents_x0 = latents - sigma * noise_pred
254
+
255
+ # use vae to decode the image
256
+ denoised_images = pipe.vae.decode((1/ 0.18215) * latents_x0).sample / 2 + 0.5 # range(0,1)
257
+
258
+ loss = image_loss(denoised_images, method) * blue_loss_scale
259
+
260
+ cond_grad = torch.autograd.grad(loss, latents)[0]
261
+ latents = latents.detach() - cond_grad * sigma**2
262
+
263
+ latents = scheduler.step(noise_pred,t, latents).prev_sample
264
+
265
+ return latents