Deadmon commited on
Commit
23c3d80
1 Parent(s): a686326

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +119 -36
app.py CHANGED
@@ -1,48 +1,131 @@
1
- import torch
2
- from diffusers.utils import load_image
3
- from diffusers import FluxControlNetPipeline, FluxControlNetModel
4
  import os
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
 
6
- # Clear unnecessary memory
7
- torch.cuda.empty_cache()
 
 
8
 
9
- # Set the environment variable to handle memory fragmentation
10
- os.environ["PYTORCH_CUDA_ALLOC_CONF"] = "expandable_segments:True"
 
 
 
 
 
 
 
 
11
 
12
- base_model = 'black-forest-labs/FLUX.1-dev'
13
- controlnet_model = 'InstantX/FLUX.1-dev-Controlnet-Union'
 
 
14
 
15
- # Use mixed precision with float16
16
- controlnet = FluxControlNetModel.from_pretrained(controlnet_model, torch_dtype=torch.float16)
17
- pipe = FluxControlNetPipeline.from_pretrained(base_model, controlnet=controlnet, torch_dtype=torch.float16)
 
 
 
 
18
 
19
- # Offload some parts to CPU
20
- pipe.enable_model_cpu_offload()
 
 
 
 
 
21
 
22
- pipe.to("cuda")
 
 
 
 
 
 
 
23
 
24
- control_image_canny = load_image("https://huggingface.co/InstantX/FLUX.1-dev-Controlnet-Union-alpha/resolve/main/images/canny.jpg")
25
- controlnet_conditioning_scale = 0.5
26
- control_mode = 0
 
27
 
28
- # Reduce the image resolution if needed to fit into memory
29
- width, height = control_image_canny.size
30
- width = width // 2
31
- height = height // 2
32
 
33
- prompt = 'A bohemian-style female travel blogger with sun-kissed skin and messy beach waves.'
 
 
 
 
34
 
35
- image = pipe(
36
- prompt,
37
- control_image=control_image_canny,
38
- control_mode=control_mode,
39
- width=width,
40
- height=height,
41
- controlnet_conditioning_scale=controlnet_conditioning_scale,
42
- num_inference_steps=24,
43
- guidance_scale=3.5,
44
- ).images[0]
45
- image.save("image.jpg")
 
 
 
 
 
46
 
47
- # Empty cache after the operation to free up memory
48
- torch.cuda.empty_cache()
 
 
 
 
 
1
  import os
2
+ import torch
3
+ import gradio as gr
4
+ import numpy as np
5
+ from PIL import Image
6
+ from einops import rearrange
7
+ import requests
8
+ import spaces
9
+ from huggingface_hub import login
10
+ from gradio_imageslider import ImageSlider # Import ImageSlider
11
+
12
+ from image_datasets.canny_dataset import canny_processor, c_crop
13
+ from src.flux.sampling import denoise_controlnet, get_noise, get_schedule, prepare, unpack
14
+ from src.flux.util import load_ae, load_clip, load_t5, load_flow_model, load_controlnet, load_safetensors
15
+
16
+ # Download and load the ControlNet model
17
+ model_url = "https://huggingface.co/XLabs-AI/flux-controlnet-canny-v3/resolve/main/flux-canny-controlnet-v3.safetensors?download=true"
18
+ model_path = "./flux-canny-controlnet-v3.safetensors"
19
+ if not os.path.exists(model_path):
20
+ response = requests.get(model_url)
21
+ with open(model_path, 'wb') as f:
22
+ f.write(response.content)
23
+
24
+ # Source: https://github.com/XLabs-AI/x-flux.git
25
+ name = "flux-dev"
26
+ device = torch.device("cuda")
27
+ offload = False
28
+ is_schnell = name == "flux-schnell"
29
+
30
+ model, ae, t5, clip, controlnet = None, None, None, None, None
31
+
32
+ def load_models():
33
+ global model, ae, t5, clip, controlnet
34
+ t5 = load_t5(device, max_length=256 if is_schnell else 512)
35
+ clip = load_clip(device)
36
+ model = load_flow_model(name, device=device)
37
+ ae = load_ae(name, device=device)
38
+ controlnet = load_controlnet(name, device).to(device).to(torch.bfloat16)
39
+
40
+ checkpoint = load_safetensors(model_path)
41
+ controlnet.load_state_dict(checkpoint, strict=False)
42
+
43
+ load_models()
44
+
45
+ def preprocess_image(image, target_width, target_height, crop=True):
46
+ if crop:
47
+ image = c_crop(image) # Crop the image to square
48
+ original_width, original_height = image.size
49
 
50
+ # Resize to match the target size without stretching
51
+ scale = max(target_width / original_width, target_height / original_height)
52
+ resized_width = int(scale * original_width)
53
+ resized_height = int(scale * original_height)
54
 
55
+ image = image.resize((resized_width, resized_height), Image.LANCZOS)
56
+
57
+ # Center crop to match the target dimensions
58
+ left = (resized_width - target_width) // 2
59
+ top = (resized_height - target_height) // 2
60
+ image = image.crop((left, top, left + target_width, top + target_height))
61
+ else:
62
+ image = image.resize((target_width, target_height), Image.LANCZOS)
63
+
64
+ return image
65
 
66
+ def preprocess_canny_image(image, target_width, target_height, crop=True):
67
+ image = preprocess_image(image, target_width, target_height, crop=crop)
68
+ image = canny_processor(image)
69
+ return image
70
 
71
+ @spaces.GPU(duration=120)
72
+ def generate_image(prompt, control_image, num_steps=50, guidance=4, width=512, height=512, seed=42, random_seed=False):
73
+ if random_seed:
74
+ seed = np.random.randint(0, 10000)
75
+
76
+ if not os.path.isdir("./controlnet_results/"):
77
+ os.makedirs("./controlnet_results/")
78
 
79
+ torch_device = torch.device("cuda")
80
+
81
+ model.to(torch_device)
82
+ t5.to(torch_device)
83
+ clip.to(torch_device)
84
+ ae.to(torch_device)
85
+ controlnet.to(torch_device)
86
 
87
+ width = 16 * width // 16
88
+ height = 16 * height // 16
89
+ timesteps = get_schedule(num_steps, (width // 8) * (height // 8) // (16 * 16), shift=(not is_schnell))
90
+
91
+ processed_input = preprocess_image(control_image, width, height)
92
+ canny_processed = preprocess_canny_image(control_image, width, height)
93
+ controlnet_cond = torch.from_numpy((np.array(canny_processed) / 127.5) - 1)
94
+ controlnet_cond = controlnet_cond.permute(2, 0, 1).unsqueeze(0).to(torch.bfloat16).to(torch_device)
95
 
96
+ torch.manual_seed(seed)
97
+ with torch.no_grad():
98
+ x = get_noise(1, height, width, device=torch_device, dtype=torch.bfloat16, seed=seed)
99
+ inp_cond = prepare(t5=t5, clip=clip, img=x, prompt=prompt)
100
 
101
+ x = denoise_controlnet(model, **inp_cond, controlnet=controlnet, timesteps=timesteps, guidance=guidance, controlnet_cond=controlnet_cond)
102
+
103
+ x = unpack(x.float(), height, width)
104
+ x = ae.decode(x)
105
 
106
+ x1 = x.clamp(-1, 1)
107
+ x1 = rearrange(x1[-1], "c h w -> h w c")
108
+ output_img = Image.fromarray((127.5 * (x1 + 1.0)).cpu().byte().numpy())
109
+
110
+ return [processed_input, output_img] # Return both images for slider
111
 
112
+ interface = gr.Interface(
113
+ fn=generate_image,
114
+ inputs=[
115
+ gr.Textbox(label="Prompt"),
116
+ gr.Image(type="pil", label="Control Image"),
117
+ gr.Slider(step=1, minimum=1, maximum=64, value=28, label="Num Steps"),
118
+ gr.Slider(minimum=0.1, maximum=10, value=4, label="Guidance"),
119
+ gr.Slider(minimum=128, maximum=2048, step=128, value=1024, label="Width"),
120
+ gr.Slider(minimum=128, maximum=2048, step=128, value=1024, label="Height"),
121
+ gr.Number(value=42, label="Seed"),
122
+ gr.Checkbox(label="Random Seed")
123
+ ],
124
+ outputs=ImageSlider(label="Before / After"), # Use ImageSlider as the output
125
+ title="FLUX.1 Controlnet Canny",
126
+ description="Generate images using ControlNet and a text prompt.\n[[non-commercial license, Flux.1 Dev](https://huggingface.co/black-forest-labs/FLUX.1-dev/blob/main/LICENSE.md)]"
127
+ )
128
 
129
+ if __name__ == "__main__":
130
+ interface.launch()
131
+