Spaces:
Sleeping
Sleeping
File size: 10,985 Bytes
8175ceb 47784a4 8175ceb 47784a4 8175ceb 47784a4 8175ceb 90e835a 8175ceb | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 | # Fichier : app.py
import os
import torch
import gradio as gr
from datasets import load_dataset
from transformers import AutoTokenizer, AutoModelForCausalLM, TrainingArguments, Trainer
from huggingface_hub import HfApi
# ==============================================================================
# 🛠️ Configuration et Modèles de Base Lamina
# ==============================================================================
# Dictionnaire des modèles de base disponibles (Modèle_ID: Nom_Affiché + Description)
MODELS_CONFIG = {
"Finisha-LLM/Ilyana-pretrain": {
"name": "Ilyana (fort en français)",
"desc": "🚀 fort en français",
"max_seq": 500 # Longueur de séquence ajustée pour ce petit modèle
},
"Finisha-LLM/Serena": {
"name": "Serena, modèle espagnol",
"desc": "✨ Bon compromis.",
"max_seq": 328
},
"Finisha-LLM/Nelya-neko": {
"name": "Nelya",
"desc": "⚠️ Modèle nekolien.",
"max_seq": 256
}
}
# Clés pour le Dropdown Gradio
MODEL_CHOICES = list(MODELS_CONFIG.keys())
# ==============================================================================
# 🧠 Fonction Principale de Fine-Tuning
# ==============================================================================
def train_and_push_model(
hf_token: str,
hf_username: str,
model_name: str,
num_epochs: int,
dataset_repo: str,
base_model_repo: str
):
"""
Exécute le fine-tuning d'un modèle Lamina et le publie sur Hugging Face.
"""
# --- 0. Initialisation et Connexion ---
# Récupération de la configuration spécifique du modèle choisi
config = MODELS_CONFIG[base_model_repo]
max_seq_length = config["max_seq"]
yield f"Début du processus pour le modèle de base : **{config['name']}**"
# ⚠️ Vérification du Token et connexion
if not hf_token or not hf_username:
yield "❌ ERREUR : Le Token HF ou le Nom d'utilisateur est manquant. Veuillez les fournir."
return
os.environ["HUGGING_FACE_HUB_TOKEN"] = hf_token
api = HfApi()
# Définition du nom final du repository sur le compte de l'utilisateur
final_repo_name = f"{hf_username}/{model_name}"
# --- 1. Chargement du Modèle et du Tokenizer ---
yield f"Chargement du modèle : **{base_model_repo}**..."
try:
model = AutoModelForCausalLM.from_pretrained(base_model_repo)
tokenizer = AutoTokenizer.from_pretrained(base_model_repo)
if tokenizer.pad_token is None:
tokenizer.pad_token = tokenizer.eos_token
yield "✅ Modèle et Tokenizer chargés."
except Exception as e:
yield f"❌ ERREUR lors du chargement du modèle/tokenizer : {e}"
return
# --- 2. Préparation du Dataset ---
yield f"Chargement du dataset de Q&R : **{dataset_repo}**..."
try:
# Assurez-vous que le split 'train' est présent
dataset = load_dataset(dataset_repo, split="train")
yield f"Dataset chargé. Nombre de lignes initiales : **{len(dataset)}**"
except Exception as e:
yield f"❌ ERREUR lors du chargement de la dataset '{dataset_repo}'. Vérifiez le nom/ID et sa disponibilité. Détail : {e}"
return
# Fonction de formatage et de tokenisation (celle que tu as fournie)
def format_and_tokenize(example):
# Utilisation de 'reponse' comme dans ton exemple
formatted_text = f"### Instruction:\n{example['question']}\n\n### Response:\n{example['reponse']}{tokenizer.eos_token}"
tokenized_output = tokenizer(
formatted_text,
truncation=True,
padding="max_length",
max_length=max_seq_length
)
tokenized_output["labels"] = tokenized_output["input_ids"].copy()
return tokenized_output
yield "Tokenisation et formatage du dataset en cours..."
try:
processed_dataset = dataset.map(format_and_tokenize, remove_columns=dataset.column_names)
yield "✅ Dataset formaté et tokenisé."
except Exception as e:
yield f"❌ ERREUR lors du formatage de la dataset. Assurez-vous que les colonnes 'question' et 'reponse' existent. Détail : {e}"
return
# --- 3. Fine-Tuning ---
output_dir = "./Lamina-FineTune-Temp"
training_args = TrainingArguments(
output_dir=output_dir,
num_train_epochs=num_epochs,
per_device_train_batch_size=2, # Taille de batch par défaut raisonnable
logging_steps=5,
learning_rate=5e-5,
save_total_limit=2,
# Ajout du push vers le hub pour la fin
push_to_hub=False # On va le faire manuellement après l'entraînement
)
trainer = Trainer(
model=model,
args=training_args,
train_dataset=processed_dataset,
tokenizer=tokenizer,
)
yield f"🚀 Lancement du fine-tuning pour **{num_epochs}** époques..."
try:
trainer.train()
yield "✅ Fine-tuning terminé !"
except Exception as e:
yield f"❌ ERREUR lors de l'entraînement. Cela peut être dû à un manque de ressources ou une erreur dans le dataset. Détail : {e}"
return
# --- 4. Sauvegarde et Publication sur Hugging Face ---
# Sauvegarde locale du modèle entraîné
final_model_path = "./Lamina-Trained-Final"
trainer.save_model(final_model_path)
tokenizer.save_pretrained(final_model_path)
yield f"📦 Modèle sauvegardé localement. Publication sur **{final_repo_name}** en cours..."
try:
# Création ou utilisation d'un repository existant
api.create_repo(repo_id=final_repo_name, exist_ok=True)
# Téléchargement des fichiers
api.upload_folder(
folder_path=final_model_path,
repo_id=final_repo_name,
repo_type="model",
commit_message=f"Fine-tune de {base_model_repo} par le Lamina Generator"
)
final_link = f"https://huggingface.co/{final_repo_name}"
yield f"🎉 **SUCCÈS !** Votre modèle Lamina a été publié !\n"
yield f"Consultez votre modèle ici : {final_link}\n"
yield f"**Prochaine étape :** Créez un Space de démonstration pour votre nouveau modèle !"
except Exception as e:
yield f"❌ ERREUR lors de la publication sur Hugging Face. Vérifiez votre token (autorisation d'écriture) et votre nom d'utilisateur. Détail : {e}"
return
# ==============================================================================
# 🖥️ Interface Gradio
# ==============================================================================
# Description détaillée pour l'interface
description = """
# 🧠 Lamina Generator : Créez votre propre SLM Lamina sans code !
Bienvenue Clemylia Community ! Cet outil vous permet de *fine-tuner* un de mes modèles Lamina de *pretrain* (lamina-basic, Small-lamina-pretrain, lamina-suite-pretrain) avec votre propre dataset de questions/réponses.
Votre nouveau modèle sera automatiquement publié sur votre compte Hugging Face !
---
**⚠️ Avertissements Importants :**
1. **Token Nécessaire :** Vous devez utiliser un **Hugging Face Token avec les permissions d'écriture** (`write`) pour que le modèle puisse être publié sur votre compte.
2. **Dataset :** Votre dataset doit être **publique** et contenir au moins deux colonnes nommées : `question` et `reponse`.
3. **Taille :** Le temps d'entraînement dépend du modèle de base choisi et de la taille de votre dataset. Le grand modèle (`lamina-suite-pretrain`) peut prendre **plusieurs heures**.
Choisissez votre modèle de base ci-dessous pour voir la description complète et les recommandations.
"""
with gr.Blocks(title="Lamina Generator") as demo:
gr.Markdown(description)
# Ajout d'un affichage dynamique pour les descriptions de modèle
model_info_output = gr.Markdown("Sélectionnez un modèle de base ci-dessous.")
def update_model_info(model_id):
if model_id in MODELS_CONFIG:
config = MODELS_CONFIG[model_id]
return f"**Modèle sélectionné :** {config['name']} \n\n**Recommandation :** {config['desc']}"
return "Sélectionnez un modèle de base ci-dessous."
with gr.Row():
base_model_dropdown = gr.Dropdown(
label="1. Choisir le Modèle de Base Lamina",
choices=MODEL_CHOICES,
value=MODEL_CHOICES[1], # Default to Small-lamina-pretrain
interactive=True
)
base_model_dropdown.change(update_model_info, inputs=base_model_dropdown, outputs=model_info_output)
# Affichage des infos/avertissements du modèle
gr.Markdown("---")
model_info_output = gr.Markdown(update_model_info(MODEL_CHOICES[1]))
gr.Markdown("---")
with gr.Accordion("🔑 Informations d'Authentification (Nécessaires pour publier)", open=True):
hf_token_input = gr.Textbox(
label="2. Votre Hugging Face Write Token",
type="password",
placeholder="hf_xxxxxxxxxxxxxxxxxxxxxx",
info="Token avec permission d'écriture pour la publication du modèle."
)
hf_username_input = gr.Textbox(
label="3. Votre Nom d'utilisateur Hugging Face",
placeholder="Clemylia",
info="L'utilisateur sous lequel le modèle sera publié."
)
with gr.Accordion("📚 Configuration du Fine-Tuning", open=True):
dataset_repo_input = gr.Textbox(
label="4. Nom/ID Complet de votre Dataset (Hugging Face)",
placeholder="votre_nom_utilisateur/nom_de_votre_dataset",
info="Le dataset doit contenir les colonnes 'question' et 'reponse'."
)
model_name_input = gr.Textbox(
label="5. Nom du Modèle Final",
placeholder="mon-super-lamina",
info="Le modèle sera publié sous le nom : <votre_nom>/<nom_du_modèle>."
)
epochs_input = gr.Slider(
minimum=1,
maximum=100,
value=3,
step=1,
label="6. Nombre d'Époques d'Entraînement",
info="Plus d'époques = meilleure mémorisation, mais risque de 'sur-apprentissage'."
)
# Zone de Log et Bouton
output_log = gr.Markdown("Prêt à entraîner ! Remplissez les champs et cliquez sur le bouton.")
train_button = gr.Button("🤖 Entraîner mon propre Lamina ! 🚀", variant="primary")
# Lien du bouton à la fonction Python
train_button.click(
fn=train_and_push_model,
inputs=[
hf_token_input,
hf_username_input,
model_name_input,
epochs_input,
dataset_repo_input,
base_model_dropdown
],
outputs=output_log
)
if __name__ == "__main__":
demo.launch() |