realrebelai commited on
Commit
84efbf2
·
verified ·
1 Parent(s): 5e01b65

Upload app.py

Browse files
Files changed (1) hide show
  1. app.py +120 -0
app.py ADDED
@@ -0,0 +1,120 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ # ZeroGPU runs on MIG slices; torch's expandable-segments allocator makes NVML
3
+ # calls that fail on MIG and surface as "NVML_SUCCESS == r INTERNAL ASSERT
4
+ # FAILED (CUDACachingAllocator)". Must be set before torch is imported.
5
+ os.environ.setdefault("PYTORCH_CUDA_ALLOC_CONF", "expandable_segments:False")
6
+
7
+ import random
8
+
9
+ import gradio as gr
10
+ import spaces
11
+ import torch
12
+ from diffusers import Krea2Pipeline
13
+ from transformers import AutoConfig, AutoModel, AutoTokenizer, Qwen2Tokenizer
14
+
15
+ # ----------------------------------------------------------------------------
16
+ # Krea-R-Turbo = Krea 2 Turbo + RebelReal @ 0.31 + RebelMidjourney @ 0.13
17
+ # LoRAs are fused at startup, so inference cost is identical to the base model.
18
+ # ----------------------------------------------------------------------------
19
+ BASE = "krea/Krea-2-Turbo"
20
+
21
+ # Krea's repo ships only tokenizer.json (fast format), but the pipeline's
22
+ # model_index declares the slow Qwen2Tokenizer, and diffusers' class check
23
+ # rejects a fast instance. So: load fast (with extra_special_tokens={} to
24
+ # dodge the list-vs-dict bug in transformers 4.x), export it — which writes
25
+ # the vocab.json/merges.txt the slow class needs — then load the slow class
26
+ # from the export. Verified: slow/fast produce identical token ids.
27
+ _fast = AutoTokenizer.from_pretrained(BASE, subfolder="tokenizer",
28
+ use_fast=True, extra_special_tokens={})
29
+ _fast.save_pretrained("/tmp/krea_tokenizer")
30
+ tokenizer = Qwen2Tokenizer.from_pretrained("/tmp/krea_tokenizer",
31
+ extra_special_tokens={})
32
+
33
+ # Krea's text_encoder config has rope_scaling: null; transformers 4.57's
34
+ # Qwen3-VL calls .get() on it and crashes. Inject the dict with the exact
35
+ # values 4.57 defaults to anyway, so the math is unchanged.
36
+ te_cfg = AutoConfig.from_pretrained(BASE, subfolder="text_encoder")
37
+ _txt = getattr(te_cfg, "text_config", te_cfg)
38
+ if getattr(_txt, "rope_scaling", None) is None:
39
+ _txt.rope_scaling = {"rope_type": "default", "mrope_section": [24, 20, 20]}
40
+ text_encoder = AutoModel.from_pretrained(BASE, subfolder="text_encoder",
41
+ config=te_cfg, torch_dtype=torch.bfloat16)
42
+
43
+ pipe = Krea2Pipeline.from_pretrained(BASE, tokenizer=tokenizer,
44
+ text_encoder=text_encoder,
45
+ torch_dtype=torch.bfloat16)
46
+
47
+ pipe.load_lora_weights("realrebelai/RebelReal_LoRA_Collection",
48
+ weight_name="RebelReal_(Krea-2).safetensors",
49
+ adapter_name="rebelreal")
50
+ pipe.load_lora_weights("realrebelai/RebelMidjourney_LoRA_Collection",
51
+ weight_name="RebelMidjourney_(Krea-2).safetensors",
52
+ adapter_name="rebelmj")
53
+ pipe.set_adapters(["rebelreal", "rebelmj"], adapter_weights=[0.31, 0.13])
54
+ # Bake the LoRAs into the weights (same math as an offline merge), then drop
55
+ # the adapter machinery so sampling has zero LoRA overhead.
56
+ pipe.fuse_lora(adapter_names=["rebelreal", "rebelmj"])
57
+ pipe.unload_lora_weights()
58
+
59
+ pipe.to("cuda")
60
+ # trim peak VRAM: tiled VAE decode costs ~nothing at these resolutions and
61
+ # keeps headroom on the ZeroGPU slice alongside 35 GB of packed weights
62
+ if hasattr(pipe, "vae") and hasattr(pipe.vae, "enable_tiling"):
63
+ pipe.vae.enable_tiling()
64
+
65
+ MAX_SEED = 2**31 - 1
66
+
67
+
68
+ @spaces.GPU(duration=60)
69
+ def generate(prompt, width, height, steps, seed, randomize_seed,
70
+ progress=gr.Progress(track_tqdm=True)):
71
+ if randomize_seed:
72
+ seed = random.randint(0, MAX_SEED)
73
+ generator = torch.Generator("cuda").manual_seed(int(seed))
74
+ image = pipe(
75
+ prompt=prompt,
76
+ width=int(width),
77
+ height=int(height),
78
+ num_inference_steps=int(steps),
79
+ guidance_scale=0.0, # Turbo is CFG-free
80
+ generator=generator,
81
+ ).images[0]
82
+ return image, seed
83
+
84
+
85
+ with gr.Blocks(title="Krea-R-Turbo") as demo:
86
+ gr.Markdown(
87
+ """
88
+ # Krea-R-Turbo
89
+ **Krea 2 Turbo** with RealRebelAI's **RebelReal** (0.31) and
90
+ **RebelMidjourney** (0.13) LoRAs fused in. 8-step, CFG-free.
91
+
92
+ GGUF quants for local ComfyUI (8 GB VRAM+):
93
+ [realrebelai/Krea-R-Turbo](https://huggingface.co/realrebelai/Krea-R-Turbo)
94
+ """
95
+ )
96
+ with gr.Row():
97
+ with gr.Column():
98
+ prompt = gr.Textbox(label="Prompt", lines=3,
99
+ placeholder="a cinematic photo of ...")
100
+ run = gr.Button("Generate", variant="primary")
101
+ with gr.Accordion("Settings", open=False):
102
+ with gr.Row():
103
+ width = gr.Slider(512, 2048, value=1280, step=64, label="Width")
104
+ height = gr.Slider(512, 2048, value=1024, step=64, label="Height")
105
+ steps = gr.Slider(4, 12, value=8, step=1, label="Steps")
106
+ with gr.Row():
107
+ seed = gr.Slider(0, MAX_SEED, value=0, step=1, label="Seed")
108
+ randomize_seed = gr.Checkbox(value=True, label="Random seed")
109
+ with gr.Column():
110
+ out = gr.Image(label="Result", format="png")
111
+ used_seed = gr.Number(label="Seed used", interactive=False)
112
+
113
+ run.click(generate,
114
+ inputs=[prompt, width, height, steps, seed, randomize_seed],
115
+ outputs=[out, used_seed])
116
+ prompt.submit(generate,
117
+ inputs=[prompt, width, height, steps, seed, randomize_seed],
118
+ outputs=[out, used_seed])
119
+
120
+ demo.launch()