prog-love commited on
Commit
f6717ba
·
1 Parent(s): c41a6ad
Files changed (1) hide show
  1. app.py +185 -106
app.py CHANGED
@@ -14,7 +14,7 @@ from threading import Thread
14
 
15
 
16
  # =============================================================================
17
- # CONFIG
18
  # =============================================================================
19
 
20
  MODEL_ID = "prog-love/rostam-r1-stage13-1"
@@ -22,38 +22,77 @@ MODEL_ID = "prog-love/rostam-r1-stage13-1"
22
  print("=" * 70)
23
  print("ROSTAM R1")
24
  print("=" * 70)
25
- print(f"Loading model: {MODEL_ID}")
26
- print(f"Transformers: {transformers.__version__}")
27
- print(f"PyTorch: {torch.__version__}")
28
- print(f"CUDA available: {torch.cuda.is_available()}")
29
 
30
  if torch.cuda.is_available():
31
- print(f"CUDA device: {torch.cuda.get_device_name(0)}")
32
 
33
 
34
  # =============================================================================
35
- # GEMMA 4 / HETEROGENEOUS CONFIG COMPATIBILITY
36
  # =============================================================================
37
  #
38
- # The current Transformers stack can reject Gemma 4 configs containing
39
- # per-layer attributes such as `head_dim` when architecture validation tries
40
- # to access them globally.
41
  #
42
- # We explicitly allow that access while the configuration is being created.
 
 
43
  #
44
- # This does NOT modify the model checkpoint or its weights.
 
 
 
 
 
 
 
 
 
 
45
  # =============================================================================
46
 
 
 
47
  try:
48
- from transformers.integrations.heterogeneity.configuration_utils import (
49
- AmbiguousGlobalPerLayerAttributeError,
 
50
  )
51
 
52
- print("Detected Transformers heterogeneous configuration support.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53
 
54
- except ImportError:
55
- AmbiguousGlobalPerLayerAttributeError = None
56
- print("No heterogeneous configuration module detected.")
 
 
 
 
 
57
 
58
 
59
  # =============================================================================
@@ -67,44 +106,37 @@ config = AutoConfig.from_pretrained(
67
  trust_remote_code=True,
68
  )
69
 
70
- # The exact flag used by the error message.
71
- #
72
- # It may live directly on the configuration object depending on the
73
- # Transformers version.
74
- if hasattr(config, "allow_global_per_layer_attribute_access"):
75
- config.allow_global_per_layer_attribute_access = True
76
 
77
- # Gemma4 contains a nested text configuration.
78
- if hasattr(config, "text_config"):
79
- try:
80
- config.text_config.allow_global_per_layer_attribute_access = True
81
- except Exception:
82
- pass
83
 
 
 
 
84
 
85
- # Some Transformers versions expose the flag through the heterogeneity
86
- # configuration machinery instead of the top-level config.
87
- #
88
- # Set it defensively where available.
89
- for cfg in (
90
- config,
91
- getattr(config, "text_config", None),
92
- ):
 
 
 
 
 
93
 
94
- if cfg is None:
95
- continue
96
 
97
- try:
98
  object.__setattr__(
99
- cfg,
100
  "allow_global_per_layer_attribute_access",
101
  True,
102
  )
103
- except Exception:
104
- pass
105
-
106
 
107
- print("Configuration loaded.")
 
108
 
109
 
110
  # =============================================================================
@@ -118,7 +150,7 @@ tokenizer = AutoTokenizer.from_pretrained(
118
  trust_remote_code=True,
119
  )
120
 
121
- print("Tokenizer loaded.")
122
 
123
 
124
  # =============================================================================
@@ -139,9 +171,15 @@ model.eval()
139
 
140
  print("Model loaded successfully.")
141
 
 
 
 
 
 
142
  if torch.cuda.is_available():
143
- allocated = torch.cuda.memory_allocated() / 1024**3
144
- reserved = torch.cuda.memory_reserved() / 1024**3
 
145
 
146
  print(
147
  f"GPU memory: "
@@ -149,15 +187,22 @@ if torch.cuda.is_available():
149
  f"{reserved:.2f} GB reserved"
150
  )
151
 
 
 
 
152
  print("=" * 70)
153
 
154
 
155
  # =============================================================================
156
- # CSS
157
  # =============================================================================
158
 
159
  CUSTOM_CSS = """
160
- /* Persian / RTL messages */
 
 
 
 
161
  .message-wrap {
162
  direction: rtl !important;
163
  text-align: right !important;
@@ -168,34 +213,50 @@ CUSTOM_CSS = """
168
  text-align: right !important;
169
  }
170
 
171
- /* Chat bubbles */
172
  .chatbot {
173
- direction: rtl;
174
  }
175
 
176
- /* User input */
 
 
 
 
177
  textarea {
178
  direction: rtl !important;
179
  text-align: right !important;
180
  }
181
 
182
- /* Hide Gradio footer */
183
- footer {
184
- display: none !important;
185
- }
186
 
187
- /* Better Persian rendering */
 
 
 
188
  .prose {
189
  direction: rtl;
190
  text-align: right;
191
  }
192
 
193
- /* Keep code blocks LTR */
 
 
 
 
194
  pre,
195
  code {
196
  direction: ltr !important;
197
  text-align: left !important;
198
  }
 
 
 
 
 
 
 
 
 
 
199
  """
200
 
201
 
@@ -212,15 +273,13 @@ def generate_response(
212
  top_p,
213
  max_new_tokens,
214
  ):
215
- """
216
- Generate a streaming response from Rostam.
217
- """
218
 
219
  messages = []
220
 
221
- # -------------------------------------------------------------------------
222
- # System prompt
223
- # -------------------------------------------------------------------------
 
224
 
225
  if system_prompt and system_prompt.strip():
226
 
@@ -231,9 +290,10 @@ def generate_response(
231
  }
232
  )
233
 
234
- # -------------------------------------------------------------------------
235
- # Conversation history
236
- # -------------------------------------------------------------------------
 
237
 
238
  if history:
239
 
@@ -257,9 +317,10 @@ def generate_response(
257
  }
258
  )
259
 
260
- # -------------------------------------------------------------------------
261
- # Current message
262
- # -------------------------------------------------------------------------
 
263
 
264
  messages.append(
265
  {
@@ -268,9 +329,10 @@ def generate_response(
268
  }
269
  )
270
 
271
- # -------------------------------------------------------------------------
272
- # Chat template
273
- # -------------------------------------------------------------------------
 
274
 
275
  prompt = tokenizer.apply_chat_template(
276
  messages,
@@ -278,18 +340,21 @@ def generate_response(
278
  add_generation_prompt=True,
279
  )
280
 
281
- # -------------------------------------------------------------------------
282
- # Tokenization
283
- # -------------------------------------------------------------------------
 
284
 
285
  inputs = tokenizer(
286
  prompt,
287
  return_tensors="pt",
288
  )
289
 
290
- # device_map="auto" places the model on the appropriate device.
291
- #
292
- # For a single-GPU deployment this normally means CUDA.
 
 
293
  if torch.cuda.is_available():
294
 
295
  inputs = {
@@ -297,9 +362,10 @@ def generate_response(
297
  for key, value in inputs.items()
298
  }
299
 
300
- # -------------------------------------------------------------------------
301
- # Streamer
302
- # -------------------------------------------------------------------------
 
303
 
304
  streamer = TextIteratorStreamer(
305
  tokenizer,
@@ -307,14 +373,16 @@ def generate_response(
307
  skip_special_tokens=True,
308
  )
309
 
310
- # -------------------------------------------------------------------------
311
- # Generation parameters
312
- # -------------------------------------------------------------------------
 
313
 
314
  temperature = float(temperature)
315
  top_p = float(top_p)
316
  max_new_tokens = int(max_new_tokens)
317
 
 
318
  generation_kwargs = {
319
  **inputs,
320
 
@@ -331,9 +399,10 @@ def generate_response(
331
  ),
332
  }
333
 
334
- # -------------------------------------------------------------------------
335
- # Sampling
336
- # -------------------------------------------------------------------------
 
337
 
338
  if temperature <= 0:
339
 
@@ -345,9 +414,10 @@ def generate_response(
345
  generation_kwargs["temperature"] = temperature
346
  generation_kwargs["top_p"] = top_p
347
 
348
- # -------------------------------------------------------------------------
349
- # Start generation thread
350
- # -------------------------------------------------------------------------
 
351
 
352
  thread = Thread(
353
  target=model.generate,
@@ -357,9 +427,10 @@ def generate_response(
357
 
358
  thread.start()
359
 
360
- # -------------------------------------------------------------------------
361
- # Stream output
362
- # -------------------------------------------------------------------------
 
363
 
364
  partial_text = ""
365
 
@@ -371,7 +442,7 @@ def generate_response(
371
 
372
 
373
  # =============================================================================
374
- # GRADIO UI
375
  # =============================================================================
376
 
377
  with gr.Blocks(
@@ -380,9 +451,10 @@ with gr.Blocks(
380
  title="رستم",
381
  ) as demo:
382
 
383
- # -------------------------------------------------------------------------
384
- # Header
385
- # -------------------------------------------------------------------------
 
386
 
387
  gr.Markdown(
388
  """
@@ -392,9 +464,10 @@ with gr.Blocks(
392
  """
393
  )
394
 
395
- # -------------------------------------------------------------------------
396
- # Advanced settings
397
- # -------------------------------------------------------------------------
 
398
 
399
  with gr.Accordion(
400
  "تنظیمات پیشرفته",
@@ -407,6 +480,7 @@ with gr.Blocks(
407
  lines=2,
408
  )
409
 
 
410
  with gr.Row():
411
 
412
  temperature = gr.Slider(
@@ -417,6 +491,7 @@ with gr.Blocks(
417
  label="Temperature",
418
  )
419
 
 
420
  top_p = gr.Slider(
421
  minimum=0.1,
422
  maximum=1.0,
@@ -425,6 +500,7 @@ with gr.Blocks(
425
  label="Top-p",
426
  )
427
 
 
428
  max_new_tokens = gr.Slider(
429
  minimum=32,
430
  maximum=8000,
@@ -433,9 +509,10 @@ with gr.Blocks(
433
  label="حداکثر طول پاسخ",
434
  )
435
 
436
- # -------------------------------------------------------------------------
437
- # Chat
438
- # -------------------------------------------------------------------------
 
439
 
440
  chat = gr.ChatInterface(
441
  fn=generate_response,
@@ -455,6 +532,7 @@ with gr.Blocks(
455
  0.9,
456
  512,
457
  ],
 
458
  [
459
  "تو چه مدلی هستی؟",
460
  "",
@@ -462,6 +540,7 @@ with gr.Blocks(
462
  0.9,
463
  512,
464
  ],
 
465
  [
466
  "دربارهٔ رستم و سهراب برام بگو",
467
  "",
 
14
 
15
 
16
  # =============================================================================
17
+ # ROSTAM R1 CONFIG
18
  # =============================================================================
19
 
20
  MODEL_ID = "prog-love/rostam-r1-stage13-1"
 
22
  print("=" * 70)
23
  print("ROSTAM R1")
24
  print("=" * 70)
25
+ print(f"Model : {MODEL_ID}")
26
+ print(f"Transformers : {transformers.__version__}")
27
+ print(f"PyTorch : {torch.__version__}")
28
+ print(f"CUDA : {torch.cuda.is_available()}")
29
 
30
  if torch.cuda.is_available():
31
+ print(f"GPU : {torch.cuda.get_device_name(0)}")
32
 
33
 
34
  # =============================================================================
35
+ # GEMMA 4 / TRANSFORMERS 5.14.1 COMPATIBILITY FIX
36
  # =============================================================================
37
  #
38
+ # Transformers 5.x supports heterogeneous/per-layer configurations.
 
 
39
  #
40
+ # Rostam's Gemma 4 config contains per-layer attributes such as `head_dim`.
41
+ # During Gemma4TextConfig.__post_init__(), Transformers performs architecture
42
+ # validation and accesses config.head_dim globally.
43
  #
44
+ # In a heterogeneous config this normally raises:
45
+ #
46
+ # AmbiguousGlobalPerLayerAttributeError
47
+ #
48
+ # The important detail is that the compatibility flag MUST exist BEFORE
49
+ # Gemma4TextConfig.__post_init__() runs.
50
+ #
51
+ # Setting it after AutoConfig.from_pretrained() is too late.
52
+ #
53
+ # Therefore we wrap Gemma4TextConfig.__post_init__ and inject the flag before
54
+ # the original validation code executes.
55
  # =============================================================================
56
 
57
+ print("Installing Gemma 4 configuration compatibility patch...")
58
+
59
  try:
60
+
61
+ from transformers.models.gemma4.configuration_gemma4 import (
62
+ Gemma4TextConfig,
63
  )
64
 
65
+ _original_gemma4_text_post_init = Gemma4TextConfig.__post_init__
66
+
67
+ def _rostam_gemma4_text_post_init(self, *args, **kwargs):
68
+
69
+ # Enable intentional global access to per-layer attributes.
70
+ #
71
+ # The model architecture itself still retains the per-layer
72
+ # configuration. This only allows Transformers' architecture
73
+ # validation to read the global fallback value.
74
+ object.__setattr__(
75
+ self,
76
+ "allow_global_per_layer_attribute_access",
77
+ True,
78
+ )
79
+
80
+ return _original_gemma4_text_post_init(
81
+ self,
82
+ *args,
83
+ **kwargs,
84
+ )
85
+
86
+ Gemma4TextConfig.__post_init__ = _rostam_gemma4_text_post_init
87
 
88
+ print("Gemma 4 compatibility patch installed.")
89
+
90
+ except Exception as e:
91
+
92
+ print(
93
+ "WARNING: Could not install Gemma 4 compatibility patch:"
94
+ )
95
+ print(repr(e))
96
 
97
 
98
  # =============================================================================
 
106
  trust_remote_code=True,
107
  )
108
 
109
+ print("Configuration loaded successfully.")
 
 
 
 
 
110
 
 
 
 
 
 
 
111
 
112
+ # =============================================================================
113
+ # SAFETY: ENSURE GLOBAL ACCESS IS ENABLED ON FINAL CONFIG
114
+ # =============================================================================
115
 
116
+ try:
117
+
118
+ object.__setattr__(
119
+ config,
120
+ "allow_global_per_layer_attribute_access",
121
+ True,
122
+ )
123
+
124
+ except Exception:
125
+ pass
126
+
127
+
128
+ try:
129
 
130
+ if hasattr(config, "text_config"):
 
131
 
 
132
  object.__setattr__(
133
+ config.text_config,
134
  "allow_global_per_layer_attribute_access",
135
  True,
136
  )
 
 
 
137
 
138
+ except Exception:
139
+ pass
140
 
141
 
142
  # =============================================================================
 
150
  trust_remote_code=True,
151
  )
152
 
153
+ print("Tokenizer loaded successfully.")
154
 
155
 
156
  # =============================================================================
 
171
 
172
  print("Model loaded successfully.")
173
 
174
+
175
+ # =============================================================================
176
+ # GPU INFORMATION
177
+ # =============================================================================
178
+
179
  if torch.cuda.is_available():
180
+
181
+ allocated = torch.cuda.memory_allocated() / (1024 ** 3)
182
+ reserved = torch.cuda.memory_reserved() / (1024 ** 3)
183
 
184
  print(
185
  f"GPU memory: "
 
187
  f"{reserved:.2f} GB reserved"
188
  )
189
 
190
+
191
+ print("=" * 70)
192
+ print("ROSTAM IS READY")
193
  print("=" * 70)
194
 
195
 
196
  # =============================================================================
197
+ # UI CSS
198
  # =============================================================================
199
 
200
  CUSTOM_CSS = """
201
+
202
+ /* -------------------------------------------------------------------------
203
+ Persian / RTL chat
204
+ ------------------------------------------------------------------------- */
205
+
206
  .message-wrap {
207
  direction: rtl !important;
208
  text-align: right !important;
 
213
  text-align: right !important;
214
  }
215
 
 
216
  .chatbot {
217
+ direction: rtl !important;
218
  }
219
 
220
+
221
+ /* -------------------------------------------------------------------------
222
+ Persian input
223
+ ------------------------------------------------------------------------- */
224
+
225
  textarea {
226
  direction: rtl !important;
227
  text-align: right !important;
228
  }
229
 
 
 
 
 
230
 
231
+ /* -------------------------------------------------------------------------
232
+ Markdown
233
+ ------------------------------------------------------------------------- */
234
+
235
  .prose {
236
  direction: rtl;
237
  text-align: right;
238
  }
239
 
240
+
241
+ /* -------------------------------------------------------------------------
242
+ Code remains LTR
243
+ ------------------------------------------------------------------------- */
244
+
245
  pre,
246
  code {
247
  direction: ltr !important;
248
  text-align: left !important;
249
  }
250
+
251
+
252
+ /* -------------------------------------------------------------------------
253
+ Hide Gradio footer
254
+ ------------------------------------------------------------------------- */
255
+
256
+ footer {
257
+ display: none !important;
258
+ }
259
+
260
  """
261
 
262
 
 
273
  top_p,
274
  max_new_tokens,
275
  ):
 
 
 
276
 
277
  messages = []
278
 
279
+
280
+ # =========================================================================
281
+ # SYSTEM PROMPT
282
+ # =========================================================================
283
 
284
  if system_prompt and system_prompt.strip():
285
 
 
290
  }
291
  )
292
 
293
+
294
+ # =========================================================================
295
+ # HISTORY
296
+ # =========================================================================
297
 
298
  if history:
299
 
 
317
  }
318
  )
319
 
320
+
321
+ # =========================================================================
322
+ # CURRENT USER MESSAGE
323
+ # =========================================================================
324
 
325
  messages.append(
326
  {
 
329
  }
330
  )
331
 
332
+
333
+ # =========================================================================
334
+ # CHAT TEMPLATE
335
+ # =========================================================================
336
 
337
  prompt = tokenizer.apply_chat_template(
338
  messages,
 
340
  add_generation_prompt=True,
341
  )
342
 
343
+
344
+ # =========================================================================
345
+ # TOKENIZE
346
+ # =========================================================================
347
 
348
  inputs = tokenizer(
349
  prompt,
350
  return_tensors="pt",
351
  )
352
 
353
+
354
+ # =========================================================================
355
+ # MOVE INPUTS TO MODEL DEVICE
356
+ # =========================================================================
357
+
358
  if torch.cuda.is_available():
359
 
360
  inputs = {
 
362
  for key, value in inputs.items()
363
  }
364
 
365
+
366
+ # =========================================================================
367
+ # STREAMER
368
+ # =========================================================================
369
 
370
  streamer = TextIteratorStreamer(
371
  tokenizer,
 
373
  skip_special_tokens=True,
374
  )
375
 
376
+
377
+ # =========================================================================
378
+ # GENERATION SETTINGS
379
+ # =========================================================================
380
 
381
  temperature = float(temperature)
382
  top_p = float(top_p)
383
  max_new_tokens = int(max_new_tokens)
384
 
385
+
386
  generation_kwargs = {
387
  **inputs,
388
 
 
399
  ),
400
  }
401
 
402
+
403
+ # =========================================================================
404
+ # SAMPLING
405
+ # =========================================================================
406
 
407
  if temperature <= 0:
408
 
 
414
  generation_kwargs["temperature"] = temperature
415
  generation_kwargs["top_p"] = top_p
416
 
417
+
418
+ # =========================================================================
419
+ # GENERATION THREAD
420
+ # =========================================================================
421
 
422
  thread = Thread(
423
  target=model.generate,
 
427
 
428
  thread.start()
429
 
430
+
431
+ # =========================================================================
432
+ # STREAM OUTPUT
433
+ # =========================================================================
434
 
435
  partial_text = ""
436
 
 
442
 
443
 
444
  # =============================================================================
445
+ # GRADIO APPLICATION
446
  # =============================================================================
447
 
448
  with gr.Blocks(
 
451
  title="رستم",
452
  ) as demo:
453
 
454
+
455
+ # =========================================================================
456
+ # HEADER
457
+ # =========================================================================
458
 
459
  gr.Markdown(
460
  """
 
464
  """
465
  )
466
 
467
+
468
+ # =========================================================================
469
+ # ADVANCED SETTINGS
470
+ # =========================================================================
471
 
472
  with gr.Accordion(
473
  "تنظیمات پیشرفته",
 
480
  lines=2,
481
  )
482
 
483
+
484
  with gr.Row():
485
 
486
  temperature = gr.Slider(
 
491
  label="Temperature",
492
  )
493
 
494
+
495
  top_p = gr.Slider(
496
  minimum=0.1,
497
  maximum=1.0,
 
500
  label="Top-p",
501
  )
502
 
503
+
504
  max_new_tokens = gr.Slider(
505
  minimum=32,
506
  maximum=8000,
 
509
  label="حداکثر طول پاسخ",
510
  )
511
 
512
+
513
+ # =========================================================================
514
+ # CHAT
515
+ # =========================================================================
516
 
517
  chat = gr.ChatInterface(
518
  fn=generate_response,
 
532
  0.9,
533
  512,
534
  ],
535
+
536
  [
537
  "تو چه مدلی هستی؟",
538
  "",
 
540
  0.9,
541
  512,
542
  ],
543
+
544
  [
545
  "دربارهٔ رستم و سهراب برام بگو",
546
  "",