multimodalart HF Staff commited on
Commit
39049cd
·
verified ·
1 Parent(s): f0b2268

Upload folder using huggingface_hub

Browse files
Files changed (4) hide show
  1. README.md +10 -7
  2. __pycache__/app.cpython-312.pyc +0 -0
  3. app.py +224 -0
  4. requirements.txt +3 -0
README.md CHANGED
@@ -1,13 +1,16 @@
1
  ---
2
- title: Diffusiongemma 26B A4B It
3
- emoji: 📚
4
- colorFrom: gray
5
- colorTo: red
6
  sdk: gradio
7
  sdk_version: 6.18.0
8
- python_version: '3.12'
9
  app_file: app.py
10
- pinned: false
 
 
11
  ---
12
 
13
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
1
  ---
2
+ title: DiffusionGemma 26B A4B
3
+ emoji: 🌀
4
+ colorFrom: blue
5
+ colorTo: indigo
6
  sdk: gradio
7
  sdk_version: 6.18.0
 
8
  app_file: app.py
9
+ short_description: Block-diffusion chat with live denoising canvas
10
+ python_version: "3.12"
11
+ startup_duration_timeout: 1h
12
  ---
13
 
14
+ # DiffusionGemma 26B-A4B
15
+
16
+ Chat demo for [google/diffusiongemma-26B-A4B-it](https://huggingface.co/google/diffusiongemma-26B-A4B-it) with a real-time visualization of the block-diffusion denoising canvas. Supports image input and a thinking mode.
__pycache__/app.cpython-312.pyc ADDED
Binary file (11.5 kB). View file
 
app.py ADDED
@@ -0,0 +1,224 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import spaces
2
+ import torch
3
+ import gradio as gr
4
+ from threading import Thread
5
+ from queue import Queue
6
+ from transformers import DiffusionGemmaForBlockDiffusion, AutoProcessor, TextDiffusionStreamer
7
+
8
+ MODEL_ID = "google/diffusiongemma-26B-A4B-it"
9
+
10
+ processor = AutoProcessor.from_pretrained(MODEL_ID)
11
+ model = DiffusionGemmaForBlockDiffusion.from_pretrained(MODEL_ID, dtype=torch.bfloat16)
12
+ model.to("cuda")
13
+ model.eval()
14
+
15
+ _SENTINEL = object()
16
+
17
+
18
+ class CanvasStreamer(TextDiffusionStreamer):
19
+ """Pushes (committed_text, draft_text) snapshots to a queue for live visualization.
20
+
21
+ `put_draft` fires every denoising step with the full canvas of the block being
22
+ denoised (the text morphs as it denoises). `put` fires when a canvas/block is
23
+ committed. The prompt is skipped via `skip_prompt`.
24
+ """
25
+
26
+ def __init__(self, tokenizer, **kwargs):
27
+ super().__init__(tokenizer, skip_prompt=True, skip_special_tokens=True, **kwargs)
28
+ self.queue = Queue()
29
+ self.committed = ""
30
+ self._takes_logits = False
31
+
32
+ def put_draft(self, value, **kwargs):
33
+ if len(value.shape) > 1:
34
+ value = value[0]
35
+ draft = self.tokenizer.decode(value, skip_special_tokens=True)
36
+ self.queue.put((self.committed, draft))
37
+
38
+ def put(self, value):
39
+ if len(value.shape) > 1 and value.shape[0] > 1:
40
+ raise ValueError("batch size 1 only")
41
+ elif len(value.shape) > 1:
42
+ value = value[0]
43
+ if self.skip_prompt and self.next_tokens_are_prompt:
44
+ self.next_tokens_are_prompt = False
45
+ return
46
+ self.committed += self.tokenizer.decode(value, skip_special_tokens=True)
47
+ self.queue.put((self.committed, ""))
48
+
49
+ def end(self):
50
+ self.next_tokens_are_prompt = True
51
+ self.queue.put(_SENTINEL)
52
+
53
+
54
+ def build_highlight(committed, draft):
55
+ """Committed text green ('high'), in-progress draft canvas yellow ('mid')."""
56
+ out = []
57
+ if committed:
58
+ out.append((committed, "high"))
59
+ if draft:
60
+ out.append((draft, "mid"))
61
+ return out
62
+
63
+
64
+ @spaces.GPU(duration=150, size="xlarge")
65
+ @torch.no_grad()
66
+ def generate_streaming(messages, max_new_tokens, max_denoising_steps, enable_thinking):
67
+ inputs = processor.apply_chat_template(
68
+ messages,
69
+ add_generation_prompt=True,
70
+ tokenize=True,
71
+ return_dict=True,
72
+ return_tensors="pt",
73
+ enable_thinking=enable_thinking,
74
+ ).to("cuda")
75
+ prompt_len = inputs["input_ids"].shape[1]
76
+
77
+ streamer = CanvasStreamer(processor.tokenizer)
78
+ result = {}
79
+
80
+ def run():
81
+ try:
82
+ out = model.generate(
83
+ **inputs,
84
+ max_new_tokens=int(max_new_tokens),
85
+ max_denoising_steps=int(max_denoising_steps),
86
+ streamer=streamer,
87
+ )
88
+ result["ids"] = out
89
+ except Exception as e:
90
+ result["error"] = e
91
+ streamer.queue.put(_SENTINEL)
92
+
93
+ thread = Thread(target=run)
94
+ thread.start()
95
+
96
+ while True:
97
+ item = streamer.queue.get()
98
+ if item is _SENTINEL:
99
+ break
100
+ committed, draft = item
101
+ yield build_highlight(committed, draft), (committed + draft), None
102
+
103
+ thread.join()
104
+ if "error" in result:
105
+ raise result["error"]
106
+
107
+ generated = result["ids"][0][prompt_len:]
108
+ final_text = processor.decode(generated, skip_special_tokens=True).strip()
109
+ yield build_highlight(final_text, ""), final_text, final_text
110
+
111
+
112
+ def to_model_messages(history):
113
+ """Convert Gradio messages history into processor chat format with images."""
114
+ messages = []
115
+ for msg in history:
116
+ role = msg["role"]
117
+ content = msg["content"]
118
+ if isinstance(content, str):
119
+ parts = [{"type": "text", "text": content}]
120
+ elif isinstance(content, (list, tuple)):
121
+ # Gradio file tuple (path, alt) or list of content dicts
122
+ parts = []
123
+ if isinstance(content, tuple):
124
+ parts.append({"type": "image", "url": content[0]})
125
+ else:
126
+ for item in content:
127
+ if isinstance(item, dict) and item.get("type") == "text":
128
+ parts.append({"type": "text", "text": item["text"]})
129
+ elif isinstance(item, dict) and "path" in item:
130
+ parts.append({"type": "image", "url": item["path"]})
131
+ else:
132
+ parts = [{"type": "text", "text": str(content)}]
133
+ messages.append({"role": role, "content": parts})
134
+ return messages
135
+
136
+
137
+ css = """
138
+ .category-legend{display:none}
139
+ .legend{margin-bottom: 5px}
140
+ .legend-item{height: 25px}
141
+ """
142
+
143
+
144
+ def create_demo():
145
+ with gr.Blocks(css=css, title="DiffusionGemma") as demo:
146
+ gr.Markdown("# DiffusionGemma 26B-A4B — Block Diffusion Chat")
147
+ gr.Markdown(
148
+ "[model](https://huggingface.co/google/diffusiongemma-26B-A4B-it) · "
149
+ "Watch the canvas denoise in real time on the right. Attach an image to ask about it."
150
+ )
151
+
152
+ with gr.Row():
153
+ with gr.Column(scale=3):
154
+ chatbot = gr.Chatbot(label="Conversation", type="messages", height=520)
155
+ chat_input = gr.MultimodalTextbox(
156
+ interactive=True,
157
+ file_types=["image"],
158
+ placeholder="Type a message and/or attach an image…",
159
+ show_label=False,
160
+ )
161
+ with gr.Column(scale=2):
162
+ canvas = gr.HighlightedText(
163
+ label="Denoising canvas",
164
+ combine_adjacent=False,
165
+ show_legend=True,
166
+ color_map={"mid": "#FFAA33", "high": "#66CC66"},
167
+ )
168
+
169
+ with gr.Accordion("Generation settings", open=False):
170
+ with gr.Row():
171
+ enable_thinking = gr.Checkbox(value=False, label="Thinking mode")
172
+ with gr.Row():
173
+ max_new_tokens = gr.Slider(64, 1024, value=256, step=64, label="Max new tokens")
174
+ max_denoising_steps = gr.Slider(8, 64, value=48, step=4, label="Max denoising steps")
175
+
176
+ clear_btn = gr.Button("Clear conversation")
177
+
178
+ def add_message(message, history):
179
+ history = history or []
180
+ for f in message.get("files", []):
181
+ history.append({"role": "user", "content": {"path": f}})
182
+ if message.get("text"):
183
+ history.append({"role": "user", "content": message["text"]})
184
+ return history, gr.MultimodalTextbox(value=None, interactive=False)
185
+
186
+ def bot(history, max_new_tokens, max_denoising_steps, enable_thinking):
187
+ if not history:
188
+ yield history, []
189
+ return
190
+ messages = to_model_messages(history)
191
+ history = history + [{"role": "assistant", "content": ""}]
192
+ final = None
193
+ try:
194
+ for canvas_state, plain, text in generate_streaming(
195
+ messages, max_new_tokens, max_denoising_steps, enable_thinking
196
+ ):
197
+ if text is not None:
198
+ final = text
199
+ history[-1]["content"] = final if final is not None else plain
200
+ yield history, canvas_state
201
+ except Exception as e:
202
+ history[-1]["content"] = f"Error: {e}"
203
+ yield history, [(str(e), "mid")]
204
+
205
+ def reenable():
206
+ return gr.MultimodalTextbox(interactive=True)
207
+
208
+ chat_msg = chat_input.submit(
209
+ add_message, [chat_input, chatbot], [chatbot, chat_input]
210
+ )
211
+ bot_msg = chat_msg.then(
212
+ bot,
213
+ [chatbot, max_new_tokens, max_denoising_steps, enable_thinking],
214
+ [chatbot, canvas],
215
+ )
216
+ bot_msg.then(reenable, None, [chat_input])
217
+
218
+ clear_btn.click(lambda: ([], []), None, [chatbot, canvas])
219
+
220
+ return demo
221
+
222
+
223
+ if __name__ == "__main__":
224
+ create_demo().queue().launch()
requirements.txt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ transformers
2
+ accelerate
3
+ torchvision