kiel840524 commited on
Commit
c62e5df
·
verified ·
1 Parent(s): f9307a8

pin the quantisation stack that matches this NF4 checkpoint

Browse files
Files changed (1) hide show
  1. app.py +97 -93
app.py CHANGED
@@ -1,93 +1,97 @@
1
- """FLUX.2 [dev] 4-bit studio — text-to-image and multi-reference editing, self-contained.
2
-
3
- Runs the pre-quantized `diffusers/FLUX.2-dev-bnb-4bit` checkpoint: full dev quality at
4
- about a fifth of the footprint, with the text encoder loaded INSIDE this Space. That
5
- last part matters — the public dev demo delegates its text encoder to a separate Space,
6
- so it breaks for good whenever that other Space goes away.
7
-
8
- The /infer signature mirrors the common FLUX.2 Space API, so existing clients only need
9
- to change the space id.
10
- """
11
- import os
12
- import random
13
-
14
- import gradio as gr
15
- import numpy as np
16
- import spaces
17
- import torch
18
- from diffusers import Flux2Pipeline
19
- from PIL import Image
20
-
21
- MODEL_ID = os.environ.get("FLUX2_MODEL", "diffusers/FLUX.2-dev-bnb-4bit")
22
- MAX_SEED = np.iinfo(np.int32).max
23
- MAX_SIDE = 1536
24
-
25
- pipe = Flux2Pipeline.from_pretrained(MODEL_ID, torch_dtype=torch.bfloat16)
26
- pipe.enable_model_cpu_offload() # 4-bit weights still want room to breathe
27
-
28
-
29
- def _duration(prompt, image_list, seed, width, height, num_inference_steps, guidance_scale):
30
- """ZeroGPU reserves the slot before the call and passes it the same arguments, so
31
- this signature must mirror _run's exactly."""
32
- n = 1 + 0.6 * len(image_list or [])
33
- return int(min(300, max(90, int(num_inference_steps) * 2.4 * n + 40)))
34
-
35
-
36
- @spaces.GPU(duration=_duration)
37
- def _run(prompt, image_list, seed, width, height, num_inference_steps, guidance_scale):
38
- generator = torch.Generator(device="cuda").manual_seed(int(seed))
39
- kwargs = dict(prompt=prompt, width=int(width), height=int(height),
40
- num_inference_steps=int(num_inference_steps),
41
- guidance_scale=float(guidance_scale), generator=generator)
42
- if image_list:
43
- kwargs["image"] = image_list
44
- return pipe(**kwargs).images[0]
45
-
46
-
47
- def infer(prompt, input_images, seed=0, randomize_seed=False, width=1024, height=1024,
48
- num_inference_steps=28, guidance_scale=4.0, prompt_upsampling=False,
49
- progress=gr.Progress(track_tqdm=True)):
50
- if randomize_seed:
51
- seed = random.randint(0, MAX_SEED)
52
- images = []
53
- for item in (input_images or []):
54
- path = item[0] if isinstance(item, (list, tuple)) else item
55
- if isinstance(path, dict):
56
- path = path.get("image") or path.get("path") or path.get("name")
57
- if path:
58
- im = Image.open(path).convert("RGB")
59
- im.thumbnail((MAX_SIDE, MAX_SIDE))
60
- images.append(im)
61
- width = min(int(width), MAX_SIDE)
62
- height = min(int(height), MAX_SIDE)
63
- out = _run(prompt, images, seed, width, height, num_inference_steps, guidance_scale)
64
- return out, seed
65
-
66
-
67
- with gr.Blocks(title="FLUX.2 dev 4-bit studio") as demo:
68
- gr.Markdown("## FLUX.2 [dev] 4-bit studio\nText-to-image and multi-reference editing. "
69
- "Self-contained: the text encoder lives in this Space.")
70
- with gr.Row():
71
- with gr.Column():
72
- prompt = gr.Textbox(label="Prompt", lines=4)
73
- input_images = gr.Gallery(label="Reference images (optional)", type="filepath",
74
- columns=4, height=200)
75
- run = gr.Button("Generate", variant="primary")
76
- with gr.Accordion("Settings", open=False):
77
- seed = gr.Slider(0, MAX_SEED, value=0, step=1, label="Seed")
78
- randomize_seed = gr.Checkbox(True, label="Randomize seed")
79
- width = gr.Slider(256, MAX_SIDE, value=1024, step=32, label="Width")
80
- height = gr.Slider(256, MAX_SIDE, value=1024, step=32, label="Height")
81
- num_inference_steps = gr.Slider(4, 50, value=28, step=1, label="Steps")
82
- guidance_scale = gr.Slider(1.0, 10.0, value=4.0, step=0.1, label="Guidance")
83
- prompt_upsampling = gr.Checkbox(False, label="Prompt upsampling (unused)")
84
- with gr.Column():
85
- result = gr.Image(label="Result", type="pil")
86
- used_seed = gr.Number(label="Seed used")
87
-
88
- run.click(infer,
89
- inputs=[prompt, input_images, seed, randomize_seed, width, height,
90
- num_inference_steps, guidance_scale, prompt_upsampling],
91
- outputs=[result, used_seed], api_name="infer")
92
-
93
- demo.queue().launch(show_error=True)
 
 
 
 
 
1
+ """FLUX.2 [dev] 4-bit studio — text-to-image and multi-reference editing, self-contained.
2
+
3
+ Runs the pre-quantized `diffusers/FLUX.2-dev-bnb-4bit` checkpoint: full dev quality at
4
+ about a fifth of the footprint, with the text encoder loaded INSIDE this Space. That
5
+ last part matters — the public dev demo delegates its text encoder to a separate Space,
6
+ so it breaks for good whenever that other Space goes away.
7
+
8
+ The /infer signature mirrors the common FLUX.2 Space API, so existing clients only need
9
+ to change the space id.
10
+ """
11
+ import os
12
+ import random
13
+
14
+ import gradio as gr
15
+ import numpy as np
16
+ import spaces
17
+ import torch
18
+ from diffusers import Flux2Pipeline
19
+ from PIL import Image
20
+
21
+ MODEL_ID = os.environ.get("FLUX2_MODEL", "diffusers/FLUX.2-dev-bnb-4bit")
22
+ MAX_SEED = np.iinfo(np.int32).max
23
+ MAX_SIDE = 1536
24
+
25
+ pipe = Flux2Pipeline.from_pretrained(
26
+ MODEL_ID,
27
+ torch_dtype=torch.bfloat16,
28
+ device_map=None, # let the offload hook place things, not the loader
29
+ )
30
+ pipe.enable_model_cpu_offload() # 4-bit weights still want room to breathe
31
+
32
+
33
+ def _duration(prompt, image_list, seed, width, height, num_inference_steps, guidance_scale):
34
+ """ZeroGPU reserves the slot before the call and passes it the same arguments, so
35
+ this signature must mirror _run's exactly."""
36
+ n = 1 + 0.6 * len(image_list or [])
37
+ return int(min(300, max(90, int(num_inference_steps) * 2.4 * n + 40)))
38
+
39
+
40
+ @spaces.GPU(duration=_duration)
41
+ def _run(prompt, image_list, seed, width, height, num_inference_steps, guidance_scale):
42
+ generator = torch.Generator(device="cuda").manual_seed(int(seed))
43
+ kwargs = dict(prompt=prompt, width=int(width), height=int(height),
44
+ num_inference_steps=int(num_inference_steps),
45
+ guidance_scale=float(guidance_scale), generator=generator)
46
+ if image_list:
47
+ kwargs["image"] = image_list
48
+ return pipe(**kwargs).images[0]
49
+
50
+
51
+ def infer(prompt, input_images, seed=0, randomize_seed=False, width=1024, height=1024,
52
+ num_inference_steps=28, guidance_scale=4.0, prompt_upsampling=False,
53
+ progress=gr.Progress(track_tqdm=True)):
54
+ if randomize_seed:
55
+ seed = random.randint(0, MAX_SEED)
56
+ images = []
57
+ for item in (input_images or []):
58
+ path = item[0] if isinstance(item, (list, tuple)) else item
59
+ if isinstance(path, dict):
60
+ path = path.get("image") or path.get("path") or path.get("name")
61
+ if path:
62
+ im = Image.open(path).convert("RGB")
63
+ im.thumbnail((MAX_SIDE, MAX_SIDE))
64
+ images.append(im)
65
+ width = min(int(width), MAX_SIDE)
66
+ height = min(int(height), MAX_SIDE)
67
+ out = _run(prompt, images, seed, width, height, num_inference_steps, guidance_scale)
68
+ return out, seed
69
+
70
+
71
+ with gr.Blocks(title="FLUX.2 dev 4-bit studio") as demo:
72
+ gr.Markdown("## FLUX.2 [dev] 4-bit studio\nText-to-image and multi-reference editing. "
73
+ "Self-contained: the text encoder lives in this Space.")
74
+ with gr.Row():
75
+ with gr.Column():
76
+ prompt = gr.Textbox(label="Prompt", lines=4)
77
+ input_images = gr.Gallery(label="Reference images (optional)", type="filepath",
78
+ columns=4, height=200)
79
+ run = gr.Button("Generate", variant="primary")
80
+ with gr.Accordion("Settings", open=False):
81
+ seed = gr.Slider(0, MAX_SEED, value=0, step=1, label="Seed")
82
+ randomize_seed = gr.Checkbox(True, label="Randomize seed")
83
+ width = gr.Slider(256, MAX_SIDE, value=1024, step=32, label="Width")
84
+ height = gr.Slider(256, MAX_SIDE, value=1024, step=32, label="Height")
85
+ num_inference_steps = gr.Slider(4, 50, value=28, step=1, label="Steps")
86
+ guidance_scale = gr.Slider(1.0, 10.0, value=4.0, step=0.1, label="Guidance")
87
+ prompt_upsampling = gr.Checkbox(False, label="Prompt upsampling (unused)")
88
+ with gr.Column():
89
+ result = gr.Image(label="Result", type="pil")
90
+ used_seed = gr.Number(label="Seed used")
91
+
92
+ run.click(infer,
93
+ inputs=[prompt, input_images, seed, randomize_seed, width, height,
94
+ num_inference_steps, guidance_scale, prompt_upsampling],
95
+ outputs=[result, used_seed], api_name="infer")
96
+
97
+ demo.queue().launch(show_error=True)