Derr11 commited on
Commit
0db7e85
·
verified ·
1 Parent(s): 210a758

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +244 -111
app.py CHANGED
@@ -1,63 +1,165 @@
 
 
 
 
 
 
 
 
1
  import gradio as gr
2
  import torch
3
  import spaces
4
  from PIL import Image
5
- import numpy as np
6
  import os
7
  import tempfile
 
 
8
 
9
- # استيراد المكتبات الضرورية من Uni-MoE
10
  try:
11
  from uni_moe.model.processing_qwen2_vl import Qwen2VLProcessor
12
  from uni_moe.model.modeling_out import GrinQwen2VLOutForConditionalGeneration
13
  from uni_moe.qwen_vl_utils import process_mm_info
14
- from uni_moe.model import deepspeed_moe_inference_utils
15
- except ImportError:
16
- print("⚠️ Warning: Uni-MoE libraries not fully imported. Some features may not work.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
 
18
- # تحميل النموذج
19
- MODEL_NAME = "HIT-TMG/Uni-MoE-2.0-Omni"
20
  device = "cuda" if torch.cuda.is_available() else "cpu"
21
 
22
- print(f"🚀 Loading model: {MODEL_NAME}")
23
- print(f"📍 Device: {device}")
24
 
25
- # تحميل المعالج والنموذج
26
- try:
27
- processor = Qwen2VLProcessor.from_pretrained(MODEL_NAME)
28
- model = GrinQwen2VLOutForConditionalGeneration.from_pretrained(
29
- MODEL_NAME,
30
- torch_dtype=torch.bfloat16 if device == "cuda" else torch.float32,
31
- device_map="auto"
32
- )
33
- if device == "cuda":
34
- model = model.cuda()
 
 
35
 
36
- # تعيين data_args
37
- processor.data_args = model.config
38
- print(" Model loaded successfully!")
39
- except Exception as e:
40
- print(f"❌ Error loading model: {str(e)}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
41
  processor = None
42
  model = None
43
 
44
 
45
- @spaces.GPU(duration=120) # استخدام ZeroGPU لمدة 120 ثانية
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
46
  def generate_response(
47
  text_input: str,
48
- image_input: Image.Image = None,
49
- audio_input: str = None,
50
  temperature: float = 1.0,
51
- max_new_tokens: int = 512
52
- ):
 
 
53
  """
54
- توليد استجابة من النموذج بناءً على المدخلات المختلفة
 
55
  """
 
 
56
  if model is None or processor is None:
57
- return "❌ النموذج غير متاح حالياً. يرجى المحاولة لاحقاً."
 
 
 
58
 
59
  try:
60
- # بناء رسالة المستخدم
 
 
 
 
61
  content = []
62
 
63
  # إضافة النص
@@ -65,29 +167,23 @@ def generate_response(
65
  content.append({"type": "text", "text": text_input})
66
 
67
  # إضافة الصورة
 
68
  if image_input is not None:
69
- # حفظ الصورة مؤقتاً
70
- with tempfile.NamedTemporaryFile(delete=False, suffix=".jpg") as tmp_img:
71
- image_input.save(tmp_img.name)
72
- content.append({"type": "image", "image": tmp_img.name})
73
 
74
  # إضافة الصوت
75
  if audio_input is not None:
76
  content.append({"type": "audio", "audio": audio_input})
77
 
78
- if not content:
79
- return "⚠️ يرجى إدخال نص أو صورة أو صوت."
80
-
81
  # بناء الرسائل
82
- messages = [{
83
- "role": "user",
84
- "content": content
85
- }]
86
 
87
- # معالجة الرسائل
88
  texts = processor.apply_chat_template(
89
- messages,
90
- tokenize=False,
91
  add_generation_prompt=True
92
  )
93
 
@@ -117,47 +213,73 @@ def generate_response(
117
  inputs = inputs.to(device=model.device)
118
 
119
  # التوليد
120
- with torch.no_grad():
121
  output_ids = model.generate(
122
  **inputs,
123
  use_cache=True,
124
  pad_token_id=processor.tokenizer.eos_token_id,
125
  max_new_tokens=max_new_tokens,
126
  temperature=temperature,
127
- do_sample=True
 
 
128
  )
129
 
130
- # فك تشفير النتيجة
131
  response = processor.batch_decode(
132
- output_ids[:, inputs["input_ids"].shape[-1]:],
133
  skip_special_tokens=True
134
  )[0]
135
 
 
 
 
 
 
 
 
136
  return response
137
 
138
  except Exception as e:
139
- return f"❌ حدث خطأ: {str(e)}"
 
 
 
140
 
141
 
142
- # إنشاء واجهة Gradio
143
- with gr.Blocks(
144
- title="Uni-MoE 2.0 Omni Demo",
145
- theme=gr.themes.Soft(),
146
- css="""
147
- .rtl { direction: rtl; text-align: right; }
148
- .main-header { text-align: center; margin-bottom: 2rem; }
149
- """
150
- ) as demo:
 
 
 
 
 
 
 
 
 
 
 
 
 
151
 
152
- gr.Markdown("""
153
  <div class="main-header">
154
-
155
- # 🚀 Uni-MoE 2.0 Omni Demo
156
-
157
- نموذج متعدد الوسائط متقدم يدعم فهم وتوليد **النصوص والصور والصوت**
158
-
159
- An advanced omnimodal model supporting understanding and generation of **text, images, and audio**
160
-
 
161
  </div>
162
  """)
163
 
@@ -167,15 +289,17 @@ with gr.Blocks(
167
 
168
  text_input = gr.Textbox(
169
  label="النص / Text",
170
- placeholder="اكتب سؤالك أو وصفك هنا... / Enter your question or description here...",
171
- lines=3,
172
  rtl=True
173
  )
174
 
175
- image_input = gr.Image(
176
- label="الصورة (اختياري) / Image (Optional)",
177
- type="pil"
178
- )
 
 
179
 
180
  audio_input = gr.Audio(
181
  label="الصوت (اختياري) / Audio (Optional)",
@@ -184,42 +308,55 @@ with gr.Blocks(
184
 
185
  with gr.Accordion("⚙️ إعدادات متقدمة / Advanced Settings", open=False):
186
  temperature = gr.Slider(
187
- minimum=0.1,
188
- maximum=2.0,
189
- value=1.0,
190
- step=0.1,
191
- label="Temperature"
192
  )
193
-
194
  max_tokens = gr.Slider(
195
- minimum=64,
196
- maximum=2048,
197
- value=512,
198
- step=64,
199
- label="Max New Tokens"
 
 
 
 
 
200
  )
201
 
202
- submit_btn = gr.Button("🎯 توليد / Generate", variant="primary")
203
- clear_btn = gr.Button("🗑️ مسح / Clear")
 
204
 
205
  with gr.Column(scale=1):
206
  gr.Markdown("### 💬 النتيجة / Output")
207
 
208
  output = gr.Textbox(
209
  label="الاستجابة / Response",
210
- lines=15,
211
  show_copy_button=True,
212
  rtl=True
213
  )
214
 
 
 
 
 
 
 
 
 
 
 
 
 
215
  # أمثلة
216
  gr.Markdown("### 📚 أمثلة / Examples")
217
  gr.Examples(
218
  examples=[
219
- ["ما هي عاصمة مصر؟", None, None],
220
- ["صف هذه الصورة بالتفصيل", "https://picsum.photos/400/300", None],
221
- ["What is the capital of France?", None, None],
222
- ["Describe this image in detail", "https://picsum.photos/400/300", None],
223
  ],
224
  inputs=[text_input, image_input, audio_input],
225
  )
@@ -227,32 +364,28 @@ with gr.Blocks(
227
  # معلومات إضافية
228
  gr.Markdown("""
229
  ---
230
- ### ℹ️ معلومات / Information
231
 
232
- **Uni-MoE 2.0 Omni** هو نموذج لغوي متعدد الوسائط (Omnimodal) مبني على معماريات:
233
- - 🧠 **Mixture-of-Experts (MoE)** لكفاءة الحوسبة
234
- - 🔄 **Qwen2.5-7B** كقاعدة أساسية
235
- - 🎯 **Omni-Modality 3D RoPE** لمحاذاة متعددة الوسائط
 
236
 
237
- **القدرات:**
238
- - ✅ فهم النصوص والصور والصوت والفيديو
239
- - ✅ توليد النصوص والصور والصوت
240
- - ✅ استدلال متعدد الوسائط
241
 
242
- 📄 **ورقة بحثية:** [arXiv:2511.12609](https://arxiv.org/abs/2511.12609)
243
-
244
- 🔗 **GitHub:** [HITsz-TMG/Uni-MoE](https://github.com/HITsz-TMG/Uni-MoE)
245
-
246
- ---
247
- <p style="text-align: center; color: #666;">
248
- تم إنشاؤه باستخدام Gradio و ZeroGPU 🚀
249
- </p>
250
  """)
251
 
252
  # ربط الأحداث
253
  submit_btn.click(
254
  fn=generate_response,
255
- inputs=[text_input, image_input, audio_input, temperature, max_tokens],
256
  outputs=output
257
  )
258
 
@@ -264,7 +397,7 @@ with gr.Blocks(
264
 
265
  # تشغيل التطبيق
266
  if __name__ == "__main__":
267
- demo.queue(max_size=10)
268
  demo.launch(
269
  share=False,
270
  show_error=True,
 
1
+ """
2
+ نسخة محسّنة من app.py مع دعم Quantization و Memory Optimization
3
+ للنماذج الكبيرة على ZeroGPU
4
+
5
+ Optimized version of app.py with Quantization and Memory Optimization
6
+ for large models on ZeroGPU
7
+ """
8
+
9
  import gradio as gr
10
  import torch
11
  import spaces
12
  from PIL import Image
 
13
  import os
14
  import tempfile
15
+ import gc
16
+ from typing import Optional, Union
17
 
18
+ # استيراد المكتبات الضرورية
19
  try:
20
  from uni_moe.model.processing_qwen2_vl import Qwen2VLProcessor
21
  from uni_moe.model.modeling_out import GrinQwen2VLOutForConditionalGeneration
22
  from uni_moe.qwen_vl_utils import process_mm_info
23
+ from transformers import BitsAndBytesConfig
24
+ except ImportError as e:
25
+ print(f"⚠️ Warning: Import error - {e}")
26
+ print("Some features may not work properly.")
27
+
28
+
29
+ # ==================== الإعدادات / Configuration ====================
30
+
31
+ # اختر النموذج المناسب
32
+ # Choose appropriate model
33
+ MODEL_NAME = "HIT-TMG/Uni-MoE-2.0-Omni" # النموذج الكامل / Full model
34
+ # MODEL_NAME = "HIT-TMG/Uni-MoE-2.0-Base" # البديل الأصغر / Smaller alternative
35
+
36
+ # إعدادات التحسين / Optimization settings
37
+ USE_4BIT = True # استخدام 4-bit quantization لتوفير الذاكرة
38
+ USE_8BIT = False # بديل: استخدام 8-bit quantization
39
+ USE_FLASH_ATTENTION = True # استخدام Flash Attention للسرعة
40
+ MAX_MEMORY = "20GB" # الحد الأقصى للذاكرة المستخدمة
41
 
 
 
42
  device = "cuda" if torch.cuda.is_available() else "cpu"
43
 
44
+ # ==================== تحميل النموذج / Model Loading ====================
 
45
 
46
+ print("="*60)
47
+ print(f"🚀 Loading Uni-MoE 2.0 Model")
48
+ print(f"📍 Model: {MODEL_NAME}")
49
+ print(f"🖥️ Device: {device}")
50
+ print(f"⚙️ 4-bit Quantization: {USE_4BIT}")
51
+ print(f"⚙️ 8-bit Quantization: {USE_8BIT}")
52
+ print("="*60)
53
+
54
+
55
+ def load_model_optimized():
56
+ """تحميل النموذج بطريقة محسّنة"""
57
+ global processor, model
58
 
59
+ try:
60
+ # تحميل المعالج
61
+ print("📥 Loading processor...")
62
+ processor = Qwen2VLProcessor.from_pretrained(MODEL_NAME)
63
+
64
+ # إعداد Quantization Config
65
+ quantization_config = None
66
+ if USE_4BIT:
67
+ print("⚙️ Setting up 4-bit quantization...")
68
+ quantization_config = BitsAndBytesConfig(
69
+ load_in_4bit=True,
70
+ bnb_4bit_compute_dtype=torch.float16,
71
+ bnb_4bit_use_double_quant=True,
72
+ bnb_4bit_quant_type="nf4"
73
+ )
74
+ elif USE_8BIT:
75
+ print("⚙️ Setting up 8-bit quantization...")
76
+ quantization_config = BitsAndBytesConfig(
77
+ load_in_8bit=True,
78
+ )
79
+
80
+ # تحميل النموذج
81
+ print("📥 Loading model (this may take a few minutes)...")
82
+ load_kwargs = {
83
+ "device_map": "auto",
84
+ "torch_dtype": torch.float16 if not USE_4BIT else None,
85
+ "trust_remote_code": True,
86
+ }
87
+
88
+ if quantization_config:
89
+ load_kwargs["quantization_config"] = quantization_config
90
+
91
+ if device == "cuda" and not USE_4BIT and not USE_8BIT:
92
+ load_kwargs["max_memory"] = {0: MAX_MEMORY}
93
+
94
+ model = GrinQwen2VLOutForConditionalGeneration.from_pretrained(
95
+ MODEL_NAME,
96
+ **load_kwargs
97
+ )
98
+
99
+ # تعيين data_args
100
+ processor.data_args = model.config
101
+
102
+ print("✅ Model loaded successfully!")
103
+ print(f"💾 Model size: {sum(p.numel() for p in model.parameters()) / 1e9:.2f}B parameters")
104
+
105
+ return True
106
+
107
+ except Exception as e:
108
+ print(f"❌ Error loading model: {str(e)}")
109
+ return False
110
+
111
+
112
+ # تحميل النموذج
113
+ model_loaded = load_model_optimized()
114
+ if not model_loaded:
115
  processor = None
116
  model = None
117
 
118
 
119
+ # ==================== دوال مساعدة / Helper Functions ====================
120
+
121
+ def clear_gpu_memory():
122
+ """تنظيف ذاكرة GPU"""
123
+ if torch.cuda.is_available():
124
+ torch.cuda.empty_cache()
125
+ gc.collect()
126
+
127
+
128
+ def estimate_tokens(text: str) -> int:
129
+ """تقدير عدد التوكنات"""
130
+ return len(text.split()) * 1.3
131
+
132
+
133
+ # ==================== دالة التوليد الرئيسية / Main Generation Function ====================
134
+
135
+ @spaces.GPU(duration=120)
136
  def generate_response(
137
  text_input: str,
138
+ image_input: Optional[Image.Image] = None,
139
+ audio_input: Optional[str] = None,
140
  temperature: float = 1.0,
141
+ max_new_tokens: int = 512,
142
+ top_p: float = 0.9,
143
+ repetition_penalty: float = 1.1
144
+ ) -> str:
145
  """
146
+ توليد استجابة من النموذج
147
+ Generate response from the model
148
  """
149
+
150
+ # التحقق من توفر النموذج
151
  if model is None or processor is None:
152
+ return "❌ النموذج غير متاح. يرجى التحقق من السجلات.\n❌ Model not available. Please check logs."
153
+
154
+ # تنظيف الذاكرة قبل البدء
155
+ clear_gpu_memory()
156
 
157
  try:
158
+ # التحقق من المدخلات
159
+ if not text_input and image_input is None and audio_input is None:
160
+ return "⚠️ يرجى إدخال نص أو صورة أو صوت على الأقل.\n⚠️ Please provide at least text, image, or audio input."
161
+
162
+ # بناء محتوى الرسالة
163
  content = []
164
 
165
  # إضافة النص
 
167
  content.append({"type": "text", "text": text_input})
168
 
169
  # إضافة الصورة
170
+ temp_image_path = None
171
  if image_input is not None:
172
+ temp_image_path = tempfile.NamedTemporaryFile(delete=False, suffix=".jpg").name
173
+ image_input.save(temp_image_path)
174
+ content.append({"type": "image", "image": temp_image_path})
 
175
 
176
  # إضافة الصوت
177
  if audio_input is not None:
178
  content.append({"type": "audio", "audio": audio_input})
179
 
 
 
 
180
  # بناء الرسائل
181
+ messages = [{"role": "user", "content": content}]
 
 
 
182
 
183
+ # معالجة النص
184
  texts = processor.apply_chat_template(
185
+ messages,
186
+ tokenize=False,
187
  add_generation_prompt=True
188
  )
189
 
 
213
  inputs = inputs.to(device=model.device)
214
 
215
  # التوليد
216
+ with torch.inference_mode():
217
  output_ids = model.generate(
218
  **inputs,
219
  use_cache=True,
220
  pad_token_id=processor.tokenizer.eos_token_id,
221
  max_new_tokens=max_new_tokens,
222
  temperature=temperature,
223
+ do_sample=True,
224
+ top_p=top_p,
225
+ repetition_penalty=repetition_penalty
226
  )
227
 
228
+ # فك التشفير
229
  response = processor.batch_decode(
230
+ output_ids[:, inputs["input_ids"].shape[-1]:],
231
  skip_special_tokens=True
232
  )[0]
233
 
234
+ # تنظيف الملفات المؤقتة
235
+ if temp_image_path and os.path.exists(temp_image_path):
236
+ os.unlink(temp_image_path)
237
+
238
+ # تنظيف الذاكرة
239
+ clear_gpu_memory()
240
+
241
  return response
242
 
243
  except Exception as e:
244
+ clear_gpu_memory()
245
+ error_msg = f"❌ خطأ / Error: {str(e)}"
246
+ print(error_msg)
247
+ return error_msg
248
 
249
 
250
+ # ==================== واجهة Gradio / Gradio Interface ====================
251
+
252
+ css = """
253
+ .rtl { direction: rtl; text-align: right; }
254
+ .main-header {
255
+ text-align: center;
256
+ margin-bottom: 2rem;
257
+ padding: 2rem;
258
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
259
+ border-radius: 10px;
260
+ color: white;
261
+ }
262
+ .note-box {
263
+ padding: 1rem;
264
+ background: #f0f9ff;
265
+ border-left: 4px solid #3b82f6;
266
+ border-radius: 4px;
267
+ margin: 1rem 0;
268
+ }
269
+ """
270
+
271
+ with gr.Blocks(title="Uni-MoE 2.0 Omni - Optimized", theme=gr.themes.Soft(), css=css) as demo:
272
 
273
+ gr.HTML("""
274
  <div class="main-header">
275
+ <h1>🚀 Uni-MoE 2.0 Omni Demo</h1>
276
+ <p style="font-size: 1.1em; margin-top: 1rem;">
277
+ نموذج متعدد الوسائط متقدم - Advanced Omnimodal Model
278
+ </p>
279
+ <p style="font-size: 0.9em; opacity: 0.9; margin-top: 0.5rem;">
280
+ يدعم فهم وتوليد النصوص والصور والصوت<br>
281
+ Supports understanding and generation of text, images, and audio
282
+ </p>
283
  </div>
284
  """)
285
 
 
289
 
290
  text_input = gr.Textbox(
291
  label="النص / Text",
292
+ placeholder="اكتب سؤالك أو وصفك هنا...\nEnter your question or description here...",
293
+ lines=4,
294
  rtl=True
295
  )
296
 
297
+ with gr.Row():
298
+ image_input = gr.Image(
299
+ label="الصورة (اختياري) / Image (Optional)",
300
+ type="pil",
301
+ height=300
302
+ )
303
 
304
  audio_input = gr.Audio(
305
  label="الصوت (اختياري) / Audio (Optional)",
 
308
 
309
  with gr.Accordion("⚙️ إعدادات متقدمة / Advanced Settings", open=False):
310
  temperature = gr.Slider(
311
+ minimum=0.1, maximum=2.0, value=0.7, step=0.1,
312
+ label="Temperature (الإبداعية / Creativity)"
 
 
 
313
  )
 
314
  max_tokens = gr.Slider(
315
+ minimum=64, maximum=2048, value=512, step=64,
316
+ label="Max Tokens (الطول الأقصى / Max Length)"
317
+ )
318
+ top_p = gr.Slider(
319
+ minimum=0.1, maximum=1.0, value=0.9, step=0.05,
320
+ label="Top P (التنوع / Diversity)"
321
+ )
322
+ repetition_penalty = gr.Slider(
323
+ minimum=1.0, maximum=2.0, value=1.1, step=0.1,
324
+ label="Repetition Penalty (تجنب التكرار / Avoid Repetition)"
325
  )
326
 
327
+ with gr.Row():
328
+ submit_btn = gr.Button("🎯 توليد / Generate", variant="primary", size="lg")
329
+ clear_btn = gr.Button("🗑️ مسح / Clear", size="lg")
330
 
331
  with gr.Column(scale=1):
332
  gr.Markdown("### 💬 النتيجة / Output")
333
 
334
  output = gr.Textbox(
335
  label="الاستجابة / Response",
336
+ lines=20,
337
  show_copy_button=True,
338
  rtl=True
339
  )
340
 
341
+ # ملاحظات مهمة
342
+ gr.HTML("""
343
+ <div class="note-box">
344
+ <h3>📌 ملاحظات مهمة / Important Notes</h3>
345
+ <ul>
346
+ <li>⏱️ قد يستغرق التوليد 30-60 ثانية / Generation may take 30-60 seconds</li>
347
+ <li>💾 يستخدم النموذج quantization لتوفير الذاكرة / Model uses quantization to save memory</li>
348
+ <li>🔄 يتم تنظيف الذاكرة تلقائياً بعد كل استخدام / Memory is cleared automatically after each use</li>
349
+ </ul>
350
+ </div>
351
+ """)
352
+
353
  # أمثلة
354
  gr.Markdown("### 📚 أمثلة / Examples")
355
  gr.Examples(
356
  examples=[
357
+ ["ما هي عاصمة مصر؟ What is the capital of Egypt?", None, None],
358
+ ["صف هذه الصورة بالتفصيل\nDescribe this image in detail", "https://picsum.photos/400/300", None],
359
+ ["قارن بين Python و JavaScript\nCompare Python and JavaScript", None, None],
 
360
  ],
361
  inputs=[text_input, image_input, audio_input],
362
  )
 
364
  # معلومات إضافية
365
  gr.Markdown("""
366
  ---
367
+ ### ℹ️ حول النموذج / About the Model
368
 
369
+ **Uni-MoE 2.0 Omni** بني على:
370
+ - 🧠 Mixture-of-Experts (MoE) architecture
371
+ - 📊 Qwen2.5-7B base model (~33B parameters with experts)
372
+ - 🌐 Omni-Modality 3D RoPE for cross-modal alignment
373
+ - ⚡ Dynamic-Capacity routing mechanism
374
 
375
+ **الأداء / Performance:**
376
+ - ✅ +7% على فهم الفيديو / video understanding
377
+ - ✅ +4% على الاستدلال السمعي-البصري / audio-visual reasoning
378
+ - ✅ متفوق على Qwen2.5-Omni في 50+ معياراً / benchmarks
379
 
380
+ 📄 [ورقة بحثية / Paper](https://arxiv.org/abs/2511.12609) |
381
+ 💻 [GitHub](https://github.com/HITsz-TMG/Uni-MoE) |
382
+ 🤗 [Model](https://huggingface.co/HIT-TMG/Uni-MoE-2.0-Omni)
 
 
 
 
 
383
  """)
384
 
385
  # ربط الأحداث
386
  submit_btn.click(
387
  fn=generate_response,
388
+ inputs=[text_input, image_input, audio_input, temperature, max_tokens, top_p, repetition_penalty],
389
  outputs=output
390
  )
391
 
 
397
 
398
  # تشغيل التطبيق
399
  if __name__ == "__main__":
400
+ demo.queue(max_size=20, default_concurrency_limit=5)
401
  demo.launch(
402
  share=False,
403
  show_error=True,