Mathieu5454 commited on
Commit
a5af814
·
1 Parent(s): 5112289

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +485 -0
app.py ADDED
@@ -0,0 +1,485 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+
3
+ import os
4
+
5
+ from PIL import Image, ImageOps
6
+
7
+ import matplotlib.pyplot as plt
8
+
9
+ import numpy as np
10
+
11
+ import torch
12
+
13
+ import requests
14
+
15
+ from tqdm import tqdm
16
+
17
+ from io import BytesIO
18
+
19
+
20
+
21
+ from diffusers import StableDiffusionImg2ImgPipeline, StableDiffusionInpaintPipeline
22
+
23
+ import torchvision.transforms as T
24
+
25
+
26
+
27
+ from utils import preprocess,prepare_mask_and_masked_image, recover_image
28
+
29
+
30
+
31
+ to_pil = T.ToPILImage()
32
+
33
+
34
+
35
+ model_id_or_path = "runwayml/stable-diffusion-v1-5"
36
+
37
+ # model_id_or_path = "CompVis/stable-diffusion-v1-4"
38
+
39
+ # model_id_or_path = "CompVis/stable-diffusion-v1-3"
40
+
41
+ # model_id_or_path = "CompVis/stable-diffusion-v1-2"
42
+
43
+ # model_id_or_path = "CompVis/stable-diffusion-v1-1"
44
+
45
+
46
+
47
+ pipe_img2img = StableDiffusionImg2ImgPipeline.from_pretrained(
48
+
49
+ model_id_or_path,
50
+
51
+ revision="fp16",
52
+
53
+ torch_dtype=torch.float16,
54
+
55
+ )
56
+
57
+ pipe_img2img = pipe_img2img.to("cuda")
58
+
59
+
60
+
61
+ pipe_inpaint = StableDiffusionInpaintPipeline.from_pretrained(
62
+
63
+ "runwayml/stable-diffusion-inpainting",
64
+
65
+ revision="fp16",
66
+
67
+ torch_dtype=torch.float16,
68
+
69
+ )
70
+
71
+ pipe_inpaint = pipe_inpaint.to("cuda")
72
+
73
+
74
+
75
+ def pgd(X, model, eps=0.1, step_size=0.015, iters=40, clamp_min=0, clamp_max=1, mask=None):
76
+
77
+ X_adv = X.clone().detach() + (torch.rand(*X.shape)*2*eps-eps).cuda()
78
+
79
+ pbar = tqdm(range(iters))
80
+
81
+ for i in pbar:
82
+
83
+ actual_step_size = step_size - (step_size - step_size / 100) / iters * i
84
+
85
+
86
+
87
+ X_adv.requires_grad_(True)
88
+
89
+
90
+
91
+ loss = (model(X_adv).latent_dist.mean).norm()
92
+
93
+
94
+
95
+ pbar.set_description(f"[Running attack]: Loss {loss.item():.5f} | step size: {actual_step_size:.4}")
96
+
97
+
98
+
99
+ grad, = torch.autograd.grad(loss, [X_adv])
100
+
101
+
102
+
103
+ X_adv = X_adv - grad.detach().sign() * actual_step_size
104
+
105
+ X_adv = torch.minimum(torch.maximum(X_adv, X - eps), X + eps)
106
+
107
+ X_adv.data = torch.clamp(X_adv, min=clamp_min, max=clamp_max)
108
+
109
+ X_adv.grad = None
110
+
111
+
112
+
113
+ if mask is not None:
114
+
115
+ X_adv.data *= mask
116
+
117
+
118
+
119
+ return X_adv
120
+
121
+
122
+
123
+ def pgd_inpaint(X, target, model, criterion, eps=0.1, step_size=0.015, iters=40, clamp_min=0, clamp_max=1, mask=None):
124
+
125
+ X_adv = X.clone().detach() + (torch.rand(*X.shape)*2*eps-eps).cuda()
126
+
127
+ pbar = tqdm(range(iters))
128
+
129
+ for i in pbar:
130
+
131
+ actual_step_size = step_size - (step_size - step_size / 100) / iters * i
132
+
133
+ X_adv.requires_grad_(True)
134
+
135
+
136
+
137
+ loss = (model(X_adv).latent_dist.mean - target).norm()
138
+
139
+
140
+
141
+ pbar.set_description(f"[Running attack]: Loss {loss.item():.5f} | step size: {actual_step_size:.4}")
142
+
143
+
144
+
145
+ grad, = torch.autograd.grad(loss, [X_adv])
146
+
147
+
148
+
149
+ X_adv = X_adv - grad.detach().sign() * actual_step_size
150
+
151
+ X_adv = torch.minimum(torch.maximum(X_adv, X - eps), X + eps)
152
+
153
+ X_adv.data = torch.clamp(X_adv, min=clamp_min, max=clamp_max)
154
+
155
+ X_adv.grad = None
156
+
157
+
158
+
159
+ if mask is not None:
160
+
161
+ X_adv.data *= mask
162
+
163
+
164
+
165
+ return X_adv
166
+
167
+
168
+
169
+ def process_image_img2img(raw_image,prompt, scale, num_steps, seed):
170
+
171
+ resize = T.transforms.Resize(512)
172
+
173
+ center_crop = T.transforms.CenterCrop(512)
174
+
175
+ init_image = center_crop(resize(raw_image))
176
+
177
+ with torch.autocast('cuda'):
178
+
179
+ X = preprocess(init_image).half().cuda()
180
+
181
+ adv_X = pgd(X,
182
+
183
+ model=pipe_img2img.vae.encode,
184
+
185
+ clamp_min=-1,
186
+
187
+ clamp_max=1,
188
+
189
+ eps=0.06, # The higher, the less imperceptible the attack is
190
+
191
+ step_size=0.02, # Set smaller than eps
192
+
193
+ iters=100, # The higher, the stronger your attack will be
194
+
195
+ )
196
+
197
+
198
+
199
+ # convert pixels back to [0,1] range
200
+
201
+ adv_X = (adv_X / 2 + 0.5).clamp(0, 1)
202
+
203
+
204
+
205
+ adv_image = to_pil(adv_X[0]).convert("RGB")
206
+
207
+
208
+
209
+ # a good seed (uncomment the line below to generate new images)
210
+
211
+ SEED = seed# Default is 9222
212
+
213
+ # SEED = np.random.randint(low=0, high=10000)
214
+
215
+
216
+
217
+ # Play with these for improving generated image quality
218
+
219
+ STRENGTH = 0.5
220
+
221
+ GUIDANCE = scale # Default is 7.5
222
+
223
+ NUM_STEPS = num_steps # Default is 50
224
+
225
+
226
+
227
+ with torch.autocast('cuda'):
228
+
229
+ torch.manual_seed(SEED)
230
+
231
+ image_nat = pipe_img2img(prompt=prompt, image=init_image, strength=STRENGTH, guidance_scale=GUIDANCE, num_inference_steps=NUM_STEPS).images[0]
232
+
233
+ torch.manual_seed(SEED)
234
+
235
+ image_adv = pipe_img2img(prompt=prompt, image=adv_image, strength=STRENGTH, guidance_scale=GUIDANCE, num_inference_steps=NUM_STEPS).images[0]
236
+
237
+
238
+
239
+ return [(init_image,"Source Image"), (adv_image, "Adv Image"), (image_nat,"Gen. Image Nat"), (image_adv, "Gen. Image Adv")]
240
+
241
+
242
+
243
+ def process_image_inpaint(raw_image,mask, prompt,scale, num_steps, seed):
244
+
245
+ init_image = raw_image.convert('RGB').resize((512,512))
246
+
247
+ mask_image = mask.convert('RGB')
248
+
249
+ mask_image = ImageOps.invert(mask_image).resize((512,512))
250
+
251
+
252
+
253
+ # Attack using embedding of random image from internet
254
+
255
+ target_url = "https://bostonglobe-prod.cdn.arcpublishing.com/resizer/2-ZvyQ3aRNl_VNo7ja51BM5-Kpk=/960x0/cloudfront-us-east-1.images.arcpublishing.com/bostonglobe/CZOXE32LQQX5UNAB42AOA3SUY4.jpg"
256
+
257
+ response = requests.get(target_url)
258
+
259
+ target_image = Image.open(BytesIO(response.content)).convert("RGB")
260
+
261
+ target_image = target_image.resize((512, 512))
262
+
263
+
264
+
265
+ with torch.autocast('cuda'):
266
+
267
+ mask, X = prepare_mask_and_masked_image(init_image, mask_image)
268
+
269
+ X = X.half().cuda()
270
+
271
+ mask = mask.half().cuda()
272
+
273
+
274
+
275
+ # Here we attack towards the embedding of a random target image. You can also simply attack towards an embedding of zeros!
276
+
277
+ target = pipe_inpaint.vae.encode(preprocess(target_image).half().cuda()).latent_dist.mean
278
+
279
+
280
+
281
+ adv_X = pgd_inpaint(X,
282
+
283
+ target = target,
284
+
285
+ model=pipe_inpaint.vae.encode,
286
+
287
+ criterion=torch.nn.MSELoss(),
288
+
289
+ clamp_min=-1,
290
+
291
+ clamp_max=1,
292
+
293
+ eps=0.06,
294
+
295
+ step_size=0.01,
296
+
297
+ iters=1000,
298
+
299
+ mask=1-mask
300
+
301
+ )
302
+
303
+
304
+
305
+ adv_X = (adv_X / 2 + 0.5).clamp(0, 1)
306
+
307
+
308
+
309
+ adv_image = to_pil(adv_X[0]).convert("RGB")
310
+
311
+ adv_image = recover_image(adv_image, init_image, mask_image, background=True)
312
+
313
+
314
+
315
+ # A good seed
316
+
317
+ SEED = seed #Default is 9209
318
+
319
+
320
+
321
+ # Uncomment the below to generated other images
322
+
323
+ # SEED = np.random.randint(low=0, high=100000)
324
+
325
+
326
+
327
+ torch.manual_seed(SEED)
328
+
329
+ print(SEED)
330
+
331
+
332
+
333
+ #strength = 0.7
334
+
335
+ guidance_scale = scale# Default is 7.5
336
+
337
+ num_inference_steps = num_steps # Default is 100
338
+
339
+
340
+
341
+ image_nat = pipe_inpaint(prompt=prompt,
342
+
343
+ image=init_image,
344
+
345
+ mask_image=mask_image,
346
+
347
+ eta=1,
348
+
349
+ num_inference_steps=num_inference_steps,
350
+
351
+ guidance_scale=guidance_scale
352
+
353
+ #strength=strength
354
+
355
+ ).images[0]
356
+
357
+ image_nat = recover_image(image_nat, init_image, mask_image)
358
+
359
+
360
+
361
+ torch.manual_seed(SEED)
362
+
363
+ image_adv = pipe_inpaint(prompt=prompt,
364
+
365
+ image=adv_image,
366
+
367
+ mask_image=mask_image,
368
+
369
+ eta=1,
370
+
371
+ num_inference_steps=num_inference_steps,
372
+
373
+ guidance_scale=guidance_scale
374
+
375
+ #strength=strength
376
+
377
+ ).images[0]
378
+
379
+ image_adv = recover_image(image_adv, init_image, mask_image)
380
+
381
+
382
+
383
+ return [(init_image,"Source Image"), (adv_image, "Adv Image"), (image_nat,"Gen. Image Nat"), (image_adv, "Gen. Image Adv")]
384
+
385
+
386
+
387
+
388
+
389
+ examples_list = [["dog.png", "dog under heavy rain and muddy ground real", 7.5, 50, 9222]]
390
+
391
+
392
+
393
+
394
+
395
+ with gr.Blocks() as demo:
396
+
397
+ gr.Markdown("""
398
+
399
+ ## Interactive demo: Raising the Cost of Malicious AI-Powered Image Editing
400
+
401
+ """)
402
+
403
+ gr.HTML('''
404
+
405
+ <p style="margin-bottom: 10px; font-size: 94%">This is an unofficial demo for Photoguard, which is an approach to safeguarding images against manipulation by ML-powered photo-editing models such as stable diffusion through immunization of images. The demo is based on the <a href='https://github.com/MadryLab/photoguard' style='text-decoration: underline;' target='_blank'> Github </a> implementation provided by the authors.</p>
406
+
407
+ ''')
408
+
409
+ gr.HTML('''
410
+
411
+ <p align="center"><img src="https://raw.githubusercontent.com/MadryLab/photoguard/main/assets/hero_fig.PNG" style="width:60%"/></p>
412
+
413
+ ''')
414
+
415
+ gr.HTML('''
416
+
417
+ <p style="margin-bottom: 10px; font-size: 94%"> A malevolent actor might download
418
+
419
+ photos of people posted online and edit them maliciously using an off-the-shelf diffusion model. The adversary
420
+
421
+ describes via a textual prompt the desired changes and then uses a diffusion model to generate a realistic
422
+
423
+ image that matches the prompt (similar to the top row in the image). By immunizing the original image before the adversary can access it,
424
+
425
+ we disrupt their ability to successfully perform such edits forcing them to generate unrealistic images (similar to the bottom row in the image). For a more detailed explanation, please read the accompanying <a href='https://arxiv.org/abs/2302.06588' style='text-decoration: underline;' target='_blank'> Paper </a> or <a href='https://gradientscience.org/photoguard/' style='text-decoration: underline;' target='_blank'> Blogpost </a>
426
+
427
+ ''')
428
+
429
+
430
+
431
+ with gr.Column():
432
+
433
+ with gr.Tab("Simple Image to Image"):
434
+
435
+ input_image_img2img = gr.Image(type="pil", label = "Source Image")
436
+
437
+ input_prompt_img2img = gr.Textbox(label="Prompt")
438
+
439
+ run_btn_img2img = gr.Button('Run')
440
+
441
+
442
+
443
+ with gr.Tab("Simple Inpainting"):
444
+
445
+ input_image_inpaint = gr.Image(type="pil", label = "Source Image")
446
+
447
+ mask_image_inpaint = gr.Image(type="pil", label = "Mask")
448
+
449
+ input_prompt_inpaint = gr.Textbox(label="Prompt")
450
+
451
+ run_btn_inpaint = gr.Button('Run')
452
+
453
+
454
+
455
+ with gr.Accordion("Advanced options", open=False):
456
+
457
+ scale = gr.Slider(label="Guidance Scale", minimum=0.1, maximum=30.0, value=7.5, step=0.1)
458
+
459
+ num_steps = gr.Slider(label="Number of Inference Steps", minimum=5, maximum=125, value=100, step=5)
460
+
461
+ seed = gr.Slider(label="Seed", minimum=0, maximum=2147483647, step=1, randomize=True)
462
+
463
+
464
+
465
+ with gr.Row():
466
+
467
+ result_gallery = gr.Gallery(
468
+
469
+ label="Generated images", show_label=False, elem_id="gallery"
470
+
471
+ ).style(grid=[2], height="auto")
472
+
473
+
474
+
475
+ run_btn_img2img.click(process_image_img2img, inputs = [input_image_img2img,input_prompt_img2img, scale, num_steps, seed], outputs = [result_gallery])
476
+
477
+ examples = gr.Examples(examples=examples_list,inputs = [input_image_img2img,input_prompt_img2img,scale, num_steps, seed], outputs = [result_gallery], cache_examples = True, fn = process_image_img2img)
478
+
479
+ run_btn_inpaint.click(process_image_inpaint, inputs = [input_image_inpaint,mask_image_inpaint,input_prompt_inpaint,scale, num_steps, seed], outputs = [result_gallery])
480
+
481
+
482
+
483
+
484
+
485
+ demo.launch(debug=True)