kevinlu4588 commited on
Commit
9985d49
·
1 Parent(s): 04578d3

Setting up esd code

Browse files
Attack_code/Inpainting/inpainting_diffuser.py ADDED
@@ -0,0 +1,612 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from PIL import Image
2
+ from matplotlib import pyplot as plt
3
+ import textwrap
4
+ import argparse
5
+ import torch
6
+ import copy
7
+ import os
8
+ import re
9
+ import numpy as np
10
+ from diffusers import AutoencoderKL, UNet2DConditionModel
11
+ from PIL import Image
12
+ from tqdm.auto import tqdm
13
+ from transformers import CLIPTextModel, CLIPTokenizer, CLIPFeatureExtractor
14
+ from diffusers.schedulers import EulerAncestralDiscreteScheduler
15
+ from eta_diffusers.src.diffusers.schedulers.eta_ddim_scheduler import DDIMScheduler
16
+ from diffusers.schedulers.scheduling_ddpm import DDPMScheduler
17
+ from diffusers.schedulers.scheduling_lms_discrete import LMSDiscreteScheduler
18
+ # from diffusers.pipelines.stable_diffusion import StableDiffusionSafetyChecker
19
+
20
+ def show_image_grid(img_files, num_rows=3, num_cols=4, fig_size=(15, 10)):
21
+ # Create a grid to display the images
22
+ fig, axes = plt.subplots(num_rows, num_cols, figsize=fig_size)
23
+
24
+ # Plot each image in the grid row-wise
25
+ for i, ax in enumerate(axes.flatten()):
26
+ img_index = i # row-major order
27
+ if img_index < len(img_files):
28
+ img = img_files[img_index]
29
+ ax.imshow(img)
30
+ ax.axis('off') # Turn off axis labels
31
+
32
+ plt.tight_layout()
33
+ plt.show()
34
+
35
+ # Example usage
36
+ # img_files = [image1, image2, image3, ...] # Replace with actual images
37
+ # show_image_grid(img_files)
38
+
39
+ def to_gif(images, path):
40
+
41
+ images[0].save(path, save_all=True,
42
+ append_images=images[1:], loop=0, duration=len(images) * 20)
43
+
44
+ def figure_to_image(figure):
45
+
46
+ figure.set_dpi(300)
47
+
48
+ figure.canvas.draw()
49
+
50
+ return Image.frombytes('RGB', figure.canvas.get_width_height(), figure.canvas.tostring_rgb())
51
+
52
+ def image_grid(images, outpath=None, column_titles=None, row_titles=None):
53
+
54
+ n_rows = len(images)
55
+ n_cols = len(images[0])
56
+
57
+ fig, axs = plt.subplots(nrows=n_rows, ncols=n_cols,
58
+ figsize=(n_cols, n_rows), squeeze=False)
59
+
60
+ for row, _images in enumerate(images):
61
+
62
+ for column, image in enumerate(_images):
63
+ ax = axs[row][column]
64
+ ax.imshow(image)
65
+ if column_titles and row == 0:
66
+ ax.set_title(textwrap.fill(
67
+ column_titles[column], width=12), fontsize='x-small')
68
+ if row_titles and column == 0:
69
+ ax.set_ylabel(row_titles[row], rotation=0, fontsize='x-small', labelpad=1.6 * len(row_titles[row]))
70
+ ax.set_xticks([])
71
+ ax.set_yticks([])
72
+
73
+ plt.subplots_adjust(wspace=0, hspace=0)
74
+
75
+ if outpath is not None:
76
+ plt.savefig(outpath, bbox_inches='tight', dpi=300)
77
+ plt.close()
78
+ else:
79
+ plt.tight_layout(pad=0)
80
+ image = figure_to_image(plt.gcf())
81
+ plt.close()
82
+ return image
83
+
84
+ def get_module(module, module_name):
85
+
86
+ if isinstance(module_name, str):
87
+ module_name = module_name.split('.')
88
+
89
+ if len(module_name) == 0:
90
+ return module
91
+ else:
92
+ module = getattr(module, module_name[0])
93
+ return get_module(module, module_name[1:])
94
+
95
+ def set_module(module, module_name, new_module):
96
+
97
+ if isinstance(module_name, str):
98
+ module_name = module_name.split('.')
99
+
100
+ if len(module_name) == 1:
101
+ return setattr(module, module_name[0], new_module)
102
+ else:
103
+ module = getattr(module, module_name[0])
104
+ return set_module(module, module_name[1:], new_module)
105
+
106
+ def freeze(module):
107
+
108
+ for parameter in module.parameters():
109
+
110
+ parameter.requires_grad = False
111
+
112
+ def unfreeze(module):
113
+
114
+ for parameter in module.parameters():
115
+
116
+ parameter.requires_grad = True
117
+
118
+ def get_concat_h(im1, im2):
119
+ dst = Image.new('RGB', (im1.width + im2.width, im1.height))
120
+ dst.paste(im1, (0, 0))
121
+ dst.paste(im2, (im1.width, 0))
122
+ return dst
123
+
124
+ def get_concat_v(im1, im2):
125
+ dst = Image.new('RGB', (im1.width, im1.height + im2.height))
126
+ dst.paste(im1, (0, 0))
127
+ dst.paste(im2, (0, im1.height))
128
+ return dst
129
+
130
+ class StableDiffuser(torch.nn.Module):
131
+
132
+ def __init__(self,
133
+ scheduler='DDIM'
134
+ ):
135
+ print('code changed')
136
+
137
+ super().__init__()
138
+
139
+ # Load the autoencoder model which will be used to decode the latents into image space.
140
+ self.vae = AutoencoderKL.from_pretrained(
141
+ "CompVis/stable-diffusion-v1-4", subfolder="vae")
142
+ print(self.vae.config.scaling_factor )
143
+ # Load the tokenizer and text encoder to tokenize and encode the text.
144
+ self.tokenizer = CLIPTokenizer.from_pretrained(
145
+ "openai/clip-vit-large-patch14")
146
+ self.text_encoder = CLIPTextModel.from_pretrained(
147
+ "openai/clip-vit-large-patch14")
148
+
149
+ # The UNet model for generating the latents.
150
+ self.unet = UNet2DConditionModel.from_pretrained(
151
+ "CompVis/stable-diffusion-v1-4", subfolder="unet")
152
+
153
+ self.feature_extractor = CLIPFeatureExtractor.from_pretrained("CompVis/stable-diffusion-v1-4", subfolder="feature_extractor")
154
+ # self.safety_checker = StableDiffusionSafetyChecker.from_pretrained("CompVis/stable-diffusion-v1-4", subfolder="safety_checker")
155
+
156
+ if scheduler == 'LMS':
157
+ self.scheduler = LMSDiscreteScheduler(beta_start=0.00085, beta_end=0.012, beta_schedule="scaled_linear", num_train_timesteps=1000)
158
+ elif scheduler == 'DDIM':
159
+ self.scheduler = DDIMScheduler.from_pretrained("CompVis/stable-diffusion-v1-4", subfolder="scheduler")
160
+ elif scheduler == 'DDPM':
161
+ self.scheduler = DDPMScheduler.from_pretrained("CompVis/stable-diffusion-v1-4", subfolder="scheduler")
162
+
163
+ self.eval()
164
+
165
+ def get_noise(self, batch_size, latent_width, latent_height, generator=None):
166
+
167
+ param = list(self.parameters())[0]
168
+
169
+ return torch.randn(
170
+ (batch_size, self.unet.in_channels, latent_width, latent_height),
171
+ generator=generator).type(param.dtype).to(param.device)
172
+
173
+ def add_noise(self, latents, noise, step):
174
+
175
+ return self.scheduler.add_noise(latents, noise, torch.tensor([self.scheduler.timesteps[step]]))
176
+
177
+ def text_tokenize(self, prompts):
178
+ tokens = self.tokenizer(prompts, padding="max_length", max_length=self.tokenizer.model_max_length, truncation=True, return_tensors="pt")
179
+ print("prompts", prompts)
180
+ print("tokens", tokens)
181
+ return tokens
182
+
183
+ def text_detokenize(self, tokens):
184
+
185
+ return [self.tokenizer.decode(token) for token in tokens if token != self.tokenizer.vocab_size - 1]
186
+
187
+ def text_encode(self, tokens):
188
+
189
+ return self.text_encoder(tokens.input_ids.to(self.unet.device))[0]
190
+
191
+ def decode(self, latents):
192
+ print(self.vae.config.scaling_factor)
193
+ print(latents)
194
+ print(1 / self.vae.config.scaling_factor * latents)
195
+ print(self.vae.decode(1 / self.vae.config.scaling_factor * latents))
196
+ print(self.vae.decode(1 / self.vae.config.scaling_factor * latents).sample)
197
+ return self.vae.decode(1 / self.vae.config.scaling_factor * latents).sample
198
+
199
+ def encode(self, tensors):
200
+
201
+ return self.vae.encode(tensors).latent_dist.mode() * 0.18215
202
+
203
+ def to_image(self, image):
204
+
205
+ image = (image / 2 + 0.5).clamp(0, 1)
206
+ image = image.detach().cpu().permute(0, 2, 3, 1).numpy()
207
+ print(image)
208
+ images = (image * 255).round().astype("uint8")
209
+ pil_images = [Image.fromarray(image) for image in images]
210
+
211
+ return pil_images
212
+
213
+ def set_scheduler_timesteps(self, n_steps):
214
+ self.scheduler.set_timesteps(n_steps, device=self.unet.device)
215
+
216
+ def get_initial_latents(self, n_imgs, latent_width, latent_height, n_prompts, generator=None):
217
+
218
+ noise = self.get_noise(n_imgs, latent_width, latent_height, generator=generator).repeat(n_prompts, 1, 1, 1)
219
+
220
+ latents = noise * self.scheduler.init_noise_sigma
221
+
222
+ return latents
223
+
224
+ def get_noise(self, batch_size, latent_width, latent_height, generator=None):
225
+
226
+ param = list(self.parameters())[0]
227
+
228
+ return torch.randn(
229
+ (batch_size, self.unet.in_channels, latent_width, latent_height),
230
+ generator=generator).type(param.dtype).to(param.device)
231
+
232
+ def add_noise(self, latents, noise, step):
233
+
234
+ return self.scheduler.add_noise(latents, noise, torch.tensor([self.scheduler.timesteps[step]]))
235
+
236
+ def text_tokenize(self, prompts):
237
+
238
+ return self.tokenizer(prompts, padding="max_length", max_length=self.tokenizer.model_max_length, truncation=True, return_tensors="pt")
239
+
240
+ def text_detokenize(self, tokens):
241
+
242
+ return [self.tokenizer.decode(token) for token in tokens if token != self.tokenizer.vocab_size - 1]
243
+
244
+ def text_encode(self, tokens):
245
+
246
+ return self.text_encoder(tokens.input_ids.to(self.unet.device))[0]
247
+
248
+ def decode(self, latents):
249
+
250
+ return self.vae.decode(1 / self.vae.config.scaling_factor * latents).sample
251
+
252
+ def encode(self, tensors):
253
+
254
+ return self.vae.encode(tensors).latent_dist.mode() * 0.18215
255
+
256
+ def to_image(self, image):
257
+
258
+ image = (image / 2 + 0.5).clamp(0, 1)
259
+ image = image.detach().cpu().permute(0, 2, 3, 1).numpy()
260
+ images = (image * 255).round().astype("uint8")
261
+ pil_images = [Image.fromarray(image) for image in images]
262
+
263
+ return pil_images
264
+
265
+ def set_scheduler_timesteps(self, n_steps):
266
+ self.scheduler.set_timesteps(n_steps, device=self.unet.device)
267
+
268
+ def get_text_embeddings(self, prompts, n_imgs):
269
+
270
+ text_tokens = self.text_tokenize(prompts)
271
+
272
+ text_embeddings = self.text_encode(text_tokens)
273
+
274
+ unconditional_tokens = self.text_tokenize([""] * len(prompts))
275
+
276
+ unconditional_embeddings = self.text_encode(unconditional_tokens)
277
+
278
+ text_embeddings = torch.cat([unconditional_embeddings, text_embeddings]).repeat_interleave(n_imgs, dim=0)
279
+
280
+ return text_embeddings
281
+
282
+ def predict_noise(self,
283
+ iteration,
284
+ latents,
285
+ text_embeddings,
286
+ guidance_scale=7.5
287
+ ):
288
+
289
+ # expand the latents if we are doing classifier-free guidance to avoid doing two forward passes.
290
+ latents = torch.cat([latents] * 2)
291
+ latents = self.scheduler.scale_model_input(
292
+ latents, self.scheduler.timesteps[iteration])
293
+
294
+ # predict the noise residual
295
+ noise_prediction = self.unet(
296
+ latents, self.scheduler.timesteps[iteration], encoder_hidden_states=text_embeddings).sample
297
+
298
+ # perform guidance
299
+ noise_prediction_uncond, noise_prediction_text = noise_prediction.chunk(2)
300
+ noise_prediction = noise_prediction_uncond + guidance_scale * \
301
+ (noise_prediction_text - noise_prediction_uncond)
302
+
303
+ return noise_prediction
304
+
305
+ @torch.no_grad()
306
+ def inpaint(self, img_tensor, mask_tensor, prompts, n_steps=50, n_imgs=1, show_progress=True, **kwargs):
307
+ assert 0 <= n_steps <= 1000
308
+ assert len(prompts) == n_imgs, "Number of prompts must match number of images"
309
+
310
+ self.set_scheduler_timesteps(n_steps)
311
+ # latents = self.get_initial_latents(n_imgs, img_size, len(prompts))
312
+
313
+ latents = self.encode(img_tensor.to(self.vae.device)) # Ensure img_tensor is on the correct device
314
+ print("latents size", latents.shape)
315
+ # Prepare the mask
316
+ masked_latents = latents.clone()
317
+ print("masked_latents", masked_latents.shape)
318
+ initial_latents = self.get_initial_latents(n_imgs, latents.shape[2], latents.shape[3], len(prompts))
319
+ print("initial_latents", initial_latents.shape)
320
+ print("mask_tensor", mask_tensor.shape)
321
+ print("img_tensor", img_tensor.shape)
322
+ masked_latents[mask_tensor == 1] = initial_latents[mask_tensor == 1]
323
+
324
+ text_embeddings = self.get_text_embeddings(prompts, n_imgs)
325
+
326
+ latents_steps = self.diffusion(
327
+ masked_latents, text_embeddings, end_iteration=n_steps, mask_tensor=mask_tensor, show_progress=show_progress, **kwargs
328
+ )
329
+
330
+ # Clear CUDA cache
331
+ torch.cuda.empty_cache()
332
+
333
+ # Convert final latents to image
334
+ inpainted_image_tensor = latents_steps[-1].to(self.unet.device)
335
+ inpainted_image = self.to_image(self.decode(inpainted_image_tensor))
336
+
337
+ return inpainted_image
338
+
339
+
340
+ @torch.no_grad()
341
+ def diffusion(self, latents, text_embeddings, end_iteration=1000, start_iteration=0, mask_tensor=None, show_progress=True, **kwargs):
342
+ latents_steps = []
343
+
344
+ iterator = tqdm(range(start_iteration, end_iteration)) if show_progress else range(start_iteration, end_iteration)
345
+
346
+ for iteration in iterator:
347
+ noise_pred = self.predict_noise(iteration, latents, text_embeddings)
348
+ # Update latents only where the mask is not applied
349
+ latents[mask_tensor == 1] = self.scheduler.step(noise_pred, self.scheduler.timesteps[iteration], latents).prev_sample[mask_tensor == 1]
350
+ latents_steps.append(latents.clone())
351
+
352
+ return latents_steps
353
+
354
+ @torch.no_grad()
355
+ def __call__(self,
356
+ prompts,
357
+ img_size=512,
358
+ n_steps=50,
359
+ n_imgs=1,
360
+ end_iteration=None,
361
+ generator=None,
362
+ eta=1.0,
363
+ variance_scale = 1.0,
364
+ **kwargs):
365
+ assert 0 <= n_steps <= 1000
366
+
367
+ if not isinstance(prompts, list):
368
+ prompts = [prompts]
369
+
370
+ self.set_scheduler_timesteps(n_steps)
371
+ latents = self.get_initial_latents(n_imgs, img_size, len(prompts), generator=generator)
372
+ text_embeddings = self.get_text_embeddings(prompts, n_imgs)
373
+ end_iteration = end_iteration or n_steps
374
+
375
+ latents_steps, trace_steps, noise_preds, output_steps = self.diffusion(latents, text_embeddings, end_iteration=end_iteration, eta=eta, variance_scale=variance_scale, **kwargs)
376
+ returned_latents = latents_steps
377
+ latents_steps = [self.decode(latents.to(self.unet.device)) for latents in latents_steps]
378
+ images_steps = [self.to_image(latents) for latents in latents_steps]
379
+
380
+ np_latents = np.array([latents.cpu().numpy() for latents in latents_steps])
381
+
382
+ print("latents_steps shape: ", np_latents.shape)
383
+
384
+ # for i in range(len(images_steps)):
385
+ # self.safety_checker = self.safety_checker.float()
386
+ # safety_checker_input = self.feature_extractor(images_steps[i], return_tensors="pt").to(latents_steps[0].device)
387
+ # image, has_nsfw_concept = self.safety_checker(
388
+ # images=latents_steps[i].float().cpu().numpy(), clip_input=safety_checker_input.pixel_values.float()
389
+ # )
390
+
391
+ # images_steps[i][0] = self.to_image(torch.from_numpy(image))[0]
392
+
393
+ np_images_steps = np.array(images_steps)
394
+
395
+ final_steps = list(zip(*images_steps))
396
+
397
+
398
+ # '*' unpacks the images_steps
399
+
400
+ if trace_steps:
401
+ return images_steps, trace_steps
402
+
403
+ return final_steps, np_images_steps, latents_steps, returned_latents, noise_preds, output_steps
404
+
405
+ class FineTunedModel(torch.nn.Module):
406
+
407
+ def __init__(self,
408
+ model,
409
+ train_method,
410
+ ):
411
+
412
+ super().__init__()
413
+
414
+ self.model = model
415
+ self.ft_modules = {}
416
+ self.orig_modules = {}
417
+
418
+ freeze(self.model)
419
+
420
+ for module_name, module in model.named_modules():
421
+ if 'unet' not in module_name:
422
+ continue
423
+ if module.__class__.__name__ in ["Linear", "Conv2d", "LoRACompatibleLinear", "LoRACompatibleConv"]:
424
+ if train_method == 'xattn':
425
+ if 'attn2' not in module_name:
426
+ continue
427
+ elif train_method == 'xattn-strict':
428
+ if 'attn2' not in module_name or 'to_q' not in module_name or 'to_k' not in module_name:
429
+ continue
430
+ elif train_method == 'noxattn':
431
+ if 'attn2' in module_name:
432
+ continue
433
+ elif train_method == 'selfattn':
434
+ if 'attn1' not in module_name:
435
+ continue
436
+ else:
437
+ raise NotImplementedError(
438
+ f"train_method: {train_method} is not implemented."
439
+ )
440
+
441
+ ft_module = copy.deepcopy(module)
442
+
443
+ self.orig_modules[module_name] = module
444
+ self.ft_modules[module_name] = ft_module
445
+
446
+ unfreeze(ft_module)
447
+
448
+ self.ft_modules_list = torch.nn.ModuleList(self.ft_modules.values())
449
+ self.orig_modules_list = torch.nn.ModuleList(self.orig_modules.values())
450
+
451
+
452
+ @classmethod
453
+ def from_checkpoint(cls, model, checkpoint, train_method):
454
+
455
+ if isinstance(checkpoint, str):
456
+ checkpoint = torch.load(checkpoint)
457
+
458
+ modules = [f"{key}$" for key in list(checkpoint.keys())]
459
+
460
+ ftm = FineTunedModel(model, train_method=train_method)
461
+ ftm.load_state_dict(checkpoint)
462
+
463
+ return ftm
464
+
465
+
466
+ def __enter__(self):
467
+
468
+ for key, ft_module in self.ft_modules.items():
469
+ set_module(self.model, key, ft_module)
470
+
471
+ def __exit__(self, exc_type, exc_value, tb):
472
+
473
+ for key, module in self.orig_modules.items():
474
+ set_module(self.model, key, module)
475
+
476
+ def parameters(self):
477
+
478
+ parameters = []
479
+
480
+ for ft_module in self.ft_modules.values():
481
+
482
+ parameters.extend(list(ft_module.parameters()))
483
+
484
+ return parameters
485
+
486
+ def state_dict(self):
487
+
488
+ state_dict = {key: module.state_dict() for key, module in self.ft_modules.items()}
489
+
490
+ return state_dict
491
+
492
+ def load_state_dict(self, state_dict):
493
+
494
+ for key, sd in state_dict.items():
495
+
496
+ self.ft_modules[key].load_state_dict(sd)
497
+ def train(erase_concept, erase_from, train_method, iterations, negative_guidance, lr, save_path):
498
+
499
+ nsteps = 50
500
+
501
+ diffuser = StableDiffuser(scheduler='DDIM').to('cuda')
502
+ diffuser.train()
503
+
504
+ finetuner = FineTunedModel(diffuser, train_method=train_method)
505
+
506
+ optimizer = torch.optim.Adam(finetuner.parameters(), lr=lr)
507
+ criteria = torch.nn.MSELoss()
508
+
509
+ pbar = tqdm(range(iterations))
510
+ erase_concept = erase_concept.split(',')
511
+ erase_concept = [a.strip() for a in erase_concept]
512
+
513
+ erase_from = erase_from.split(',')
514
+ erase_from = [a.strip() for a in erase_from]
515
+
516
+
517
+ if len(erase_from)!=len(erase_concept):
518
+ if len(erase_from) == 1:
519
+ c = erase_from[0]
520
+ erase_from = [c for _ in erase_concept]
521
+ else:
522
+ print(erase_from, erase_concept)
523
+ raise Exception("Erase from concepts length need to match erase concepts length")
524
+
525
+ erase_concept_ = []
526
+ for e, f in zip(erase_concept, erase_from):
527
+ erase_concept_.append([e,f])
528
+
529
+
530
+
531
+ erase_concept = erase_concept_
532
+
533
+
534
+
535
+ print(erase_concept)
536
+
537
+ # del diffuser.vae
538
+ # del diffuser.text_encoder
539
+ # del diffuser.tokenizer
540
+
541
+ torch.cuda.empty_cache()
542
+
543
+ for i in pbar:
544
+ with torch.no_grad():
545
+ index = np.random.choice(len(erase_concept), 1, replace=False)[0]
546
+ erase_concept_sampled = erase_concept[index]
547
+
548
+
549
+ neutral_text_embeddings = diffuser.get_text_embeddings([''],n_imgs=1)
550
+ positive_text_embeddings = diffuser.get_text_embeddings([erase_concept_sampled[0]],n_imgs=1)
551
+ target_text_embeddings = diffuser.get_text_embeddings([erase_concept_sampled[1]],n_imgs=1)
552
+
553
+
554
+ diffuser.set_scheduler_timesteps(nsteps)
555
+
556
+ optimizer.zero_grad()
557
+
558
+ iteration = torch.randint(1, nsteps - 1, (1,)).item()
559
+
560
+ latents = diffuser.get_initial_latents(1, 512, 1)
561
+
562
+ with finetuner:
563
+
564
+ latents_steps, _ = diffuser.diffusion(
565
+ latents,
566
+ positive_text_embeddings,
567
+ start_iteration=0,
568
+ end_iteration=iteration,
569
+ guidance_scale=3,
570
+ show_progress=False
571
+ )
572
+
573
+ diffuser.set_scheduler_timesteps(1000)
574
+
575
+ iteration = int(iteration / nsteps * 1000)
576
+
577
+ positive_latents = diffuser.predict_noise(iteration, latents_steps[0], positive_text_embeddings, guidance_scale=1)
578
+ neutral_latents = diffuser.predict_noise(iteration, latents_steps[0], neutral_text_embeddings, guidance_scale=1)
579
+ target_latents = diffuser.predict_noise(iteration, latents_steps[0], target_text_embeddings, guidance_scale=1)
580
+ if erase_concept_sampled[0] == erase_concept_sampled[1]:
581
+ target_latents = neutral_latents.clone().detach()
582
+ with finetuner:
583
+ negative_latents = diffuser.predict_noise(iteration, latents_steps[0], target_text_embeddings, guidance_scale=1)
584
+
585
+ positive_latents.requires_grad = False
586
+ neutral_latents.requires_grad = False
587
+
588
+
589
+ loss = criteria(negative_latents, target_latents - (negative_guidance*(positive_latents - neutral_latents))) #loss = criteria(e_n, e_0) works the best try 5000 epochs
590
+
591
+ loss.backward()
592
+ optimizer.step()
593
+
594
+ torch.save(finetuner.state_dict(), save_path)
595
+
596
+ del diffuser, loss, optimizer, finetuner, negative_latents, neutral_latents, positive_latents, latents_steps, latents
597
+
598
+ torch.cuda.empty_cache()
599
+
600
+ if __name__ == '__main__':
601
+ model_path='ESD_Models/car_noxattn_200.pt'
602
+ state_dict = torch.load(model_path)
603
+ diffuser = StableDiffuser(scheduler='DDIM').to('cuda')
604
+ finetuner = FineTunedModel(diffuser, train_method='noxattn')
605
+
606
+ finetuner.load_state_dict(state_dict)
607
+
608
+ #generation loop
609
+ all_images = []
610
+ with finetuner:
611
+ images = diffuser('image of a car', n_steps=50, generator=torch.manual_seed(2440), eta=1.0)
612
+ plt.imshow(images[0][0])
Attack_code/Inpainting/inpainting_diffusion.ipynb ADDED
The diff for this file is too large to render. See raw diff
 
Attack_code/Noisy Diffusion(Eta attack)/clilp_utils.py ADDED
@@ -0,0 +1,366 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from PIL import Image
2
+ import requests
3
+ import os, glob
4
+ import pandas as pd
5
+ import numpy as np
6
+ import re
7
+ from transformers import CLIPProcessor, CLIPModel
8
+ import importlib
9
+ import torch
10
+ # Make changes to esd_diffusers.py file here
11
+ from eta_diffusion import FineTunedModel, StableDiffuser
12
+
13
+ class ExperimentImageSet:
14
+ def __init__(self, stable_diffusion, eta_0_image, attack_images, interference_images = None, prompt: str = None, interference_prompt1 = None, interference_prompt2 = None, seed: int = None):
15
+ self.stable_diffusion: np.ndarray = stable_diffusion
16
+ self.eta_0_image: np.ndarray = eta_0_image
17
+ self.attack_images: np.ndarray = attack_images
18
+ self.interference_images: np.ndarray = interference_images
19
+ self.target_prompt = prompt
20
+ self.seed = seed
21
+ self.interference_prompt1 = interference_prompt1
22
+ self.interference_prompt2 = interference_prompt2
23
+
24
+ def erased_gen(target_csv_path, target_model_path, train_method, etas, num_prompts):
25
+ # Load the CSV file
26
+ target_data = pd.read_csv(target_csv_path)
27
+
28
+ torch.cuda.empty_cache()
29
+ variance_scales = [1.0]
30
+
31
+ # Placeholder for the total images and experiment sets
32
+ total_images = []
33
+ total_experiment_sets = []
34
+ ct = 0
35
+
36
+ # Initialize the diffuser and finetuner models
37
+ state_dict = torch.load(target_model_path)
38
+ diffuser = StableDiffuser(scheduler='DDIM').to('cuda')
39
+ finetuner = FineTunedModel(diffuser, train_method=train_method)
40
+ finetuner.load_state_dict(state_dict)
41
+
42
+ # Iterate through the target data
43
+ for index, row in target_data.head(num_prompts).iterrows():
44
+ prompt = row['prompt']
45
+ seed = int(row['evaluation_seed']) # Assuming 'evaluation_seed' contains the seed values
46
+
47
+ # Base stable diffusion image
48
+ stable_diffusion, images_steps, decoded_latents, latents, noise_preds, output_steps = diffuser(
49
+ prompt,
50
+ n_steps=50,
51
+ generator=torch.manual_seed(seed),
52
+ eta=0.0,
53
+ variance_scale=0.0
54
+ )
55
+ total_images.append(stable_diffusion)
56
+
57
+ # Finetuned no attack image
58
+ with finetuner:
59
+ finetuned_no_attack, images_steps, decoded_latents, latents, noise_preds, output_steps = diffuser(
60
+ prompt,
61
+ n_steps=50,
62
+ generator=torch.manual_seed(seed),
63
+ eta=0.0,
64
+ variance_scale=0.0
65
+ )
66
+ total_images.append(finetuned_no_attack)
67
+
68
+ attack_images = []
69
+ for eta in etas:
70
+ for variance_scale in variance_scales:
71
+ eta_image, images_steps, decoded_latents, latents, noise_preds, output_steps = diffuser(
72
+ prompt,
73
+ n_steps=50,
74
+ generator=torch.manual_seed(seed),
75
+ eta=eta,
76
+ variance_scale=variance_scale
77
+ )
78
+ attack_images.append(eta_image)
79
+ total_images.extend(attack_images)
80
+
81
+ # Construct an experiment set with the images
82
+ experiment_set = ExperimentImageSet(
83
+ stable_diffusion=stable_diffusion,
84
+ eta_0_image=finetuned_no_attack,
85
+ attack_images=np.array(attack_images),
86
+ interference_images=None, # Assuming no interference images in this case
87
+ prompt=prompt,
88
+ seed=seed,
89
+ interference_prompt1 = None,
90
+ interference_prompt2 = None
91
+ )
92
+ total_experiment_sets.append(experiment_set)
93
+
94
+ ct += 1 + len(etas)
95
+ print(f"diffusion-count {ct} for prompt: {prompt}")
96
+
97
+ # Convert total images to a NumPy array
98
+ total_images = np.array(total_images)
99
+
100
+ # Assuming fixed_images is needed as an array of final images
101
+ fixed_images = []
102
+ for image in total_images:
103
+ fixed_images.append(image[0][49])
104
+
105
+ # Convert fixed_images to NumPy array
106
+ fixed_images = np.array(fixed_images)
107
+
108
+ print("Image grid shape:", fixed_images.shape)
109
+
110
+ return fixed_images, total_experiment_sets
111
+
112
+ from transformers import CLIPModel, CLIPProcessor
113
+ import torch
114
+ import numpy as np
115
+
116
+ from transformers import CLIPModel, CLIPProcessor
117
+ import torch
118
+ import numpy as np
119
+
120
+ def process_images(model, processor, prompt: str, images: list):
121
+ """Processes images and returns CLIP scores."""
122
+ images = np.array(images)
123
+ images = images.squeeze()
124
+ print(images.shape)
125
+ images = [image[49] for image in images]
126
+ inputs = processor(text=[prompt], images=images, return_tensors="pt", padding=True)
127
+ outputs = model(**inputs)
128
+ return [clip_score.item() for clip_score in outputs.logits_per_image]
129
+
130
+ def calculate_experiment_scores(experiment, model, processor):
131
+ """Calculates CLIP scores for each image set in the experiment."""
132
+ targeted_images = [experiment.stable_diffusion, experiment.eta_0_image]
133
+ targeted_images.extend(experiment.attack_images)
134
+ clip_scores = process_images(model, processor, experiment.target_prompt, targeted_images)
135
+
136
+ scores = {
137
+ 'SD': clip_scores[0], # Stable diffusion image score
138
+ 'ETA_0': clip_scores[1], # ETA_0 image score
139
+ 'ATTACK': max(clip_scores[2:]), # Best attack image score
140
+ }
141
+
142
+ if experiment.interference_images:
143
+ interference_images = experiment.interference_images
144
+ interference_images = np.array(interference_images)
145
+ interference_images = interference_images.squeeze()
146
+ interference_images = [interference_image[49] for interference_image in interference_images]
147
+ inputs = processor(text=[experiment.interference_prompt1], images=interference_images[0], return_tensors="pt", padding=True)
148
+ outputs = model(**inputs)
149
+ interference_1 = outputs.logits_per_image.item()
150
+
151
+ inputs = processor(text=[experiment.interference_prompt2], images=interference_images[1], return_tensors="pt", padding=True)
152
+ outputs = model(**inputs)
153
+ interference_2 = outputs.logits_per_image.item()
154
+ scores['INTERFERENCE1'] = interference_1 # Assuming first interference score is used
155
+ scores['INTERFERENCE2'] = interference_2 # Assuming first interference score is used
156
+
157
+ return scores
158
+
159
+ def get_clip_scores(experiment_sets: list['ExperimentImageSet']):
160
+ """Processes a list of experiments and returns mean CLIP scores."""
161
+ model = CLIPModel.from_pretrained("openai/clip-vit-base-patch32")
162
+ processor = CLIPProcessor.from_pretrained("openai/clip-vit-base-patch32")
163
+
164
+ total_clip_scores = {'SD': 0, 'ETA_0': 0, 'ATTACK': 0, 'INTERFERENCE1': 0, 'INTERFERENCE2' : 0}
165
+ experiment_count = len(experiment_sets)
166
+
167
+ for experiment in experiment_sets:
168
+ experiment_scores = calculate_experiment_scores(experiment, model, processor)
169
+ for key in total_clip_scores:
170
+ total_clip_scores[key] += experiment_scores.get(key, 0)
171
+
172
+ # Calculate mean scores
173
+ mean_clip_scores = {key: score / experiment_count for key, score in total_clip_scores.items()}
174
+ return mean_clip_scores
175
+
176
+ def get_simple_clip_scores(images_list, prompts):
177
+ """
178
+ Processes a list of images and prompts and returns the mean CLIP score for each prompt-image pair.
179
+
180
+ Args:
181
+ images_list (list of lists): List of image sets where each sublist contains images for one prompt.
182
+ prompts (list of str): List of prompts corresponding to each image set.
183
+
184
+ Returns:
185
+ mean_clip_score (float): Mean CLIP score across all image-prompt pairs.
186
+ """
187
+ model = CLIPModel.from_pretrained("openai/clip-vit-base-patch32")
188
+ processor = CLIPProcessor.from_pretrained("openai/clip-vit-base-patch32")
189
+
190
+ total_score = 0.0
191
+ total_images = 0
192
+ full_clip_set = []
193
+ for images, prompt in zip(images_list, prompts):
194
+ inputs = processor(text=[prompt], images=images, return_tensors="pt", padding=True) # Indentation fixed here
195
+ outputs = model(**inputs)
196
+ clip_scores = [clip_score.item() for clip_score in outputs.logits_per_image]
197
+ full_clip_set.extend(np.round(clip_scores, 2))
198
+
199
+ # Calculate mean score
200
+ return full_clip_set
201
+
202
+ import matplotlib.pyplot as plt
203
+ import matplotlib.pyplot as plt
204
+
205
+ def show_image_grid_with_scores(img_files, subtitles=None, clip_scores=None, num_rows=3, num_cols=4, fig_size=(15, 10)):
206
+ """
207
+ Displays a grid of images with subtitles and optional CLIP scores.
208
+
209
+ Args:
210
+ img_files (list of np.ndarray): List of images to display.
211
+ subtitles (list of str): List of labels for the images.
212
+ clip_scores (list of float): List of CLIP scores for the images.
213
+ num_rows (int): Number of rows in the grid.
214
+ num_cols (int): Number of columns in the grid.
215
+ fig_size (tuple): Size of the figure.
216
+ """
217
+ # Create a grid to display the images
218
+ fig, axes = plt.subplots(num_rows, num_cols, figsize=fig_size)
219
+ if not subtitles and clip_scores:
220
+ subtitles = ['SD', 'Finetuned', 'ETA', "ETA", "ETA", 'eta']*(len(clip_scores)//6)
221
+ else:
222
+ subtitles = ['SD', 'Finetuned', 'ETA', "ETA", "ETA", 'eta']
223
+ # Plot each image in the grid row-wise
224
+ for i, ax in enumerate(axes.flatten()):
225
+ img_index = i # row-major order
226
+ if img_index < len(img_files):
227
+ img = img_files[img_index]
228
+ ax.imshow(img)
229
+
230
+ # Construct subtitle with label and optional CLIP score
231
+ if subtitles and img_index < len(subtitles):
232
+ subtitle = subtitles[img_index]
233
+ if clip_scores and img_index < len(clip_scores):
234
+ subtitle += f" CLIP: {clip_scores[img_index]:.3f}"
235
+ ax.set_title(subtitle, fontsize=14)
236
+
237
+ ax.axis('off') # Turn off axis labels
238
+
239
+ plt.tight_layout()
240
+ plt.show()
241
+
242
+ # Example usage
243
+ # erased_images = [image1, image2, image3, ...] # Replace with actual images
244
+ # subtitles = ["Original", "Finetuner no attack", "Eta Attack", ...] # Replace with actual subtitles
245
+ # clip_scores = [0.85, 0.92, 0.75, ...] # Replace with actual CLIP scores
246
+ # show_image_grid_with_scores(erased_images, subtitles=subtitles, clip_scores=clip_scores, num_rows=2, num_cols=6)
247
+
248
+ def interference_gen(target_csv_path, interference_path1, interference_path2, target_model_path, train_method, etas, num_prompts):
249
+ # Load the target and interference CSV files
250
+ target_data = pd.read_csv(target_csv_path)
251
+ interference_data1 = pd.read_csv(interference_path1)
252
+ interference_data2 = pd.read_csv(interference_path2)
253
+
254
+ torch.cuda.empty_cache()
255
+ variance_scales = [1.0]
256
+
257
+ # Placeholder for the total images and experiment sets
258
+ total_images = []
259
+ total_experiment_sets = []
260
+ ct = 0
261
+
262
+ # Initialize the diffuser and finetuner models
263
+ state_dict = torch.load(target_model_path)
264
+ diffuser = StableDiffuser(scheduler='DDIM').to('cuda')
265
+ finetuner = FineTunedModel(diffuser, train_method=train_method)
266
+ finetuner.load_state_dict(state_dict)
267
+
268
+ # Iterate through the target data along with interference data from the other two CSVs
269
+ for (index, row), (index1, row1), (index2, row2) in zip(
270
+ target_data.head(num_prompts).iterrows(),
271
+ interference_data1.head(num_prompts).iterrows(),
272
+ interference_data2.head(num_prompts).iterrows()
273
+ ):
274
+
275
+ prompt = row['prompt']
276
+ seed = int(row['evaluation_seed']) # Assuming 'evaluation_seed' contains the seed values
277
+
278
+ interference_prompt1 = row1['prompt']
279
+ interference_seed1 = int(row1['evaluation_seed'])
280
+
281
+ interference_prompt2 = row2['prompt']
282
+ interference_seed2 = int(row2['evaluation_seed'])
283
+
284
+ # Base stable diffusion image
285
+ stable_diffusion, images_steps, decoded_latents, latents, noise_preds, output_steps = diffuser(
286
+ prompt,
287
+ n_steps=50,
288
+ generator=torch.manual_seed(seed),
289
+ eta=0.0,
290
+ variance_scale=0.0
291
+ )
292
+ total_images.append(stable_diffusion)
293
+
294
+ # Finetuned no attack image
295
+ with finetuner:
296
+ finetuned_no_attack, images_steps, decoded_latents, latents, noise_preds, output_steps = diffuser(
297
+ prompt,
298
+ n_steps=50,
299
+ generator=torch.manual_seed(seed),
300
+ eta=0.0,
301
+ variance_scale=0.0
302
+ )
303
+ total_images.append(finetuned_no_attack)
304
+
305
+ attack_images = []
306
+ for eta in etas:
307
+ for variance_scale in variance_scales:
308
+ eta_image, images_steps, decoded_latents, latents, noise_preds, output_steps = diffuser(
309
+ prompt,
310
+ n_steps=50,
311
+ generator=torch.manual_seed(seed),
312
+ eta=eta,
313
+ variance_scale=variance_scale
314
+ )
315
+ attack_images.append(eta_image)
316
+ total_images.extend(attack_images)
317
+
318
+ # Generate interference images using prompts and seeds from the interference CSVs
319
+ interference_image1, images_steps, decoded_latents, latents, noise_preds, output_steps = diffuser(
320
+ interference_prompt1,
321
+ n_steps=50,
322
+ generator=torch.manual_seed(interference_seed1),
323
+ eta=0.0, # No attack (eta = 0)
324
+ variance_scale=0.0 # No attack variance
325
+ )
326
+ total_images.append(interference_image1)
327
+
328
+ interference_image2, images_steps, decoded_latents, latents, noise_preds, output_steps = diffuser(
329
+ interference_prompt2,
330
+ n_steps=50,
331
+ generator=torch.manual_seed(interference_seed2),
332
+ eta=0.0, # No attack (eta = 0)
333
+ variance_scale=0.0 # No attack variance
334
+ )
335
+ total_images.append(interference_image2)
336
+
337
+ # Construct an experiment set with the images, including the interference images
338
+ experiment_set = ExperimentImageSet(
339
+ stable_diffusion=stable_diffusion,
340
+ eta_0_image=finetuned_no_attack,
341
+ attack_images=np.array(attack_images),
342
+ interference_images=[interference_image1, interference_image2], # Adding interference images
343
+ prompt=prompt,
344
+ seed=seed,
345
+ interference_prompt1=interference_prompt1,
346
+ interference_prompt2=interference_prompt2
347
+ )
348
+ total_experiment_sets.append(experiment_set)
349
+
350
+ ct += 1 + len(etas)
351
+ print(f"diffusion-count {ct} for prompt: {prompt}")
352
+
353
+ # Convert total images to a NumPy array
354
+ total_images = np.array(total_images)
355
+
356
+ # Assuming fixed_images is needed as an array of final images
357
+ fixed_images = []
358
+ for image in total_images:
359
+ fixed_images.append(image[0][49])
360
+
361
+ # Convert fixed_images to NumPy array
362
+ fixed_images = np.array(fixed_images)
363
+
364
+ print("Image grid shape:", fixed_images.shape)
365
+
366
+ return fixed_images, total_experiment_sets
Attack_code/Noisy Diffusion(Eta attack)/clip_gen_tests.ipynb ADDED
The diff for this file is too large to render. See raw diff
 
Attack_code/Noisy Diffusion(Eta attack)/eta_diffusion.py ADDED
@@ -0,0 +1,661 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from PIL import Image
2
+ from matplotlib import pyplot as plt
3
+ import textwrap
4
+ import argparse
5
+ import torch
6
+ import copy
7
+ import os
8
+ import re
9
+ import numpy as np
10
+ from diffusers import AutoencoderKL, UNet2DConditionModel
11
+ from PIL import Image
12
+ from tqdm.auto import tqdm
13
+ from transformers import CLIPTextModel, CLIPTokenizer, CLIPFeatureExtractor
14
+ from diffusers.schedulers import EulerAncestralDiscreteScheduler
15
+ from eta_diffusers.src.diffusers.schedulers.eta_ddim_scheduler import DDIMScheduler
16
+ from diffusers.schedulers.scheduling_ddpm import DDPMScheduler
17
+ from diffusers.schedulers.scheduling_lms_discrete import LMSDiscreteScheduler
18
+ # from diffusers.pipelines.stable_diffusion import StableDiffusionSafetyChecker
19
+
20
+ def show_image_grid(img_files, num_rows=3, num_cols=4, fig_size=(15, 10)):
21
+ # Create a grid to display the images
22
+ fig, axes = plt.subplots(num_rows, num_cols, figsize=fig_size)
23
+
24
+ # Plot each image in the grid row-wise
25
+ for i, ax in enumerate(axes.flatten()):
26
+ img_index = i # row-major order
27
+ if img_index < len(img_files):
28
+ img = img_files[img_index]
29
+ ax.imshow(img)
30
+ ax.axis('off') # Turn off axis labels
31
+
32
+ plt.tight_layout()
33
+ plt.show()
34
+
35
+ # Example usage
36
+ # img_files = [image1, image2, image3, ...] # Replace with actual images
37
+ # show_image_grid(img_files)
38
+
39
+ def to_gif(images, path):
40
+
41
+ images[0].save(path, save_all=True,
42
+ append_images=images[1:], loop=0, duration=len(images) * 20)
43
+
44
+ def figure_to_image(figure):
45
+
46
+ figure.set_dpi(300)
47
+
48
+ figure.canvas.draw()
49
+
50
+ return Image.frombytes('RGB', figure.canvas.get_width_height(), figure.canvas.tostring_rgb())
51
+
52
+ def image_grid(images, outpath=None, column_titles=None, row_titles=None):
53
+
54
+ n_rows = len(images)
55
+ n_cols = len(images[0])
56
+
57
+ fig, axs = plt.subplots(nrows=n_rows, ncols=n_cols,
58
+ figsize=(n_cols, n_rows), squeeze=False)
59
+
60
+ for row, _images in enumerate(images):
61
+
62
+ for column, image in enumerate(_images):
63
+ ax = axs[row][column]
64
+ ax.imshow(image)
65
+ if column_titles and row == 0:
66
+ ax.set_title(textwrap.fill(
67
+ column_titles[column], width=12), fontsize='x-small')
68
+ if row_titles and column == 0:
69
+ ax.set_ylabel(row_titles[row], rotation=0, fontsize='x-small', labelpad=1.6 * len(row_titles[row]))
70
+ ax.set_xticks([])
71
+ ax.set_yticks([])
72
+
73
+ plt.subplots_adjust(wspace=0, hspace=0)
74
+
75
+ if outpath is not None:
76
+ plt.savefig(outpath, bbox_inches='tight', dpi=300)
77
+ plt.close()
78
+ else:
79
+ plt.tight_layout(pad=0)
80
+ image = figure_to_image(plt.gcf())
81
+ plt.close()
82
+ return image
83
+
84
+ def get_module(module, module_name):
85
+
86
+ if isinstance(module_name, str):
87
+ module_name = module_name.split('.')
88
+
89
+ if len(module_name) == 0:
90
+ return module
91
+ else:
92
+ module = getattr(module, module_name[0])
93
+ return get_module(module, module_name[1:])
94
+
95
+ def set_module(module, module_name, new_module):
96
+
97
+ if isinstance(module_name, str):
98
+ module_name = module_name.split('.')
99
+
100
+ if len(module_name) == 1:
101
+ return setattr(module, module_name[0], new_module)
102
+ else:
103
+ module = getattr(module, module_name[0])
104
+ return set_module(module, module_name[1:], new_module)
105
+
106
+ def freeze(module):
107
+
108
+ for parameter in module.parameters():
109
+
110
+ parameter.requires_grad = False
111
+
112
+ def unfreeze(module):
113
+
114
+ for parameter in module.parameters():
115
+
116
+ parameter.requires_grad = True
117
+
118
+ def get_concat_h(im1, im2):
119
+ dst = Image.new('RGB', (im1.width + im2.width, im1.height))
120
+ dst.paste(im1, (0, 0))
121
+ dst.paste(im2, (im1.width, 0))
122
+ return dst
123
+
124
+ def get_concat_v(im1, im2):
125
+ dst = Image.new('RGB', (im1.width, im1.height + im2.height))
126
+ dst.paste(im1, (0, 0))
127
+ dst.paste(im2, (0, im1.height))
128
+ return dst
129
+
130
+ class StableDiffuser(torch.nn.Module):
131
+
132
+ def __init__(self,
133
+ scheduler='DDIM'
134
+ ):
135
+ print('code changed')
136
+
137
+ super().__init__()
138
+
139
+ # Load the autoencoder model which will be used to decode the latents into image space.
140
+ self.vae = AutoencoderKL.from_pretrained(
141
+ "CompVis/stable-diffusion-v1-4", subfolder="vae")
142
+ print(self.vae.config.scaling_factor )
143
+ # Load the tokenizer and text encoder to tokenize and encode the text.
144
+ self.tokenizer = CLIPTokenizer.from_pretrained(
145
+ "openai/clip-vit-large-patch14")
146
+ self.text_encoder = CLIPTextModel.from_pretrained(
147
+ "openai/clip-vit-large-patch14")
148
+
149
+ # The UNet model for generating the latents.
150
+ self.unet = UNet2DConditionModel.from_pretrained(
151
+ "CompVis/stable-diffusion-v1-4", subfolder="unet")
152
+
153
+ self.feature_extractor = CLIPFeatureExtractor.from_pretrained("CompVis/stable-diffusion-v1-4", subfolder="feature_extractor")
154
+ # self.safety_checker = StableDiffusionSafetyChecker.from_pretrained("CompVis/stable-diffusion-v1-4", subfolder="safety_checker")
155
+
156
+ if scheduler == 'LMS':
157
+ self.scheduler = LMSDiscreteScheduler(beta_start=0.00085, beta_end=0.012, beta_schedule="scaled_linear", num_train_timesteps=1000)
158
+ elif scheduler == 'DDIM':
159
+ self.scheduler = DDIMScheduler.from_pretrained("CompVis/stable-diffusion-v1-4", subfolder="scheduler")
160
+ elif scheduler == 'DDPM':
161
+ self.scheduler = DDPMScheduler.from_pretrained("CompVis/stable-diffusion-v1-4", subfolder="scheduler")
162
+
163
+ self.eval()
164
+
165
+ def get_noise(self, batch_size, img_size, generator=None):
166
+
167
+ param = list(self.parameters())[0]
168
+
169
+ return torch.randn(
170
+ (batch_size, self.unet.in_channels, img_size // 8, img_size // 8),
171
+ generator=generator).type(param.dtype).to(param.device)
172
+
173
+ def add_noise(self, latents, noise, step):
174
+
175
+ return self.scheduler.add_noise(latents, noise, torch.tensor([self.scheduler.timesteps[step]]))
176
+
177
+ def text_tokenize(self, prompts):
178
+ tokens = self.tokenizer(prompts, padding="max_length", max_length=self.tokenizer.model_max_length, truncation=True, return_tensors="pt")
179
+ print("prompts", prompts)
180
+ print("tokens", tokens)
181
+ return tokens
182
+
183
+ def text_detokenize(self, tokens):
184
+
185
+ return [self.tokenizer.decode(token) for token in tokens if token != self.tokenizer.vocab_size - 1]
186
+
187
+ def text_encode(self, tokens):
188
+
189
+ return self.text_encoder(tokens.input_ids.to(self.unet.device))[0]
190
+
191
+ def decode(self, latents):
192
+ print(self.vae.config.scaling_factor)
193
+ print(latents)
194
+ print(1 / self.vae.config.scaling_factor * latents)
195
+ print(self.vae.decode(1 / self.vae.config.scaling_factor * latents))
196
+ print(self.vae.decode(1 / self.vae.config.scaling_factor * latents).sample)
197
+ return self.vae.decode(1 / self.vae.config.scaling_factor * latents).sample
198
+
199
+ def encode(self, tensors):
200
+
201
+ return self.vae.encode(tensors).latent_dist.mode() * 0.18215
202
+
203
+ def to_image(self, image):
204
+
205
+ image = (image / 2 + 0.5).clamp(0, 1)
206
+ image = image.detach().cpu().permute(0, 2, 3, 1).numpy()
207
+ print(image)
208
+ images = (image * 255).round().astype("uint8")
209
+ pil_images = [Image.fromarray(image) for image in images]
210
+
211
+ return pil_images
212
+
213
+ def set_scheduler_timesteps(self, n_steps):
214
+ self.scheduler.set_timesteps(n_steps, device=self.unet.device)
215
+
216
+ def get_initial_latents(self, n_imgs, img_size, n_prompts, generator=None):
217
+
218
+ noise = self.get_noise(n_imgs, img_size, generator=generator).repeat(n_prompts, 1, 1, 1)
219
+
220
+ latents = noise * self.scheduler.init_noise_sigma
221
+
222
+ return latents
223
+
224
+ def get_noise(self, batch_size, img_size, generator=None):
225
+
226
+ param = list(self.parameters())[0]
227
+
228
+ return torch.randn(
229
+ (batch_size, self.unet.in_channels, img_size // 8, img_size // 8),
230
+ generator=generator).type(param.dtype).to(param.device)
231
+
232
+ def add_noise(self, latents, noise, step):
233
+
234
+ return self.scheduler.add_noise(latents, noise, torch.tensor([self.scheduler.timesteps[step]]))
235
+
236
+ def text_tokenize(self, prompts):
237
+
238
+ return self.tokenizer(prompts, padding="max_length", max_length=self.tokenizer.model_max_length, truncation=True, return_tensors="pt")
239
+
240
+ def text_detokenize(self, tokens):
241
+
242
+ return [self.tokenizer.decode(token) for token in tokens if token != self.tokenizer.vocab_size - 1]
243
+
244
+ def text_encode(self, tokens):
245
+
246
+ return self.text_encoder(tokens.input_ids.to(self.unet.device))[0]
247
+
248
+ def decode(self, latents):
249
+
250
+ return self.vae.decode(1 / self.vae.config.scaling_factor * latents).sample
251
+
252
+ def encode(self, tensors):
253
+
254
+ return self.vae.encode(tensors).latent_dist.mode() * 0.18215
255
+
256
+ def to_image(self, image):
257
+
258
+ image = (image / 2 + 0.5).clamp(0, 1)
259
+ image = image.detach().cpu().permute(0, 2, 3, 1).numpy()
260
+ images = (image * 255).round().astype("uint8")
261
+ pil_images = [Image.fromarray(image) for image in images]
262
+
263
+ return pil_images
264
+
265
+ def set_scheduler_timesteps(self, n_steps):
266
+ self.scheduler.set_timesteps(n_steps, device=self.unet.device)
267
+
268
+ def get_initial_latents(self, n_imgs, img_size, n_prompts, generator=None):
269
+
270
+ noise = self.get_noise(n_imgs, img_size, generator=generator).repeat(n_prompts, 1, 1, 1)
271
+
272
+ latents = noise * self.scheduler.init_noise_sigma
273
+
274
+ return latents
275
+
276
+ def get_text_embeddings(self, prompts, n_imgs):
277
+
278
+ text_tokens = self.text_tokenize(prompts)
279
+
280
+ text_embeddings = self.text_encode(text_tokens)
281
+
282
+ unconditional_tokens = self.text_tokenize([""] * len(prompts))
283
+
284
+ unconditional_embeddings = self.text_encode(unconditional_tokens)
285
+
286
+ text_embeddings = torch.cat([unconditional_embeddings, text_embeddings]).repeat_interleave(n_imgs, dim=0)
287
+
288
+ return text_embeddings
289
+
290
+ def predict_noise(self,
291
+ iteration,
292
+ latents,
293
+ text_embeddings,
294
+ guidance_scale=7.5
295
+ ):
296
+
297
+ # expand the latents if we are doing classifier-free guidance to avoid doing two forward passes.
298
+ latents = torch.cat([latents] * 2)
299
+ latents = self.scheduler.scale_model_input(
300
+ latents, self.scheduler.timesteps[iteration])
301
+
302
+ # predict the noise residual
303
+ noise_prediction = self.unet(
304
+ latents, self.scheduler.timesteps[iteration], encoder_hidden_states=text_embeddings).sample
305
+
306
+ # perform guidance
307
+ noise_prediction_uncond, noise_prediction_text = noise_prediction.chunk(2)
308
+ noise_prediction = noise_prediction_uncond + guidance_scale * \
309
+ (noise_prediction_text - noise_prediction_uncond)
310
+
311
+ return noise_prediction
312
+ # New method for inpainting
313
+ @torch.no_grad()
314
+ def inpaint(self, img_tensor, mask_tensor, prompts, img_size=512, n_steps=50, n_imgs=1, **kwargs):
315
+ assert 0 <= n_steps <= 1000
316
+
317
+ self.set_scheduler_timesteps(n_steps)
318
+ latents = self.get_initial_latents(n_imgs, img_size, len(prompts))
319
+
320
+ # Prepare the mask
321
+ masked_latents = latents.clone()
322
+ masked_latents[mask_tensor == 1] = 0 # Set masked areas to 0 or noise
323
+
324
+ text_embeddings = self.get_text_embeddings(prompts, n_imgs)
325
+
326
+ latents_steps, trace_steps, noise_preds, output_steps = self.diffusion(
327
+ masked_latents, text_embeddings, end_iteration=n_steps, **kwargs
328
+ )
329
+
330
+ images_steps = [self.to_image(latents) for latents in latents_steps]
331
+ return images_steps
332
+
333
+ @torch.no_grad()
334
+ def diffusion(self, latents, text_embeddings, end_iteration=1000, start_iteration=0, **kwargs):
335
+ latents_steps = []
336
+
337
+ for iteration in tqdm(range(start_iteration, end_iteration)):
338
+ noise_pred = self.predict_noise(iteration, latents, text_embeddings)
339
+ # Only update latents where the mask is not applied
340
+ latents[mask_tensor == 1] = self.scheduler.step(noise_pred, self.scheduler.timesteps[iteration], latents).prev_sample[mask_tensor == 1]
341
+ latents_steps.append(latents.clone())
342
+
343
+ return latents_steps
344
+ @torch.no_grad()
345
+ def diffusion(self,
346
+ latents,
347
+ text_embeddings,
348
+ end_iteration=1000,
349
+ start_iteration=0,
350
+ return_steps=True,#This was False before
351
+ pred_x0=False,
352
+ trace_args=None,
353
+ show_progress=True,
354
+ eta=0.0,
355
+ variance_scale = 0.0,
356
+ **kwargs):
357
+
358
+ latents_steps = []
359
+ trace_steps = []
360
+ noise_preds = []
361
+ output_steps = []
362
+ trace = None
363
+
364
+ for iteration in tqdm(range(start_iteration, end_iteration), disable=not show_progress):
365
+
366
+ if trace_args:
367
+
368
+ trace = TraceDict(self, **trace_args)
369
+
370
+ noise_pred = self.predict_noise(
371
+ iteration,
372
+ latents,
373
+ text_embeddings,
374
+ **kwargs)
375
+ # compute the previous noisy sample x_t -> x_t-1
376
+ # print("Noise_Pred")
377
+ # print(noise_pred)
378
+ noise_preds.append(noise_pred)
379
+ output = self.scheduler.step(noise_pred, self.scheduler.timesteps[iteration], latents, eta=eta, variance_scale=variance_scale)
380
+ # print("Output")
381
+ # print(output)
382
+ output_steps.append(output)
383
+ if trace_args:
384
+
385
+ trace.close()
386
+
387
+ trace_steps.append(trace)
388
+
389
+ latents = output.prev_sample
390
+ # print("latents")
391
+ # print(latents)
392
+ if return_steps or iteration == end_iteration - 1:
393
+
394
+ output = output.pred_original_sample if pred_x0 else latents
395
+
396
+ if return_steps:
397
+ latents_steps.append(output.cpu())
398
+ else:
399
+ latents_steps.append(output)
400
+
401
+ return latents_steps, trace_steps, noise_preds, output_steps
402
+
403
+ @torch.no_grad()
404
+ def __call__(self,
405
+ prompts,
406
+ img_size=512,
407
+ n_steps=50,
408
+ n_imgs=1,
409
+ end_iteration=None,
410
+ generator=None,
411
+ eta=0.0,
412
+ variance_scale = 0.0,
413
+ **kwargs):
414
+ assert 0 <= n_steps <= 1000
415
+
416
+ if not isinstance(prompts, list):
417
+ prompts = [prompts]
418
+
419
+ self.set_scheduler_timesteps(n_steps)
420
+ latents = self.get_initial_latents(n_imgs, img_size, len(prompts), generator=generator)
421
+ text_embeddings = self.get_text_embeddings(prompts, n_imgs)
422
+ end_iteration = end_iteration or n_steps
423
+
424
+ latents_steps, trace_steps, noise_preds, output_steps = self.diffusion(latents, text_embeddings, end_iteration=end_iteration, eta=eta, variance_scale=variance_scale, **kwargs)
425
+ returned_latents = latents_steps
426
+ latents_steps = [self.decode(latents.to(self.unet.device)) for latents in latents_steps]
427
+ images_steps = [self.to_image(latents) for latents in latents_steps]
428
+
429
+ np_latents = np.array([latents.cpu().numpy() for latents in latents_steps])
430
+
431
+ print("latents_steps shape: ", np_latents.shape)
432
+
433
+ # for i in range(len(images_steps)):
434
+ # self.safety_checker = self.safety_checker.float()
435
+ # safety_checker_input = self.feature_extractor(images_steps[i], return_tensors="pt").to(latents_steps[0].device)
436
+ # image, has_nsfw_concept = self.safety_checker(
437
+ # images=latents_steps[i].float().cpu().numpy(), clip_input=safety_checker_input.pixel_values.float()
438
+ # )
439
+
440
+ # images_steps[i][0] = self.to_image(torch.from_numpy(image))[0]
441
+
442
+ np_images_steps = np.array(images_steps)
443
+
444
+ final_steps = list(zip(*images_steps))
445
+
446
+
447
+ # '*' unpacks the images_steps
448
+
449
+ if trace_steps:
450
+ return images_steps, trace_steps
451
+
452
+ return final_steps, np_images_steps, latents_steps, returned_latents, noise_preds, output_steps
453
+
454
+ class FineTunedModel(torch.nn.Module):
455
+
456
+ def __init__(self,
457
+ model,
458
+ train_method,
459
+ ):
460
+
461
+ super().__init__()
462
+
463
+ self.model = model
464
+ self.ft_modules = {}
465
+ self.orig_modules = {}
466
+
467
+ freeze(self.model)
468
+
469
+ for module_name, module in model.named_modules():
470
+ if 'unet' not in module_name:
471
+ continue
472
+ if module.__class__.__name__ in ["Linear", "Conv2d", "LoRACompatibleLinear", "LoRACompatibleConv"]:
473
+ if train_method == 'xattn':
474
+ if 'attn2' not in module_name:
475
+ continue
476
+ elif train_method == 'xattn-strict':
477
+ if 'attn2' not in module_name or 'to_q' not in module_name or 'to_k' not in module_name:
478
+ continue
479
+ elif train_method == 'noxattn':
480
+ if 'attn2' in module_name:
481
+ continue
482
+ elif train_method == 'selfattn':
483
+ if 'attn1' not in module_name:
484
+ continue
485
+ else:
486
+ raise NotImplementedError(
487
+ f"train_method: {train_method} is not implemented."
488
+ )
489
+
490
+ ft_module = copy.deepcopy(module)
491
+
492
+ self.orig_modules[module_name] = module
493
+ self.ft_modules[module_name] = ft_module
494
+
495
+ unfreeze(ft_module)
496
+
497
+ self.ft_modules_list = torch.nn.ModuleList(self.ft_modules.values())
498
+ self.orig_modules_list = torch.nn.ModuleList(self.orig_modules.values())
499
+
500
+
501
+ @classmethod
502
+ def from_checkpoint(cls, model, checkpoint, train_method):
503
+
504
+ if isinstance(checkpoint, str):
505
+ checkpoint = torch.load(checkpoint)
506
+
507
+ modules = [f"{key}$" for key in list(checkpoint.keys())]
508
+
509
+ ftm = FineTunedModel(model, train_method=train_method)
510
+ ftm.load_state_dict(checkpoint)
511
+
512
+ return ftm
513
+
514
+
515
+ def __enter__(self):
516
+
517
+ for key, ft_module in self.ft_modules.items():
518
+ set_module(self.model, key, ft_module)
519
+
520
+ def __exit__(self, exc_type, exc_value, tb):
521
+
522
+ for key, module in self.orig_modules.items():
523
+ set_module(self.model, key, module)
524
+
525
+ def parameters(self):
526
+
527
+ parameters = []
528
+
529
+ for ft_module in self.ft_modules.values():
530
+
531
+ parameters.extend(list(ft_module.parameters()))
532
+
533
+ return parameters
534
+
535
+ def state_dict(self):
536
+
537
+ state_dict = {key: module.state_dict() for key, module in self.ft_modules.items()}
538
+
539
+ return state_dict
540
+
541
+ def load_state_dict(self, state_dict):
542
+
543
+ for key, sd in state_dict.items():
544
+
545
+ self.ft_modules[key].load_state_dict(sd)
546
+ def train(erase_concept, erase_from, train_method, iterations, negative_guidance, lr, save_path):
547
+
548
+ nsteps = 50
549
+
550
+ diffuser = StableDiffuser(scheduler='DDIM').to('cuda')
551
+ diffuser.train()
552
+
553
+ finetuner = FineTunedModel(diffuser, train_method=train_method)
554
+
555
+ optimizer = torch.optim.Adam(finetuner.parameters(), lr=lr)
556
+ criteria = torch.nn.MSELoss()
557
+
558
+ pbar = tqdm(range(iterations))
559
+ erase_concept = erase_concept.split(',')
560
+ erase_concept = [a.strip() for a in erase_concept]
561
+
562
+ erase_from = erase_from.split(',')
563
+ erase_from = [a.strip() for a in erase_from]
564
+
565
+
566
+ if len(erase_from)!=len(erase_concept):
567
+ if len(erase_from) == 1:
568
+ c = erase_from[0]
569
+ erase_from = [c for _ in erase_concept]
570
+ else:
571
+ print(erase_from, erase_concept)
572
+ raise Exception("Erase from concepts length need to match erase concepts length")
573
+
574
+ erase_concept_ = []
575
+ for e, f in zip(erase_concept, erase_from):
576
+ erase_concept_.append([e,f])
577
+
578
+
579
+
580
+ erase_concept = erase_concept_
581
+
582
+
583
+
584
+ print(erase_concept)
585
+
586
+ # del diffuser.vae
587
+ # del diffuser.text_encoder
588
+ # del diffuser.tokenizer
589
+
590
+ torch.cuda.empty_cache()
591
+
592
+ for i in pbar:
593
+ with torch.no_grad():
594
+ index = np.random.choice(len(erase_concept), 1, replace=False)[0]
595
+ erase_concept_sampled = erase_concept[index]
596
+
597
+
598
+ neutral_text_embeddings = diffuser.get_text_embeddings([''],n_imgs=1)
599
+ positive_text_embeddings = diffuser.get_text_embeddings([erase_concept_sampled[0]],n_imgs=1)
600
+ target_text_embeddings = diffuser.get_text_embeddings([erase_concept_sampled[1]],n_imgs=1)
601
+
602
+
603
+ diffuser.set_scheduler_timesteps(nsteps)
604
+
605
+ optimizer.zero_grad()
606
+
607
+ iteration = torch.randint(1, nsteps - 1, (1,)).item()
608
+
609
+ latents = diffuser.get_initial_latents(1, 512, 1)
610
+
611
+ with finetuner:
612
+
613
+ latents_steps, _ = diffuser.diffusion(
614
+ latents,
615
+ positive_text_embeddings,
616
+ start_iteration=0,
617
+ end_iteration=iteration,
618
+ guidance_scale=3,
619
+ show_progress=False
620
+ )
621
+
622
+ diffuser.set_scheduler_timesteps(1000)
623
+
624
+ iteration = int(iteration / nsteps * 1000)
625
+
626
+ positive_latents = diffuser.predict_noise(iteration, latents_steps[0], positive_text_embeddings, guidance_scale=1)
627
+ neutral_latents = diffuser.predict_noise(iteration, latents_steps[0], neutral_text_embeddings, guidance_scale=1)
628
+ target_latents = diffuser.predict_noise(iteration, latents_steps[0], target_text_embeddings, guidance_scale=1)
629
+ if erase_concept_sampled[0] == erase_concept_sampled[1]:
630
+ target_latents = neutral_latents.clone().detach()
631
+ with finetuner:
632
+ negative_latents = diffuser.predict_noise(iteration, latents_steps[0], target_text_embeddings, guidance_scale=1)
633
+
634
+ positive_latents.requires_grad = False
635
+ neutral_latents.requires_grad = False
636
+
637
+
638
+ loss = criteria(negative_latents, target_latents - (negative_guidance*(positive_latents - neutral_latents))) #loss = criteria(e_n, e_0) works the best try 5000 epochs
639
+
640
+ loss.backward()
641
+ optimizer.step()
642
+
643
+ torch.save(finetuner.state_dict(), save_path)
644
+
645
+ del diffuser, loss, optimizer, finetuner, negative_latents, neutral_latents, positive_latents, latents_steps, latents
646
+
647
+ torch.cuda.empty_cache()
648
+
649
+ if __name__ == '__main__':
650
+ model_path='ESD_Models/car_noxattn_200.pt'
651
+ state_dict = torch.load(model_path)
652
+ diffuser = StableDiffuser(scheduler='DDIM').to('cuda')
653
+ finetuner = FineTunedModel(diffuser, train_method='noxattn')
654
+
655
+ finetuner.load_state_dict(state_dict)
656
+
657
+ #generation loop
658
+ all_images = []
659
+ with finetuner:
660
+ images = diffuser('image of a car', n_steps=50, generator=torch.manual_seed(2440), eta=1.0)
661
+ plt.imshow(images[0][0])
Attack_code/Noisy Diffusion(Eta attack)/gradient_asc_clip.ipynb ADDED
The diff for this file is too large to render. See raw diff
 
ESD Training Scripts/esd_diffusers.py ADDED
@@ -0,0 +1,560 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from PIL import Image
2
+ from matplotlib import pyplot as plt
3
+ import textwrap
4
+ import argparse
5
+ import torch
6
+ import copy
7
+ import os
8
+ import re
9
+ import numpy as np
10
+ from diffusers import AutoencoderKL, UNet2DConditionModel
11
+ from PIL import Image
12
+ from tqdm.auto import tqdm
13
+ from transformers import CLIPTextModel, CLIPTokenizer, CLIPFeatureExtractor
14
+ from diffusers.schedulers import EulerAncestralDiscreteScheduler
15
+ from diffusers.schedulers.scheduling_ddim import DDIMScheduler
16
+ from diffusers.schedulers.scheduling_ddpm import DDPMScheduler
17
+ from diffusers.schedulers.scheduling_lms_discrete import LMSDiscreteScheduler
18
+ from diffusers.pipelines.stable_diffusion import StableDiffusionSafetyChecker
19
+
20
+ def to_gif(images, path):
21
+
22
+ images[0].save(path, save_all=True,
23
+ append_images=images[1:], loop=0, duration=len(images) * 20)
24
+
25
+ def figure_to_image(figure):
26
+
27
+ figure.set_dpi(300)
28
+
29
+ figure.canvas.draw()
30
+
31
+ return Image.frombytes('RGB', figure.canvas.get_width_height(), figure.canvas.tostring_rgb())
32
+
33
+ def image_grid(images, outpath=None, column_titles=None, row_titles=None):
34
+
35
+ n_rows = len(images)
36
+ n_cols = len(images[0])
37
+
38
+ fig, axs = plt.subplots(nrows=n_rows, ncols=n_cols,
39
+ figsize=(n_cols, n_rows), squeeze=False)
40
+
41
+ for row, _images in enumerate(images):
42
+
43
+ for column, image in enumerate(_images):
44
+ ax = axs[row][column]
45
+ ax.imshow(image)
46
+ if column_titles and row == 0:
47
+ ax.set_title(textwrap.fill(
48
+ column_titles[column], width=12), fontsize='x-small')
49
+ if row_titles and column == 0:
50
+ ax.set_ylabel(row_titles[row], rotation=0, fontsize='x-small', labelpad=1.6 * len(row_titles[row]))
51
+ ax.set_xticks([])
52
+ ax.set_yticks([])
53
+
54
+ plt.subplots_adjust(wspace=0, hspace=0)
55
+
56
+ if outpath is not None:
57
+ plt.savefig(outpath, bbox_inches='tight', dpi=300)
58
+ plt.close()
59
+ else:
60
+ plt.tight_layout(pad=0)
61
+ image = figure_to_image(plt.gcf())
62
+ plt.close()
63
+ return image
64
+
65
+ def get_module(module, module_name):
66
+
67
+ if isinstance(module_name, str):
68
+ module_name = module_name.split('.')
69
+
70
+ if len(module_name) == 0:
71
+ return module
72
+ else:
73
+ module = getattr(module, module_name[0])
74
+ return get_module(module, module_name[1:])
75
+
76
+ def set_module(module, module_name, new_module):
77
+
78
+ if isinstance(module_name, str):
79
+ module_name = module_name.split('.')
80
+
81
+ if len(module_name) == 1:
82
+ return setattr(module, module_name[0], new_module)
83
+ else:
84
+ module = getattr(module, module_name[0])
85
+ return set_module(module, module_name[1:], new_module)
86
+
87
+ def freeze(module):
88
+
89
+ for parameter in module.parameters():
90
+
91
+ parameter.requires_grad = False
92
+
93
+ def unfreeze(module):
94
+
95
+ for parameter in module.parameters():
96
+
97
+ parameter.requires_grad = True
98
+
99
+ def get_concat_h(im1, im2):
100
+ dst = Image.new('RGB', (im1.width + im2.width, im1.height))
101
+ dst.paste(im1, (0, 0))
102
+ dst.paste(im2, (im1.width, 0))
103
+ return dst
104
+
105
+ def get_concat_v(im1, im2):
106
+ dst = Image.new('RGB', (im1.width, im1.height + im2.height))
107
+ dst.paste(im1, (0, 0))
108
+ dst.paste(im2, (0, im1.height))
109
+ return dst
110
+
111
+ class StableDiffuser(torch.nn.Module):
112
+
113
+ def __init__(self,
114
+ scheduler='LMS'
115
+ ):
116
+
117
+ super().__init__()
118
+
119
+ # Load the autoencoder model which will be used to decode the latents into image space.
120
+ self.vae = AutoencoderKL.from_pretrained(
121
+ "CompVis/stable-diffusion-v1-4", subfolder="vae")
122
+
123
+ # Load the tokenizer and text encoder to tokenize and encode the text.
124
+ self.tokenizer = CLIPTokenizer.from_pretrained(
125
+ "openai/clip-vit-large-patch14")
126
+ self.text_encoder = CLIPTextModel.from_pretrained(
127
+ "openai/clip-vit-large-patch14")
128
+
129
+ # The UNet model for generating the latents.
130
+ self.unet = UNet2DConditionModel.from_pretrained(
131
+ "CompVis/stable-diffusion-v1-4", subfolder="unet")
132
+
133
+ self.feature_extractor = CLIPFeatureExtractor.from_pretrained("CompVis/stable-diffusion-v1-4", subfolder="feature_extractor")
134
+ self.safety_checker = StableDiffusionSafetyChecker.from_pretrained("CompVis/stable-diffusion-v1-4", subfolder="safety_checker")
135
+
136
+ if scheduler == 'LMS':
137
+ self.scheduler = LMSDiscreteScheduler(beta_start=0.00085, beta_end=0.012, beta_schedule="scaled_linear", num_train_timesteps=1000)
138
+ elif scheduler == 'DDIM':
139
+ self.scheduler = DDIMScheduler.from_pretrained("CompVis/stable-diffusion-v1-4", subfolder="scheduler")
140
+ elif scheduler == 'DDPM':
141
+ self.scheduler = DDPMScheduler.from_pretrained("CompVis/stable-diffusion-v1-4", subfolder="scheduler")
142
+
143
+ self.eval()
144
+
145
+ def get_noise(self, batch_size, img_size, generator=None):
146
+
147
+ param = list(self.parameters())[0]
148
+
149
+ return torch.randn(
150
+ (batch_size, self.unet.in_channels, img_size // 8, img_size // 8),
151
+ generator=generator).type(param.dtype).to(param.device)
152
+
153
+ def add_noise(self, latents, noise, step):
154
+
155
+ return self.scheduler.add_noise(latents, noise, torch.tensor([self.scheduler.timesteps[step]]))
156
+
157
+ def text_tokenize(self, prompts):
158
+
159
+ return self.tokenizer(prompts, padding="max_length", max_length=self.tokenizer.model_max_length, truncation=True, return_tensors="pt")
160
+
161
+ def text_detokenize(self, tokens):
162
+
163
+ return [self.tokenizer.decode(token) for token in tokens if token != self.tokenizer.vocab_size - 1]
164
+
165
+ def text_encode(self, tokens):
166
+
167
+ return self.text_encoder(tokens.input_ids.to(self.unet.device))[0]
168
+
169
+ def decode(self, latents):
170
+
171
+ return self.vae.decode(1 / self.vae.config.scaling_factor * latents).sample
172
+
173
+ def encode(self, tensors):
174
+
175
+ return self.vae.encode(tensors).latent_dist.mode() * 0.18215
176
+
177
+ def to_image(self, image):
178
+
179
+ image = (image / 2 + 0.5).clamp(0, 1)
180
+ image = image.detach().cpu().permute(0, 2, 3, 1).numpy()
181
+ images = (image * 255).round().astype("uint8")
182
+ pil_images = [Image.fromarray(image) for image in images]
183
+
184
+ return pil_images
185
+
186
+ def set_scheduler_timesteps(self, n_steps):
187
+ self.scheduler.set_timesteps(n_steps, device=self.unet.device)
188
+
189
+ def get_initial_latents(self, n_imgs, img_size, n_prompts, generator=None):
190
+
191
+ noise = self.get_noise(n_imgs, img_size, generator=generator).repeat(n_prompts, 1, 1, 1)
192
+
193
+ latents = noise * self.scheduler.init_noise_sigma
194
+
195
+ return latents
196
+
197
+ def get_text_embeddings(self, prompts, n_imgs):
198
+
199
+ text_tokens = self.text_tokenize(prompts)
200
+
201
+ text_embeddings = self.text_encode(text_tokens)
202
+
203
+ unconditional_tokens = self.text_tokenize([""] * len(prompts))
204
+
205
+ unconditional_embeddings = self.text_encode(unconditional_tokens)
206
+
207
+ text_embeddings = torch.cat([unconditional_embeddings, text_embeddings]).repeat_interleave(n_imgs, dim=0)
208
+
209
+ return text_embeddings
210
+
211
+ def predict_noise(self,
212
+ iteration,
213
+ latents,
214
+ text_embeddings,
215
+ guidance_scale=7.5
216
+ ):
217
+
218
+ # expand the latents if we are doing classifier-free guidance to avoid doing two forward passes.
219
+ latents = torch.cat([latents] * 2)
220
+ latents = self.scheduler.scale_model_input(
221
+ latents, self.scheduler.timesteps[iteration])
222
+
223
+ # predict the noise residual
224
+ noise_prediction = self.unet(
225
+ latents, self.scheduler.timesteps[iteration], encoder_hidden_states=text_embeddings).sample
226
+
227
+ # perform guidance
228
+ noise_prediction_uncond, noise_prediction_text = noise_prediction.chunk(2)
229
+ noise_prediction = noise_prediction_uncond + guidance_scale * \
230
+ (noise_prediction_text - noise_prediction_uncond)
231
+
232
+ return noise_prediction
233
+
234
+ @torch.no_grad()
235
+ def diffusion(self,
236
+ latents,
237
+ text_embeddings,
238
+ end_iteration=1000,
239
+ start_iteration=0,
240
+ return_steps=False,
241
+ pred_x0=False,
242
+ trace_args=None,
243
+ show_progress=True,
244
+ **kwargs):
245
+
246
+ latents_steps = []
247
+ trace_steps = []
248
+
249
+ trace = None
250
+
251
+ for iteration in tqdm(range(start_iteration, end_iteration), disable=not show_progress):
252
+
253
+ if trace_args:
254
+
255
+ trace = TraceDict(self, **trace_args)
256
+
257
+ noise_pred = self.predict_noise(
258
+ iteration,
259
+ latents,
260
+ text_embeddings,
261
+ **kwargs)
262
+
263
+ # compute the previous noisy sample x_t -> x_t-1
264
+ output = self.scheduler.step(noise_pred, self.scheduler.timesteps[iteration], latents)
265
+
266
+ if trace_args:
267
+
268
+ trace.close()
269
+
270
+ trace_steps.append(trace)
271
+
272
+ latents = output.prev_sample
273
+
274
+ if return_steps or iteration == end_iteration - 1:
275
+
276
+ output = output.pred_original_sample if pred_x0 else latents
277
+
278
+ if return_steps:
279
+ latents_steps.append(output.cpu())
280
+ else:
281
+ latents_steps.append(output)
282
+
283
+ return latents_steps, trace_steps
284
+
285
+ @torch.no_grad()
286
+ def __call__(self,
287
+ prompts,
288
+ img_size=512,
289
+ n_steps=50,
290
+ n_imgs=1,
291
+ end_iteration=None,
292
+ generator=None,
293
+ **kwargs
294
+ ):
295
+
296
+ assert 0 <= n_steps <= 1000
297
+
298
+ if not isinstance(prompts, list):
299
+
300
+ prompts = [prompts]
301
+
302
+ self.set_scheduler_timesteps(n_steps)
303
+
304
+ latents = self.get_initial_latents(n_imgs, img_size, len(prompts), generator=generator)
305
+
306
+ text_embeddings = self.get_text_embeddings(prompts,n_imgs=n_imgs)
307
+
308
+ end_iteration = end_iteration or n_steps
309
+
310
+ latents_steps, trace_steps = self.diffusion(
311
+ latents,
312
+ text_embeddings,
313
+ end_iteration=end_iteration,
314
+ **kwargs
315
+ )
316
+
317
+ latents_steps = [self.decode(latents.to(self.unet.device)) for latents in latents_steps]
318
+ images_steps = [self.to_image(latents) for latents in latents_steps]
319
+
320
+ # for i in range(len(images_steps)):
321
+ # self.safety_checker = self.safety_checker.float()
322
+ # safety_checker_input = self.feature_extractor(images_steps[i], return_tensors="pt").to(latents_steps[0].device)
323
+ # image, has_nsfw_concept = self.safety_checker(
324
+ # images=latents_steps[i].float().cpu().numpy(), clip_input=safety_checker_input.pixel_values.float()
325
+ # )
326
+
327
+ # images_steps[i][0] = self.to_image(torch.from_numpy(image))[0]
328
+
329
+ images_steps = list(zip(*images_steps))
330
+
331
+ if trace_steps:
332
+
333
+ return images_steps, trace_steps
334
+
335
+ return images_steps
336
+
337
+ class FineTunedModel(torch.nn.Module):
338
+
339
+ def __init__(self,
340
+ model,
341
+ train_method,
342
+ ):
343
+
344
+ super().__init__()
345
+
346
+ self.model = model
347
+ self.ft_modules = {}
348
+ self.orig_modules = {}
349
+
350
+ freeze(self.model)
351
+
352
+ for module_name, module in model.named_modules():
353
+ if 'unet' not in module_name:
354
+ continue
355
+ if module.__class__.__name__ in ["Linear", "Conv2d", "LoRACompatibleLinear", "LoRACompatibleConv"]:
356
+ if train_method == 'xattn':
357
+ if 'attn2' not in module_name:
358
+ continue
359
+ elif train_method == 'xattn-strict':
360
+ if 'attn2' not in module_name or 'to_q' not in module_name or 'to_k' not in module_name:
361
+ continue
362
+ elif train_method == 'noxattn':
363
+ if 'attn2' in module_name:
364
+ continue
365
+ elif train_method == 'selfattn':
366
+ if 'attn1' not in module_name:
367
+ continue
368
+ else:
369
+ raise NotImplementedError(
370
+ f"train_method: {train_method} is not implemented."
371
+ )
372
+ print(module_name)
373
+ ft_module = copy.deepcopy(module)
374
+
375
+ self.orig_modules[module_name] = module
376
+ self.ft_modules[module_name] = ft_module
377
+
378
+ unfreeze(ft_module)
379
+
380
+ self.ft_modules_list = torch.nn.ModuleList(self.ft_modules.values())
381
+ self.orig_modules_list = torch.nn.ModuleList(self.orig_modules.values())
382
+
383
+
384
+ @classmethod
385
+ def from_checkpoint(cls, model, checkpoint, train_method):
386
+
387
+ if isinstance(checkpoint, str):
388
+ checkpoint = torch.load(checkpoint)
389
+
390
+ modules = [f"{key}$" for key in list(checkpoint.keys())]
391
+
392
+ ftm = FineTunedModel(model, train_method=train_method)
393
+ ftm.load_state_dict(checkpoint)
394
+
395
+ return ftm
396
+
397
+
398
+ def __enter__(self):
399
+
400
+ for key, ft_module in self.ft_modules.items():
401
+ set_module(self.model, key, ft_module)
402
+
403
+ def __exit__(self, exc_type, exc_value, tb):
404
+
405
+ for key, module in self.orig_modules.items():
406
+ set_module(self.model, key, module)
407
+
408
+ def parameters(self):
409
+
410
+ parameters = []
411
+
412
+ for ft_module in self.ft_modules.values():
413
+
414
+ parameters.extend(list(ft_module.parameters()))
415
+
416
+ return parameters
417
+
418
+ def state_dict(self):
419
+
420
+ state_dict = {key: module.state_dict() for key, module in self.ft_modules.items()}
421
+
422
+ return state_dict
423
+
424
+ def load_state_dict(self, state_dict):
425
+
426
+ for key, sd in state_dict.items():
427
+
428
+ self.ft_modules[key].load_state_dict(sd)
429
+ def train(erase_concept, erase_from, train_method, iterations, negative_guidance, lr, save_path):
430
+
431
+ nsteps = 50
432
+
433
+ diffuser = StableDiffuser(scheduler='DDIM').to('cuda')
434
+ diffuser.train()
435
+
436
+ finetuner = FineTunedModel(diffuser, train_method=train_method)
437
+
438
+ optimizer = torch.optim.Adam(finetuner.parameters(), lr=lr)
439
+ criteria = torch.nn.MSELoss()
440
+
441
+ pbar = tqdm(range(iterations))
442
+ erase_concept = erase_concept.split(',')
443
+ erase_concept = [a.strip() for a in erase_concept]
444
+
445
+ erase_from = erase_from.split(',')
446
+ erase_from = [a.strip() for a in erase_from]
447
+
448
+
449
+ if len(erase_from)!=len(erase_concept):
450
+ if len(erase_from) == 1:
451
+ c = erase_from[0]
452
+ erase_from = [c for _ in erase_concept]
453
+ else:
454
+ print(erase_from, erase_concept)
455
+ raise Exception("Erase from concepts length need to match erase concepts length")
456
+
457
+ erase_concept_ = []
458
+ for e, f in zip(erase_concept, erase_from):
459
+ erase_concept_.append([e,f])
460
+
461
+
462
+
463
+ erase_concept = erase_concept_
464
+
465
+
466
+
467
+ print(erase_concept)
468
+
469
+ # del diffuser.vae
470
+ # del diffuser.text_encoder
471
+ # del diffuser.tokenizer
472
+
473
+ torch.cuda.empty_cache()
474
+
475
+ for i in pbar:
476
+ with torch.no_grad():
477
+ index = np.random.choice(len(erase_concept), 1, replace=False)[0]
478
+ erase_concept_sampled = erase_concept[index]
479
+
480
+
481
+ neutral_text_embeddings = diffuser.get_text_embeddings([''],n_imgs=1)
482
+ positive_text_embeddings = diffuser.get_text_embeddings([erase_concept_sampled[0]],n_imgs=1)
483
+ target_text_embeddings = diffuser.get_text_embeddings([erase_concept_sampled[1]],n_imgs=1)
484
+
485
+
486
+ diffuser.set_scheduler_timesteps(nsteps)
487
+
488
+ optimizer.zero_grad()
489
+
490
+ iteration = torch.randint(1, nsteps - 1, (1,)).item()
491
+
492
+ latents = diffuser.get_initial_latents(1, 512, 1)
493
+
494
+ with finetuner:
495
+
496
+ latents_steps, _ = diffuser.diffusion(
497
+ latents,
498
+ positive_text_embeddings,
499
+ start_iteration=0,
500
+ end_iteration=iteration,
501
+ guidance_scale=3,
502
+ show_progress=False
503
+ )
504
+
505
+ diffuser.set_scheduler_timesteps(1000)
506
+
507
+ iteration = int(iteration / nsteps * 1000)
508
+
509
+ positive_latents = diffuser.predict_noise(iteration, latents_steps[0], positive_text_embeddings, guidance_scale=1)
510
+ neutral_latents = diffuser.predict_noise(iteration, latents_steps[0], neutral_text_embeddings, guidance_scale=1)
511
+ target_latents = diffuser.predict_noise(iteration, latents_steps[0], target_text_embeddings, guidance_scale=1)
512
+ if erase_concept_sampled[0] == erase_concept_sampled[1]:
513
+ target_latents = neutral_latents.clone().detach()
514
+ with finetuner:
515
+ negative_latents = diffuser.predict_noise(iteration, latents_steps[0], target_text_embeddings, guidance_scale=1)
516
+
517
+ positive_latents.requires_grad = False
518
+ neutral_latents.requires_grad = False
519
+
520
+
521
+ loss = criteria(negative_latents, target_latents - (negative_guidance*(positive_latents - neutral_latents))) #loss = criteria(e_n, e_0) works the best try 5000 epochs
522
+
523
+ loss.backward()
524
+ optimizer.step()
525
+
526
+ torch.save(finetuner.state_dict(), save_path)
527
+
528
+ del diffuser, loss, optimizer, finetuner, negative_latents, neutral_latents, positive_latents, latents_steps, latents
529
+
530
+ torch.cuda.empty_cache()
531
+
532
+ if __name__ == '__main__':
533
+ parser = argparse.ArgumentParser(
534
+ prog = 'TrainESD',
535
+ description = 'Finetuning stable diffusion to erase the concepts')
536
+ parser.add_argument('--erase_concept', help='concept to erase', type=str, required=True)
537
+ parser.add_argument('--erase_from', help='target concept to erase from', type=str, required=False, default = None)
538
+ parser.add_argument('--train_method', help='Type of method (xattn, noxattn, full, xattn-strict', type=str, required=True)
539
+ parser.add_argument('--iterations', help='Number of iterations', type=int, default=200)
540
+ parser.add_argument('--lr', help='Learning rate', type=float, default=2e-5)
541
+ parser.add_argument('--negative_guidance', help='Negative guidance value', type=float, required=False, default=1)
542
+ parser.add_argument('--save_path', help='Path to save model', type=str, default='models/')
543
+ parser.add_argument('--device', help='cuda device to train on', type=str, required=False, default='cuda:0')
544
+
545
+ args = parser.parse_args()
546
+
547
+ prompt = args.erase_concept #'car'
548
+ erase_concept = args.erase_concept
549
+ erase_from = args.erase_from
550
+ if erase_from is None:
551
+ erase_from = erase_concept
552
+ train_method = args.train_method #'noxattn'
553
+ iterations = args.iterations #200
554
+ negative_guidance = args.negative_guidance #1
555
+ lr = args.lr #1e-5
556
+ name = f"esd-{erase_concept.lower().replace(' ','').replace(',','')}_from_{erase_from.lower().replace(' ','').replace(',','')}-{train_method}_{negative_guidance}-epochs_{iterations}"
557
+ if not os.path.exists(args.save_path):
558
+ os.makedirs(args.save_path, exist_ok = True)
559
+ save_path = f'{args.save_path}/{name}.pt'
560
+ train(erase_concept=erase_concept, erase_from=erase_from, train_method=train_method, iterations=iterations, negative_guidance=negative_guidance, lr=lr, save_path=save_path)
Pipfile ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [[source]]
2
+ url = "https://pypi.org/simple"
3
+ verify_ssl = true
4
+ name = "pypi"
5
+
6
+ [packages]
7
+ pillow = "*"
8
+ requests = "*"
9
+ pandas = "*"
10
+ numpy = "*"
11
+ transformers = "*"
12
+ torch = "*"
13
+ diffusers = "*"
14
+
15
+ [dev-packages]
16
+
17
+ [requires]
18
+ python_version = "3.12"
19
+ python_full_version = "3.12.6"
Pipfile.lock ADDED
@@ -0,0 +1,981 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "_meta": {
3
+ "hash": {
4
+ "sha256": "c187f0d79da53236f1ef7cf6e37c48bd750594b5870a901518759b09f45830f0"
5
+ },
6
+ "pipfile-spec": 6,
7
+ "requires": {
8
+ "python_full_version": "3.12.6",
9
+ "python_version": "3.12"
10
+ },
11
+ "sources": [
12
+ {
13
+ "name": "pypi",
14
+ "url": "https://pypi.org/simple",
15
+ "verify_ssl": true
16
+ }
17
+ ]
18
+ },
19
+ "default": {
20
+ "certifi": {
21
+ "hashes": [
22
+ "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8",
23
+ "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9"
24
+ ],
25
+ "markers": "python_version >= '3.6'",
26
+ "version": "==2024.8.30"
27
+ },
28
+ "charset-normalizer": {
29
+ "hashes": [
30
+ "sha256:0099d79bdfcf5c1f0c2c72f91516702ebf8b0b8ddd8905f97a8aecf49712c621",
31
+ "sha256:0713f3adb9d03d49d365b70b84775d0a0d18e4ab08d12bc46baa6132ba78aaf6",
32
+ "sha256:07afec21bbbbf8a5cc3651aa96b980afe2526e7f048fdfb7f1014d84acc8b6d8",
33
+ "sha256:0b309d1747110feb25d7ed6b01afdec269c647d382c857ef4663bbe6ad95a912",
34
+ "sha256:0d99dd8ff461990f12d6e42c7347fd9ab2532fb70e9621ba520f9e8637161d7c",
35
+ "sha256:0de7b687289d3c1b3e8660d0741874abe7888100efe14bd0f9fd7141bcbda92b",
36
+ "sha256:1110e22af8ca26b90bd6364fe4c763329b0ebf1ee213ba32b68c73de5752323d",
37
+ "sha256:130272c698667a982a5d0e626851ceff662565379baf0ff2cc58067b81d4f11d",
38
+ "sha256:136815f06a3ae311fae551c3df1f998a1ebd01ddd424aa5603a4336997629e95",
39
+ "sha256:14215b71a762336254351b00ec720a8e85cada43b987da5a042e4ce3e82bd68e",
40
+ "sha256:1db4e7fefefd0f548d73e2e2e041f9df5c59e178b4c72fbac4cc6f535cfb1565",
41
+ "sha256:1ffd9493de4c922f2a38c2bf62b831dcec90ac673ed1ca182fe11b4d8e9f2a64",
42
+ "sha256:2006769bd1640bdf4d5641c69a3d63b71b81445473cac5ded39740a226fa88ab",
43
+ "sha256:20587d20f557fe189b7947d8e7ec5afa110ccf72a3128d61a2a387c3313f46be",
44
+ "sha256:223217c3d4f82c3ac5e29032b3f1c2eb0fb591b72161f86d93f5719079dae93e",
45
+ "sha256:27623ba66c183eca01bf9ff833875b459cad267aeeb044477fedac35e19ba907",
46
+ "sha256:285e96d9d53422efc0d7a17c60e59f37fbf3dfa942073f666db4ac71e8d726d0",
47
+ "sha256:2de62e8801ddfff069cd5c504ce3bc9672b23266597d4e4f50eda28846c322f2",
48
+ "sha256:2f6c34da58ea9c1a9515621f4d9ac379871a8f21168ba1b5e09d74250de5ad62",
49
+ "sha256:309a7de0a0ff3040acaebb35ec45d18db4b28232f21998851cfa709eeff49d62",
50
+ "sha256:35c404d74c2926d0287fbd63ed5d27eb911eb9e4a3bb2c6d294f3cfd4a9e0c23",
51
+ "sha256:3710a9751938947e6327ea9f3ea6332a09bf0ba0c09cae9cb1f250bd1f1549bc",
52
+ "sha256:3d59d125ffbd6d552765510e3f31ed75ebac2c7470c7274195b9161a32350284",
53
+ "sha256:40d3ff7fc90b98c637bda91c89d51264a3dcf210cade3a2c6f838c7268d7a4ca",
54
+ "sha256:425c5f215d0eecee9a56cdb703203dda90423247421bf0d67125add85d0c4455",
55
+ "sha256:43193c5cda5d612f247172016c4bb71251c784d7a4d9314677186a838ad34858",
56
+ "sha256:44aeb140295a2f0659e113b31cfe92c9061622cadbc9e2a2f7b8ef6b1e29ef4b",
57
+ "sha256:47334db71978b23ebcf3c0f9f5ee98b8d65992b65c9c4f2d34c2eaf5bcaf0594",
58
+ "sha256:4796efc4faf6b53a18e3d46343535caed491776a22af773f366534056c4e1fbc",
59
+ "sha256:4a51b48f42d9358460b78725283f04bddaf44a9358197b889657deba38f329db",
60
+ "sha256:4b67fdab07fdd3c10bb21edab3cbfe8cf5696f453afce75d815d9d7223fbe88b",
61
+ "sha256:4ec9dd88a5b71abfc74e9df5ebe7921c35cbb3b641181a531ca65cdb5e8e4dea",
62
+ "sha256:4f9fc98dad6c2eaa32fc3af1417d95b5e3d08aff968df0cd320066def971f9a6",
63
+ "sha256:54b6a92d009cbe2fb11054ba694bc9e284dad30a26757b1e372a1fdddaf21920",
64
+ "sha256:55f56e2ebd4e3bc50442fbc0888c9d8c94e4e06a933804e2af3e89e2f9c1c749",
65
+ "sha256:5726cf76c982532c1863fb64d8c6dd0e4c90b6ece9feb06c9f202417a31f7dd7",
66
+ "sha256:5d447056e2ca60382d460a604b6302d8db69476fd2015c81e7c35417cfabe4cd",
67
+ "sha256:5ed2e36c3e9b4f21dd9422f6893dec0abf2cca553af509b10cd630f878d3eb99",
68
+ "sha256:5ff2ed8194587faf56555927b3aa10e6fb69d931e33953943bc4f837dfee2242",
69
+ "sha256:62f60aebecfc7f4b82e3f639a7d1433a20ec32824db2199a11ad4f5e146ef5ee",
70
+ "sha256:63bc5c4ae26e4bc6be6469943b8253c0fd4e4186c43ad46e713ea61a0ba49129",
71
+ "sha256:6b40e8d38afe634559e398cc32b1472f376a4099c75fe6299ae607e404c033b2",
72
+ "sha256:6b493a043635eb376e50eedf7818f2f322eabbaa974e948bd8bdd29eb7ef2a51",
73
+ "sha256:6dba5d19c4dfab08e58d5b36304b3f92f3bd5d42c1a3fa37b5ba5cdf6dfcbcee",
74
+ "sha256:6fd30dc99682dc2c603c2b315bded2799019cea829f8bf57dc6b61efde6611c8",
75
+ "sha256:707b82d19e65c9bd28b81dde95249b07bf9f5b90ebe1ef17d9b57473f8a64b7b",
76
+ "sha256:7706f5850360ac01d80c89bcef1640683cc12ed87f42579dab6c5d3ed6888613",
77
+ "sha256:7782afc9b6b42200f7362858f9e73b1f8316afb276d316336c0ec3bd73312742",
78
+ "sha256:79983512b108e4a164b9c8d34de3992f76d48cadc9554c9e60b43f308988aabe",
79
+ "sha256:7f683ddc7eedd742e2889d2bfb96d69573fde1d92fcb811979cdb7165bb9c7d3",
80
+ "sha256:82357d85de703176b5587dbe6ade8ff67f9f69a41c0733cf2425378b49954de5",
81
+ "sha256:84450ba661fb96e9fd67629b93d2941c871ca86fc38d835d19d4225ff946a631",
82
+ "sha256:86f4e8cca779080f66ff4f191a685ced73d2f72d50216f7112185dc02b90b9b7",
83
+ "sha256:8cda06946eac330cbe6598f77bb54e690b4ca93f593dee1568ad22b04f347c15",
84
+ "sha256:8ce7fd6767a1cc5a92a639b391891bf1c268b03ec7e021c7d6d902285259685c",
85
+ "sha256:8ff4e7cdfdb1ab5698e675ca622e72d58a6fa2a8aa58195de0c0061288e6e3ea",
86
+ "sha256:9289fd5dddcf57bab41d044f1756550f9e7cf0c8e373b8cdf0ce8773dc4bd417",
87
+ "sha256:92a7e36b000bf022ef3dbb9c46bfe2d52c047d5e3f3343f43204263c5addc250",
88
+ "sha256:92db3c28b5b2a273346bebb24857fda45601aef6ae1c011c0a997106581e8a88",
89
+ "sha256:95c3c157765b031331dd4db3c775e58deaee050a3042fcad72cbc4189d7c8dca",
90
+ "sha256:980b4f289d1d90ca5efcf07958d3eb38ed9c0b7676bf2831a54d4f66f9c27dfa",
91
+ "sha256:9ae4ef0b3f6b41bad6366fb0ea4fc1d7ed051528e113a60fa2a65a9abb5b1d99",
92
+ "sha256:9c98230f5042f4945f957d006edccc2af1e03ed5e37ce7c373f00a5a4daa6149",
93
+ "sha256:9fa2566ca27d67c86569e8c85297aaf413ffab85a8960500f12ea34ff98e4c41",
94
+ "sha256:a14969b8691f7998e74663b77b4c36c0337cb1df552da83d5c9004a93afdb574",
95
+ "sha256:a8aacce6e2e1edcb6ac625fb0f8c3a9570ccc7bfba1f63419b3769ccf6a00ed0",
96
+ "sha256:a8e538f46104c815be19c975572d74afb53f29650ea2025bbfaef359d2de2f7f",
97
+ "sha256:aa41e526a5d4a9dfcfbab0716c7e8a1b215abd3f3df5a45cf18a12721d31cb5d",
98
+ "sha256:aa693779a8b50cd97570e5a0f343538a8dbd3e496fa5dcb87e29406ad0299654",
99
+ "sha256:ab22fbd9765e6954bc0bcff24c25ff71dcbfdb185fcdaca49e81bac68fe724d3",
100
+ "sha256:ab2e5bef076f5a235c3774b4f4028a680432cded7cad37bba0fd90d64b187d19",
101
+ "sha256:ab973df98fc99ab39080bfb0eb3a925181454d7c3ac8a1e695fddfae696d9e90",
102
+ "sha256:af73657b7a68211996527dbfeffbb0864e043d270580c5aef06dc4b659a4b578",
103
+ "sha256:b197e7094f232959f8f20541ead1d9862ac5ebea1d58e9849c1bf979255dfac9",
104
+ "sha256:b295729485b06c1a0683af02a9e42d2caa9db04a373dc38a6a58cdd1e8abddf1",
105
+ "sha256:b8831399554b92b72af5932cdbbd4ddc55c55f631bb13ff8fe4e6536a06c5c51",
106
+ "sha256:b8dcd239c743aa2f9c22ce674a145e0a25cb1566c495928440a181ca1ccf6719",
107
+ "sha256:bcb4f8ea87d03bc51ad04add8ceaf9b0f085ac045ab4d74e73bbc2dc033f0236",
108
+ "sha256:bd7af3717683bea4c87acd8c0d3d5b44d56120b26fd3f8a692bdd2d5260c620a",
109
+ "sha256:bf4475b82be41b07cc5e5ff94810e6a01f276e37c2d55571e3fe175e467a1a1c",
110
+ "sha256:c3e446d253bd88f6377260d07c895816ebf33ffffd56c1c792b13bff9c3e1ade",
111
+ "sha256:c57516e58fd17d03ebe67e181a4e4e2ccab1168f8c2976c6a334d4f819fe5944",
112
+ "sha256:c94057af19bc953643a33581844649a7fdab902624d2eb739738a30e2b3e60fc",
113
+ "sha256:cab5d0b79d987c67f3b9e9c53f54a61360422a5a0bc075f43cab5621d530c3b6",
114
+ "sha256:ce031db0408e487fd2775d745ce30a7cd2923667cf3b69d48d219f1d8f5ddeb6",
115
+ "sha256:cee4373f4d3ad28f1ab6290684d8e2ebdb9e7a1b74fdc39e4c211995f77bec27",
116
+ "sha256:d5b054862739d276e09928de37c79ddeec42a6e1bfc55863be96a36ba22926f6",
117
+ "sha256:dbe03226baf438ac4fda9e2d0715022fd579cb641c4cf639fa40d53b2fe6f3e2",
118
+ "sha256:dc15e99b2d8a656f8e666854404f1ba54765871104e50c8e9813af8a7db07f12",
119
+ "sha256:dcaf7c1524c0542ee2fc82cc8ec337f7a9f7edee2532421ab200d2b920fc97cf",
120
+ "sha256:dd4eda173a9fcccb5f2e2bd2a9f423d180194b1bf17cf59e3269899235b2a114",
121
+ "sha256:dd9a8bd8900e65504a305bf8ae6fa9fbc66de94178c420791d0293702fce2df7",
122
+ "sha256:de7376c29d95d6719048c194a9cf1a1b0393fbe8488a22008610b0361d834ecf",
123
+ "sha256:e7fdd52961feb4c96507aa649550ec2a0d527c086d284749b2f582f2d40a2e0d",
124
+ "sha256:e91f541a85298cf35433bf66f3fab2a4a2cff05c127eeca4af174f6d497f0d4b",
125
+ "sha256:e9e3c4c9e1ed40ea53acf11e2a386383c3304212c965773704e4603d589343ed",
126
+ "sha256:ee803480535c44e7f5ad00788526da7d85525cfefaf8acf8ab9a310000be4b03",
127
+ "sha256:f09cb5a7bbe1ecae6e87901a2eb23e0256bb524a79ccc53eb0b7629fbe7677c4",
128
+ "sha256:f19c1585933c82098c2a520f8ec1227f20e339e33aca8fa6f956f6691b784e67",
129
+ "sha256:f1a2f519ae173b5b6a2c9d5fa3116ce16e48b3462c8b96dfdded11055e3d6365",
130
+ "sha256:f28f891ccd15c514a0981f3b9db9aa23d62fe1a99997512b0491d2ed323d229a",
131
+ "sha256:f3e73a4255342d4eb26ef6df01e3962e73aa29baa3124a8e824c5d3364a65748",
132
+ "sha256:f606a1881d2663630ea5b8ce2efe2111740df4b687bd78b34a8131baa007f79b",
133
+ "sha256:fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079",
134
+ "sha256:ffc519621dce0c767e96b9c53f09c5d215578e10b02c285809f76509a3931482"
135
+ ],
136
+ "markers": "python_full_version >= '3.7.0'",
137
+ "version": "==3.4.0"
138
+ },
139
+ "diffusers": {
140
+ "hashes": [
141
+ "sha256:b1d01a73e45d43a0630c299173915dddd69fc50f2ae8f2ab5de4fd245eaed72f",
142
+ "sha256:cbc498ae63f4abfc7c3a07649cdcbee229ef2f9a9a1f0d19c9bbaf22f8d30c1f"
143
+ ],
144
+ "index": "pypi",
145
+ "markers": "python_full_version >= '3.8.0'",
146
+ "version": "==0.31.0"
147
+ },
148
+ "filelock": {
149
+ "hashes": [
150
+ "sha256:2082e5703d51fbf98ea75855d9d5527e33d8ff23099bec374a134febee6946b0",
151
+ "sha256:c249fbfcd5db47e5e2d6d62198e565475ee65e4831e2561c8e313fa7eb961435"
152
+ ],
153
+ "markers": "python_version >= '3.8'",
154
+ "version": "==3.16.1"
155
+ },
156
+ "fsspec": {
157
+ "hashes": [
158
+ "sha256:03b9a6785766a4de40368b88906366755e2819e758b83705c88cd7cb5fe81871",
159
+ "sha256:eda2d8a4116d4f2429db8550f2457da57279247dd930bb12f821b58391359493"
160
+ ],
161
+ "markers": "python_version >= '3.8'",
162
+ "version": "==2024.10.0"
163
+ },
164
+ "huggingface-hub": {
165
+ "hashes": [
166
+ "sha256:414c0d9b769eecc86c70f9d939d0f48bb28e8461dd1130021542eff0212db890",
167
+ "sha256:5927a8fc64ae68859cd954b7cc29d1c8390a5e15caba6d3d349c973be8fdacf3"
168
+ ],
169
+ "markers": "python_full_version >= '3.8.0'",
170
+ "version": "==0.26.1"
171
+ },
172
+ "idna": {
173
+ "hashes": [
174
+ "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9",
175
+ "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"
176
+ ],
177
+ "markers": "python_version >= '3.6'",
178
+ "version": "==3.10"
179
+ },
180
+ "importlib-metadata": {
181
+ "hashes": [
182
+ "sha256:45e54197d28b7a7f1559e60b95e7c567032b602131fbd588f1497f47880aa68b",
183
+ "sha256:71522656f0abace1d072b9e5481a48f07c138e00f079c38c8f883823f9c26bd7"
184
+ ],
185
+ "markers": "python_version >= '3.8'",
186
+ "version": "==8.5.0"
187
+ },
188
+ "jinja2": {
189
+ "hashes": [
190
+ "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369",
191
+ "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d"
192
+ ],
193
+ "markers": "python_version >= '3.7'",
194
+ "version": "==3.1.4"
195
+ },
196
+ "markupsafe": {
197
+ "hashes": [
198
+ "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4",
199
+ "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30",
200
+ "sha256:1225beacc926f536dc82e45f8a4d68502949dc67eea90eab715dea3a21c1b5f0",
201
+ "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9",
202
+ "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396",
203
+ "sha256:1a9d3f5f0901fdec14d8d2f66ef7d035f2157240a433441719ac9a3fba440b13",
204
+ "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028",
205
+ "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca",
206
+ "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557",
207
+ "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832",
208
+ "sha256:3169b1eefae027567d1ce6ee7cae382c57fe26e82775f460f0b2778beaad66c0",
209
+ "sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b",
210
+ "sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579",
211
+ "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a",
212
+ "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c",
213
+ "sha256:48032821bbdf20f5799ff537c7ac3d1fba0ba032cfc06194faffa8cda8b560ff",
214
+ "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c",
215
+ "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22",
216
+ "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094",
217
+ "sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb",
218
+ "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e",
219
+ "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5",
220
+ "sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a",
221
+ "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d",
222
+ "sha256:6e296a513ca3d94054c2c881cc913116e90fd030ad1c656b3869762b754f5f8a",
223
+ "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b",
224
+ "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8",
225
+ "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225",
226
+ "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c",
227
+ "sha256:88b49a3b9ff31e19998750c38e030fc7bb937398b1f78cfa599aaef92d693144",
228
+ "sha256:8c4e8c3ce11e1f92f6536ff07154f9d49677ebaaafc32db9db4620bc11ed480f",
229
+ "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87",
230
+ "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d",
231
+ "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93",
232
+ "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf",
233
+ "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158",
234
+ "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84",
235
+ "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb",
236
+ "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48",
237
+ "sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171",
238
+ "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c",
239
+ "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6",
240
+ "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd",
241
+ "sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d",
242
+ "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1",
243
+ "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d",
244
+ "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca",
245
+ "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a",
246
+ "sha256:cfad01eed2c2e0c01fd0ecd2ef42c492f7f93902e39a42fc9ee1692961443a29",
247
+ "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe",
248
+ "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798",
249
+ "sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c",
250
+ "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8",
251
+ "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f",
252
+ "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f",
253
+ "sha256:eaa0a10b7f72326f1372a713e73c3f739b524b3af41feb43e4921cb529f5929a",
254
+ "sha256:eb7972a85c54febfb25b5c4b4f3af4dcc731994c7da0d8a0b4a6eb0640e1d178",
255
+ "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0",
256
+ "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79",
257
+ "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430",
258
+ "sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50"
259
+ ],
260
+ "markers": "python_version >= '3.9'",
261
+ "version": "==3.0.2"
262
+ },
263
+ "mpmath": {
264
+ "hashes": [
265
+ "sha256:7a28eb2a9774d00c7bc92411c19a89209d5da7c4c9a9e227be8330a23a25b91f",
266
+ "sha256:a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c"
267
+ ],
268
+ "version": "==1.3.0"
269
+ },
270
+ "networkx": {
271
+ "hashes": [
272
+ "sha256:307c3669428c5362aab27c8a1260aa8f47c4e91d3891f48be0141738d8d053e1",
273
+ "sha256:df5d4365b724cf81b8c6a7312509d0c22386097011ad1abe274afd5e9d3bbc5f"
274
+ ],
275
+ "markers": "python_version >= '3.10'",
276
+ "version": "==3.4.2"
277
+ },
278
+ "numpy": {
279
+ "hashes": [
280
+ "sha256:05b2d4e667895cc55e3ff2b56077e4c8a5604361fc21a042845ea3ad67465aa8",
281
+ "sha256:12edb90831ff481f7ef5f6bc6431a9d74dc0e5ff401559a71e5e4611d4f2d466",
282
+ "sha256:13311c2db4c5f7609b462bc0f43d3c465424d25c626d95040f073e30f7570e35",
283
+ "sha256:13532a088217fa624c99b843eeb54640de23b3414b14aa66d023805eb731066c",
284
+ "sha256:13602b3174432a35b16c4cfb5de9a12d229727c3dd47a6ce35111f2ebdf66ff4",
285
+ "sha256:1600068c262af1ca9580a527d43dc9d959b0b1d8e56f8a05d830eea39b7c8af6",
286
+ "sha256:1b8cde4f11f0a975d1fd59373b32e2f5a562ade7cde4f85b7137f3de8fbb29a0",
287
+ "sha256:1c193d0b0238638e6fc5f10f1b074a6993cb13b0b431f64079a509d63d3aa8b7",
288
+ "sha256:1ebec5fd716c5a5b3d8dfcc439be82a8407b7b24b230d0ad28a81b61c2f4659a",
289
+ "sha256:242b39d00e4944431a3cd2db2f5377e15b5785920421993770cddb89992c3f3a",
290
+ "sha256:259ec80d54999cc34cd1eb8ded513cb053c3bf4829152a2e00de2371bd406f5e",
291
+ "sha256:2abbf905a0b568706391ec6fa15161fad0fb5d8b68d73c461b3c1bab6064dd62",
292
+ "sha256:2cbba4b30bf31ddbe97f1c7205ef976909a93a66bb1583e983adbd155ba72ac2",
293
+ "sha256:2ffef621c14ebb0188a8633348504a35c13680d6da93ab5cb86f4e54b7e922b5",
294
+ "sha256:30d53720b726ec36a7f88dc873f0eec8447fbc93d93a8f079dfac2629598d6ee",
295
+ "sha256:32e16a03138cabe0cb28e1007ee82264296ac0983714094380b408097a418cfe",
296
+ "sha256:43cca367bf94a14aca50b89e9bc2061683116cfe864e56740e083392f533ce7a",
297
+ "sha256:456e3b11cb79ac9946c822a56346ec80275eaf2950314b249b512896c0d2505e",
298
+ "sha256:4d6ec0d4222e8ffdab1744da2560f07856421b367928026fb540e1945f2eeeaf",
299
+ "sha256:5006b13a06e0b38d561fab5ccc37581f23c9511879be7693bd33c7cd15ca227c",
300
+ "sha256:675c741d4739af2dc20cd6c6a5c4b7355c728167845e3c6b0e824e4e5d36a6c3",
301
+ "sha256:6cdb606a7478f9ad91c6283e238544451e3a95f30fb5467fbf715964341a8a86",
302
+ "sha256:6d95f286b8244b3649b477ac066c6906fbb2905f8ac19b170e2175d3d799f4df",
303
+ "sha256:76322dcdb16fccf2ac56f99048af32259dcc488d9b7e25b51e5eca5147a3fb98",
304
+ "sha256:7c1c60328bd964b53f8b835df69ae8198659e2b9302ff9ebb7de4e5a5994db3d",
305
+ "sha256:860ec6e63e2c5c2ee5e9121808145c7bf86c96cca9ad396c0bd3e0f2798ccbe2",
306
+ "sha256:8e00ea6fc82e8a804433d3e9cedaa1051a1422cb6e443011590c14d2dea59146",
307
+ "sha256:9c6c754df29ce6a89ed23afb25550d1c2d5fdb9901d9c67a16e0b16eaf7e2550",
308
+ "sha256:a26ae94658d3ba3781d5e103ac07a876b3e9b29db53f68ed7df432fd033358a8",
309
+ "sha256:a65acfdb9c6ebb8368490dbafe83c03c7e277b37e6857f0caeadbbc56e12f4fb",
310
+ "sha256:a7d80b2e904faa63068ead63107189164ca443b42dd1930299e0d1cb041cec2e",
311
+ "sha256:a84498e0d0a1174f2b3ed769b67b656aa5460c92c9554039e11f20a05650f00d",
312
+ "sha256:ab4754d432e3ac42d33a269c8567413bdb541689b02d93788af4131018cbf366",
313
+ "sha256:ad369ed238b1959dfbade9018a740fb9392c5ac4f9b5173f420bd4f37ba1f7a0",
314
+ "sha256:b1d0fcae4f0949f215d4632be684a539859b295e2d0cb14f78ec231915d644db",
315
+ "sha256:b42a1a511c81cc78cbc4539675713bbcf9d9c3913386243ceff0e9429ca892fe",
316
+ "sha256:bd33f82e95ba7ad632bc57837ee99dba3d7e006536200c4e9124089e1bf42426",
317
+ "sha256:bdd407c40483463898b84490770199d5714dcc9dd9b792f6c6caccc523c00952",
318
+ "sha256:c6eef7a2dbd0abfb0d9eaf78b73017dbfd0b54051102ff4e6a7b2980d5ac1a03",
319
+ "sha256:c82af4b2ddd2ee72d1fc0c6695048d457e00b3582ccde72d8a1c991b808bb20f",
320
+ "sha256:d666cb72687559689e9906197e3bec7b736764df6a2e58ee265e360663e9baf7",
321
+ "sha256:d7bf0a4f9f15b32b5ba53147369e94296f5fffb783db5aacc1be15b4bf72f43b",
322
+ "sha256:d82075752f40c0ddf57e6e02673a17f6cb0f8eb3f587f63ca1eaab5594da5b17",
323
+ "sha256:da65fb46d4cbb75cb417cddf6ba5e7582eb7bb0b47db4b99c9fe5787ce5d91f5",
324
+ "sha256:e2b49c3c0804e8ecb05d59af8386ec2f74877f7ca8fd9c1e00be2672e4d399b1",
325
+ "sha256:e585c8ae871fd38ac50598f4763d73ec5497b0de9a0ab4ef5b69f01c6a046142",
326
+ "sha256:e8d3ca0a72dd8846eb6f7dfe8f19088060fcb76931ed592d29128e0219652884",
327
+ "sha256:ef444c57d664d35cac4e18c298c47d7b504c66b17c2ea91312e979fcfbdfb08a",
328
+ "sha256:f1eb068ead09f4994dec71c24b2844f1e4e4e013b9629f812f292f04bd1510d9",
329
+ "sha256:f2ded8d9b6f68cc26f8425eda5d3877b47343e68ca23d0d0846f4d312ecaa445",
330
+ "sha256:f751ed0a2f250541e19dfca9f1eafa31a392c71c832b6bb9e113b10d050cb0f1",
331
+ "sha256:faa88bc527d0f097abdc2c663cddf37c05a1c2f113716601555249805cf573f1",
332
+ "sha256:fc44e3c68ff00fd991b59092a54350e6e4911152682b4782f68070985aa9e648"
333
+ ],
334
+ "index": "pypi",
335
+ "markers": "python_version >= '3.10'",
336
+ "version": "==2.1.2"
337
+ },
338
+ "packaging": {
339
+ "hashes": [
340
+ "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002",
341
+ "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"
342
+ ],
343
+ "markers": "python_version >= '3.8'",
344
+ "version": "==24.1"
345
+ },
346
+ "pandas": {
347
+ "hashes": [
348
+ "sha256:062309c1b9ea12a50e8ce661145c6aab431b1e99530d3cd60640e255778bd43a",
349
+ "sha256:15c0e1e02e93116177d29ff83e8b1619c93ddc9c49083f237d4312337a61165d",
350
+ "sha256:1948ddde24197a0f7add2bdc4ca83bf2b1ef84a1bc8ccffd95eda17fd836ecb5",
351
+ "sha256:1db71525a1538b30142094edb9adc10be3f3e176748cd7acc2240c2f2e5aa3a4",
352
+ "sha256:22a9d949bfc9a502d320aa04e5d02feab689d61da4e7764b62c30b991c42c5f0",
353
+ "sha256:29401dbfa9ad77319367d36940cd8a0b3a11aba16063e39632d98b0e931ddf32",
354
+ "sha256:31d0ced62d4ea3e231a9f228366919a5ea0b07440d9d4dac345376fd8e1477ea",
355
+ "sha256:3508d914817e153ad359d7e069d752cdd736a247c322d932eb89e6bc84217f28",
356
+ "sha256:37e0aced3e8f539eccf2e099f65cdb9c8aa85109b0be6e93e2baff94264bdc6f",
357
+ "sha256:381175499d3802cde0eabbaf6324cce0c4f5d52ca6f8c377c29ad442f50f6348",
358
+ "sha256:38cf8125c40dae9d5acc10fa66af8ea6fdf760b2714ee482ca691fc66e6fcb18",
359
+ "sha256:3b71f27954685ee685317063bf13c7709a7ba74fc996b84fc6821c59b0f06468",
360
+ "sha256:3fc6873a41186404dad67245896a6e440baacc92f5b716ccd1bc9ed2995ab2c5",
361
+ "sha256:4850ba03528b6dd51d6c5d273c46f183f39a9baf3f0143e566b89450965b105e",
362
+ "sha256:4f18ba62b61d7e192368b84517265a99b4d7ee8912f8708660fb4a366cc82667",
363
+ "sha256:56534ce0746a58afaf7942ba4863e0ef81c9c50d3f0ae93e9497d6a41a057645",
364
+ "sha256:59ef3764d0fe818125a5097d2ae867ca3fa64df032331b7e0917cf5d7bf66b13",
365
+ "sha256:5dbca4c1acd72e8eeef4753eeca07de9b1db4f398669d5994086f788a5d7cc30",
366
+ "sha256:5de54125a92bb4d1c051c0659e6fcb75256bf799a732a87184e5ea503965bce3",
367
+ "sha256:61c5ad4043f791b61dd4752191d9f07f0ae412515d59ba8f005832a532f8736d",
368
+ "sha256:6374c452ff3ec675a8f46fd9ab25c4ad0ba590b71cf0656f8b6daa5202bca3fb",
369
+ "sha256:63cc132e40a2e084cf01adf0775b15ac515ba905d7dcca47e9a251819c575ef3",
370
+ "sha256:66108071e1b935240e74525006034333f98bcdb87ea116de573a6a0dccb6c039",
371
+ "sha256:6dfcb5ee8d4d50c06a51c2fffa6cff6272098ad6540aed1a76d15fb9318194d8",
372
+ "sha256:7c2875855b0ff77b2a64a0365e24455d9990730d6431b9e0ee18ad8acee13dbd",
373
+ "sha256:7eee9e7cea6adf3e3d24e304ac6b8300646e2a5d1cd3a3c2abed9101b0846761",
374
+ "sha256:800250ecdadb6d9c78eae4990da62743b857b470883fa27f652db8bdde7f6659",
375
+ "sha256:86976a1c5b25ae3f8ccae3a5306e443569ee3c3faf444dfd0f41cda24667ad57",
376
+ "sha256:8cd6d7cc958a3910f934ea8dbdf17b2364827bb4dafc38ce6eef6bb3d65ff09c",
377
+ "sha256:99df71520d25fade9db7c1076ac94eb994f4d2673ef2aa2e86ee039b6746d20c",
378
+ "sha256:a5a1595fe639f5988ba6a8e5bc9649af3baf26df3998a0abe56c02609392e0a4",
379
+ "sha256:ad5b65698ab28ed8d7f18790a0dc58005c7629f227be9ecc1072aa74c0c1d43a",
380
+ "sha256:b1d432e8d08679a40e2a6d8b2f9770a5c21793a6f9f47fdd52c5ce1948a5a8a9",
381
+ "sha256:b8661b0238a69d7aafe156b7fa86c44b881387509653fdf857bebc5e4008ad42",
382
+ "sha256:ba96630bc17c875161df3818780af30e43be9b166ce51c9a18c1feae342906c2",
383
+ "sha256:bc6b93f9b966093cb0fd62ff1a7e4c09e6d546ad7c1de191767baffc57628f39",
384
+ "sha256:c124333816c3a9b03fbeef3a9f230ba9a737e9e5bb4060aa2107a86cc0a497fc",
385
+ "sha256:cd8d0c3be0515c12fed0bdbae072551c8b54b7192c7b1fda0ba56059a0179698",
386
+ "sha256:d9c45366def9a3dd85a6454c0e7908f2b3b8e9c138f5dc38fed7ce720d8453ed",
387
+ "sha256:f00d1345d84d8c86a63e476bb4955e46458b304b9575dcf71102b5c705320015",
388
+ "sha256:f3a255b2c19987fbbe62a9dfd6cff7ff2aa9ccab3fc75218fd4b7530f01efa24",
389
+ "sha256:fffb8ae78d8af97f849404f21411c95062db1496aeb3e56f146f0355c9989319"
390
+ ],
391
+ "index": "pypi",
392
+ "markers": "python_version >= '3.9'",
393
+ "version": "==2.2.3"
394
+ },
395
+ "pillow": {
396
+ "hashes": [
397
+ "sha256:00177a63030d612148e659b55ba99527803288cea7c75fb05766ab7981a8c1b7",
398
+ "sha256:006bcdd307cc47ba43e924099a038cbf9591062e6c50e570819743f5607404f5",
399
+ "sha256:084a07ef0821cfe4858fe86652fffac8e187b6ae677e9906e192aafcc1b69903",
400
+ "sha256:0ae08bd8ffc41aebf578c2af2f9d8749d91f448b3bfd41d7d9ff573d74f2a6b2",
401
+ "sha256:0e038b0745997c7dcaae350d35859c9715c71e92ffb7e0f4a8e8a16732150f38",
402
+ "sha256:1187739620f2b365de756ce086fdb3604573337cc28a0d3ac4a01ab6b2d2a6d2",
403
+ "sha256:16095692a253047fe3ec028e951fa4221a1f3ed3d80c397e83541a3037ff67c9",
404
+ "sha256:1a61b54f87ab5786b8479f81c4b11f4d61702830354520837f8cc791ebba0f5f",
405
+ "sha256:1c1d72714f429a521d8d2d018badc42414c3077eb187a59579f28e4270b4b0fc",
406
+ "sha256:1e2688958a840c822279fda0086fec1fdab2f95bf2b717b66871c4ad9859d7e8",
407
+ "sha256:20ec184af98a121fb2da42642dea8a29ec80fc3efbaefb86d8fdd2606619045d",
408
+ "sha256:21a0d3b115009ebb8ac3d2ebec5c2982cc693da935f4ab7bb5c8ebe2f47d36f2",
409
+ "sha256:224aaa38177597bb179f3ec87eeefcce8e4f85e608025e9cfac60de237ba6316",
410
+ "sha256:2679d2258b7f1192b378e2893a8a0a0ca472234d4c2c0e6bdd3380e8dfa21b6a",
411
+ "sha256:27a7860107500d813fcd203b4ea19b04babe79448268403172782754870dac25",
412
+ "sha256:290f2cc809f9da7d6d622550bbf4c1e57518212da51b6a30fe8e0a270a5b78bd",
413
+ "sha256:2e46773dc9f35a1dd28bd6981332fd7f27bec001a918a72a79b4133cf5291dba",
414
+ "sha256:3107c66e43bda25359d5ef446f59c497de2b5ed4c7fdba0894f8d6cf3822dafc",
415
+ "sha256:375b8dd15a1f5d2feafff536d47e22f69625c1aa92f12b339ec0b2ca40263273",
416
+ "sha256:45c566eb10b8967d71bf1ab8e4a525e5a93519e29ea071459ce517f6b903d7fa",
417
+ "sha256:499c3a1b0d6fc8213519e193796eb1a86a1be4b1877d678b30f83fd979811d1a",
418
+ "sha256:4ad70c4214f67d7466bea6a08061eba35c01b1b89eaa098040a35272a8efb22b",
419
+ "sha256:4b60c9520f7207aaf2e1d94de026682fc227806c6e1f55bba7606d1c94dd623a",
420
+ "sha256:5178952973e588b3f1360868847334e9e3bf49d19e169bbbdfaf8398002419ae",
421
+ "sha256:52a2d8323a465f84faaba5236567d212c3668f2ab53e1c74c15583cf507a0291",
422
+ "sha256:598b4e238f13276e0008299bd2482003f48158e2b11826862b1eb2ad7c768b97",
423
+ "sha256:5bd2d3bdb846d757055910f0a59792d33b555800813c3b39ada1829c372ccb06",
424
+ "sha256:5c39ed17edea3bc69c743a8dd3e9853b7509625c2462532e62baa0732163a904",
425
+ "sha256:5d203af30149ae339ad1b4f710d9844ed8796e97fda23ffbc4cc472968a47d0b",
426
+ "sha256:5ddbfd761ee00c12ee1be86c9c0683ecf5bb14c9772ddbd782085779a63dd55b",
427
+ "sha256:607bbe123c74e272e381a8d1957083a9463401f7bd01287f50521ecb05a313f8",
428
+ "sha256:61b887f9ddba63ddf62fd02a3ba7add935d053b6dd7d58998c630e6dbade8527",
429
+ "sha256:6619654954dc4936fcff82db8eb6401d3159ec6be81e33c6000dfd76ae189947",
430
+ "sha256:674629ff60030d144b7bca2b8330225a9b11c482ed408813924619c6f302fdbb",
431
+ "sha256:6ec0d5af64f2e3d64a165f490d96368bb5dea8b8f9ad04487f9ab60dc4bb6003",
432
+ "sha256:6f4dba50cfa56f910241eb7f883c20f1e7b1d8f7d91c750cd0b318bad443f4d5",
433
+ "sha256:70fbbdacd1d271b77b7721fe3cdd2d537bbbd75d29e6300c672ec6bb38d9672f",
434
+ "sha256:72bacbaf24ac003fea9bff9837d1eedb6088758d41e100c1552930151f677739",
435
+ "sha256:7326a1787e3c7b0429659e0a944725e1b03eeaa10edd945a86dead1913383944",
436
+ "sha256:73853108f56df97baf2bb8b522f3578221e56f646ba345a372c78326710d3830",
437
+ "sha256:73e3a0200cdda995c7e43dd47436c1548f87a30bb27fb871f352a22ab8dcf45f",
438
+ "sha256:75acbbeb05b86bc53cbe7b7e6fe00fbcf82ad7c684b3ad82e3d711da9ba287d3",
439
+ "sha256:8069c5179902dcdce0be9bfc8235347fdbac249d23bd90514b7a47a72d9fecf4",
440
+ "sha256:846e193e103b41e984ac921b335df59195356ce3f71dcfd155aa79c603873b84",
441
+ "sha256:8594f42df584e5b4bb9281799698403f7af489fba84c34d53d1c4bfb71b7c4e7",
442
+ "sha256:86510e3f5eca0ab87429dd77fafc04693195eec7fd6a137c389c3eeb4cfb77c6",
443
+ "sha256:8853a3bf12afddfdf15f57c4b02d7ded92c7a75a5d7331d19f4f9572a89c17e6",
444
+ "sha256:88a58d8ac0cc0e7f3a014509f0455248a76629ca9b604eca7dc5927cc593c5e9",
445
+ "sha256:8ba470552b48e5835f1d23ecb936bb7f71d206f9dfeee64245f30c3270b994de",
446
+ "sha256:8c676b587da5673d3c75bd67dd2a8cdfeb282ca38a30f37950511766b26858c4",
447
+ "sha256:8ec4a89295cd6cd4d1058a5e6aec6bf51e0eaaf9714774e1bfac7cfc9051db47",
448
+ "sha256:94f3e1780abb45062287b4614a5bc0874519c86a777d4a7ad34978e86428b8dd",
449
+ "sha256:9a0f748eaa434a41fccf8e1ee7a3eed68af1b690e75328fd7a60af123c193b50",
450
+ "sha256:a5629742881bcbc1f42e840af185fd4d83a5edeb96475a575f4da50d6ede337c",
451
+ "sha256:a65149d8ada1055029fcb665452b2814fe7d7082fcb0c5bed6db851cb69b2086",
452
+ "sha256:b3c5ac4bed7519088103d9450a1107f76308ecf91d6dabc8a33a2fcfb18d0fba",
453
+ "sha256:b4fd7bd29610a83a8c9b564d457cf5bd92b4e11e79a4ee4716a63c959699b306",
454
+ "sha256:bcd1fb5bb7b07f64c15618c89efcc2cfa3e95f0e3bcdbaf4642509de1942a699",
455
+ "sha256:c12b5ae868897c7338519c03049a806af85b9b8c237b7d675b8c5e089e4a618e",
456
+ "sha256:c26845094b1af3c91852745ae78e3ea47abf3dbcd1cf962f16b9a5fbe3ee8488",
457
+ "sha256:c6a660307ca9d4867caa8d9ca2c2658ab685de83792d1876274991adec7b93fa",
458
+ "sha256:c809a70e43c7977c4a42aefd62f0131823ebf7dd73556fa5d5950f5b354087e2",
459
+ "sha256:c8b2351c85d855293a299038e1f89db92a2f35e8d2f783489c6f0b2b5f3fe8a3",
460
+ "sha256:cb929ca942d0ec4fac404cbf520ee6cac37bf35be479b970c4ffadf2b6a1cad9",
461
+ "sha256:d2c0a187a92a1cb5ef2c8ed5412dd8d4334272617f532d4ad4de31e0495bd923",
462
+ "sha256:d69bfd8ec3219ae71bcde1f942b728903cad25fafe3100ba2258b973bd2bc1b2",
463
+ "sha256:daffdf51ee5db69a82dd127eabecce20729e21f7a3680cf7cbb23f0829189790",
464
+ "sha256:e58876c91f97b0952eb766123bfef372792ab3f4e3e1f1a2267834c2ab131734",
465
+ "sha256:eda2616eb2313cbb3eebbe51f19362eb434b18e3bb599466a1ffa76a033fb916",
466
+ "sha256:ee217c198f2e41f184f3869f3e485557296d505b5195c513b2bfe0062dc537f1",
467
+ "sha256:f02541ef64077f22bf4924f225c0fd1248c168f86e4b7abdedd87d6ebaceab0f",
468
+ "sha256:f1b82c27e89fffc6da125d5eb0ca6e68017faf5efc078128cfaa42cf5cb38798",
469
+ "sha256:fba162b8872d30fea8c52b258a542c5dfd7b235fb5cb352240c8d63b414013eb",
470
+ "sha256:fbbcb7b57dc9c794843e3d1258c0fbf0f48656d46ffe9e09b63bbd6e8cd5d0a2",
471
+ "sha256:fcb4621042ac4b7865c179bb972ed0da0218a076dc1820ffc48b1d74c1e37fe9"
472
+ ],
473
+ "index": "pypi",
474
+ "markers": "python_version >= '3.9'",
475
+ "version": "==11.0.0"
476
+ },
477
+ "python-dateutil": {
478
+ "hashes": [
479
+ "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3",
480
+ "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"
481
+ ],
482
+ "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
483
+ "version": "==2.9.0.post0"
484
+ },
485
+ "pytz": {
486
+ "hashes": [
487
+ "sha256:2aa355083c50a0f93fa581709deac0c9ad65cca8a9e9beac660adcbd493c798a",
488
+ "sha256:31c7c1817eb7fae7ca4b8c7ee50c72f93aa2dd863de768e1ef4245d426aa0725"
489
+ ],
490
+ "version": "==2024.2"
491
+ },
492
+ "pyyaml": {
493
+ "hashes": [
494
+ "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff",
495
+ "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48",
496
+ "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086",
497
+ "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e",
498
+ "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133",
499
+ "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5",
500
+ "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484",
501
+ "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee",
502
+ "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5",
503
+ "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68",
504
+ "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a",
505
+ "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf",
506
+ "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99",
507
+ "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8",
508
+ "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85",
509
+ "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19",
510
+ "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc",
511
+ "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a",
512
+ "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1",
513
+ "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317",
514
+ "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c",
515
+ "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631",
516
+ "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d",
517
+ "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652",
518
+ "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5",
519
+ "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e",
520
+ "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b",
521
+ "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8",
522
+ "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476",
523
+ "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706",
524
+ "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563",
525
+ "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237",
526
+ "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b",
527
+ "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083",
528
+ "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180",
529
+ "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425",
530
+ "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e",
531
+ "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f",
532
+ "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725",
533
+ "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183",
534
+ "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab",
535
+ "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774",
536
+ "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725",
537
+ "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e",
538
+ "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5",
539
+ "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d",
540
+ "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290",
541
+ "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44",
542
+ "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed",
543
+ "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4",
544
+ "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba",
545
+ "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12",
546
+ "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4"
547
+ ],
548
+ "markers": "python_version >= '3.8'",
549
+ "version": "==6.0.2"
550
+ },
551
+ "regex": {
552
+ "hashes": [
553
+ "sha256:01c2acb51f8a7d6494c8c5eafe3d8e06d76563d8a8a4643b37e9b2dd8a2ff623",
554
+ "sha256:02087ea0a03b4af1ed6ebab2c54d7118127fee8d71b26398e8e4b05b78963199",
555
+ "sha256:040562757795eeea356394a7fb13076ad4f99d3c62ab0f8bdfb21f99a1f85664",
556
+ "sha256:042c55879cfeb21a8adacc84ea347721d3d83a159da6acdf1116859e2427c43f",
557
+ "sha256:079400a8269544b955ffa9e31f186f01d96829110a3bf79dc338e9910f794fca",
558
+ "sha256:07f45f287469039ffc2c53caf6803cd506eb5f5f637f1d4acb37a738f71dd066",
559
+ "sha256:09d77559e80dcc9d24570da3745ab859a9cf91953062e4ab126ba9d5993688ca",
560
+ "sha256:0cbff728659ce4bbf4c30b2a1be040faafaa9eca6ecde40aaff86f7889f4ab39",
561
+ "sha256:0e12c481ad92d129c78f13a2a3662317e46ee7ef96c94fd332e1c29131875b7d",
562
+ "sha256:0ea51dcc0835eea2ea31d66456210a4e01a076d820e9039b04ae8d17ac11dee6",
563
+ "sha256:0ffbcf9221e04502fc35e54d1ce9567541979c3fdfb93d2c554f0ca583a19b35",
564
+ "sha256:1494fa8725c285a81d01dc8c06b55287a1ee5e0e382d8413adc0a9197aac6408",
565
+ "sha256:16e13a7929791ac1216afde26f712802e3df7bf0360b32e4914dca3ab8baeea5",
566
+ "sha256:18406efb2f5a0e57e3a5881cd9354c1512d3bb4f5c45d96d110a66114d84d23a",
567
+ "sha256:18e707ce6c92d7282dfce370cd205098384b8ee21544e7cb29b8aab955b66fa9",
568
+ "sha256:220e92a30b426daf23bb67a7962900ed4613589bab80382be09b48896d211e92",
569
+ "sha256:23b30c62d0f16827f2ae9f2bb87619bc4fba2044911e2e6c2eb1af0161cdb766",
570
+ "sha256:23f9985c8784e544d53fc2930fc1ac1a7319f5d5332d228437acc9f418f2f168",
571
+ "sha256:297f54910247508e6e5cae669f2bc308985c60540a4edd1c77203ef19bfa63ca",
572
+ "sha256:2b08fce89fbd45664d3df6ad93e554b6c16933ffa9d55cb7e01182baaf971508",
573
+ "sha256:2cce2449e5927a0bf084d346da6cd5eb016b2beca10d0013ab50e3c226ffc0df",
574
+ "sha256:313ea15e5ff2a8cbbad96ccef6be638393041b0a7863183c2d31e0c6116688cf",
575
+ "sha256:323c1f04be6b2968944d730e5c2091c8c89767903ecaa135203eec4565ed2b2b",
576
+ "sha256:35f4a6f96aa6cb3f2f7247027b07b15a374f0d5b912c0001418d1d55024d5cb4",
577
+ "sha256:3b37fa423beefa44919e009745ccbf353d8c981516e807995b2bd11c2c77d268",
578
+ "sha256:3ce4f1185db3fbde8ed8aa223fc9620f276c58de8b0d4f8cc86fd1360829edb6",
579
+ "sha256:46989629904bad940bbec2106528140a218b4a36bb3042d8406980be1941429c",
580
+ "sha256:4838e24ee015101d9f901988001038f7f0d90dc0c3b115541a1365fb439add62",
581
+ "sha256:49b0e06786ea663f933f3710a51e9385ce0cba0ea56b67107fd841a55d56a231",
582
+ "sha256:4db21ece84dfeefc5d8a3863f101995de646c6cb0536952c321a2650aa202c36",
583
+ "sha256:54c4a097b8bc5bb0dfc83ae498061d53ad7b5762e00f4adaa23bee22b012e6ba",
584
+ "sha256:54d9ff35d4515debf14bc27f1e3b38bfc453eff3220f5bce159642fa762fe5d4",
585
+ "sha256:55b96e7ce3a69a8449a66984c268062fbaa0d8ae437b285428e12797baefce7e",
586
+ "sha256:57fdd2e0b2694ce6fc2e5ccf189789c3e2962916fb38779d3e3521ff8fe7a822",
587
+ "sha256:587d4af3979376652010e400accc30404e6c16b7df574048ab1f581af82065e4",
588
+ "sha256:5b513b6997a0b2f10e4fd3a1313568e373926e8c252bd76c960f96fd039cd28d",
589
+ "sha256:5ddcd9a179c0a6fa8add279a4444015acddcd7f232a49071ae57fa6e278f1f71",
590
+ "sha256:6113c008a7780792efc80f9dfe10ba0cd043cbf8dc9a76ef757850f51b4edc50",
591
+ "sha256:635a1d96665f84b292e401c3d62775851aedc31d4f8784117b3c68c4fcd4118d",
592
+ "sha256:64ce2799bd75039b480cc0360907c4fb2f50022f030bf9e7a8705b636e408fad",
593
+ "sha256:69dee6a020693d12a3cf892aba4808fe168d2a4cef368eb9bf74f5398bfd4ee8",
594
+ "sha256:6a2644a93da36c784e546de579ec1806bfd2763ef47babc1b03d765fe560c9f8",
595
+ "sha256:6b41e1adc61fa347662b09398e31ad446afadff932a24807d3ceb955ed865cc8",
596
+ "sha256:6c188c307e8433bcb63dc1915022deb553b4203a70722fc542c363bf120a01fd",
597
+ "sha256:6edd623bae6a737f10ce853ea076f56f507fd7726bee96a41ee3d68d347e4d16",
598
+ "sha256:73d6d2f64f4d894c96626a75578b0bf7d9e56dcda8c3d037a2118fdfe9b1c664",
599
+ "sha256:7a22ccefd4db3f12b526eccb129390942fe874a3a9fdbdd24cf55773a1faab1a",
600
+ "sha256:7fb89ee5d106e4a7a51bce305ac4efb981536301895f7bdcf93ec92ae0d91c7f",
601
+ "sha256:846bc79ee753acf93aef4184c040d709940c9d001029ceb7b7a52747b80ed2dd",
602
+ "sha256:85ab7824093d8f10d44330fe1e6493f756f252d145323dd17ab6b48733ff6c0a",
603
+ "sha256:8dee5b4810a89447151999428fe096977346cf2f29f4d5e29609d2e19e0199c9",
604
+ "sha256:8e5fb5f77c8745a60105403a774fe2c1759b71d3e7b4ca237a5e67ad066c7199",
605
+ "sha256:98eeee2f2e63edae2181c886d7911ce502e1292794f4c5ee71e60e23e8d26b5d",
606
+ "sha256:9d4a76b96f398697fe01117093613166e6aa8195d63f1b4ec3f21ab637632963",
607
+ "sha256:9e8719792ca63c6b8340380352c24dcb8cd7ec49dae36e963742a275dfae6009",
608
+ "sha256:a0b2b80321c2ed3fcf0385ec9e51a12253c50f146fddb2abbb10f033fe3d049a",
609
+ "sha256:a4cc92bb6db56ab0c1cbd17294e14f5e9224f0cc6521167ef388332604e92679",
610
+ "sha256:a738b937d512b30bf75995c0159c0ddf9eec0775c9d72ac0202076c72f24aa96",
611
+ "sha256:a8f877c89719d759e52783f7fe6e1c67121076b87b40542966c02de5503ace42",
612
+ "sha256:a906ed5e47a0ce5f04b2c981af1c9acf9e8696066900bf03b9d7879a6f679fc8",
613
+ "sha256:ae2941333154baff9838e88aa71c1d84f4438189ecc6021a12c7573728b5838e",
614
+ "sha256:b0d0a6c64fcc4ef9c69bd5b3b3626cc3776520a1637d8abaa62b9edc147a58f7",
615
+ "sha256:b5b029322e6e7b94fff16cd120ab35a253236a5f99a79fb04fda7ae71ca20ae8",
616
+ "sha256:b7aaa315101c6567a9a45d2839322c51c8d6e81f67683d529512f5bcfb99c802",
617
+ "sha256:be1c8ed48c4c4065ecb19d882a0ce1afe0745dfad8ce48c49586b90a55f02366",
618
+ "sha256:c0256beda696edcf7d97ef16b2a33a8e5a875affd6fa6567b54f7c577b30a137",
619
+ "sha256:c157bb447303070f256e084668b702073db99bbb61d44f85d811025fcf38f784",
620
+ "sha256:c57d08ad67aba97af57a7263c2d9006d5c404d721c5f7542f077f109ec2a4a29",
621
+ "sha256:c69ada171c2d0e97a4b5aa78fbb835e0ffbb6b13fc5da968c09811346564f0d3",
622
+ "sha256:c94bb0a9f1db10a1d16c00880bdebd5f9faf267273b8f5bd1878126e0fbde771",
623
+ "sha256:cb130fccd1a37ed894824b8c046321540263013da72745d755f2d35114b81a60",
624
+ "sha256:ced479f601cd2f8ca1fd7b23925a7e0ad512a56d6e9476f79b8f381d9d37090a",
625
+ "sha256:d05ac6fa06959c4172eccd99a222e1fbf17b5670c4d596cb1e5cde99600674c4",
626
+ "sha256:d552c78411f60b1fdaafd117a1fca2f02e562e309223b9d44b7de8be451ec5e0",
627
+ "sha256:dd4490a33eb909ef5078ab20f5f000087afa2a4daa27b4c072ccb3cb3050ad84",
628
+ "sha256:df5cbb1fbc74a8305b6065d4ade43b993be03dbe0f8b30032cced0d7740994bd",
629
+ "sha256:e28f9faeb14b6f23ac55bfbbfd3643f5c7c18ede093977f1df249f73fd22c7b1",
630
+ "sha256:e464b467f1588e2c42d26814231edecbcfe77f5ac414d92cbf4e7b55b2c2a776",
631
+ "sha256:e4c22e1ac1f1ec1e09f72e6c44d8f2244173db7eb9629cc3a346a8d7ccc31142",
632
+ "sha256:e53b5fbab5d675aec9f0c501274c467c0f9a5d23696cfc94247e1fb56501ed89",
633
+ "sha256:e93f1c331ca8e86fe877a48ad64e77882c0c4da0097f2212873a69bbfea95d0c",
634
+ "sha256:e997fd30430c57138adc06bba4c7c2968fb13d101e57dd5bb9355bf8ce3fa7e8",
635
+ "sha256:e9a091b0550b3b0207784a7d6d0f1a00d1d1c8a11699c1a4d93db3fbefc3ad35",
636
+ "sha256:eab4bb380f15e189d1313195b062a6aa908f5bd687a0ceccd47c8211e9cf0d4a",
637
+ "sha256:eb1ae19e64c14c7ec1995f40bd932448713d3c73509e82d8cd7744dc00e29e86",
638
+ "sha256:ecea58b43a67b1b79805f1a0255730edaf5191ecef84dbc4cc85eb30bc8b63b9",
639
+ "sha256:ee439691d8c23e76f9802c42a95cfeebf9d47cf4ffd06f18489122dbb0a7ad64",
640
+ "sha256:eee9130eaad130649fd73e5cd92f60e55708952260ede70da64de420cdcad554",
641
+ "sha256:f47cd43a5bfa48f86925fe26fbdd0a488ff15b62468abb5d2a1e092a4fb10e85",
642
+ "sha256:f6fff13ef6b5f29221d6904aa816c34701462956aa72a77f1f151a8ec4f56aeb",
643
+ "sha256:f745ec09bc1b0bd15cfc73df6fa4f726dcc26bb16c23a03f9e3367d357eeedd0",
644
+ "sha256:f8404bf61298bb6f8224bb9176c1424548ee1181130818fcd2cbffddc768bed8",
645
+ "sha256:f9268774428ec173654985ce55fc6caf4c6d11ade0f6f914d48ef4719eb05ebb",
646
+ "sha256:faa3c142464efec496967359ca99696c896c591c56c53506bac1ad465f66e919"
647
+ ],
648
+ "markers": "python_version >= '3.8'",
649
+ "version": "==2024.9.11"
650
+ },
651
+ "requests": {
652
+ "hashes": [
653
+ "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760",
654
+ "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"
655
+ ],
656
+ "index": "pypi",
657
+ "markers": "python_version >= '3.8'",
658
+ "version": "==2.32.3"
659
+ },
660
+ "safetensors": {
661
+ "hashes": [
662
+ "sha256:01c8f00da537af711979e1b42a69a8ec9e1d7112f208e0e9b8a35d2c381085ef",
663
+ "sha256:023b6e5facda76989f4cba95a861b7e656b87e225f61811065d5c501f78cdb3f",
664
+ "sha256:09566792588d77b68abe53754c9f1308fadd35c9f87be939e22c623eaacbed6b",
665
+ "sha256:098923e2574ff237c517d6e840acada8e5b311cb1fa226019105ed82e9c3b62f",
666
+ "sha256:09dedf7c2fda934ee68143202acff6e9e8eb0ddeeb4cfc24182bef999efa9f42",
667
+ "sha256:133620f443450429322f238fda74d512c4008621227fccf2f8cf4a76206fea7c",
668
+ "sha256:139fbee92570ecea774e6344fee908907db79646d00b12c535f66bc78bd5ea2c",
669
+ "sha256:13ca0902d2648775089fa6a0c8fc9e6390c5f8ee576517d33f9261656f851e3f",
670
+ "sha256:1500418454529d0ed5c1564bda376c4ddff43f30fce9517d9bee7bcce5a8ef50",
671
+ "sha256:1524b54246e422ad6fb6aea1ac71edeeb77666efa67230e1faf6999df9b2e27f",
672
+ "sha256:21742b391b859e67b26c0b2ac37f52c9c0944a879a25ad2f9f9f3cd61e7fda8f",
673
+ "sha256:21f848d7aebd5954f92538552d6d75f7c1b4500f51664078b5b49720d180e47c",
674
+ "sha256:23fc9b4ec7b602915cbb4ec1a7c1ad96d2743c322f20ab709e2c35d1b66dad27",
675
+ "sha256:25e5f8e2e92a74f05b4ca55686234c32aac19927903792b30ee6d7bd5653d54e",
676
+ "sha256:2783956926303dcfeb1de91a4d1204cd4089ab441e622e7caee0642281109db3",
677
+ "sha256:309aaec9b66cbf07ad3a2e5cb8a03205663324fea024ba391594423d0f00d9fe",
678
+ "sha256:313514b0b9b73ff4ddfb4edd71860696dbe3c1c9dc4d5cc13dbd74da283d2cbf",
679
+ "sha256:31fa33ee326f750a2f2134a6174773c281d9a266ccd000bd4686d8021f1f3dac",
680
+ "sha256:3685ce7ed036f916316b567152482b7e959dc754fcc4a8342333d222e05f407c",
681
+ "sha256:39371fc551c1072976073ab258c3119395294cf49cdc1f8476794627de3130df",
682
+ "sha256:3a6ba28118636a130ccbb968bc33d4684c48678695dba2590169d5ab03a45646",
683
+ "sha256:4037676c86365a721a8c9510323a51861d703b399b78a6b4486a54a65a975fca",
684
+ "sha256:473300314e026bd1043cef391bb16a8689453363381561b8a3e443870937cc1e",
685
+ "sha256:4b99fbf72e3faf0b2f5f16e5e3458b93b7d0a83984fe8d5364c60aa169f2da89",
686
+ "sha256:4fb3e0609ec12d2a77e882f07cced530b8262027f64b75d399f1504ffec0ba56",
687
+ "sha256:500cac01d50b301ab7bb192353317035011c5ceeef0fca652f9f43c000bb7f8d",
688
+ "sha256:52452fa5999dc50c4decaf0c53aa28371f7f1e0fe5c2dd9129059fbe1e1599c7",
689
+ "sha256:53946c5813b8f9e26103c5efff4a931cc45d874f45229edd68557ffb35ffb9f8",
690
+ "sha256:540ce6c4bf6b58cb0fd93fa5f143bc0ee341c93bb4f9287ccd92cf898cc1b0dd",
691
+ "sha256:585f1703a518b437f5103aa9cf70e9bd437cb78eea9c51024329e4fb8a3e3679",
692
+ "sha256:59b77e4b7a708988d84f26de3ebead61ef1659c73dcbc9946c18f3b1786d2688",
693
+ "sha256:5a2d68a523a4cefd791156a4174189a4114cf0bf9c50ceb89f261600f3b2b81a",
694
+ "sha256:5d3bc83e14d67adc2e9387e511097f254bd1b43c3020440e708858c684cbac68",
695
+ "sha256:5f0032bedc869c56f8d26259fe39cd21c5199cd57f2228d817a0e23e8370af25",
696
+ "sha256:60c828a27e852ded2c85fc0f87bf1ec20e464c5cd4d56ff0e0711855cc2e17f8",
697
+ "sha256:63bfd425e25f5c733f572e2246e08a1c38bd6f2e027d3f7c87e2e43f228d1345",
698
+ "sha256:65573dc35be9059770808e276b017256fa30058802c29e1038eb1c00028502ea",
699
+ "sha256:670e95fe34e0d591d0529e5e59fd9d3d72bc77b1444fcaa14dccda4f36b5a38b",
700
+ "sha256:67e1e7cb8678bb1b37ac48ec0df04faf689e2f4e9e81e566b5c63d9f23748523",
701
+ "sha256:68814d599d25ed2fdd045ed54d370d1d03cf35e02dce56de44c651f828fb9b7b",
702
+ "sha256:6885016f34bef80ea1085b7e99b3c1f92cb1be78a49839203060f67b40aee761",
703
+ "sha256:6ac85d9a8c1af0e3132371d9f2d134695a06a96993c2e2f0bbe25debb9e3f67a",
704
+ "sha256:6d3de65718b86c3eeaa8b73a9c3d123f9307a96bbd7be9698e21e76a56443af5",
705
+ "sha256:7389129c03fadd1ccc37fd1ebbc773f2b031483b04700923c3511d2a939252cc",
706
+ "sha256:73e7d408e9012cd17511b382b43547850969c7979efc2bc353f317abaf23c84c",
707
+ "sha256:7469d70d3de970b1698d47c11ebbf296a308702cbaae7fcb993944751cf985f4",
708
+ "sha256:75331c0c746f03158ded32465b7d0b0e24c5a22121743662a2393439c43a45cf",
709
+ "sha256:76ded72f69209c9780fdb23ea89e56d35c54ae6abcdec67ccb22af8e696e449a",
710
+ "sha256:775409ce0fcc58b10773fdb4221ed1eb007de10fe7adbdf8f5e8a56096b6f0bc",
711
+ "sha256:77d9b228da8374c7262046a36c1f656ba32a93df6cc51cd4453af932011e77f1",
712
+ "sha256:788ee7d04cc0e0e7f944c52ff05f52a4415b312f5efd2ee66389fb7685ee030c",
713
+ "sha256:78dd8adfb48716233c45f676d6e48534d34b4bceb50162c13d1f0bdf6f78590a",
714
+ "sha256:801183a0f76dc647f51a2d9141ad341f9665602a7899a693207a82fb102cc53e",
715
+ "sha256:8158938cf3324172df024da511839d373c40fbfaa83e9abf467174b2910d7b4c",
716
+ "sha256:81efb124b58af39fcd684254c645e35692fea81c51627259cdf6d67ff4458916",
717
+ "sha256:834001bed193e4440c4a3950a31059523ee5090605c907c66808664c932b549c",
718
+ "sha256:83c4f13a9e687335c3928f615cd63a37e3f8ef072a3f2a0599fa09f863fb06a2",
719
+ "sha256:868f9df9e99ad1e7f38c52194063a982bc88fedc7d05096f4f8160403aaf4bd6",
720
+ "sha256:87bc42bd04fd9ca31396d3ca0433db0be1411b6b53ac5a32b7845a85d01ffc2e",
721
+ "sha256:8e8deb16c4321d61ae72533b8451ec4a9af8656d1c61ff81aa49f966406e4b68",
722
+ "sha256:9483f42be3b6bc8ff77dd67302de8ae411c4db39f7224dec66b0eb95822e4163",
723
+ "sha256:951d2fcf1817f4fb0ef0b48f6696688a4e852a95922a042b3f96aaa67eedc920",
724
+ "sha256:9633b663393d5796f0b60249549371e392b75a0b955c07e9c6f8708a87fc841f",
725
+ "sha256:96f1d038c827cdc552d97e71f522e1049fef0542be575421f7684756a748e457",
726
+ "sha256:9cc9449bd0b0bc538bd5e268221f0c5590bc5c14c1934a6ae359d44410dc68c4",
727
+ "sha256:9d1a94b9d793ed8fe35ab6d5cea28d540a46559bafc6aae98f30ee0867000cab",
728
+ "sha256:9e347d77e2c77eb7624400ccd09bed69d35c0332f417ce8c048d404a096c593b",
729
+ "sha256:9f556eea3aec1d3d955403159fe2123ddd68e880f83954ee9b4a3f2e15e716b6",
730
+ "sha256:a01e232e6d3d5cf8b1667bc3b657a77bdab73f0743c26c1d3c5dd7ce86bd3a92",
731
+ "sha256:a0dd565f83b30f2ca79b5d35748d0d99dd4b3454f80e03dfb41f0038e3bdf180",
732
+ "sha256:a3a315a6d0054bc6889a17f5668a73f94f7fe55121ff59e0a199e3519c08565f",
733
+ "sha256:a63eaccd22243c67e4f2b1c3e258b257effc4acd78f3b9d397edc8cf8f1298a7",
734
+ "sha256:a659467495de201e2f282063808a41170448c78bada1e62707b07a27b05e6943",
735
+ "sha256:a6c19feda32b931cae0acd42748a670bdf56bee6476a046af20181ad3fee4090",
736
+ "sha256:adaa9c6dead67e2dd90d634f89131e43162012479d86e25618e821a03d1eb1dc",
737
+ "sha256:b17b299ca9966ca983ecda1c0791a3f07f9ca6ab5ded8ef3d283fff45f6bcd5f",
738
+ "sha256:b3139098e3e8b2ad7afbca96d30ad29157b50c90861084e69fcb80dec7430461",
739
+ "sha256:b4db6a61d968de73722b858038c616a1bebd4a86abe2688e46ca0cc2d17558f2",
740
+ "sha256:b5a8810ad6a6f933fff6c276eae92c1da217b39b4d8b1bc1c0b8af2d270dc532",
741
+ "sha256:b75a616e02f21b6f1d5785b20cecbab5e2bd3f6358a90e8925b813d557666ec1",
742
+ "sha256:b98d40a2ffa560653f6274e15b27b3544e8e3713a44627ce268f419f35c49478",
743
+ "sha256:bad5e4b2476949bcd638a89f71b6916fa9a5cae5c1ae7eede337aca2100435c0",
744
+ "sha256:bb07000b19d41e35eecef9a454f31a8b4718a185293f0d0b1c4b61d6e4487971",
745
+ "sha256:bfeaa1a699c6b9ed514bd15e6a91e74738b71125a9292159e3d6b7f0a53d2cde",
746
+ "sha256:c36302c1c69eebb383775a89645a32b9d266878fab619819ce660309d6176c9b",
747
+ "sha256:c6d156bdb26732feada84f9388a9f135528c1ef5b05fae153da365ad4319c4c5",
748
+ "sha256:c7db3006a4915151ce1913652e907cdede299b974641a83fbc092102ac41b644",
749
+ "sha256:c859c7ed90b0047f58ee27751c8e56951452ed36a67afee1b0a87847d065eec6",
750
+ "sha256:cbd39cae1ad3e3ef6f63a6f07296b080c951f24cec60188378e43d3713000c04",
751
+ "sha256:cf727bb1281d66699bef5683b04d98c894a2803442c490a8d45cd365abfbdeb2",
752
+ "sha256:d0f1dd769f064adc33831f5e97ad07babbd728427f98e3e1db6902e369122737",
753
+ "sha256:d42ffd4c2259f31832cb17ff866c111684c87bd930892a1ba53fed28370c918c",
754
+ "sha256:d5f23198821e227cfc52d50fa989813513db381255c6d100927b012f0cfec63d",
755
+ "sha256:d641f5b8149ea98deb5ffcf604d764aad1de38a8285f86771ce1abf8e74c4891",
756
+ "sha256:d73de19682deabb02524b3d5d1f8b3aaba94c72f1bbfc7911b9b9d5d391c0310",
757
+ "sha256:d94581aab8c6b204def4d7320f07534d6ee34cd4855688004a4354e63b639a35",
758
+ "sha256:dbd280b07e6054ea68b0cb4b16ad9703e7d63cd6890f577cb98acc5354780142",
759
+ "sha256:dd8a1f6d2063a92cd04145c7fd9e31a1c7d85fbec20113a14b487563fdbc0597",
760
+ "sha256:dde2bf390d25f67908278d6f5d59e46211ef98e44108727084d4637ee70ab4f1",
761
+ "sha256:e3cec4a29eb7fe8da0b1c7988bc3828183080439dd559f720414450de076fcab",
762
+ "sha256:e7a97058f96340850da0601a3309f3d29d6191b0702b2da201e54c6e3e44ccf0",
763
+ "sha256:e98ef5524f8b6620c8cdef97220c0b6a5c1cef69852fcd2f174bb96c2bb316b1",
764
+ "sha256:f0b6453c54c57c1781292c46593f8a37254b8b99004c68d6c3ce229688931a22",
765
+ "sha256:f3664ac565d0e809b0b929dae7ccd74e4d3273cd0c6d1220c6430035befb678e",
766
+ "sha256:f4b15f51b4f8f2a512341d9ce3475cacc19c5fdfc5db1f0e19449e75f95c7dc8",
767
+ "sha256:f4beb84b6073b1247a773141a6331117e35d07134b3bb0383003f39971d414bb",
768
+ "sha256:f6594d130d0ad933d885c6a7b75c5183cb0e8450f799b80a39eae2b8508955eb",
769
+ "sha256:f68bf99ea970960a237f416ea394e266e0361895753df06e3e06e6ea7907d98b",
770
+ "sha256:fd33da8e9407559f8779c82a0448e2133737f922d71f884da27184549416bfed",
771
+ "sha256:fdadf66b5a22ceb645d5435a0be7a0292ce59648ca1d46b352f13cff3ea80410"
772
+ ],
773
+ "markers": "python_version >= '3.7'",
774
+ "version": "==0.4.5"
775
+ },
776
+ "setuptools": {
777
+ "hashes": [
778
+ "sha256:753bb6ebf1f465a1912e19ed1d41f403a79173a9acf66a42e7e6aec45c3c16ec",
779
+ "sha256:a7fcb66f68b4d9e8e66b42f9876150a3371558f98fa32222ffaa5bced76406f8"
780
+ ],
781
+ "markers": "python_version >= '3.12'",
782
+ "version": "==75.2.0"
783
+ },
784
+ "six": {
785
+ "hashes": [
786
+ "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926",
787
+ "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"
788
+ ],
789
+ "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
790
+ "version": "==1.16.0"
791
+ },
792
+ "sympy": {
793
+ "hashes": [
794
+ "sha256:9cebf7e04ff162015ce31c9c6c9144daa34a93bd082f54fd8f12deca4f47515f",
795
+ "sha256:db36cdc64bf61b9b24578b6f7bab1ecdd2452cf008f34faa33776680c26d66f8"
796
+ ],
797
+ "markers": "python_version >= '3.9'",
798
+ "version": "==1.13.1"
799
+ },
800
+ "tokenizers": {
801
+ "hashes": [
802
+ "sha256:02e18da58cf115b7c40de973609c35bde95856012ba42a41ee919c77935af251",
803
+ "sha256:03b03cf8b9a32254b1bf8a305fb95c6daf1baae0c1f93b27f2b08c9759f41dee",
804
+ "sha256:03dae629d99068b1ea5416d50de0fea13008f04129cc79af77a2a6392792d93c",
805
+ "sha256:05e41e302c315bd2ed86c02e917bf03a6cf7d2f652c9cee1a0eb0d0f1ca0d32c",
806
+ "sha256:07c4b7be58da142b0730cc4e5fd66bb7bf6f57f4986ddda73833cd39efef8a01",
807
+ "sha256:08aaa0d72bb65058e8c4b0455f61b840b156c557e2aca57627056624c3a93976",
808
+ "sha256:094663dd0e85ee2e573126918747bdb40044a848fde388efb5b09d57bc74c680",
809
+ "sha256:0b4872647ea6f25224e2833b044b0b19084e39400e8ead3cfe751238b0802140",
810
+ "sha256:0b7f515c83397e73292accdbbbedc62264e070bae9682f06061e2ddce67cacaf",
811
+ "sha256:0c6a796ddcd9a19ad13cf146997cd5895a421fe6aec8fd970d69f9117bddb45c",
812
+ "sha256:0d3caf244ce89d24c87545aafc3448be15870096e796c703a0d68547187192e1",
813
+ "sha256:0ecaf7b0e39caeb1aa6dd6e0975c405716c82c1312b55ac4f716ef563a906969",
814
+ "sha256:10be14ebd8082086a342d969e17fc2d6edc856c59dbdbddd25f158fa40eaf043",
815
+ "sha256:128c1110e950534426e2274837fc06b118ab5f2fa61c3436e60e0aada0ccfd67",
816
+ "sha256:130e35e76f9337ed6c31be386e75d4925ea807055acf18ca1a9b0eec03d8fe23",
817
+ "sha256:14e4cf033a2aa207d7ac790e91adca598b679999710a632c4a494aab0fc3a1b2",
818
+ "sha256:17f98fccb5c12ab1ce1f471731a9cd86df5d4bd2cf2880c5a66b229802d96145",
819
+ "sha256:1ba72260449e16c4c2f6f3252823b059fbf2d31b32617e582003f2b18b415c39",
820
+ "sha256:1fbbaf17a393c78d8aedb6a334097c91cb4119a9ced4764ab8cfdc8d254dc9f9",
821
+ "sha256:212231ab7dfcdc879baf4892ca87c726259fa7c887e1688e3f3cead384d8c305",
822
+ "sha256:218e5a3561561ea0f0ef1559c6d95b825308dbec23fb55b70b92589e7ff2e1e8",
823
+ "sha256:2847843c53f445e0f19ea842a4e48b89dd0db4e62ba6e1e47a2749d6ec11f50d",
824
+ "sha256:299c85c1d21135bc01542237979bf25c32efa0d66595dd0069ae259b97fb2dbe",
825
+ "sha256:2f13a2d16032ebc8bd812eb8099b035ac65887d8f0c207261472803b9633cf3e",
826
+ "sha256:31e87fca4f6bbf5cc67481b562147fe932f73d5602734de7dd18a8f2eee9c6dd",
827
+ "sha256:359eceb6a620c965988fc559cebc0a98db26713758ec4df43fb76d41486a8ed5",
828
+ "sha256:37d1e6f616c84fceefa7c6484a01df05caf1e207669121c66213cb5b2911d653",
829
+ "sha256:3d4d218573a3d8b121a1f8c801029d70444ffb6d8f129d4cca1c7b672ee4a24c",
830
+ "sha256:3e0305fc1ec6b1e5052d30d9c1d5c807081a7bd0cae46a33d03117082e91908c",
831
+ "sha256:3ea919687aa7001a8ff1ba36ac64f165c4e89035f57998fa6cedcfd877be619d",
832
+ "sha256:3f84dad1ff1863c648d80628b1b55353d16303431283e4efbb6ab1af56a75832",
833
+ "sha256:407ab666b38e02228fa785e81f7cf79ef929f104bcccf68a64525a54a93ceac9",
834
+ "sha256:42c097390e2f0ed0a5c5d569e6669dd4e9fff7b31c6a5ce6e9c66a61687197de",
835
+ "sha256:439261da7c0a5c88bda97acb284d49fbdaf67e9d3b623c0bfd107512d22787a9",
836
+ "sha256:47c1bcdd61e61136087459cb9e0b069ff23b5568b008265e5cbc927eae3387ce",
837
+ "sha256:48689da7a395df41114f516208d6550e3e905e1239cc5ad386686d9358e9cef0",
838
+ "sha256:4a717dcb08f2dabbf27ae4b6b20cbbb2ad7ed78ce05a829fae100ff4b3c7ff15",
839
+ "sha256:4b39356df4575d37f9b187bb623aab5abb7b62c8cb702867a1768002f814800c",
840
+ "sha256:514cf279b22fa1ae0bc08e143458c74ad3b56cd078b319464959685a35c53d5e",
841
+ "sha256:5170be9ec942f3d1d317817ced8d749b3e1202670865e4fd465e35d8c259de83",
842
+ "sha256:57b7a8880b208866508b06ce365dc631e7a2472a3faa24daa430d046fb56c885",
843
+ "sha256:5dc611e6ac0fa00a41de19c3bf6391a05ea201d2d22b757d63f5491ec0e67faa",
844
+ "sha256:62eb9daea2a2c06bcd8113a5824af8ef8ee7405d3a71123ba4d52c79bb3d9f1a",
845
+ "sha256:62f7fbd3c2c38b179556d879edae442b45f68312019c3a6013e56c3947a4e648",
846
+ "sha256:65f34e5b731a262dfa562820818533c38ce32a45864437f3d9c82f26c139ca7f",
847
+ "sha256:689b93d2e26d04da337ac407acec8b5d081d8d135e3e5066a88edd5bdb5aff89",
848
+ "sha256:6d3ac5c1f48358ffe20086bf065e843c0d0a9fce0d7f0f45d5f2f9fba3609ca5",
849
+ "sha256:712f90ea33f9bd2586b4a90d697c26d56d0a22fd3c91104c5858c4b5b6489a79",
850
+ "sha256:741fb22788482d09d68e73ece1495cfc6d9b29a06c37b3df90564a9cfa688e6d",
851
+ "sha256:7cdf379219e1e1dd432091058dab325a2e6235ebb23e0aec8d0508567c90cd01",
852
+ "sha256:81970b80b8ac126910295f8aab2d7ef962009ea39e0d86d304769493f69aaa1e",
853
+ "sha256:84edcc7cdeeee45ceedb65d518fffb77aec69311c9c8e30f77ad84da3025f002",
854
+ "sha256:86dcd08da163912e17b27bbaba5efdc71b4fbffb841530fdb74c5707f3c49216",
855
+ "sha256:88b3bc76ab4db1ab95ead623d49c95205411e26302cf9f74203e762ac7e85685",
856
+ "sha256:896195eb9dfdc85c8c052e29947169c1fcbe75a254c4b5792cdbd451587bce85",
857
+ "sha256:899152a78b095559c287b4c6d0099469573bb2055347bb8154db106651296f39",
858
+ "sha256:89d5c337d74ea6e5e7dc8af124cf177be843bbb9ca6e58c01f75ea103c12c8a9",
859
+ "sha256:9041ee665d0fa7f5c4ccf0f81f5e6b7087f797f85b143c094126fc2611fec9d0",
860
+ "sha256:910b96ed87316e4277b23c7bcaf667ce849c7cc379a453fa179e7e09290eeb25",
861
+ "sha256:929c8f3afa16a5130a81ab5079c589226273ec618949cce79b46d96e59a84f61",
862
+ "sha256:9300fac73ddc7e4b0330acbdda4efaabf74929a4a61e119a32a181f534a11b47",
863
+ "sha256:9310951c92c9fb91660de0c19a923c432f110dbfad1a2d429fbc44fa956bf64f",
864
+ "sha256:956f21d359ae29dd51ca5726d2c9a44ffafa041c623f5aa33749da87cfa809b9",
865
+ "sha256:96af92e833bd44760fb17f23f402e07a66339c1dcbe17d79a9b55bb0cc4f038e",
866
+ "sha256:998700177b45f70afeb206ad22c08d9e5f3a80639dae1032bf41e8cbc4dada4b",
867
+ "sha256:9af2dc4ee97d037bc6b05fa4429ddc87532c706316c5e11ce2f0596dfcfa77af",
868
+ "sha256:a12c3cebb8c92e9c35a23ab10d3852aee522f385c28d0b4fe48c0b7527d59762",
869
+ "sha256:a25dcb2f41a0a6aac31999e6c96a75e9152fa0127af8ece46c2f784f23b8197a",
870
+ "sha256:a2ffd9a8895575ac636d44500c66dffaef133823b6b25067604fa73bbc5ec09d",
871
+ "sha256:a647c5b7cb896d6430cf3e01b4e9a2d77f719c84cefcef825d404830c2071da2",
872
+ "sha256:a908c69c2897a68f412aa05ba38bfa87a02980df70f5a72fa8490479308b1f2d",
873
+ "sha256:b0874481aea54a178f2bccc45aa2d0c99cd3f79143a0948af6a9a21dcc49173b",
874
+ "sha256:b605c540753e62199bf15cf69c333e934077ef2350262af2ccada46026f83d1c",
875
+ "sha256:b61f561f329ffe4b28367798b89d60c4abf3f815d37413b6352bc6412a359867",
876
+ "sha256:b8c0fc3542cf9370bf92c932eb71bdeb33d2d4aeeb4126d9fd567b60bd04cb30",
877
+ "sha256:bdd67a0e3503a9a7cf8bc5a4a49cdde5fa5bada09a51e4c7e1c73900297539bd",
878
+ "sha256:bfdad27b0e50544f6b838895a373db6114b85112ba5c0cefadffa78d6daae563",
879
+ "sha256:c5ffe0d7f7bfcfa3b2585776ecf11da2e01c317027c8573c78ebcb8985279e23",
880
+ "sha256:cd28a8614f5c82a54ab2463554e84ad79526c5184cf4573bbac2efbbbcead457",
881
+ "sha256:ce6238a3311bb8e4c15b12600927d35c267b92a52c881ef5717a900ca14793f7",
882
+ "sha256:d10766473954397e2d370f215ebed1cc46dcf6fd3906a2a116aa1d6219bfedc3",
883
+ "sha256:d388d1ea8b7447da784e32e3b86a75cce55887e3b22b31c19d0b186b1c677800",
884
+ "sha256:d412a74cf5b3f68a90c615611a5aa4478bb303d1c65961d22db45001df68afcb",
885
+ "sha256:da1001aa46f4490099c82e2facc4fbc06a6a32bf7de3918ba798010954b775e0",
886
+ "sha256:de291633fb9303555793cc544d4a86e858da529b7d0b752bcaf721ae1d74b2c9",
887
+ "sha256:e2e2d47a819d2954f2c1cd0ad51bb58ffac6f53a872d5d82d65d79bf76b9896d",
888
+ "sha256:e53975a6694428a0586534cc1354b2408d4e010a3103117f617cbb550299797c",
889
+ "sha256:e7edb8ec12c100d5458d15b1e47c0eb30ad606a05641f19af7563bc3d1608c14",
890
+ "sha256:e96f6c14c9752bb82145636b614d5a78e9cde95edfbe0a85dad0dd5ddd6ec95c",
891
+ "sha256:e98eee4dca22849fbb56a80acaa899eec5b72055d79637dd6aa15d5e4b8628c9",
892
+ "sha256:ebe63e31f9c1a970c53866d814e35ec2ec26fda03097c486f82f3891cee60830",
893
+ "sha256:ec870fce1ee5248a10be69f7a8408a234d6f2109f8ea827b4f7ecdbf08c9fd15",
894
+ "sha256:ee86d4095d3542d73579e953c2e5e07d9321af2ffea6ecc097d16d538a2dea16",
895
+ "sha256:ef3f1ae08fa9aea5891cbd69df29913e11d3841798e0bfb1ff78b78e4e7ea0a4",
896
+ "sha256:f22dee205329a636148c325921c73cf3e412e87d31f4d9c3153b302a0200057b",
897
+ "sha256:f326a1ac51ae909b9760e34671c26cd0dfe15662f447302a9d5bb2d872bab8ab",
898
+ "sha256:f40df5e0294a95131cc5f0e0eb91fe86d88837abfbee46b9b3610b09860195a7",
899
+ "sha256:f861889707b54a9ab1204030b65fd6c22bdd4a95205deec7994dc22a8baa2ea4",
900
+ "sha256:f9aa93eacd865f2798b9e62f7ce4533cfff4f5fbd50c02926a78e81c74e432cd",
901
+ "sha256:fc9e95ad49c932b80abfbfeaf63b155761e695ad9f8a58c52a47d962d76e310f"
902
+ ],
903
+ "markers": "python_version >= '3.7'",
904
+ "version": "==0.20.1"
905
+ },
906
+ "torch": {
907
+ "hashes": [
908
+ "sha256:03e53f577a96e4d41aca472da8faa40e55df89d2273664af390ce1f570e885bd",
909
+ "sha256:15fbc95e38d330e5b0ef1593b7bc0a19f30e5bdad76895a5cffa1a6a044235e9",
910
+ "sha256:2dd40c885a05ef7fe29356cca81be1435a893096ceb984441d6e2c27aff8c6f4",
911
+ "sha256:38c21ff1bd39f076d72ab06e3c88c2ea6874f2e6f235c9450816b6c8e7627094",
912
+ "sha256:499a68a756d3b30d10f7e0f6214dc3767b130b797265db3b1c02e9094e2a07be",
913
+ "sha256:65e0a60894435608334d68c8811e55fd8f73e5bf8ee6f9ccedb0064486a7b418",
914
+ "sha256:6de1fd253e27e7f01f05cd7c37929ae521ca23ca4620cfc7c485299941679112",
915
+ "sha256:7f179373a047b947dec448243f4e6598a1c960fa3bb978a9a7eecd529fbc363f",
916
+ "sha256:83dcf518685db20912b71fc49cbddcc8849438cdb0e9dcc919b02a849e2cd9e8",
917
+ "sha256:9f3df8138a1126a851440b7d5a4869bfb7c9cc43563d64fd9d96d0465b581024",
918
+ "sha256:b81da3bdb58c9de29d0e1361e52f12fcf10a89673f17a11a5c6c7da1cb1a8376",
919
+ "sha256:ba135923295d564355326dc409b6b7f5bd6edc80f764cdaef1fb0a1b23ff2f9c",
920
+ "sha256:bc52d603d87fe1da24439c0d5fdbbb14e0ae4874451d53f0120ffb1f6c192727",
921
+ "sha256:c54db1fade17287aabbeed685d8e8ab3a56fea9dd8d46e71ced2da367f09a49f",
922
+ "sha256:ce4baeba9804da5a346e210b3b70826f5811330c343e4fe1582200359ee77fe5",
923
+ "sha256:ea718746469246cc63b3353afd75698a288344adb55e29b7f814a5d3c0a7c78d",
924
+ "sha256:f499212f1cffea5d587e5f06144630ed9aa9c399bba12ec8905798d833bd1404"
925
+ ],
926
+ "index": "pypi",
927
+ "markers": "python_full_version >= '3.8.0'",
928
+ "version": "==2.5.0"
929
+ },
930
+ "tqdm": {
931
+ "hashes": [
932
+ "sha256:90279a3770753eafc9194a0364852159802111925aa30eb3f9d85b0e805ac7cd",
933
+ "sha256:e1020aef2e5096702d8a025ac7d16b1577279c9d63f8375b63083e9a5f0fcbad"
934
+ ],
935
+ "markers": "python_version >= '3.7'",
936
+ "version": "==4.66.5"
937
+ },
938
+ "transformers": {
939
+ "hashes": [
940
+ "sha256:3a9e2eb537094db11c3652334d281afa4766c0e5091c4dcdb454e9921bb0d2b7",
941
+ "sha256:e161268ae8bee315eb9e9b4c0b27f1bd6980f91e0fc292d75249193d339704c0"
942
+ ],
943
+ "index": "pypi",
944
+ "markers": "python_full_version >= '3.8.0'",
945
+ "version": "==4.46.0"
946
+ },
947
+ "typing-extensions": {
948
+ "hashes": [
949
+ "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d",
950
+ "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"
951
+ ],
952
+ "markers": "python_version >= '3.8'",
953
+ "version": "==4.12.2"
954
+ },
955
+ "tzdata": {
956
+ "hashes": [
957
+ "sha256:7d85cc416e9382e69095b7bdf4afd9e3880418a2413feec7069d533d6b4e31cc",
958
+ "sha256:a48093786cdcde33cad18c2555e8532f34422074448fbc874186f0abd79565cd"
959
+ ],
960
+ "markers": "python_version >= '2'",
961
+ "version": "==2024.2"
962
+ },
963
+ "urllib3": {
964
+ "hashes": [
965
+ "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac",
966
+ "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9"
967
+ ],
968
+ "markers": "python_version >= '3.8'",
969
+ "version": "==2.2.3"
970
+ },
971
+ "zipp": {
972
+ "hashes": [
973
+ "sha256:a817ac80d6cf4b23bf7f2828b7cabf326f15a001bea8b1f9b49631780ba28350",
974
+ "sha256:bc9eb26f4506fda01b81bcde0ca78103b6e62f991b381fec825435c836edbc29"
975
+ ],
976
+ "markers": "python_version >= '3.8'",
977
+ "version": "==3.20.2"
978
+ }
979
+ },
980
+ "develop": {}
981
+ }
README.md CHANGED
@@ -2,4 +2,51 @@
2
  license: mit
3
  ---
4
 
5
- ESD-u, ESD-x, GA Models
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
  license: mit
3
  ---
4
 
5
+ # Erasing Concepts from Diffusion Models
6
+ ### [Project Website](https://erasing.baulab.info) | [Arxiv Preprint](https://arxiv.org/pdf/2303.07345.pdf) | [Fine-tuned Weights](https://erasing.baulab.info/weights/esd_models/) | [Demo](https://huggingface.co/spaces/baulab/Erasing-Concepts-In-Diffusion) <br>
7
+
8
+ <div align='center'>
9
+ <img src = 'images/applications.png'>
10
+ </div>
11
+
12
+ Motivated by recent advancements in text-to-image diffusion, we study erasure of specific concepts from the model's weights. While Stable Diffusion has shown promise in producing explicit or realistic artwork, it has raised concerns regarding its potential for misuse. We propose a fine-tuning method that can erase a visual concept from a pre-trained diffusion model, given only the name of the style and using negative guidance as a teacher. We benchmark our method against previous approaches that remove sexually explicit content and demonstrate its effectiveness, performing on par with Safe Latent Diffusion and censored training.
13
+
14
+ To evaluate artistic style removal, we conduct experiments erasing five modern artists from the network and conduct a user study to assess the human perception of the removed styles. Unlike previous methods, our approach can remove concepts from a diffusion model permanently rather than modifying the output at the inference time, so it cannot be circumvented even if a user has access to model weights
15
+
16
+ Given only a short text description of an undesired visual concept and no additional data, our method fine-tunes model weights to erase the targeted concept. Our method can avoid NSFW content, stop imitation of a specific artist's style, or even erase a whole object class from model output, while preserving the model's behavior and capabilities on other topics.
17
+
18
+ ## Fine-tuned Weights
19
+
20
+ The finetuned weights for both NSFW and art style erasures are available on our [project page](https://erasing.baulab.info).
21
+
22
+ ## Running Gradio Demo Locally
23
+
24
+ To run the gradio interactive demo locally, clone the files from [demo repository](https://huggingface.co/spaces/baulab/Erasing-Concepts-In-Diffusion/tree/main) <br>
25
+
26
+ * Create an environment using the packages included in the requirements.txt file
27
+ * Run `python app.py`
28
+ * Open the application in browser at `http://127.0.0.1:7860/`
29
+ * Train, evaluate, and save models using our method
30
+
31
+ ## Installation Guide
32
+
33
+ * To get started clone the following repository of Original Stable Diffusion [Link](https://github.com/CompVis/stable-diffusion)
34
+ * Then download the files from our repository to `stable-diffusion` main directory of stable diffusion. This would replace the `ldm` folder of the original repo with our custom `ldm` directory
35
+ * Download the weights from [here](https://huggingface.co/CompVis/stable-diffusion-v-1-4-original/resolve/main/sd-v1-4-full-ema.ckpt) and move them to `stable-diffusion/models/ldm/` (This will be `ckpt_path` variable in `train-scripts/train-esd.py`)
36
+ * [Only for training] To convert your trained models to diffusers download the diffusers Unet config from [here](https://huggingface.co/CompVis/stable-diffusion-v1-4/blob/main/unet/config.json) (This will be `diffusers_config_path` variable in `train-scripts/train-esd.py`)
37
+
38
+ ## Training Guide
39
+
40
+ After installation, follow these instructions to train a custom ESD model:
41
+
42
+ * `cd stable-diffusion` to the main repository of stable-diffusion
43
+ * [IMPORTANT] Edit `train-script/train-esd.py` and change the default argparser values according to your convenience (especially the config paths)
44
+ * To choose train_method, pick from following `'xattn'`,`'noxattn'`, `'selfattn'`, `'full'`
45
+ * `python train-scripts/train-esd.py --prompt 'your prompt' --train_method 'your choice of training' --devices '0,1'`
46
+
47
+ Note that the default argparser values must be changed!
48
+
49
+ The optimization process for erasing undesired visual concepts from pre-trained diffusion model weights involves using a short text description of the concept as guidance. The ESD model is fine-tuned with the conditioned and unconditioned scores obtained from frozen SD model to guide the output away from the concept being erased. The model learns from it's own knowledge to steer the diffusion process away from the undesired concept.
50
+ <div align='center'>
51
+ <img src = 'images/ESD.png'>
52
+ </div>
esd-vangogh_from_vangogh-noxattn_1-epochs_200.pt → models/ESD-U/esd-vangogh_from_vangogh-noxattn_1-epochs_200.pt RENAMED
File without changes
esd-picasso_from_picasso-xattn_1-epochs_200.pt → models/ESD-X/esd-picasso_from_picasso-xattn_1-epochs_200.pt RENAMED
File without changes