krystv commited on
Commit
739fdde
·
verified ·
1 Parent(s): 322ae07

Add Colab training notebook

Browse files
Files changed (1) hide show
  1. NeuroLex_v4_Training.ipynb +702 -0
NeuroLex_v4_Training.ipynb ADDED
@@ -0,0 +1,702 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "nbformat": 4,
3
+ "nbformat_minor": 0,
4
+ "metadata": {
5
+ "colab": {
6
+ "provenance": [],
7
+ "gpuType": "T4"
8
+ },
9
+ "kernelspec": {
10
+ "name": "python3",
11
+ "display_name": "Python 3"
12
+ },
13
+ "language_info": {
14
+ "name": "python"
15
+ },
16
+ "accelerator": "GPU"
17
+ },
18
+ "cells": [
19
+ {
20
+ "cell_type": "markdown",
21
+ "metadata": {},
22
+ "source": [
23
+ "# 🧠 NeuroLex v4 — Creative Name Diffusion Engine\n",
24
+ "\n",
25
+ "## Why This Architecture is Fundamentally Different\n",
26
+ "\n",
27
+ "**The Problem with LLMs / Autoregressive Models for Name Generation:**\n",
28
+ "\n",
29
+ "| Issue | Root Cause | Effect |\n",
30
+ "|-------|-----------|--------|\n",
31
+ "| Repetition | Probability feedback loops (Holtzman et al. 2019) | Same 5-10 names over and over |\n",
32
+ "| Generic outputs | Training on natural text optimizes for common patterns | \"TechFlow\", \"DataStream\" |\n",
33
+ "| Mode collapse | Maximum likelihood concentrates probability mass | 47% uniqueness |\n",
34
+ "| Can't create NEW words | Subword tokenizers recombine existing pieces | Just concatenation |\n",
35
+ "| Script leakage | Mixed training data bleeds through | Thai characters in English names |\n",
36
+ "\n",
37
+ "**Our Solution: Uniform Discrete Language Diffusion (UDLM)**\n",
38
+ "\n",
39
+ "```\n",
40
+ "AR Model: [Start] → P(next|left) → P(next|left) → ... (same path every time)\n",
41
+ "UDLM: [Random Noise] ← iterative denoising ← [Clean Name] (different path each time)\n",
42
+ "```\n",
43
+ "\n",
44
+ "Key innovations:\n",
45
+ "1. **Non-autoregressive**: No left-to-right = no feedback loops = no repetition\n",
46
+ "2. **Bidirectional attention**: Model sees ALL characters simultaneously\n",
47
+ "3. **Classifier-Free Guidance (CFG)**: Steer generation without mode collapse\n",
48
+ "4. **ODD (Orthogonal Diversity Diffusion)**: Actively repels samples from each other\n",
49
+ "5. **Character-level vocab**: Can generate truly novel character sequences\n",
50
+ "\n",
51
+ "Based on:\n",
52
+ "- MDLM (NeurIPS 2024, arxiv:2406.07524)\n",
53
+ "- Discrete CFG (arxiv:2412.10193)\n",
54
+ "- ODD diversity (arxiv:2603.04893)\n",
55
+ "- GFlowNet principles (arxiv:2106.04399)\n",
56
+ "- Sound symbolism research (arxiv:2310.16781)\n",
57
+ "\n",
58
+ "**Supports 25 languages**, 20 domains, 10 styles. Trains in ~25 minutes on free Colab T4."
59
+ ]
60
+ },
61
+ {
62
+ "cell_type": "markdown",
63
+ "metadata": {},
64
+ "source": [
65
+ "## 1. Setup & Installation"
66
+ ]
67
+ },
68
+ {
69
+ "cell_type": "code",
70
+ "execution_count": null,
71
+ "metadata": {},
72
+ "outputs": [],
73
+ "source": [
74
+ "# Install dependencies (all standard, no special packages needed)\n",
75
+ "!pip install torch --quiet\n",
76
+ "\n",
77
+ "# Clone the repo\n",
78
+ "!git clone https://huggingface.co/krystv/neurolex-v4-creative-name-diffusion\n",
79
+ "%cd neurolex-v4-creative-name-diffusion\n",
80
+ "\n",
81
+ "# Check GPU\n",
82
+ "import torch\n",
83
+ "print(f\"PyTorch version: {torch.__version__}\")\n",
84
+ "print(f\"CUDA available: {torch.cuda.is_available()}\")\n",
85
+ "if torch.cuda.is_available():\n",
86
+ " print(f\"GPU: {torch.cuda.get_device_name()}\")\n",
87
+ " print(f\"Memory: {torch.cuda.get_device_properties(0).total_mem / 1e9:.1f} GB\")"
88
+ ]
89
+ },
90
+ {
91
+ "cell_type": "markdown",
92
+ "metadata": {},
93
+ "source": [
94
+ "## 2. Understanding the Architecture\n",
95
+ "\n",
96
+ "### How Discrete Diffusion Works for Names:\n",
97
+ "\n",
98
+ "```\n",
99
+ "Training (learning to denoise):\n",
100
+ " Clean name: \"Nexora\" → [N][e][x][o][r][a]\n",
101
+ " Add noise: \"Nqxw_a\" → randomly replace some chars\n",
102
+ " Model learns: given noisy input + conditions → predict clean chars\n",
103
+ "\n",
104
+ "Generation (iterative denoising):\n",
105
+ " Step 0: \"kqwpzm\" (fully random)\n",
106
+ " Step 20: \"kexprm\" (some structure emerging)\n",
107
+ " Step 40: \"Nexprm\" (getting clearer)\n",
108
+ " Step 60: \"Nexora\" (nearly clean)\n",
109
+ " Step 80: \"Nexora\" (final)\n",
110
+ "```\n",
111
+ "\n",
112
+ "### Why This Guarantees Diversity:\n",
113
+ "- Each sample starts from DIFFERENT random noise\n",
114
+ "- Different noise → different denoising trajectory → different output\n",
115
+ "- CFG guides toward conditions WITHOUT collapsing to modes\n",
116
+ "- ODD actively pushes batch samples apart in feature space"
117
+ ]
118
+ },
119
+ {
120
+ "cell_type": "code",
121
+ "execution_count": null,
122
+ "metadata": {},
123
+ "outputs": [],
124
+ "source": [
125
+ "# Import model and dataset\n",
126
+ "from neurolex_v4_model import (\n",
127
+ " NeuroLexV4, NeuroLexConfig, CharTokenizer, create_model,\n",
128
+ " DOMAINS, STYLES, LANGUAGES, DOMAIN_TO_ID, STYLE_TO_ID, LANG_TO_ID\n",
129
+ ")\n",
130
+ "from neurolex_v4_dataset import (\n",
131
+ " create_dataloaders, NeuroLexDataset, StreamingNeuroLexDataset,\n",
132
+ " LANGUAGE_WORDS, DOMAIN_NAMES\n",
133
+ ")\n",
134
+ "\n",
135
+ "# Show what we're working with\n",
136
+ "print(\"=\" * 60)\n",
137
+ "print(\" NEUROLEX v4 — ARCHITECTURE OVERVIEW\")\n",
138
+ "print(\"=\" * 60)\n",
139
+ "print(f\"\\n Domains ({len(DOMAINS)}): {', '.join(DOMAINS[:10])}...\")\n",
140
+ "print(f\" Styles ({len(STYLES)}): {', '.join(STYLES)}\")\n",
141
+ "print(f\" Languages ({len(LANGUAGES)}): {', '.join(LANGUAGES[:12])}...\")\n",
142
+ "print(f\"\\n Total language words: {sum(len(v) for v in LANGUAGE_WORDS.values())}\")\n",
143
+ "print(f\" Total domain names: {sum(len(v) for v in DOMAIN_NAMES.values())}\")"
144
+ ]
145
+ },
146
+ {
147
+ "cell_type": "markdown",
148
+ "metadata": {},
149
+ "source": [
150
+ "## 3. Create Model"
151
+ ]
152
+ },
153
+ {
154
+ "cell_type": "code",
155
+ "execution_count": null,
156
+ "metadata": {},
157
+ "outputs": [],
158
+ "source": [
159
+ "# Create model — 'base' is recommended (12M params, fits easily in T4)\n",
160
+ "# Options: 'tiny' (2M), 'small' (5M), 'base' (12M), 'large' (25M)\n",
161
+ "MODEL_SIZE = 'base'\n",
162
+ "\n",
163
+ "model, config = create_model(MODEL_SIZE)\n",
164
+ "\n",
165
+ "print(f\"\\nModel architecture:\")\n",
166
+ "print(f\" Type: Uniform Discrete Language Diffusion Model (UDLM)\")\n",
167
+ "print(f\" Attention: BIDIRECTIONAL (not causal!)\")\n",
168
+ "print(f\" Conditioning: Adaptive LayerNorm (adaLN)\")\n",
169
+ "print(f\" Noise: Uniform random token replacement\")\n",
170
+ "print(f\" Schedule: Cosine α_t = cos²(πt/2)\")\n",
171
+ "print(f\" CFG dropout: {config.cfg_dropout}\")\n",
172
+ "print(f\"\\n Memory estimate: ~{model.count_parameters() * 4 / 1e6:.0f} MB (fp32)\")"
173
+ ]
174
+ },
175
+ {
176
+ "cell_type": "markdown",
177
+ "metadata": {},
178
+ "source": [
179
+ "## 4. Prepare Dataset\n",
180
+ "\n",
181
+ "The dataset is **built into the code** — no downloads needed!\n",
182
+ "\n",
183
+ "It includes:\n",
184
+ "- ~2,500 real words from 25 languages (phonotactic patterns)\n",
185
+ "- ~1,000 real brand/domain names\n",
186
+ "- ~97,000+ augmented names via morphological blending rules\n",
187
+ "- All properly labeled with domain, style, language, and length"
188
+ ]
189
+ },
190
+ {
191
+ "cell_type": "code",
192
+ "execution_count": null,
193
+ "metadata": {},
194
+ "outputs": [],
195
+ "source": [
196
+ "# Create dataset and dataloaders\n",
197
+ "# streaming=True gives infinite unique data each epoch (recommended)\n",
198
+ "# streaming=False uses a fixed cached dataset (faster per-step)\n",
199
+ "\n",
200
+ "BATCH_SIZE = 256 # Fits easily in T4 16GB\n",
201
+ "N_SAMPLES = 100000 # Total training examples per epoch\n",
202
+ "\n",
203
+ "train_loader, val_loader = create_dataloaders(\n",
204
+ " batch_size=BATCH_SIZE,\n",
205
+ " n_samples=N_SAMPLES,\n",
206
+ " num_workers=2,\n",
207
+ " streaming=False # Set True for infinite data\n",
208
+ ")\n",
209
+ "\n",
210
+ "print(f\"\\nDataloader ready:\")\n",
211
+ "print(f\" Train batches: {len(train_loader)}\")\n",
212
+ "print(f\" Val batches: {len(val_loader)}\")\n",
213
+ "print(f\" Batch size: {BATCH_SIZE}\")\n",
214
+ "\n",
215
+ "# Preview a batch\n",
216
+ "batch = next(iter(train_loader))\n",
217
+ "tokenizer = CharTokenizer()\n",
218
+ "print(f\"\\n Sample names from batch:\")\n",
219
+ "for i in range(min(10, len(batch['input_ids']))):\n",
220
+ " name = tokenizer.decode(batch['input_ids'][i].tolist())\n",
221
+ " domain = DOMAINS[batch['domain'][i].item()]\n",
222
+ " style = STYLES[batch['style'][i].item()]\n",
223
+ " lang = LANGUAGES[batch['language'][i].item()]\n",
224
+ " print(f\" {name:20s} | {domain:12s} | {style:12s} | {lang}\")"
225
+ ]
226
+ },
227
+ {
228
+ "cell_type": "markdown",
229
+ "metadata": {},
230
+ "source": [
231
+ "## 5. Train the Model\n",
232
+ "\n",
233
+ "Training takes ~20-30 minutes on free Colab T4.\n",
234
+ "\n",
235
+ "What to watch for:\n",
236
+ "- Loss should decrease steadily from ~4.0 to ~1.5-2.0\n",
237
+ "- Diversity % should stay HIGH (>80%) — unlike v3's 47%!\n",
238
+ "- Generated names should be different each time they're sampled"
239
+ ]
240
+ },
241
+ {
242
+ "cell_type": "code",
243
+ "execution_count": null,
244
+ "metadata": {},
245
+ "outputs": [],
246
+ "source": [
247
+ "from train import Trainer\n",
248
+ "import argparse\n",
249
+ "\n",
250
+ "# Training configuration\n",
251
+ "class Args:\n",
252
+ " size = MODEL_SIZE\n",
253
+ " epochs = 30\n",
254
+ " batch_size = BATCH_SIZE\n",
255
+ " lr = 3e-4\n",
256
+ " warmup_steps = 500\n",
257
+ " n_samples = N_SAMPLES\n",
258
+ " streaming = False\n",
259
+ " save_dir = './checkpoints'\n",
260
+ " log_every = 100\n",
261
+ " sample_every = 5 # Generate samples every 5 epochs\n",
262
+ " device = 'auto'\n",
263
+ " seed = 42\n",
264
+ " gradient_clip = 1.0\n",
265
+ " weight_decay = 0.01\n",
266
+ " num_workers = 2\n",
267
+ "\n",
268
+ "args = Args()\n",
269
+ "device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\n",
270
+ "\n",
271
+ "# Create trainer\n",
272
+ "trainer = Trainer(model, config, args, device)\n",
273
+ "\n",
274
+ "# Train!\n",
275
+ "best_loss = trainer.train(train_loader, val_loader)"
276
+ ]
277
+ },
278
+ {
279
+ "cell_type": "markdown",
280
+ "metadata": {},
281
+ "source": [
282
+ "## 6. Generate Names! 🎉\n",
283
+ "\n",
284
+ "Now let's use the trained model to generate creative names.\n",
285
+ "\n",
286
+ "Key parameters:\n",
287
+ "- **cfg_scale**: Higher = more faithful to conditions (2-4 is good)\n",
288
+ "- **temperature**: Higher = more creative/wild (0.7-1.2 is good)\n",
289
+ "- **odd_alpha**: Higher = more diversity between batch samples (5-15)\n",
290
+ "- **n_steps**: More = better quality but slower (60-100)"
291
+ ]
292
+ },
293
+ {
294
+ "cell_type": "code",
295
+ "execution_count": null,
296
+ "metadata": {},
297
+ "outputs": [],
298
+ "source": [
299
+ "# Load best model\n",
300
+ "import os\n",
301
+ "best_path = './checkpoints/neurolex_v4_best.pt'\n",
302
+ "if os.path.exists(best_path):\n",
303
+ " checkpoint = torch.load(best_path, map_location=device)\n",
304
+ " model.load_state_dict(checkpoint['state_dict'])\n",
305
+ " print(f\"Loaded best model (val_loss={checkpoint['best_loss']:.4f})\")\n",
306
+ "\n",
307
+ "model.eval()\n",
308
+ "model.to(device)\n",
309
+ "\n",
310
+ "def generate(domain='tech', style='sharp', lang='english', \n",
311
+ " length=8, n=20, cfg=2.5, temp=0.9, steps=80, diversity=8.0):\n",
312
+ " \"\"\"Generate creative names with specified parameters.\"\"\"\n",
313
+ " names = model.generate(\n",
314
+ " domain_id=DOMAIN_TO_ID[domain],\n",
315
+ " style_id=STYLE_TO_ID[style],\n",
316
+ " lang_id=LANG_TO_ID[lang],\n",
317
+ " target_length=length,\n",
318
+ " batch_size=n,\n",
319
+ " cfg_scale=cfg,\n",
320
+ " temperature=temp,\n",
321
+ " n_steps=steps,\n",
322
+ " odd_alpha=diversity,\n",
323
+ " device=str(device)\n",
324
+ " )\n",
325
+ " return names\n",
326
+ "\n",
327
+ "# === TECH STARTUP NAMES ===\n",
328
+ "print(\"\\n🖥️ TECH STARTUP (sharp, English):\")\n",
329
+ "names = generate('tech', 'sharp', 'english', length=8, n=20)\n",
330
+ "for i, name in enumerate(names, 1):\n",
331
+ " print(f\" {i:2d}. {name}\")\n",
332
+ "print(f\" Unique: {len(set(n.lower() for n in names))}/{len(names)}\")"
333
+ ]
334
+ },
335
+ {
336
+ "cell_type": "code",
337
+ "execution_count": null,
338
+ "metadata": {},
339
+ "outputs": [],
340
+ "source": [
341
+ "# === GENERATE ACROSS ALL DOMAINS ===\n",
342
+ "print(\"\\n\" + \"=\" * 70)\n",
343
+ "print(\" COMPREHENSIVE NAME GENERATION\")\n",
344
+ "print(\"=\" * 70)\n",
345
+ "\n",
346
+ "showcases = [\n",
347
+ " ('🖥️ Tech Startup', 'tech', 'futuristic', 'english', 8),\n",
348
+ " ('🍜 Food Brand', 'food', 'warm', 'french', 7),\n",
349
+ " ('🎮 Gaming Channel', 'gaming', 'bold', 'japanese', 9),\n",
350
+ " ('💎 Luxury Brand', 'luxury', 'elegant', 'italian', 8),\n",
351
+ " ('🤖 AI Company', 'ai', 'sharp', 'latin', 7),\n",
352
+ " ('🌿 Health App', 'health', 'organic', 'hawaiian', 7),\n",
353
+ " ('🪙 Crypto Project', 'crypto', 'futuristic', 'greek', 8),\n",
354
+ " ('🎵 Music Platform', 'music', 'playful', 'spanish', 7),\n",
355
+ " ('♻️ Eco Brand', 'eco', 'warm', 'swedish', 7),\n",
356
+ " ('💪 Fitness App', 'fitness', 'bold', 'german', 8),\n",
357
+ " ('🌐 Social Platform', 'social', 'playful', 'korean', 6),\n",
358
+ " ('✨ Beauty Brand', 'beauty', 'elegant', 'french', 8),\n",
359
+ "]\n",
360
+ "\n",
361
+ "all_generated = []\n",
362
+ "for label, domain, style, lang, length in showcases:\n",
363
+ " names = generate(domain, style, lang, length=length, n=15)\n",
364
+ " all_generated.extend(names)\n",
365
+ " print(f\"\\n {label} ({style}, {lang}):\")\n",
366
+ " for name in names[:8]:\n",
367
+ " print(f\" → {name}\")\n",
368
+ "\n",
369
+ "# Diversity analysis\n",
370
+ "unique = set(n.lower() for n in all_generated)\n",
371
+ "print(f\"\\n{'─' * 70}\")\n",
372
+ "print(f\" 📊 TOTAL GENERATED: {len(all_generated)}\")\n",
373
+ "print(f\" 🎯 UNIQUE: {len(unique)} ({len(unique)/len(all_generated)*100:.1f}%)\")\n",
374
+ "print(f\" 📏 AVG LENGTH: {sum(len(n) for n in all_generated)/len(all_generated):.1f} chars\")"
375
+ ]
376
+ },
377
+ {
378
+ "cell_type": "code",
379
+ "execution_count": null,
380
+ "metadata": {},
381
+ "outputs": [],
382
+ "source": [
383
+ "# === STYLE COMPARISON FOR SAME DOMAIN ===\n",
384
+ "print(\"\\n\" + \"=\" * 70)\n",
385
+ "print(\" STYLE COMPARISON: Same domain (TECH), different vibes\")\n",
386
+ "print(\"=\" * 70)\n",
387
+ "\n",
388
+ "for style in STYLES:\n",
389
+ " names = generate('tech', style, 'english', length=8, n=10)\n",
390
+ " print(f\"\\n [{style.upper():12s}]: {', '.join(names[:6])}\")"
391
+ ]
392
+ },
393
+ {
394
+ "cell_type": "code",
395
+ "execution_count": null,
396
+ "metadata": {},
397
+ "outputs": [],
398
+ "source": [
399
+ "# === LANGUAGE INFLUENCE COMPARISON ===\n",
400
+ "print(\"\\n\" + \"=\" * 70)\n",
401
+ "print(\" LANGUAGE INFLUENCE: Same domain (LUXURY), different languages\")\n",
402
+ "print(\"=\" * 70)\n",
403
+ "\n",
404
+ "for lang in ['english', 'french', 'italian', 'japanese', 'arabic', \n",
405
+ " 'hindi', 'swedish', 'swahili', 'greek', 'finnish']:\n",
406
+ " names = generate('luxury', 'elegant', lang, length=8, n=10)\n",
407
+ " print(f\"\\n [{lang.upper():12s}]: {', '.join(names[:6])}\")"
408
+ ]
409
+ },
410
+ {
411
+ "cell_type": "code",
412
+ "execution_count": null,
413
+ "metadata": {},
414
+ "outputs": [],
415
+ "source": [
416
+ "# === CREATIVITY DIAL: Temperature exploration ===\n",
417
+ "print(\"\\n\" + \"=\" * 70)\n",
418
+ "print(\" CREATIVITY DIAL: Same conditions, different temperatures\")\n",
419
+ "print(\"=\" * 70)\n",
420
+ "\n",
421
+ "for temp in [0.5, 0.7, 0.9, 1.1, 1.3, 1.5]:\n",
422
+ " names = generate('tech', 'sharp', 'english', length=8, n=10, temp=temp)\n",
423
+ " print(f\"\\n Temp={temp:.1f}: {', '.join(names[:6])}\")\n",
424
+ "\n",
425
+ "print(\"\\n (Lower = safer/familiar, Higher = wilder/novel)\")"
426
+ ]
427
+ },
428
+ {
429
+ "cell_type": "code",
430
+ "execution_count": null,
431
+ "metadata": {},
432
+ "outputs": [],
433
+ "source": [
434
+ "# === DIVERSITY TEST: Generate 100 names, check uniqueness ===\n",
435
+ "print(\"\\n\" + \"=\" * 70)\n",
436
+ "print(\" DIVERSITY STRESS TEST: 100 names, same conditions\")\n",
437
+ "print(\"=\" * 70)\n",
438
+ "\n",
439
+ "# Generate 100 names with the same conditions\n",
440
+ "# An AR model would give ~47% unique. UDLM should give 90%+\n",
441
+ "\n",
442
+ "stress_names = []\n",
443
+ "for _ in range(5): # 5 batches of 20\n",
444
+ " batch_names = generate('tech', 'sharp', 'english', length=8, n=20)\n",
445
+ " stress_names.extend(batch_names)\n",
446
+ "\n",
447
+ "unique_stress = set(n.lower() for n in stress_names)\n",
448
+ "print(f\"\\n Generated: {len(stress_names)} names\")\n",
449
+ "print(f\" Unique: {len(unique_stress)} ({len(unique_stress)/len(stress_names)*100:.1f}%)\")\n",
450
+ "print(f\" Repeated: {len(stress_names) - len(unique_stress)}\")\n",
451
+ "print(f\"\\n Sample of unique names:\")\n",
452
+ "for name in sorted(unique_stress)[:30]:\n",
453
+ " print(f\" • {name}\")\n",
454
+ "\n",
455
+ "# Compare with v3's 47% uniqueness\n",
456
+ "improvement = (len(unique_stress)/len(stress_names)*100) / 47.1 * 100 - 100\n",
457
+ "print(f\"\\n vs. NeuroLex v3 (47.1% unique): {improvement:+.0f}% improvement\")"
458
+ ]
459
+ },
460
+ {
461
+ "cell_type": "code",
462
+ "execution_count": null,
463
+ "metadata": {},
464
+ "outputs": [],
465
+ "source": [
466
+ "# === YouTube Channel Name Generator ===\n",
467
+ "print(\"\\n\" + \"=\" * 70)\n",
468
+ "print(\" 🎬 YOUTUBE CHANNEL NAME GENERATOR\")\n",
469
+ "print(\"=\" * 70)\n",
470
+ "\n",
471
+ "yt_categories = [\n",
472
+ " (\"Tech Reviews\", 'tech', 'sharp', 'english', 9),\n",
473
+ " (\"Cooking\", 'food', 'warm', 'italian', 8),\n",
474
+ " (\"Gaming\", 'gaming', 'playful', 'japanese', 8),\n",
475
+ " (\"Fitness\", 'fitness', 'bold', 'english', 7),\n",
476
+ " (\"Education\", 'education', 'professional', 'latin', 8),\n",
477
+ " (\"Music\", 'music', 'playful', 'spanish', 7),\n",
478
+ " (\"Travel Vlog\", 'travel', 'warm', 'hawaiian', 7),\n",
479
+ " (\"AI/Science\", 'ai', 'futuristic', 'greek', 8),\n",
480
+ "]\n",
481
+ "\n",
482
+ "for category, domain, style, lang, length in yt_categories:\n",
483
+ " names = generate(domain, style, lang, length=length, n=12)\n",
484
+ " print(f\"\\n 📺 {category}:\")\n",
485
+ " for name in names[:6]:\n",
486
+ " print(f\" → {name}\")"
487
+ ]
488
+ },
489
+ {
490
+ "cell_type": "code",
491
+ "execution_count": null,
492
+ "metadata": {},
493
+ "outputs": [],
494
+ "source": [
495
+ "# === Social Media Handle Generator ===\n",
496
+ "print(\"\\n\" + \"=\" * 70)\n",
497
+ "print(\" 📱 SOCIAL MEDIA HANDLE GENERATOR\")\n",
498
+ "print(\"=\" * 70)\n",
499
+ "\n",
500
+ "# Short, punchy names for handles\n",
501
+ "for style in ['sharp', 'playful', 'minimal', 'bold', 'mystical']:\n",
502
+ " names = generate('social', style, 'english', length=6, n=12, cfg=3.0)\n",
503
+ " print(f\"\\n @{style}: {', '.join(f'@{n.lower()}' for n in names[:8])}\")"
504
+ ]
505
+ },
506
+ {
507
+ "cell_type": "markdown",
508
+ "metadata": {},
509
+ "source": [
510
+ "## 7. Save & Export Model"
511
+ ]
512
+ },
513
+ {
514
+ "cell_type": "code",
515
+ "execution_count": null,
516
+ "metadata": {},
517
+ "outputs": [],
518
+ "source": [
519
+ "# Save the final model with all metadata\n",
520
+ "import json\n",
521
+ "\n",
522
+ "save_path = 'neurolex_v4_trained.pt'\n",
523
+ "torch.save({\n",
524
+ " 'config': vars(config),\n",
525
+ " 'state_dict': model.state_dict(),\n",
526
+ " 'vocab_size': CharTokenizer().vocab_size,\n",
527
+ " 'vocab': CharTokenizer().vocab,\n",
528
+ " 'domains': DOMAINS,\n",
529
+ " 'styles': STYLES,\n",
530
+ " 'languages': LANGUAGES,\n",
531
+ "}, save_path)\n",
532
+ "\n",
533
+ "model_size_mb = os.path.getsize(save_path) / 1e6\n",
534
+ "print(f\"Model saved to {save_path}\")\n",
535
+ "print(f\"Size: {model_size_mb:.1f} MB\")\n",
536
+ "print(f\"Parameters: {model.count_parameters():,}\")\n",
537
+ "\n",
538
+ "print(f\"\\n{'=' * 60}\")\n",
539
+ "print(f\" To reload this model anywhere:\")\n",
540
+ "print(f\"{'=' * 60}\")\n",
541
+ "print(f\"\"\"\n",
542
+ "from neurolex_v4_model import NeuroLexV4, NeuroLexConfig, CharTokenizer\n",
543
+ "from neurolex_v4_model import DOMAIN_TO_ID, STYLE_TO_ID, LANG_TO_ID\n",
544
+ "\n",
545
+ "checkpoint = torch.load('{save_path}')\n",
546
+ "config = NeuroLexConfig(**checkpoint['config'])\n",
547
+ "model = NeuroLexV4(config).to('cuda')\n",
548
+ "model.load_state_dict(checkpoint['state_dict'])\n",
549
+ "model.eval()\n",
550
+ "\n",
551
+ "# Generate 20 tech names:\n",
552
+ "names = model.generate(\n",
553
+ " domain_id=DOMAIN_TO_ID['tech'],\n",
554
+ " style_id=STYLE_TO_ID['sharp'],\n",
555
+ " lang_id=LANG_TO_ID['english'],\n",
556
+ " target_length=8,\n",
557
+ " batch_size=20,\n",
558
+ " cfg_scale=2.5,\n",
559
+ " temperature=0.9,\n",
560
+ " n_steps=80,\n",
561
+ " odd_alpha=8.0,\n",
562
+ " device='cuda'\n",
563
+ ")\n",
564
+ "print(names)\n",
565
+ "\"\"\")"
566
+ ]
567
+ },
568
+ {
569
+ "cell_type": "markdown",
570
+ "metadata": {},
571
+ "source": [
572
+ "## 8. Architecture Deep Dive\n",
573
+ "\n",
574
+ "### Why Each Component Exists:\n",
575
+ "\n",
576
+ "| Component | Purpose | Why It Helps |\n",
577
+ "|-----------|---------|-------------|\n",
578
+ "| UDLM (vs AR) | Non-autoregressive generation | Eliminates probability feedback loops → no repetition |\n",
579
+ "| Bidirectional Attention | See all positions simultaneously | Better character interactions (\"x\" after \"e\" changes what comes next) |\n",
580
+ "| adaLN Conditioning | Modulate every layer's computation | Stronger style/domain control than prefix tokens |\n",
581
+ "| Cosine Noise Schedule | More time spent on easy (low-noise) steps | Better fine details in final characters |\n",
582
+ "| CFG (Classifier-Free Guidance) | Steer without external classifier | Controls condition-faithfulness without collapse |\n",
583
+ "| ODD (Orthogonal Diversity) | Repel samples from each other | Guarantees batch diversity without quality loss |\n",
584
+ "| Character Vocab | No subword tokenization | Can generate truly novel character sequences |\n",
585
+ "| Time Embedding | Tell model the noise level | Appropriate confidence at each denoising step |\n",
586
+ "\n",
587
+ "### The Key Insight: Why Diffusion Beats AR for Creativity\n",
588
+ "\n",
589
+ "**Autoregressive** models learn P(next_char | previous_chars). This creates a **path dependency** — once you start down a common path (like \"Nex...\"), the model's probability distribution narrows to familiar completions.\n",
590
+ "\n",
591
+ "**Diffusion** models learn P(clean_name | noisy_name, conditions). They can:\n",
592
+ "1. Revise any position at any time (bidirectional)\n",
593
+ "2. Start from genuinely random noise (no path dependency)\n",
594
+ "3. Make holistic decisions about the name (\"these letters sound good together\")\n",
595
+ "4. Each random seed gives a fundamentally different starting point"
596
+ ]
597
+ },
598
+ {
599
+ "cell_type": "code",
600
+ "execution_count": null,
601
+ "metadata": {},
602
+ "outputs": [],
603
+ "source": [
604
+ "# Visualize the diffusion process\n",
605
+ "print(\"\\n\" + \"=\" * 70)\n",
606
+ "print(\" VISUALIZING THE DIFFUSION PROCESS\")\n",
607
+ "print(\"=\" * 70)\n",
608
+ "print(\"\\n Watch how a name emerges from pure noise:\")\n",
609
+ "print(\" (Each step shows the current state of denoising)\\n\")\n",
610
+ "\n",
611
+ "# Manual step-by-step generation to show the process\n",
612
+ "model.eval()\n",
613
+ "tokenizer = CharTokenizer()\n",
614
+ "\n",
615
+ "with torch.no_grad():\n",
616
+ " batch_size = 1\n",
617
+ " seq_len = 12\n",
618
+ " \n",
619
+ " d_ids = torch.full((batch_size,), DOMAIN_TO_ID['tech'], device=device, dtype=torch.long)\n",
620
+ " s_ids = torch.full((batch_size,), STYLE_TO_ID['sharp'], device=device, dtype=torch.long)\n",
621
+ " l_ids = torch.full((batch_size,), LANG_TO_ID['english'], device=device, dtype=torch.long)\n",
622
+ " len_ids = torch.full((batch_size,), 5, device=device, dtype=torch.long)\n",
623
+ " \n",
624
+ " # Start from noise\n",
625
+ " x = torch.randint(4, config.vocab_size, (batch_size, seq_len), device=device)\n",
626
+ " x[:, 0] = CharTokenizer.BOS\n",
627
+ " x[:, -2] = CharTokenizer.EOS\n",
628
+ " x[:, -1] = CharTokenizer.PAD\n",
629
+ " \n",
630
+ " print(f\" Step 0: '{tokenizer.decode(x[0].tolist())}' (random noise)\")\n",
631
+ " \n",
632
+ " n_steps = 60\n",
633
+ " for step in range(n_steps):\n",
634
+ " t_val = 1.0 - step / n_steps\n",
635
+ " t = torch.full((batch_size,), t_val, device=device)\n",
636
+ " \n",
637
+ " logits = model.forward(x, t, d_ids, s_ids, l_ids, len_ids,\n",
638
+ " cfg_mask=torch.zeros(batch_size, device=device, dtype=torch.bool))\n",
639
+ " logits = logits / 0.9\n",
640
+ " logits[:, :, :4] = -float('inf')\n",
641
+ " \n",
642
+ " probs = F.softmax(logits, dim=-1)\n",
643
+ " predicted = torch.multinomial(probs.reshape(-1, config.vocab_size), 1).reshape(batch_size, seq_len)\n",
644
+ " \n",
645
+ " confidence = probs.max(dim=-1).values\n",
646
+ " update_prob = (1.0 - t_val) * confidence\n",
647
+ " update_prob[:, 0] = 0\n",
648
+ " update_prob[:, -2:] = 0\n",
649
+ " \n",
650
+ " should_update = torch.bernoulli(update_prob).bool()\n",
651
+ " x = torch.where(should_update, predicted, x)\n",
652
+ " x[:, 0] = CharTokenizer.BOS\n",
653
+ " x[:, -2] = CharTokenizer.EOS\n",
654
+ " x[:, -1] = CharTokenizer.PAD\n",
655
+ " \n",
656
+ " if (step + 1) % 10 == 0:\n",
657
+ " current = tokenizer.decode(x[0].tolist())\n",
658
+ " print(f\" Step {step+1:2d}: '{current}' (t={t_val:.2f})\")\n",
659
+ " \n",
660
+ " final = tokenizer.decode(x[0].tolist())\n",
661
+ " print(f\"\\n Final: '{final.strip()[0].upper() + final.strip()[1:]}' ✨\")"
662
+ ]
663
+ },
664
+ {
665
+ "cell_type": "markdown",
666
+ "metadata": {},
667
+ "source": [
668
+ "## 9. Comparison: v3 (AR) vs v4 (Diffusion)\n",
669
+ "\n",
670
+ "| Metric | NeuroLex v3 (AR) | NeuroLex v4 (UDLM) |\n",
671
+ "|--------|-----------------|--------------------|\n",
672
+ "| Architecture | Autoregressive Transformer | Diffusion Transformer |\n",
673
+ "| Attention | Causal (left-to-right) | Bidirectional |\n",
674
+ "| Conditioning | Control token prefixes | Adaptive LayerNorm (adaLN) |\n",
675
+ "| Diversity | 47.1% unique | Target: 90%+ unique |\n",
676
+ "| Repetition | Severe (same 5-10 names) | Structurally prevented |\n",
677
+ "| Script leakage | Thai chars in English | Impossible (vocab-constrained) |\n",
678
+ "| Generation | Left-to-right, deterministic path | Stochastic denoising, unique each time |\n",
679
+ "| Parameters | 4.8M | 12M (still Colab-friendly) |\n",
680
+ "| Training time | 25 min | ~25-30 min |\n",
681
+ "| Novel word generation | Recombines memorized chunks | Creates from noise (truly novel) |"
682
+ ]
683
+ },
684
+ {
685
+ "cell_type": "code",
686
+ "execution_count": null,
687
+ "metadata": {},
688
+ "outputs": [],
689
+ "source": [
690
+ "print(\"\\n🎉 Training complete! Your model is ready to generate creative names.\")\n",
691
+ "print(\"\\nKey advantages over LLMs/AR models:\")\n",
692
+ "print(\" ✅ No repetition (each noise seed → unique output)\")\n",
693
+ "print(\" ✅ No memorization (denoising can't memorize sequences)\")\n",
694
+ "print(\" ✅ Controllable (domain/style/language/length)\")\n",
695
+ "print(\" ✅ Diverse (ODD repels batch samples from each other)\")\n",
696
+ "print(\" ✅ Multilingual (25 language phonotactic patterns)\")\n",
697
+ "print(\" ✅ Fast (12M params, runs on CPU or GPU)\")\n",
698
+ "print(\" ✅ Novel (character-level vocab = truly new words)\")"
699
+ ]
700
+ }
701
+ ]
702
+ }