--- --- extra_gated_prompt: "🌸 Pour accéder a ce modèle, vous devez accepter de l'utiliser pour ce dont il a été conçu, et ne pas attendre de texte conventionnels.🌸" extra_gated_fields: Company: text Country: country Specific date: date_picker I want to use this model for: type: select options: - Création de chansons - Philosophie - label: Other value: other I agree to use this model for non-commercial use ONLY: checkbox license: mit language: - fr pipeline_tag: text-generation tags: - Slm - Charlotte - Aricate - pretrain - Completion - Modèle d'IA --- # 📚 Documentation Utilisateur : Charlotte-1 SLM (Aricate) ![Charlotte](http://www.image-heberg.fr/files/17613754291411254766.jpg) ## Présentation Générale ✨ Bienvenue dans la documentation du modèle **Charlotte-1**, un Small Language Model (SLM) entraîné *from scratch* par Clemylia, utilisant l'architecture Aricate (GRU + Attention). Charlotte-1 est spécialisé dans la continuation de phrases et la génération de contenu textuel basé sur des articles (Espoir, amour, amitié). Il excelle à prédire le mot le plus pertinent suivant un contexte donné. | Caractéristique | Détail | | :--- | :--- | | **Architecte** | Clemylia | | **Architecture** | Aricate (GRU + Attention) | | **Dépôt Hugging Face** | `Clemylia/Charlotte-1.0` | | **Fonction** | Prédiction du mot suivant et génération de phrases | | **Langue** | Français | ----- ## 🛠️ Prérequis et Installation Pour utiliser Charlotte-1, vous devez disposer d'un environnement Python avec les bibliothèques suivantes : 1. **PyTorch** : Le framework principal. 2. **Hugging Face Hub** : Pour télécharger les fichiers du modèle. 3. **SafeTensors** : Pour charger les poids du modèle. ```bash # Installation des dépendances nécessaires pip install torch huggingface-hub safetensors tqdm ``` ----- ## 📦 Utilisation du Modèle pour la Génération de Texte Le code ci-dessous vous permet de charger le modèle directement depuis le profil Hugging Face de Clemylia et de générer du texte en fournissant une phrase de départ (**prompt**). ### Code d'Inférence (À Exécuter) Vous pouvez copier et exécuter le code suivant (en le sauvegardant par exemple sous le nom `generate_charlotte.py`) : ```python import torch import torch.nn as nn import torch.nn.functional as F import json import os from safetensors.torch import load_file as load_safetensors_file from huggingface_hub import hf_hub_download # --- Configuration (CRITIQUE : DOIT ÊTRE IDENTIQUE À L'ENTRAÎNEMENT) --- CONFIG = { "HF_REPO_ID": "Clemylia/Charlotte-1.0", "MODEL_NAME": "Charlotte-1", "MAX_LEN_INPUT": 80, "EMBEDDING_DIM": 100, "HIDDEN_DIM": 128, "NUM_LAYERS": 2, "DEVICE": torch.device("cuda" if torch.cuda.is_available() else "cpu"), } WEIGHTS_FILENAME = f"{CONFIG['MODEL_NAME']}_best_weights.safetensors" TOKENIZER_FILENAME = f"{CONFIG['MODEL_NAME']}_tokenizer.json" # --- Définitions des Classes Aricate (Omisses pour la concision, mais doivent être incluses) --- # NOTE: Inclure ici les classes AricateAttentionLayer, AricateModel et InferenceTokenizer # exactement comme dans le script d'inférence précédent. # Pour une exécution directe, ces classes DOIVENT être présentes dans le script. # --- Fonctions de Chargement et Génération --- def load_model_from_hub(repo_id, weights_filename, tokenizer_filename): """Télécharge les fichiers et charge le modèle Charlotte-1.""" # print(f"🌍 Téléchargement des fichiers depuis {repo_id}...") try: # Téléchargement du Tokenizer tokenizer_path = hf_hub_download(repo_id=repo_id, filename=tokenizer_filename) tokenizer = InferenceTokenizer(tokenizer_path) # Téléchargement des Poids weights_path = hf_hub_download(repo_id=repo_id, filename=weights_filename) state_dict = load_safetensors_file(weights_path) # Initialisation du Modèle (Les classes AricateModel/Attention/Tokenizer doivent être définies ici) model = AricateModel( vocab_size=tokenizer.vocab_size, embedding_dim=CONFIG['EMBEDDING_DIM'], hidden_dim=CONFIG['HIDDEN_DIM'], num_layers=CONFIG['NUM_LAYERS'] ).to(CONFIG['DEVICE']) model.load_state_dict(state_dict) model.eval() print(f"✅ Modèle {CONFIG['MODEL_NAME']} chargé avec succès.") return model, tokenizer except Exception as e: print(f"❌ ERREUR lors du chargement: {e}") return None, None def generate_sentence(model, tokenizer, prompt, max_length=50, temperature=0.7): """Génère du texte mot par mot (boucle séquentielle Aricate).""" model.eval() current_prompt = prompt.lower() separator_token = ' ' print(f"\n[Génération démarrée] Température: {temperature}") print("--------------------------------------------------") print(current_prompt, end=" ", flush=True) generated_text = current_prompt.split() with torch.no_grad(): for i in range(max_length): input_text = current_prompt + separator_token input_ids = tokenizer.encode(input_text) if len(input_ids) > CONFIG['MAX_LEN_INPUT']: input_ids = input_ids[-CONFIG['MAX_LEN_INPUT']:] padding_needed = CONFIG['MAX_LEN_INPUT'] - len(input_ids) padded_ids = input_ids + [tokenizer.special_tokens['']] * padding_needed input_tensor = torch.tensor([padded_ids], dtype=torch.long, device=CONFIG['DEVICE']) logits = model(input_tensor) output_position = len(input_ids) - 1 if output_position < 0: output_position = 0 next_token_logits = logits[0, output_position, :] if temperature == 0: next_token_id = torch.argmax(next_token_logits).item() else: probabilities = F.softmax(next_token_logits / temperature, dim=-1).squeeze(0) next_token_id = torch.multinomial(probabilities, num_samples=1).item() next_word = tokenizer.decode_id(next_token_id) if next_word in ['', '', '']: print("...", end="") break print(next_word, end=" ", flush=True) current_prompt += f" {next_word}" generated_text.append(next_word) if next_word.endswith(('.', '!', '?')) and len(generated_text) > 5: break print("\n--------------------------------------------------") if __name__ == '__main__': # ⚠️ REMPLACER LES CLASSES MANQUANTES ICI # (Incluez les définitions d'AricateModel, AricateAttentionLayer, InferenceTokenizer) # ... (Les classes AricateAttentionLayer, AricateModel et InferenceTokenizer du script précédent doivent être définies ici) ... model, tokenizer = load_model_from_hub( CONFIG['HF_REPO_ID'], WEIGHTS_FILENAME, TOKENIZER_FILENAME ) if model: # Exemple d'utilisation prompt_1 = "l'intelligence artificielle est un domaine en pleine" generate_sentence(model, tokenizer, prompt=prompt_1, max_length=25, temperature=0.8) ``` ----- ## ⚙️ Paramètres de Génération Vous pouvez ajuster deux paramètres principaux dans la fonction `generate_sentence` pour contrôler le style du texte généré : ### 1\. `max_length` 📏 * **Description** : Le nombre maximal de nouveaux mots que le modèle est autorisé à générer après le prompt. * **Recommandation** : Fixez-le à une valeur raisonnable (ex. 20 à 50) pour les phrases courtes ou les continuations d'articles. ### 2\. `temperature` 🌡️ (Créativité) * **Description** : Contrôle la liberté et l'aléatoire de la sélection du prochain mot. * **Température basse (proche de 0.0)** : Le modèle choisit les mots les plus probables, ce qui donne un texte cohérent et prédictible (**Greedy**). Idéal pour les suites logiques ou les faits. * **Température élevée (proche de 1.0)** : Le modèle est plus créatif et explore des options moins probables, ce qui peut conduire à des résultats inattendus, mais potentiellement plus intéressants. | Température | Résultat | Utilisation | | :--- | :--- | :--- | | **0.0** | Déterministe, logique. | Suites de faits, complétion simple. | | **0.7 - 0.9** | Équilibré, fluide, créatif. | Génération d'articles, histoires courtes. | | **1.0+** | Chaotique, hautement aléatoire. | Expérimentation. | **Si le code par défaut ne fonctionne pas, voici un exemple d'utilisation qui fonctionnera** : ``` import torch import torch.nn as nn import torch.nn.functional as F import json import os import collections from safetensors.torch import load_file as load_safetensors_file from huggingface_hub import hf_hub_download # Import essentiel pour le Hub from tqdm import tqdm # --- Configuration Globale (Doit correspondre à l'entraînement) --- CONFIG = { "HF_REPO_ID": "Clemylia/Charlotte-1.0", # Votre dépôt Hugging Face "MODEL_NAME": "Charlotte-1", # Nom du modèle dans les fichiers "MAX_LEN_INPUT": 80, "EMBEDDING_DIM": 100, "HIDDEN_DIM": 128, "NUM_LAYERS": 2, "DEVICE": torch.device("cuda" if torch.cuda.is_available() else "cpu"), } # --- Noms de Fichiers sur le Hub --- WEIGHTS_FILENAME = f"{CONFIG['MODEL_NAME']}_best_weights.safetensors" TOKENIZER_FILENAME = f"{CONFIG['MODEL_NAME']}_tokenizer.json" # ---------------------------------------------------------------------- ## 1. Classes (Tokenizer et Architecture Aricate) # ---------------------------------------------------------------------- class InferenceTokenizer: """Charge le vocabulaire pour l'inférence.""" def __init__(self, tokenizer_file_path): with open(tokenizer_file_path, 'r', encoding='utf-8') as f: self.word_to_id = json.load(f) self.id_to_word = {v: k for k, v in self.word_to_id.items()} self.vocab_size = len(self.word_to_id) self.special_tokens = { '': self.word_to_id.get('', 0), '': self.word_to_id.get('', 1), '': self.word_to_id.get('', 2) } def encode(self, text): tokens = text.lower().split() ids = [self.word_to_id.get(token, self.special_tokens['']) for token in tokens] return ids def decode_id(self, token_id): return self.id_to_word.get(int(token_id), '') # --- Architecture Aricate (Identique à l'entraînement) --- class AricateAttentionLayer(nn.Module): def __init__(self, hidden_dim): super().__init__() self.W = nn.Linear(hidden_dim, hidden_dim) self.U = nn.Linear(hidden_dim, hidden_dim) self.V = nn.Linear(hidden_dim, 1, bias=False) def forward(self, rnn_outputs, last_hidden): last_hidden_expanded = last_hidden.unsqueeze(1) energy = torch.tanh(self.W(rnn_outputs) + self.U(last_hidden_expanded)) attention_weights_raw = self.V(energy).squeeze(2) attention_weights = F.softmax(attention_weights_raw, dim=1) context_vector = torch.sum(rnn_outputs * attention_weights.unsqueeze(2), dim=1) return context_vector class AricateModel(nn.Module): def __init__(self, vocab_size: int, embedding_dim: int, hidden_dim: int, num_layers: int): super().__init__() self.word_embeddings = nn.Embedding( num_embeddings=vocab_size, embedding_dim=embedding_dim, padding_idx=0 ) self.rnn = nn.GRU( input_size=embedding_dim, hidden_size=hidden_dim, num_layers=num_layers, batch_first=True ) self.attention = AricateAttentionLayer(hidden_dim) self.hidden_to_vocab = nn.Linear(hidden_dim * 2, vocab_size) def forward(self, input_words): embeds = self.word_embeddings(input_words) rnn_out, hn = self.rnn(embeds) last_hidden = hn[-1] context_vector = self.attention(rnn_out, last_hidden) combined_features = torch.cat((context_vector, last_hidden), dim=1) logits = self.hidden_to_vocab(combined_features) return logits # ---------------------------------------------------------------------- ## 3. Fonctions de Chargement depuis Hugging Face et de Génération # ---------------------------------------------------------------------- def load_model_from_hub(repo_id, weights_filename, tokenizer_filename): """Télécharge les fichiers et charge le modèle Charlotte-1.""" print(f"🌍 Téléchargement des fichiers depuis {repo_id}...") try: # Téléchargement du Tokenizer tokenizer_path = hf_hub_download(repo_id=repo_id, filename=tokenizer_filename) tokenizer = InferenceTokenizer(tokenizer_path) # Téléchargement des Poids weights_path = hf_hub_download(repo_id=repo_id, filename=weights_filename) state_dict = load_safetensors_file(weights_path) # Initialisation du Modèle model = AricateModel( vocab_size=tokenizer.vocab_size, embedding_dim=CONFIG['EMBEDDING_DIM'], hidden_dim=CONFIG['HIDDEN_DIM'], num_layers=CONFIG['NUM_LAYERS'] ).to(CONFIG['DEVICE']) # Chargement des Poids model.load_state_dict(state_dict) model.eval() print(f"✅ Modèle {CONFIG['MODEL_NAME']} chargé avec succès depuis Hugging Face.") return model, tokenizer except Exception as e: print(f"❌ ERREUR lors du chargement depuis Hugging Face: {e}") print("Vérifiez l'ID du dépôt, le nom des fichiers et les hyperparamètres du modèle.") return None, None def generate_sentence(model, tokenizer, prompt, max_length=50, temperature=0.7): """Génère du texte mot par mot.""" model.eval() current_prompt = prompt.lower() separator_token = ' ' print(f"\n[Génération démarrée] Température: {temperature}") print("--------------------------------------------------") print(current_prompt, end=" ", flush=True) generated_text = current_prompt.split() with torch.no_grad(): for i in range(max_length): # 1. Préparation de l'entrée input_text = current_prompt + separator_token input_ids = tokenizer.encode(input_text) # 2. Tronquage et Padding if len(input_ids) > CONFIG['MAX_LEN_INPUT']: input_ids = input_ids[-CONFIG['MAX_LEN_INPUT']:] padding_needed = CONFIG['MAX_LEN_INPUT'] - len(input_ids) padded_ids = input_ids + [tokenizer.special_tokens['']] * padding_needed input_tensor = torch.tensor([padded_ids], dtype=torch.long, device=CONFIG['DEVICE']) # 3. Prédiction logits = model(input_tensor) # L'output est pour la position du token (dernière position non-padding) # CORRECTION: The AricateModel outputs a single prediction for the next token, # so the logits tensor shape is [batch_size, vocab_size]. # We directly use the logits for the first (and only) item in the batch. next_token_logits = logits[0, :] # 4. Choix du token (Sampling ou Greedy) if temperature == 0: next_token_id = torch.argmax(next_token_logits).item() else: probabilities = F.softmax(next_token_logits / temperature, dim=-1).squeeze(0) next_token_id = torch.multinomial(probabilities, num_samples=1).item() # 5. Décodage et Arrêt next_word = tokenizer.decode_id(next_token_id) if next_word in ['', '', '']: print("...", end="") break print(next_word, end=" ", flush=True) # 6. Mise à jour du Prompt current_prompt += f" {next_word}" generated_text.append(next_word) if next_word.endswith(('.', '!', '?')) and len(generated_text) > 5: break print("\n--------------------------------------------------") return " ".join(generated_text) # ---------------------------------------------------------------------- ## 4. Bloc d'Exécution Principal # ---------------------------------------------------------------------- if __name__ == '__main__': model, tokenizer = load_model_from_hub( CONFIG['HF_REPO_ID'], WEIGHTS_FILENAME, TOKENIZER_FILENAME ) if model is None: exit() print("\n" + "="*70) print(f"TEST DE GÉNÉRATION CHARLOTTE-1 DEPUIS {CONFIG['HF_REPO_ID']}") print("="*70) # --- Test 1: Génération Créative --- prompt_1 = "l'intelligence artificielle permet aux entreprises de" generate_sentence( model, tokenizer, prompt=prompt_1, max_length=30, temperature=0.9 ) # --- Test 2: Génération plus déterministe --- prompt_2 = "les dernières actualités scientifiques parlent de l'amitié" generate_sentence( model, tokenizer, prompt=prompt_2, max_length=20, temperature=0.8 ) print("\nTests de génération terminés.") ```