multimodalart HF Staff commited on
Commit
ccfbf24
·
verified ·
1 Parent(s): ad6ce4d

Upload folder using huggingface_hub

Browse files
.gitattributes CHANGED
@@ -33,3 +33,6 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ examples/cat_tabby.jpg filter=lfs diff=lfs merge=lfs -text
37
+ examples/city_skyline_night.jpg filter=lfs diff=lfs merge=lfs -text
38
+ examples/sushi_platter.jpg filter=lfs diff=lfs merge=lfs -text
README.md CHANGED
@@ -1,13 +1,30 @@
1
  ---
2
- title: Grug 9b Demo
3
- emoji: 👀
4
- colorFrom: pink
5
- colorTo: gray
6
  sdk: gradio
7
  sdk_version: 6.20.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: Grug-9B Reasoning VLM
3
+ emoji: 🧠
4
+ colorFrom: red
5
+ colorTo: yellow
6
  sdk: gradio
7
  sdk_version: 6.20.0
 
8
  app_file: app.py
9
+ short_description: 9B reasoning VLM with vision and shortened thinking
10
+ python_version: "3.12"
11
+ startup_duration_timeout: 1h
12
  ---
13
 
14
+ # Grug-9B Reasoning VLM
15
+
16
+ A demo for [ProCreations/grug-9b](https://huggingface.co/ProCreations/grug-9b) — a 9B-parameter vision-language reasoning model fine-tuned from Ornith-1.0-9B (Qwen3.5 architecture) to produce shorter internal reasoning while maintaining coding and agent capabilities.
17
+
18
+ ## Features
19
+
20
+ - **Vision + Language**: Upload an image and ask questions about it.
21
+ - **Reasoning**: The model thinks inside `` tags before producing its answer.
22
+ - **Chat**: Multi-turn conversation with the model.
23
+ - **Code**: Ask the model to write functions, explain concepts, etc.
24
+
25
+ ## Usage
26
+
27
+ 1. Optionally upload an image.
28
+ 2. Type your message in the text box.
29
+ 3. Press Send or hit Enter.
30
+ 4. Adjust advanced settings (max tokens, temperature, thinking mode) as needed.
app.py ADDED
@@ -0,0 +1,219 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+
3
+ os.environ.setdefault("PYTORCH_CUDA_ALLOC_CONF", "expandable_segments:True")
4
+
5
+ import spaces # MUST come before torch / transformers
6
+ import torch
7
+ import gradio as gr
8
+ import numpy as np
9
+ from PIL import Image
10
+ from threading import Thread
11
+ from transformers import (
12
+ AutoProcessor,
13
+ Qwen3_5ForConditionalGeneration,
14
+ TextIteratorStreamer,
15
+ )
16
+
17
+ MODEL_ID = "ProCreations/grug-9b"
18
+
19
+ print(f"Loading model {MODEL_ID} ...")
20
+ processor = AutoProcessor.from_pretrained(MODEL_ID)
21
+ model = Qwen3_5ForConditionalGeneration.from_pretrained(
22
+ MODEL_ID,
23
+ torch_dtype=torch.bfloat16,
24
+ ).to("cuda").eval()
25
+ print("Model loaded.")
26
+
27
+
28
+ @spaces.GPU(duration=120)
29
+ def chat_with_image(
30
+ image: Image.Image,
31
+ message: str,
32
+ history: list,
33
+ max_new_tokens: int = 1024,
34
+ temperature: float = 0.7,
35
+ enable_thinking: bool = True,
36
+ ):
37
+ """Chat with the grug-9b reasoning VLM about an image.
38
+
39
+ Args:
40
+ image: An optional image to discuss with the model.
41
+ message: The user's text message / question.
42
+ history: Prior conversation turns (list of [user, assistant] pairs).
43
+ max_new_tokens: Maximum number of tokens to generate.
44
+ temperature: Sampling temperature; lower = more deterministic.
45
+ enable_thinking: Whether the model produces reasoning inside tags.
46
+ """
47
+ if not message or not message.strip():
48
+ yield history + [(message, "")], "Please enter a message."
49
+ return
50
+
51
+ # Build the conversation
52
+ messages = []
53
+ if image is not None:
54
+ messages.append({
55
+ "role": "user",
56
+ "content": [
57
+ {"type": "image", "image": image},
58
+ {"type": "text", "text": message},
59
+ ],
60
+ })
61
+ else:
62
+ messages.append({"role": "user", "content": message})
63
+
64
+ # Add conversation history
65
+ conv_messages = []
66
+ for user_msg, asst_msg in history:
67
+ conv_messages.append({"role": "user", "content": user_msg})
68
+ if asst_msg:
69
+ conv_messages.append({"role": "assistant", "content": asst_msg})
70
+ conv_messages.extend(messages)
71
+
72
+ # Prepare inputs
73
+ if image is not None:
74
+ text = processor.apply_chat_template(
75
+ conv_messages,
76
+ tokenize=False,
77
+ add_generation_prompt=True,
78
+ enable_thinking=enable_thinking,
79
+ )
80
+ inputs = processor(
81
+ text=[text],
82
+ images=[image],
83
+ return_tensors="pt",
84
+ padding=True,
85
+ ).to("cuda")
86
+ else:
87
+ text = processor.apply_chat_template(
88
+ conv_messages,
89
+ tokenize=False,
90
+ add_generation_prompt=True,
91
+ enable_thinking=enable_thinking,
92
+ )
93
+ inputs = processor(
94
+ text=[text],
95
+ return_tensors="pt",
96
+ padding=True,
97
+ ).to("cuda")
98
+
99
+ # Stream the response
100
+ streamer = TextIteratorStreamer(
101
+ processor.tokenizer,
102
+ skip_prompt=True,
103
+ skip_special_tokens=True,
104
+ timeout=120,
105
+ )
106
+
107
+ generation_kwargs = dict(
108
+ **inputs,
109
+ streamer=streamer,
110
+ max_new_tokens=max_new_tokens,
111
+ temperature=temperature,
112
+ use_cache=True,
113
+ )
114
+
115
+ thread = Thread(target=model.generate, kwargs=generation_kwargs)
116
+ thread.start()
117
+
118
+ full_response = ""
119
+ new_history = history + [(message, "")]
120
+ for token in streamer:
121
+ full_response += token
122
+ new_history[-1] = (message, full_response)
123
+ yield new_history, ""
124
+
125
+ thread.join()
126
+ yield new_history, ""
127
+
128
+
129
+ CSS = """
130
+ #col-container { max-width: 1100px; margin: 0 auto; }
131
+ .dark .gradio-container { color: var(--body-text-color); }
132
+ """
133
+
134
+ with gr.Blocks(theme=gr.themes.Citrus(), css=CSS) as demo:
135
+ gr.Markdown(
136
+ """
137
+ # 🧠 Grug-9B Reasoning VLM
138
+ A 9B-parameter vision-language reasoning model fine-tuned from Ornith-1.0-9B (Qwen3.5 architecture)
139
+ to "think small" — shorter internal reasoning while maintaining coding and agent capabilities.
140
+
141
+ Upload an image (optional) and ask a question. The model reasons inside `` tags before answering.
142
+ """
143
+ )
144
+
145
+ with gr.Column(elem_id="col-container"):
146
+ with gr.Row():
147
+ image_input = gr.Image(
148
+ label="Image (optional)",
149
+ type="pil",
150
+ height=350,
151
+ )
152
+ with gr.Column(scale=2):
153
+ chatbot = gr.Chatbot(
154
+ label="Chat",
155
+ height=450,
156
+ show_label=True,
157
+ )
158
+ msg_input = gr.Textbox(
159
+ label="Message",
160
+ placeholder="Ask something about the image, or just chat...",
161
+ show_label=False,
162
+ lines=2,
163
+ )
164
+ with gr.Row():
165
+ send_btn = gr.Button("Send", variant="primary", scale=2)
166
+ clear_btn = gr.Button("Clear", scale=1)
167
+
168
+ with gr.Accordion("Advanced settings", open=False):
169
+ with gr.Row():
170
+ max_tokens = gr.Slider(
171
+ label="Max new tokens",
172
+ minimum=128,
173
+ maximum=4096,
174
+ value=1024,
175
+ step=128,
176
+ )
177
+ temperature = gr.Slider(
178
+ label="Temperature",
179
+ minimum=0.1,
180
+ maximum=2.0,
181
+ value=0.7,
182
+ step=0.1,
183
+ )
184
+ thinking_toggle = gr.Checkbox(
185
+ label="Enable thinking (reasoning mode)",
186
+ value=True,
187
+ )
188
+
189
+ gr.Examples(
190
+ examples=[
191
+ [None, "Write a Python function that checks if a number is prime.", 512, 0.7, True],
192
+ [None, "Explain the difference between TCP and UDP in networking.", 1024, 0.7, True],
193
+ ["examples/cat_tabby.jpg", "What breed is this cat? Describe what you see in detail.", 1024, 0.7, True],
194
+ ["examples/city_skyline_night.jpg", "What city might this be? Describe the architectural style.", 1024, 0.7, True],
195
+ ["examples/sushi_platter.jpg", "What kinds of sushi are on this platter?", 1024, 0.7, True],
196
+ ],
197
+ inputs=[image_input, msg_input, max_tokens, temperature, thinking_toggle],
198
+ outputs=[chatbot, msg_input],
199
+ fn=chat_with_image,
200
+ cache_examples=True,
201
+ cache_mode="lazy",
202
+ )
203
+
204
+ def clear_chat():
205
+ return [], ""
206
+
207
+ clear_btn.click(clear_chat, outputs=[chatbot, msg_input])
208
+ send_btn.click(
209
+ chat_with_image,
210
+ inputs=[image_input, msg_input, chatbot, max_tokens, temperature, thinking_toggle],
211
+ outputs=[chatbot, msg_input],
212
+ )
213
+ msg_input.submit(
214
+ chat_with_image,
215
+ inputs=[image_input, msg_input, chatbot, max_tokens, temperature, thinking_toggle],
216
+ outputs=[chatbot, msg_input],
217
+ )
218
+
219
+ demo.launch(mcp_server=True)
examples/cat_tabby.jpg ADDED

Git LFS Details

  • SHA256: 7d17010bdc32ffc33df0e3fae71660db6e896ae759edb0202857120afda9f296
  • Pointer size: 131 Bytes
  • Size of remote file: 232 kB
examples/city_skyline_night.jpg ADDED

Git LFS Details

  • SHA256: dfad69af4d0d10417a5b6e049e97fe2827dbd29133fe0b390abc20ba9e786600
  • Pointer size: 131 Bytes
  • Size of remote file: 160 kB
examples/sushi_platter.jpg ADDED

Git LFS Details

  • SHA256: 6b8b64a5d2a67358ea20653ec59b01c559fcce52eed9fba277d6f0485c965da5
  • Pointer size: 131 Bytes
  • Size of remote file: 124 kB
requirements.txt ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ transformers==5.13.0
2
+ accelerate
3
+ sentencepiece
4
+ qwen-vl-utils
5
+ einops
6
+ pillow
7
+ numpy
8
+ torchvision