Cómo un pedazo de texto ("Hola mundo") se convierte en una lista de números que el modelo puede procesar.
La tokenización es el primer paso de todos: convierte el texto crudo en algo que el modelo pueda recibir.
Convertir texto ("Hola mundo") en una lista de números enteros (IDs) que el modelo pueda procesar. Es el "traductor de entrada" del Transformer.
Define el vocabulario del modelo: el conjunto de "piezas" (tokens) con las que va a trabajar. Cada pieza recibe un ID único y estable.
Las redes neuronales SOLO operan con números. No pueden recibir letras ni palabras directamente. Sin tokenización, no hay forma de meterle texto al modelo.
↓ A continuación, el detalle con ejemplos y visualizaciones ↓
Las redes neuronales solo entienden números — específicamente, números en arrays (vectores y matrices). No saben qué es la letra "A" ni qué es la palabra "perro". Antes de poder darle texto a un Transformer, tenemos que traducirlo a números.
generar_texto(input) pero input debe ser number[]. No puedes pasarle un string directo. Necesitas un convertidor: string → number[]. Ese convertidor es el tokenizer.
Un token es un pedacito de texto al que le asignamos un número (su ID). El tokenizer mantiene un vocabulario: una tabla que dice "este pedacito ↔ este número".
La idea más simple: cada carácter es un token. "Hola" → ['H', 'o', 'l', 'a'] → [4 IDs].
function tokenizeChars(text) { // 1. Construir vocabulario: un Map de char → ID const vocab = new Map(); let nextId = 0; // 2. Recorrer cada carácter const tokens = []; for (const ch of text) { if (!vocab.has(ch)) { vocab.set(ch, nextId++); } tokens.push({ text: ch, id: vocab.get(ch) }); } return tokens; }
Solución obvia: cada palabra es un token. "Hola mundo" → ['Hola', 'mundo'] → 2 tokens.
function tokenizeWords(text) { const vocab = new Map(); let nextId = 0; // split por espacios const words = text.split(/\s+/); const tokens = []; for (const w of words) { if (!vocab.has(w)) vocab.set(w, nextId++); tokens.push({ text: w, id: vocab.get(w) }); } return tokens; }
GPT, Claude, LLaMA y prácticamente todos los LLMs modernos usan una variante de BPE. La idea es brillante: encontrar un punto medio entre caracteres y palabras.
BPE se construye aprendiendo del texto. El algoritmo:
Vamos a entrenar un BPE con un corpus chiquito y ver cómo aprende las fusiones (merges) paso a paso.
function trainBPE(corpus, numMerges) { // 1. Empezamos: cada palabra = lista de caracteres // "gato" → ["g","a","t","o"] let words = corpus.split(/\s+/) .map(w => w.split("")); const merges = []; for (let i = 0; i < numMerges; i++) { // 2. Contar pares adyacentes en todo el corpus const pairs = new Map(); for (const w of words) { for (let j=0; j<w.length-1; j++) { const pair = w[j] + "|" + w[j+1]; pairs.set(pair, (pairs.get(pair)||0)+1); } } // 3. Encontrar el par más frecuente const best = [...pairs.entries()] .sort((a,b) => b[1]-a[1])[0]; // 4. Fusionar ese par en todas las palabras const [a,b] = best[0].split("|"); words = words.map(w => mergePair(w, a, b)); merges.push(a + b); } return merges; }
Escribe algo (puede ser texto del corpus o palabras nuevas):
function applyBPE(text, merges) { const words = text.split(/\s+/); const result = []; for (let w of words) { // Empezar como lista de caracteres let tokens = w.split(""); // Aplicar cada merge aprendido, en orden for (const merge of merges) { tokens = applyMerge(tokens, merge); } result.push(...tokens); } return result; }
Los tokenizers reales (como tiktoken de OpenAI o el de Claude) son BPE entrenados sobre terabytes de texto de internet.
Tienen vocabularios de ~50,000 a 200,000 tokens. Algunos detalles extra:
<|endoftext|>, <|user|>, <|assistant|> que el modelo usa para estructurar conversaciones.Un dato curioso: cuando pagas por la API de un LLM, pagas por token. Por eso el español sale más caro que el inglés para la misma cantidad de información.
Al final de la tokenización, lo que tenemos es:
En el Paso 2: Embeddings, esos números (que son solo IDs, sin significado matemático) se convertirán en vectores de cientos de dimensiones que SÍ capturan el significado de cada token. Ahí empieza lo interesante.