kvn420 commited on
Commit
794b299
·
verified ·
1 Parent(s): 8137cde

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +220 -311
app.py CHANGED
@@ -1,5 +1,7 @@
1
  import gradio as gr
2
  import os
 
 
3
  import requests
4
  import json
5
  import logging
@@ -8,40 +10,41 @@ import time
8
  import tempfile
9
  import shutil
10
 
11
- # Imports conditionnels pour éviter les erreurs
12
- try:
13
- import numpy as np
14
- NUMPY_AVAILABLE = True
15
- except ImportError:
16
- NUMPY_AVAILABLE = False
17
- import array
18
-
19
- try:
20
- from pathlib import Path
21
- PATHLIB_AVAILABLE = True
22
- except ImportError:
23
- PATHLIB_AVAILABLE = False
24
 
25
- try:
26
- from huggingface_hub import HfApi
27
- HF_HUB_AVAILABLE = True
28
- except ImportError:
29
- HF_HUB_AVAILABLE = False
30
-
31
- try:
32
- import numpy as np
33
- NUMPY_AVAILABLE = True
34
- except ImportError:
35
- NUMPY_AVAILABLE = False
 
 
 
 
36
 
37
- try:
38
- import torch
39
- import torch.nn as nn
40
- TORCH_AVAILABLE = True
41
- except ImportError:
42
- TORCH_AVAILABLE = False
 
 
 
 
 
 
43
  torch = None
44
 
 
45
  try:
46
  from transformers import (
47
  AutoTokenizer, AutoModel, AutoProcessor,
@@ -51,87 +54,131 @@ try:
51
  TRANSFORMERS_AVAILABLE = True
52
  except ImportError:
53
  TRANSFORMERS_AVAILABLE = False
 
54
 
 
55
  try:
56
  from datasets import Dataset, load_dataset, concatenate_datasets
57
  DATASETS_AVAILABLE = True
58
  except ImportError:
59
  DATASETS_AVAILABLE = False
 
 
 
 
 
 
 
 
 
60
 
 
61
  try:
62
  from PIL import Image
63
  PIL_AVAILABLE = True
64
  except ImportError:
65
  PIL_AVAILABLE = False
66
 
 
67
  try:
68
  import librosa
69
  LIBROSA_AVAILABLE = True
70
  except ImportError:
71
  LIBROSA_AVAILABLE = False
72
 
 
73
  try:
74
  import cv2
75
  CV2_AVAILABLE = True
76
  except ImportError:
77
  CV2_AVAILABLE = False
78
 
79
- # Configuration du logging
80
- logging.basicConfig(level=logging.INFO)
81
- logger = logging.getLogger(__name__)
82
-
83
  class MultimodalTrainer:
84
  def __init__(self):
85
- # Vérification des dépendances
86
- self.dependencies_ok = self.check_dependencies()
87
-
88
- if not TORCH_AVAILABLE:
89
- self.device = "cpu"
90
- logger.warning("PyTorch non disponible")
91
- else:
92
- self.device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
93
-
94
  self.current_model = None
95
  self.current_tokenizer = None
96
  self.current_processor = None
97
  self.training_data = []
98
 
 
 
 
 
 
 
 
99
  if HF_HUB_AVAILABLE:
100
  self.hf_api = HfApi()
101
  else:
102
  self.hf_api = None
103
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
104
  def check_dependencies(self):
105
- """Vérifie les dépendances installées"""
106
  deps = {
 
107
  "PyTorch": TORCH_AVAILABLE,
108
  "Transformers": TRANSFORMERS_AVAILABLE,
109
  "Datasets": DATASETS_AVAILABLE,
110
- "PIL": PIL_AVAILABLE,
111
- "Librosa": LIBROSA_AVAILABLE,
112
- "OpenCV": CV2_AVAILABLE,
113
- "NumPy": NUMPY_AVAILABLE,
114
- "HuggingFace Hub": HF_HUB_AVAILABLE
115
  }
116
 
117
- status = "📦 État des dépendances:\n"
118
- for name, available in deps.items():
119
- status += f"{'✅' if available else '❌'} {name}\n"
120
-
121
- if not TORCH_AVAILABLE:
122
- status += "\n⚠️ PyTorch requis pour l'entraînement!"
123
- if not TRANSFORMERS_AVAILABLE:
124
- status += "\n⚠️ Transformers requis pour les modèles!"
125
-
126
- return status
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
127
 
 
 
128
  def load_model(self, model_name: str, model_type: str = "causal"):
129
  """Charge un modèle depuis Hugging Face"""
130
  if not TRANSFORMERS_AVAILABLE:
131
- return "❌ Transformers non installé!"
132
 
133
  if not TORCH_AVAILABLE:
134
- return "❌ PyTorch non installé!"
 
 
 
135
 
136
  try:
137
  logger.info(f"Chargement du modèle: {model_name}")
@@ -151,232 +198,98 @@ class MultimodalTrainer:
151
  trust_remote_code=True
152
  )
153
 
154
- # Charge le tokenizer et processor
155
  try:
156
  self.current_tokenizer = AutoTokenizer.from_pretrained(
157
  model_name, trust_remote_code=True
158
  )
159
- except:
160
- logger.warning("Tokenizer non trouvé, utilisation d'un tokenizer par défaut")
 
 
161
 
 
162
  try:
163
  self.current_processor = AutoProcessor.from_pretrained(
164
  model_name, trust_remote_code=True
165
  )
166
- except:
167
- logger.warning("Processor non trouvé")
168
 
169
- return f"✅ Modèle {model_name} chargé avec succès!"
170
 
171
  except Exception as e:
172
  error_msg = f"❌ Erreur lors du chargement: {str(e)}"
173
  logger.error(error_msg)
174
  return error_msg
175
 
176
- def load_collection_datasets(self, collection_url: str):
177
- """Charge tous les datasets d'une collection HF"""
178
  if not DATASETS_AVAILABLE:
179
- return "❌ Datasets non installé!"
180
-
181
- try:
182
- # Extrait l'ID de la collection depuis l'URL
183
- collection_id = collection_url.split("/")[-1]
184
-
185
- # Pour l'instant, utilise l'API HF de base
186
- try:
187
- from huggingface_hub import list_datasets_in_collection
188
- collection_items = list_datasets_in_collection(collection_id)
189
- except ImportError:
190
- return "❌ Fonction collection non disponible, ajoutez manuellement les datasets"
191
-
192
- datasets_info = []
193
- loaded_datasets = []
194
-
195
- for item in collection_items:
196
- try:
197
- dataset_name = item.id
198
- dataset = load_dataset(dataset_name, split='train', streaming=False)
199
- loaded_datasets.append(dataset)
200
- datasets_info.append(f"✅ {dataset_name}: {len(dataset)} exemples")
201
- logger.info(f"Dataset chargé: {dataset_name}")
202
- except Exception as e:
203
- datasets_info.append(f"❌ {dataset_name}: {str(e)}")
204
- logger.error(f"Erreur dataset {dataset_name}: {e}")
205
 
206
- # Combine tous les datasets
207
- if loaded_datasets:
208
- combined_dataset = concatenate_datasets(loaded_datasets)
209
- self.training_data = combined_dataset
210
-
211
- result = f"📊 Collection chargée!\n" + "\n".join(datasets_info)
212
- result += f"\n\n🔢 Total combiné: {len(self.training_data)} exemples"
213
-
214
- return result
215
 
216
- except Exception as e:
217
- error_msg = f"❌ Erreur collection: {str(e)}"
218
- logger.error(error_msg)
219
- return error_msg
220
-
221
- def load_single_dataset(self, dataset_name: str, split: str = "train"):
222
- """Charge un dataset individuel"""
223
  try:
224
  dataset = load_dataset(dataset_name, split=split)
225
 
226
  if hasattr(self, 'training_data') and self.training_data:
227
- # Combine avec les données existantes
228
  self.training_data = concatenate_datasets([self.training_data, dataset])
229
  else:
230
  self.training_data = dataset
231
 
232
- return f"✅ Dataset {dataset_name} ajouté! Total: {len(self.training_data)} exemples"
233
 
234
  except Exception as e:
235
  error_msg = f"❌ Erreur dataset: {str(e)}"
236
  logger.error(error_msg)
237
  return error_msg
238
 
239
- def process_multimodal_data(self, example):
240
- """Traite les données multimodales pour l'entraînement"""
241
- processed = {}
 
242
 
243
- # Traitement du texte
244
- if 'text' in example:
245
- if self.current_tokenizer:
246
- tokens = self.current_tokenizer(
247
- example['text'],
248
- truncation=True,
249
- padding=True,
250
- max_length=512,
251
- return_tensors="pt"
252
- )
253
- processed.update(tokens)
254
 
255
- # Traitement des images
256
- if 'image' in example:
257
- try:
258
- if isinstance(example['image'], str):
259
- # URL ou chemin
260
- if example['image'].startswith('http'):
261
- response = requests.get(example['image'])
262
- image = Image.open(io.BytesIO(response.content))
263
- else:
264
- image = Image.open(example['image'])
265
- else:
266
- image = example['image']
267
-
268
- if self.current_processor:
269
- image_inputs = self.current_processor(
270
- images=image, return_tensors="pt"
271
- )
272
- processed.update(image_inputs)
273
-
274
- except Exception as e:
275
- logger.warning(f"Erreur traitement image: {e}")
276
-
277
- # Traitement audio
278
- if 'audio' in example:
279
- try:
280
- if isinstance(example['audio'], str):
281
- audio_data, sr = librosa.load(example['audio'], sr=16000)
282
- else:
283
- audio_data = example['audio']
284
- sr = 16000
285
-
286
- # Conversion basique pour l'exemple
287
- processed['audio'] = torch.tensor(audio_data).unsqueeze(0)
288
-
289
- except Exception as e:
290
- logger.warning(f"Erreur traitement audio: {e}")
291
-
292
- return processed
293
-
294
- def start_training(self,
295
- output_dir: str,
296
- num_epochs: int = 3,
297
- learning_rate: float = 5e-5,
298
- batch_size: int = 4,
299
- save_steps: int = 500):
300
- """Lance l'entraînement du modèle"""
301
-
302
- if not self.current_model:
303
- return "❌ Aucun modèle chargé!"
304
-
305
- if not self.training_data:
306
- return "❌ Aucune donnée d'entraînement!"
307
-
308
- try:
309
- # Préparation des données
310
- logger.info("Préparation des données...")
311
-
312
- # Arguments d'entraînement
313
- training_args = TrainingArguments(
314
- output_dir=output_dir,
315
- num_train_epochs=num_epochs,
316
- per_device_train_batch_size=batch_size,
317
- learning_rate=learning_rate,
318
- logging_steps=50,
319
- save_steps=save_steps,
320
- eval_steps=save_steps,
321
- warmup_steps=100,
322
- fp16=torch.cuda.is_available(),
323
- dataloader_num_workers=2,
324
- remove_unused_columns=False,
325
- report_to=None # Désactive wandb/tensorboard
326
- )
327
 
328
- # Data collator
329
- data_collator = DataCollatorForLanguageModeling(
330
- tokenizer=self.current_tokenizer,
331
- mlm=False
332
- ) if self.current_tokenizer else None
333
-
334
- # Trainer
335
- trainer = Trainer(
336
- model=self.current_model,
337
- args=training_args,
338
- train_dataset=self.training_data,
339
- data_collator=data_collator,
340
- )
341
-
342
- # Lance l'entraînement
343
- logger.info("🚀 Début de l'entraînement...")
344
- trainer.train()
345
-
346
- # Sauvegarde
347
- trainer.save_model()
348
- if self.current_tokenizer:
349
- self.current_tokenizer.save_pretrained(output_dir)
350
-
351
- return f"✅ Entraînement terminé! Modèle sauvegardé dans {output_dir}"
352
-
353
- except Exception as e:
354
- error_msg = f"❌ Erreur entraînement: {str(e)}"
355
- logger.error(error_msg)
356
- return error_msg
357
 
358
  def get_model_info(self):
359
  """Retourne les informations du modèle actuel"""
360
  if not self.current_model:
361
- return "Aucun modèle chargé"
362
 
363
- info = f"📋 Modèle actuel:\n"
364
- info += f"Type: {type(self.current_model).__name__}\n"
365
- info += f"Device: {next(self.current_model.parameters()).device}\n"
366
 
367
  # Compte les paramètres
368
- total_params = sum(p.numel() for p in self.current_model.parameters())
369
- trainable_params = sum(p.numel() for p in self.current_model.parameters() if p.requires_grad)
370
-
371
- info += f"Paramètres totaux: {total_params:,}\n"
372
- info += f"Paramètres entraînables: {trainable_params:,}\n"
 
373
 
374
  if hasattr(self, 'training_data') and self.training_data:
375
- info += f"\n📊 Données: {len(self.training_data)} exemples"
 
 
376
 
377
  return info
378
 
379
- # Initialisation du trainer
380
  trainer = MultimodalTrainer()
381
 
382
  # Interface Gradio
@@ -385,11 +298,55 @@ def create_interface():
385
 
386
  gr.Markdown("""
387
  # 🔥 Multimodal Training Hub
388
- ### Entraînez vos modèles multimodaux avec facilité!
389
 
390
- Supporté: Texte 📝 Images 🖼️Audio 🎵Vidéo 🎬
391
  """)
392
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
393
  with gr.Tab("🤖 Modèle"):
394
  with gr.Row():
395
  with gr.Column():
@@ -411,23 +368,25 @@ def create_interface():
411
  interactive=False,
412
  lines=8
413
  )
 
 
 
 
 
 
 
414
 
415
  load_model_btn.click(
416
  trainer.load_model,
417
  inputs=[model_input, model_type],
418
  outputs=model_status
419
  )
 
 
420
 
421
  with gr.Tab("📊 Données"):
422
  with gr.Row():
423
  with gr.Column():
424
- gr.Markdown("### 📦 Collection HuggingFace")
425
- collection_input = gr.Textbox(
426
- label="URL de la collection",
427
- placeholder="https://huggingface.co/collections/kvn420/op-67aa4430ba254a4ff0689742"
428
- )
429
- load_collection_btn = gr.Button("📥 Charger collection", variant="secondary")
430
-
431
  gr.Markdown("### 📝 Dataset individuel")
432
  dataset_input = gr.Textbox(
433
  label="Nom du dataset",
@@ -437,7 +396,7 @@ def create_interface():
437
  label="Split",
438
  value="train"
439
  )
440
- load_dataset_btn = gr.Button("➕ Ajouter dataset", variant="secondary")
441
 
442
  with gr.Column():
443
  data_status = gr.Textbox(
@@ -446,12 +405,6 @@ def create_interface():
446
  lines=12
447
  )
448
 
449
- load_collection_btn.click(
450
- trainer.load_collection_datasets,
451
- inputs=collection_input,
452
- outputs=data_status
453
- )
454
-
455
  load_dataset_btn.click(
456
  trainer.load_single_dataset,
457
  inputs=[dataset_input, dataset_split],
@@ -478,77 +431,33 @@ def create_interface():
478
  minimum=1
479
  )
480
 
481
- with gr.Row():
482
- learning_rate = gr.Number(
483
- label="Learning rate",
484
- value=5e-5,
485
- step=1e-6
486
- )
487
- save_steps = gr.Number(
488
- label="Save steps",
489
- value=500,
490
- minimum=100
491
- )
492
 
493
- train_btn = gr.Button("🚀 Lancer l'entraînement", variant="primary", size="lg")
494
 
495
  with gr.Column():
496
  training_status = gr.Textbox(
497
  label="Status de l'entraînement",
498
  interactive=False,
499
- lines=8
500
- )
501
-
502
- info_btn = gr.Button("ℹ️ Info modèle")
503
- model_info = gr.Textbox(
504
- label="Informations du modèle",
505
- interactive=False,
506
- lines=6
507
  )
508
 
509
  train_btn.click(
510
- trainer.start_training,
511
- inputs=[output_dir, num_epochs, learning_rate, batch_size, save_steps],
512
  outputs=training_status
513
  )
514
-
515
- info_btn.click(
516
- trainer.get_model_info,
517
- outputs=model_info
518
- )
519
 
520
- with gr.Tab("📚 Aide"):
521
- gr.Markdown("""
522
- ## 🚀 Guide d'utilisation
523
-
524
- ### 1. Charger un modèle
525
- - Entrez le nom d'un modèle HuggingFace (ex: `kvn420/Tenro_V4.1`)
526
- - Choisissez le type (causal pour génération, base pour embedding)
527
- - Cliquez sur "Charger le modèle"
528
-
529
- ### 2. Ajouter des données
530
- **Collection:** Chargez tous les datasets d'une collection HF
531
- **Dataset individuel:** Ajoutez un dataset spécifique
532
-
533
- ### 3. Entraîner
534
- - Configurez les paramètres d'entraînement
535
- - Lancez l'entraînement avec "🚀 Lancer l'entraînement"
536
-
537
- ### 📋 Formats supportés
538
- - **Texte:** Colonnes `text`, `prompt`, `conversation`
539
- - **Images:** Colonnes `image`, `images` (URLs ou chemins)
540
- - **Audio:** Colonnes `audio` (fichiers audio)
541
- - **Vidéo:** Colonnes `video` (fichiers vidéo)
542
-
543
- ### ⚡ Conseils
544
- - Utilisez un GPU pour l'entraînement (T4, A10G recommandé)
545
- - Ajustez le batch_size selon votre mémoire GPU
546
- - Sauvegardez régulièrement avec save_steps
547
- """)
548
 
549
  return app
550
 
551
- # Lancement de l'application
552
  if __name__ == "__main__":
553
  app = create_interface()
554
  app.launch(share=True, server_name="0.0.0.0", server_port=7860)
 
1
  import gradio as gr
2
  import os
3
+ import subprocess
4
+ import sys
5
  import requests
6
  import json
7
  import logging
 
10
  import tempfile
11
  import shutil
12
 
13
+ # Configuration du logging
14
+ logging.basicConfig(level=logging.INFO)
15
+ logger = logging.getLogger(__name__)
 
 
 
 
 
 
 
 
 
 
16
 
17
+ # Fonction d'installation automatique
18
+ def install_package(package_name):
19
+ """Installe un package Python"""
20
+ try:
21
+ subprocess.check_call([sys.executable, "-m", "pip", "install", package_name])
22
+ return True
23
+ except subprocess.CalledProcessError as e:
24
+ logger.error(f"Erreur installation {package_name}: {e}")
25
+ return False
26
+
27
+ # Imports conditionnels avec tentative d'installation
28
+ def safe_import(module_name, package_name=None):
29
+ """Import sécurisé avec possibilité d'installation"""
30
+ if package_name is None:
31
+ package_name = module_name
32
 
33
+ try:
34
+ return __import__(module_name), True
35
+ except ImportError:
36
+ logger.warning(f"{module_name} non trouvé")
37
+ return None, False
38
+
39
+ # Tentative d'imports
40
+ numpy, NUMPY_AVAILABLE = safe_import('numpy')
41
+ torch_module, TORCH_AVAILABLE = safe_import('torch')
42
+ if torch_module:
43
+ torch = torch_module
44
+ else:
45
  torch = None
46
 
47
+ # Import transformers
48
  try:
49
  from transformers import (
50
  AutoTokenizer, AutoModel, AutoProcessor,
 
54
  TRANSFORMERS_AVAILABLE = True
55
  except ImportError:
56
  TRANSFORMERS_AVAILABLE = False
57
+ logger.warning("Transformers non disponible")
58
 
59
+ # Import datasets
60
  try:
61
  from datasets import Dataset, load_dataset, concatenate_datasets
62
  DATASETS_AVAILABLE = True
63
  except ImportError:
64
  DATASETS_AVAILABLE = False
65
+ logger.warning("Datasets non disponible")
66
+
67
+ # Import HuggingFace Hub
68
+ try:
69
+ from huggingface_hub import HfApi
70
+ HF_HUB_AVAILABLE = True
71
+ except ImportError:
72
+ HF_HUB_AVAILABLE = False
73
+ logger.warning("HuggingFace Hub non disponible")
74
 
75
+ # Import PIL
76
  try:
77
  from PIL import Image
78
  PIL_AVAILABLE = True
79
  except ImportError:
80
  PIL_AVAILABLE = False
81
 
82
+ # Import librosa
83
  try:
84
  import librosa
85
  LIBROSA_AVAILABLE = True
86
  except ImportError:
87
  LIBROSA_AVAILABLE = False
88
 
89
+ # Import OpenCV
90
  try:
91
  import cv2
92
  CV2_AVAILABLE = True
93
  except ImportError:
94
  CV2_AVAILABLE = False
95
 
 
 
 
 
96
  class MultimodalTrainer:
97
  def __init__(self):
 
 
 
 
 
 
 
 
 
98
  self.current_model = None
99
  self.current_tokenizer = None
100
  self.current_processor = None
101
  self.training_data = []
102
 
103
+ # Device selection
104
+ if TORCH_AVAILABLE and torch.cuda.is_available():
105
+ self.device = torch.device("cuda")
106
+ else:
107
+ self.device = "cpu"
108
+
109
+ # HF API
110
  if HF_HUB_AVAILABLE:
111
  self.hf_api = HfApi()
112
  else:
113
  self.hf_api = None
114
 
115
+ def install_dependencies(self, packages_to_install):
116
+ """Installe les dépendances manquantes"""
117
+ installation_results = []
118
+
119
+ for package in packages_to_install:
120
+ installation_results.append(f"📦 Installation de {package}...")
121
+ success = install_package(package)
122
+ if success:
123
+ installation_results.append(f"✅ {package} installé avec succès!")
124
+ else:
125
+ installation_results.append(f"❌ Échec installation {package}")
126
+
127
+ installation_results.append("\n🔄 Redémarrage requis pour prendre effet")
128
+ return "\n".join(installation_results)
129
+
130
  def check_dependencies(self):
131
+ """Vérifie et affiche l'état des dépendances"""
132
  deps = {
133
+ "NumPy": NUMPY_AVAILABLE,
134
  "PyTorch": TORCH_AVAILABLE,
135
  "Transformers": TRANSFORMERS_AVAILABLE,
136
  "Datasets": DATASETS_AVAILABLE,
137
+ "HuggingFace Hub": HF_HUB_AVAILABLE,
138
+ "PIL (Images)": PIL_AVAILABLE,
139
+ "Librosa (Audio)": LIBROSA_AVAILABLE,
140
+ "OpenCV (Vidéo)": CV2_AVAILABLE
 
141
  }
142
 
143
+ status = "📦 État des dépendances:\n\n"
144
+
145
+ # Dépendances critiques
146
+ critical_deps = ["PyTorch", "Transformers", "Datasets"]
147
+ status += "🔥 CRITIQUES:\n"
148
+ for dep in critical_deps:
149
+ icon = "✅" if deps.get(dep.replace(" ", "").replace("(", "").replace(")", "")) else "❌"
150
+ status += f"{icon} {dep}\n"
151
+
152
+ status += "\n🔧 OPTIONNELLES:\n"
153
+ optional_deps = ["NumPy", "HuggingFace Hub", "PIL (Images)", "Librosa (Audio)", "OpenCV (Vidéo)"]
154
+ for dep in optional_deps:
155
+ key = dep.replace(" ", "").replace("(", "").replace(")", "").replace("Images", "").replace("Audio", "").replace("Vidéo", "")
156
+ if key == "HuggingFaceHub":
157
+ key = "HuggingFace Hub"
158
+ icon = "✅" if deps.get(key) else "⚠️"
159
+ status += f"{icon} {dep}\n"
160
+
161
+ # Système info
162
+ status += f"\n💻 SYSTÈME:\n"
163
+ status += f"🐍 Python: {sys.version.split()[0]}\n"
164
+ status += f"💾 Device: {self.device}\n"
165
+
166
+ if TORCH_AVAILABLE and torch.cuda.is_available():
167
+ status += f"🚀 GPU: {torch.cuda.get_device_name()}\n"
168
+ status += f"🔋 VRAM: {torch.cuda.get_device_properties(0).total_memory / 1e9:.1f}GB\n"
169
 
170
+ return status
171
+
172
  def load_model(self, model_name: str, model_type: str = "causal"):
173
  """Charge un modèle depuis Hugging Face"""
174
  if not TRANSFORMERS_AVAILABLE:
175
+ return "❌ Transformers non installé! Utilisez l'outil d'installation."
176
 
177
  if not TORCH_AVAILABLE:
178
+ return "❌ PyTorch non installé! Utilisez l'outil d'installation."
179
+
180
+ if not model_name.strip():
181
+ return "❌ Veuillez entrer un nom de modèle"
182
 
183
  try:
184
  logger.info(f"Chargement du modèle: {model_name}")
 
198
  trust_remote_code=True
199
  )
200
 
201
+ # Charge le tokenizer
202
  try:
203
  self.current_tokenizer = AutoTokenizer.from_pretrained(
204
  model_name, trust_remote_code=True
205
  )
206
+ if self.current_tokenizer.pad_token is None:
207
+ self.current_tokenizer.pad_token = self.current_tokenizer.eos_token
208
+ except Exception as e:
209
+ logger.warning(f"Tokenizer non trouvé: {e}")
210
 
211
+ # Charge le processor
212
  try:
213
  self.current_processor = AutoProcessor.from_pretrained(
214
  model_name, trust_remote_code=True
215
  )
216
+ except Exception as e:
217
+ logger.warning(f"Processor non trouvé: {e}")
218
 
219
+ return f"✅ Modèle {model_name} chargé avec succès!\nType: {type(self.current_model).__name__}"
220
 
221
  except Exception as e:
222
  error_msg = f"❌ Erreur lors du chargement: {str(e)}"
223
  logger.error(error_msg)
224
  return error_msg
225
 
226
+ def load_single_dataset(self, dataset_name: str, split: str = "train"):
227
+ """Charge un dataset individuel"""
228
  if not DATASETS_AVAILABLE:
229
+ return "❌ Datasets non installé! Utilisez l'outil d'installation."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
230
 
231
+ if not dataset_name.strip():
232
+ return "❌ Veuillez entrer un nom de dataset"
 
 
 
 
 
 
 
233
 
 
 
 
 
 
 
 
234
  try:
235
  dataset = load_dataset(dataset_name, split=split)
236
 
237
  if hasattr(self, 'training_data') and self.training_data:
 
238
  self.training_data = concatenate_datasets([self.training_data, dataset])
239
  else:
240
  self.training_data = dataset
241
 
242
+ return f"✅ Dataset {dataset_name} ajouté!\n📊 Total: {len(self.training_data)} exemples\n🔍 Colonnes: {list(self.training_data.column_names)}"
243
 
244
  except Exception as e:
245
  error_msg = f"❌ Erreur dataset: {str(e)}"
246
  logger.error(error_msg)
247
  return error_msg
248
 
249
+ def simulate_training(self, output_dir: str, num_epochs: int, learning_rate: float, batch_size: int):
250
+ """Simulation d'entraînement (mode démo)"""
251
+ if not self.current_model and not self.training_data:
252
+ return "❌ Aucun modèle ou donnée chargé!"
253
 
254
+ # Simulation
255
+ steps = ["🏗️ Préparation des données", "🔧 Configuration du modèle", "🚀 Début entraînement"]
256
+ result = "📋 SIMULATION D'ENTRAÎNEMENT:\n\n"
257
+ result += f"📂 Sortie: {output_dir}\n"
258
+ result += f"🔄 Époques: {num_epochs}\n"
259
+ result += f"📚 Learning rate: {learning_rate}\n"
260
+ result += f"📦 Batch size: {batch_size}\n\n"
 
 
 
 
261
 
262
+ for i, step in enumerate(steps):
263
+ result += f"Étape {i+1}: {step} ✅\n"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
264
 
265
+ result += "\n⚠️ MODE DÉMO - Pour un vrai entraînement, installez PyTorch + Transformers"
266
+ return result
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
267
 
268
  def get_model_info(self):
269
  """Retourne les informations du modèle actuel"""
270
  if not self.current_model:
271
+ return "Aucun modèle chargé"
272
 
273
+ info = f"📋 INFORMATIONS DU MODÈLE:\n\n"
274
+ info += f"🏷️ Type: {type(self.current_model).__name__}\n"
275
+ info += f"💾 Device: {next(self.current_model.parameters()).device}\n"
276
 
277
  # Compte les paramètres
278
+ if TORCH_AVAILABLE:
279
+ total_params = sum(p.numel() for p in self.current_model.parameters())
280
+ trainable_params = sum(p.numel() for p in self.current_model.parameters() if p.requires_grad)
281
+
282
+ info += f"🔢 Paramètres totaux: {total_params:,}\n"
283
+ info += f"🎯 Paramètres entraînables: {trainable_params:,}\n"
284
 
285
  if hasattr(self, 'training_data') and self.training_data:
286
+ info += f"\n📊 DONNÉES:\n"
287
+ info += f"📈 Exemples: {len(self.training_data):,}\n"
288
+ info += f"📝 Colonnes: {list(self.training_data.column_names)}\n"
289
 
290
  return info
291
 
292
+ # Initialisation
293
  trainer = MultimodalTrainer()
294
 
295
  # Interface Gradio
 
298
 
299
  gr.Markdown("""
300
  # 🔥 Multimodal Training Hub
301
+ ### Plateforme d'entraînement de modèles multimodaux
302
 
303
+ 🤖 Modèles📊 Datasets🏋️ Training🛠️ Outils
304
  """)
305
 
306
+ with gr.Tab("🔧 Diagnostic"):
307
+ gr.Markdown("### 🩺 Vérification du système")
308
+
309
+ with gr.Row():
310
+ check_deps_btn = gr.Button("🔍 Vérifier dépendances", variant="primary")
311
+ install_core_btn = gr.Button("📦 Installer packages critiques", variant="secondary")
312
+
313
+ deps_status = gr.Textbox(
314
+ label="État des dépendances",
315
+ lines=15,
316
+ interactive=False
317
+ )
318
+
319
+ with gr.Row():
320
+ install_transformers_btn = gr.Button("🤗 Installer Transformers")
321
+ install_torch_btn = gr.Button("🔥 Installer PyTorch")
322
+ install_datasets_btn = gr.Button("📊 Installer Datasets")
323
+
324
+ install_status = gr.Textbox(
325
+ label="Status d'installation",
326
+ lines=5,
327
+ interactive=False
328
+ )
329
+
330
+ # Events
331
+ check_deps_btn.click(trainer.check_dependencies, outputs=deps_status)
332
+
333
+ install_transformers_btn.click(
334
+ lambda: trainer.install_dependencies(["transformers"]),
335
+ outputs=install_status
336
+ )
337
+ install_torch_btn.click(
338
+ lambda: trainer.install_dependencies(["torch", "torchvision"]),
339
+ outputs=install_status
340
+ )
341
+ install_datasets_btn.click(
342
+ lambda: trainer.install_dependencies(["datasets"]),
343
+ outputs=install_status
344
+ )
345
+ install_core_btn.click(
346
+ lambda: trainer.install_dependencies(["torch", "transformers", "datasets", "accelerate"]),
347
+ outputs=install_status
348
+ )
349
+
350
  with gr.Tab("🤖 Modèle"):
351
  with gr.Row():
352
  with gr.Column():
 
368
  interactive=False,
369
  lines=8
370
  )
371
+
372
+ info_btn = gr.Button("ℹ️ Info modèle")
373
+ model_info = gr.Textbox(
374
+ label="Informations détaillées",
375
+ interactive=False,
376
+ lines=8
377
+ )
378
 
379
  load_model_btn.click(
380
  trainer.load_model,
381
  inputs=[model_input, model_type],
382
  outputs=model_status
383
  )
384
+
385
+ info_btn.click(trainer.get_model_info, outputs=model_info)
386
 
387
  with gr.Tab("📊 Données"):
388
  with gr.Row():
389
  with gr.Column():
 
 
 
 
 
 
 
390
  gr.Markdown("### 📝 Dataset individuel")
391
  dataset_input = gr.Textbox(
392
  label="Nom du dataset",
 
396
  label="Split",
397
  value="train"
398
  )
399
+ load_dataset_btn = gr.Button("➕ Ajouter dataset", variant="primary")
400
 
401
  with gr.Column():
402
  data_status = gr.Textbox(
 
405
  lines=12
406
  )
407
 
 
 
 
 
 
 
408
  load_dataset_btn.click(
409
  trainer.load_single_dataset,
410
  inputs=[dataset_input, dataset_split],
 
431
  minimum=1
432
  )
433
 
434
+ learning_rate = gr.Number(
435
+ label="Learning rate",
436
+ value=5e-5,
437
+ step=1e-6
438
+ )
 
 
 
 
 
 
439
 
440
+ train_btn = gr.Button("🚀 Simuler entraînement", variant="primary", size="lg")
441
 
442
  with gr.Column():
443
  training_status = gr.Textbox(
444
  label="Status de l'entraînement",
445
  interactive=False,
446
+ lines=12
 
 
 
 
 
 
 
447
  )
448
 
449
  train_btn.click(
450
+ trainer.simulate_training,
451
+ inputs=[output_dir, num_epochs, learning_rate, batch_size],
452
  outputs=training_status
453
  )
 
 
 
 
 
454
 
455
+ # Auto-check au démarrage
456
+ app.load(trainer.check_dependencies, outputs=deps_status)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
457
 
458
  return app
459
 
460
+ # Lancement
461
  if __name__ == "__main__":
462
  app = create_interface()
463
  app.launch(share=True, server_name="0.0.0.0", server_port=7860)