File size: 15,331 Bytes
1a92342 eae6d52 1a92342 eae6d52 1a92342 618e7e7 1a92342 618e7e7 1a92342 49187e4 |
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 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 |
---
license: mit
language:
- fr
pipeline_tag: text-generation
---
## 💾 Documentation Technique : Xadia-charlotte (SLM)

Bienvenue dans l'expérience **Xadia-charlotte**. Ce Small Language Model (SLM) est un outil d'**exploration lexicale** conçu pour les auteurs-compositeurs cherchant à briser le blocage créatif en travaillant à partir de fragments de langage non structurés.
### ⚙️ Philosophie du Modèle
**Xadia-charlotte** n'est **PAS** un générateur de texte traditionnel. Il est votre partenaire pour le **"décorticage créatif"**.
* **Fonctionnement :** Le modèle a été entraîné sur un corpus de chansons de haute qualité (créé par Clemylia), mais il est paramétré pour générer des séquences avec une **diversité lexicale maximale** et une **faible cohérence sémantique/syntaxique**.
* **Objectif :** Générer une **matière première brute** (mots, ponctuations, fragments) que l'utilisateur doit **trier, réorganiser et interpréter** pour y découvrir de nouvelles idées, métaphores ou tournures de phrases.
* **Thèmes Cibles :** Le vocabulaire généré sera majoritairement orienté vers l'**Espoir** ✨, l'**Amitié** 🤝, et l'**Écologie** 🌳.
### 🛠️ Mode d'Utilisation (Le Prompt)
Le modèle fonctionne uniquement par **complétion de séquence**. Vous devez lui fournir un début de refrain ou de couplet (le *prompt*) pour amorcer la génération.
#### 1. Formuler votre Prompt (Début de Chanson)
Le prompt idéal est un début de phrase ou une phrase complète qui **pose le contexte thématique** souhaité.
| Thème Cible | Exemple de Prompt |
| :--- | :--- |
| **Espoir** ✨ | `Malgré la nuit qui tombe, je vois encore...` |
| **Amitié** 🤝 | `Ce lien qui nous unit est comme...` |
| **Écologie** 🌳 | `Quand le vent se lève, il porte la voix...` |
> ⚠️ **Note Importante :** Ne demandez **JAMAIS** une action au modèle (`Génère une idée sur...`). Le prompt doit être une **séquence de mots** à compléter.
#### 2. Interpréter la Sortie (L'Art de l'Extraction)
La sortie de **Xadia-charlotte** sera une longue chaîne de mots, d'articles, et de ponctuations, souvent creative.
**Exemple de Sortie (après le prompt) :**
`un le , je n’a qui , est s de , rêves , qui plus , pas , , est suis ne , est je perdu , très : ne , le ne , , , la de sans frais n’a de , de . rien , y , tour est`
**Processus d'Extraction/Idéation :**
1. **Scanner pour les Mots-Clés :** Lisez rapidement la séquence et notez les mots porteurs de sens : `rêves`, `perdu`, `frais`, `guide`, `flamme`, `trésor`.
2. **Former des Groupes de Mots :** Assemblez les mots-clés qui résonnent ensemble, ignorant les articles ou la ponctuation parasites :
* `rêves perdu`
* `flamme trésor`
* `sans frais`
3. **Construire l'Idée :** Utilisez ces fragments pour *inspirer* de nouvelles lignes pour votre chanson.
| Fragment Généré | Interprétation (Ligne de Chanson) |
| :--- | :--- |
| `flamme trésor` | "Notre amitié est une **flamme** qui garde le **trésor** au chaud." |
| `rêves perdu guide` | "Même si je me sens **perdu**, mes **rêves** sont mon seul **guide**." |
### 🛑 Limites & Responsabilité de l'Auteur
* **Cohérence Zéro :** N'attendez **aucune** cohérence syntaxique ou sémantique. Le modèle est intentionnellement sous-optimisé pour cette tâche afin de stimuler une pensée non linéaire.
* **La Créativité est Manuelle :** L'utilisateur est le seul responsable de la **soudure, du rythme, des rimes et de la structure** de la chanson finale. Xadia-charlotte n'est qu'un **dictionnaire de suggestions par probabilité**.
exemple de code d'utilisation :
```
# ==============================================================================
# CHARGEMENT ET TEST DE XADIA-CHARLOTTE
# ==============================================================================
# 1. INSTALLATION DES LIBRAIRIES
# !pip install torch huggingface_hub
import torch
import torch.nn as nn
from huggingface_hub import hf_hub_download
import json
import collections
import math
import re
# --- PARAMÈTRES DE CHARGEMENT ---
# ⚠️ REMPLACEZ CETTE VALEUR PAR VOTRE ID DE MODÈLE RÉEL !
MODEL_ID = "Clemylia/Xadia-Charlotte"
TEMP_DIR = "./xadia_charlotte_download"
DEVICE = 'cuda' if torch.cuda.is_available() else 'cpu'
# ==============================================================================
# 2. REDÉFINITION DES CLASSES ORIGINALES (CRUCIAL)
# ==============================================================================
# Nous devons redéfinir les classes utilisées pour l'entraînement car elles ne sont
# pas dans la bibliothèque standard de Hugging Face.
# --- Redéfinition des Constantes Spéciales ---
UNK_TOKEN = "[UNK]"
PAD_TOKEN = "[PAD]"
SOS_TOKEN = "[SOS]"
EOS_TOKEN = "[EOS]"
# --- Redéfinition du Tokenizer Word-Level ---
class WordLevelTokenizer:
"""
Tokenizer simple basé sur le niveau du mot, adapté pour le chargement.
Il chargera la carte vocabulaire directement à partir du fichier vocab.json.
"""
def __init__(self, vocab_map):
# vocab_map est le dictionnaire {mot: id} chargé depuis HF
self.word_to_id = vocab_map
self.id_to_word = [None] * len(vocab_map)
for word, id_ in vocab_map.items():
self.id_to_word[id_] = word
# Récupération des IDs spéciaux
self._pad_token_id = self.word_to_id.get(PAD_TOKEN)
self._sos_token_id = self.word_to_id.get(SOS_TOKEN)
self._eos_token_id = self.word_to_id.get(EOS_TOKEN)
self._unk_token_id = self.word_to_id.get(UNK_TOKEN)
def encode(self, text):
"""Convertit une phrase en liste d'IDs (utilise la même logique de nettoyage)."""
text = text.lower()
# Logique de gestion de l'apostrophe (doit correspondre à l'entraînement !)
text = re.sub(r"([cjlmnst])'", r'\1 ', text)
for punc in '.,!?:;()"-':
text = text.replace(punc, f' {punc} ')
words = text.split()
return [self.word_to_id.get(word, self._unk_token_id) for word in words]
def decode(self, token_ids):
"""Convertit une liste d'IDs en phrase."""
return " ".join([self.id_to_word[id_.item()] if isinstance(id_, torch.Tensor) else self.id_to_word[id_]
for id_ in token_ids if id_ < len(self.id_to_word)])
@property
def vocab_size_final(self): return len(self.word_to_id)
@property
def pad_token_id(self): return self._pad_token_id
@property
def sos_token_id(self): return self._sos_token_id
@property
def eos_token_id(self): return self._eos_token_id
# --- Redéfinition des Blocs d'Architecture (CausalSelfAttention, XadiaBlock) ---
# (Ces classes sont complexes et n'ont pas besoin d'être modifiées si elles sont
# identiques à celles de l'entraînement.)
class CausalSelfAttention(nn.Module):
def __init__(self, d_model, num_heads, dropout):
super().__init__()
self.d_model = d_model
self.num_heads = num_heads
self.head_dim = d_model // num_heads
self.q_proj = nn.Linear(d_model, d_model)
self.k_proj = nn.Linear(d_model, d_model)
self.v_proj = nn.Linear(d_model, d_model)
self.out_proj = nn.Linear(d_model, d_model)
self.dropout = nn.Dropout(dropout)
def forward(self, x):
B, T, C = x.size()
q = self.q_proj(x).view(B, T, self.num_heads, self.head_dim).transpose(1, 2)
k = self.k_proj(x).view(B, T, self.num_heads, self.head_dim).transpose(1, 2)
v = self.v_proj(x).view(B, T, self.num_heads, self.head_dim).transpose(1, 2)
attn_scores = (q @ k.transpose(-2, -1)) / math.sqrt(self.head_dim)
causal_mask = torch.triu(torch.ones(T, T), diagonal=1).bool().to(x.device)
attn_scores = attn_scores.masked_fill(causal_mask, float('-inf'))
attn_weights = nn.functional.softmax(attn_scores, dim=-1)
attn_weights = self.dropout(attn_weights)
output = attn_weights @ v
output = output.transpose(1, 2).contiguous().view(B, T, C)
output = self.out_proj(output)
return output
class XadiaBlock(nn.Module):
def __init__(self, d_model, num_heads, ffn_factor, dropout):
super().__init__()
self.norm1 = nn.LayerNorm(d_model)
self.attn = CausalSelfAttention(d_model, num_heads, dropout)
self.norm2 = nn.LayerNorm(d_model)
self.ffn = nn.Sequential(
nn.Linear(d_model, d_model * ffn_factor),
nn.GELU(),
nn.Linear(d_model * ffn_factor, d_model),
nn.Dropout(dropout)
)
self.dropout = nn.Dropout(dropout)
def forward(self, x):
x = x + self.dropout(self.attn(self.norm1(x)))
x = x + self.dropout(self.ffn(self.norm2(x)))
return x
# --- Redéfinition de la Classe Modèle Principale ---
class XadiaCharlotteSLM(nn.Module):
def __init__(self, vocab_size, d_model, num_layers, num_heads, ffn_factor, max_seq_length, dropout):
super().__init__()
self.max_seq_length = max_seq_length
self.word_embedding = nn.Embedding(vocab_size, d_model)
self.position_embedding = nn.Embedding(max_seq_length, d_model)
self.dropout = nn.Dropout(dropout)
self.transformer_blocks = nn.ModuleList([
XadiaBlock(d_model, num_heads, ffn_factor, dropout)
for _ in range(num_layers)
])
self.norm_final = nn.LayerNorm(d_model)
self.lm_head = nn.Linear(d_model, vocab_size, bias=False)
# Pas besoin d'init weights ici, car nous chargeons des poids entraînés
def forward(self, input_ids):
B, T = input_ids.size()
token_emb = self.word_embedding(input_ids)
position_ids = torch.arange(0, T, dtype=torch.long, device=input_ids.device)
position_emb = self.position_embedding(position_ids)
x = self.dropout(token_emb + position_emb)
for block in self.transformer_blocks:
x = block(x)
x = self.norm_final(x)
logits = self.lm_head(x)
return logits
# ==============================================================================
# 3. CHARGEMENT DU MODÈLE DEPUIS HUGGING FACE
# ==============================================================================
def load_xadia_charlotte(model_id, device):
"""
Télécharge les fichiers de config, vocabulaire et poids, et instancie le modèle.
"""
print(f"--- ⬇️ TÉLÉCHARGEMENT DE {model_id} ---")
# Téléchargement des fichiers essentiels
try:
# Configuration
config_path = hf_hub_download(repo_id=model_id, filename="config.json", local_dir=TEMP_DIR)
with open(config_path, 'r') as f:
config = json.load(f)
print(f"Configuration chargée: {config['vocab_size']} mots, {config['num_layers']} couches.")
# Vocabulaire
vocab_path = hf_hub_download(repo_id=model_id, filename="vocab.json", local_dir=TEMP_DIR)
with open(vocab_path, 'r', encoding='utf-8') as f:
vocab_map = json.load(f)
# Poids
weights_path = hf_hub_download(repo_id=model_id, filename="pytorch_model.bin", local_dir=TEMP_DIR)
except Exception as e:
print(f"ERREUR lors du téléchargement. Assurez-vous que l'ID de modèle est correct et que les fichiers sont présents. Détail: {e}")
return None, None
# 1. Initialisation du Tokenizer
tokenizer = WordLevelTokenizer(vocab_map)
# 2. Initialisation du Modèle
model = XadiaCharlotteSLM(
vocab_size=config['vocab_size'],
d_model=config['d_model'],
num_layers=config['num_layers'],
num_heads=config['num_heads'],
ffn_factor=config['ffn_factor'],
max_seq_length=config['max_seq_length'],
dropout=config['dropout']
).to(device)
# 3. Chargement des poids
model.load_state_dict(torch.load(weights_path, map_location=device))
model.eval() # Mode évaluation pour l'inférence
print("Modèle Xadia-Charlotte chargé et prêt.")
return model, tokenizer
# ==============================================================================
# 4. FONCTION DE GÉNÉRATION (TEST)
# ==============================================================================
def generate_text(model, tokenizer, prompt, max_new_tokens=100, temperature=0.9):
"""
Génère du texte conditionné par un prompt (refrain).
"""
# 1. Préparation du prompt
prompt_ids = tokenizer.encode(prompt)
if not prompt_ids:
print("Erreur: Prompt vide ou ne contient aucun mot reconnu.")
return
input_ids = torch.tensor([prompt_ids], dtype=torch.long).to(model.lm_head.weight.device)
print(f"\n--- 🎶 TEST DE GÉNÉRATION (Temp={temperature:.2f}) ---")
print(f"Prompt (Refrain): {prompt}")
print("-" * 50)
generated_tokens = prompt_ids
with torch.no_grad():
for _ in range(max_new_tokens):
# Limiter l'input au contexte max
input_context = input_ids[:, -model.max_seq_length:]
# Forward Pass : obtenir les logits
logits = model(input_context)
# Seul le dernier token prédit nous intéresse
last_token_logits = logits[0, -1, :] / temperature
# Échantillonnage (Sampling)
probs = torch.nn.functional.softmax(last_token_logits, dim=-1)
next_token_id = torch.multinomial(probs, num_samples=1)
# Arrêt si EOS est généré
if next_token_id.item() == tokenizer.eos_token_id:
break
# Mise à jour de la séquence
input_ids = torch.cat([input_ids, next_token_id.unsqueeze(0)], dim=-1)
generated_tokens.append(next_token_id.item())
# Décodage
prompt_len = len(tokenizer.encode(prompt))
generated_couplet = tokenizer.decode(generated_tokens[prompt_len:])
print(f"Résultat Généré (Couplet): {generated_couplet}")
print("-" * 50)
# ==============================================================================
# 5. EXÉCUTION
# ==============================================================================
if __name__ == '__main__':
# ⚠️ IMPORTANT : REMPLACER PAR VOTRE ID DE MODÈLE PUBLIÉ
# Exemple : "Clemylia/Xadia-Charlotte"
YOUR_MODEL_ID = "Clemylia/Xadia-Charlotte"
# 1. Chargement du Modèle et du Tokenizer
model, tokenizer = load_xadia_charlotte(YOUR_MODEL_ID, DEVICE)
if model and tokenizer:
# 2. Test du Modèle
prompt_refrain = "quand la lumière s'éteint, mon cœur s'allume pour toi"
# Test 1: Créativité (Température élevée)
generate_text(model, tokenizer, prompt_refrain, max_new_tokens=150, temperature=0.9)
# Test 2: Cohérence (Température faible)
generate_text(model, tokenizer, prompt_refrain, max_new_tokens=150, temperature=0.5)
``` |