Skip to content

English · Español

Lab 00 — Conectar el tokenizer de la Fase 11 + corpus de la Fase 12 como entradas

Objetivo: producir una tripleta limpia (train_ids, dev_ids, test_ids) que consumen todos los demás laboratorios de la Fase 14. De una sola vez.

Tiempo estimado: 20–40 minutos.

Prerrequisito: Fase 11 (tokenizer BPE) y Fase 12 (corpus de gramática de verbos) ambas comprometidas.


Lo que produces

Un único archivo comprometido: experiments/14-tokenize/dataset.py (o .npz — cualquiera vale) que expone:

train_ids: list[list[int]]   # una lista interna por fila del split de train
dev_ids:   list[list[int]]   # ídem para dev
test_ids:  list[list[int]]   # ídem para test
vocab:     dict[str, int]    # mapeo token -> id
inv_vocab: dict[int, str]    # id -> token (para imprimir)

Más un manifest.json documentando las elecciones de tokenización.

TODOs

Bloque A — cargar el corpus

  • Leer data/processed/train.jsonl, dev.jsonl, test.jsonl de la Fase 12.
  • Confirmar que cada fila es una tripleta (english_form, spanish_form, metadata). Los nombres exactos de los campos se fijan en corpus_spec.md de la Fase 12; consúltalo.
  • Concatenar cada fila en una única string usando el formato que la Fase 12 fijó. Default: f"{english} / {spanish}" seguido de un token <eos>.

Bloque B — tokenizar

  • Cargar el tokenizer BPE de la Fase 11 (src/minitokenizer/bpe.py + los archivos guardados de vocab/merges).
  • Codificar cada fila a una lista de IDs de token.
  • Anteponer <bos> y añadir <eos> a cada fila. (Si la Fase 11 no reservó estos en el vocab, añádelos ahora y documenta el cambio en manifest.json.)
  • Verificar: decodificar una fila tokenizada reproduce la string original exactamente. Comprobación puntual de 5 filas aleatorias.

Bloque C — alternativa: fallback a nivel de palabra

Si el tokenizer BPE de la Fase 11 produce demasiados tokens subword para el corpus de gramática de verbos (más de ~80 tokens únicos), considera una tokenización a nivel de palabra como fallback solo-para-Fase-14. La gramática de verbos tiene tan pocas formas únicas (~600) que un token por palabra es razonable. Esta es una decisión de apertura de fase — pregunta abierta (b) de PHASE_14_PLAN.md.

  • Ejecutar un diagnóstico de cuenta de tokens: len(set(t for row in all_rows for t in tokenize(row))). Si > 80, márcalo y discute antes de proceder.
  • Si usas a nivel de palabra, guarda el mapeo de vocab de palabras por separado como vocab_wordlevel.json. No sobrescribas el vocab BPE de la Fase 11.

Bloque D — comprobaciones de cordura del split

  • Imprime las cuentas de tokens por split y las cuentas de tokens únicos. Esperado (aprox): train ~5000 tokens, dev ~600 tokens, test ~600 tokens.
  • Confirma que ninguna fila está duplicada entre splits (es un asunto de la Fase 12, pero re-verifica aquí — la intersección de set entre train y dev debe ser 0).
  • Confirma que tanto formas en inglés como en español están presentes en cada split. (Para algunos splits, la Fase 12 puede haber elegido solo-inglés o solo-español — si es así, documéntalo.)

Bloque E — manifest

Esquema de manifest.json:

{
  "experiment": "14-tokenize",
  "date": "YYYY-MM-DD",
  "seed": 42,
  "upstream": {
    "phase_11_tokenizer": "path/to/bpe/vocab",
    "phase_12_corpus": "path/to/data/processed/"
  },
  "tokenization": {
    "scheme": "bpe" | "wordlevel",
    "vocab_size": null,
    "added_special_tokens": ["<bos>", "<eos>", "<sep>"]
  },
  "splits": {
    "train_rows": null,
    "dev_rows": null,
    "test_rows": null,
    "train_tokens_total": null
  },
  "versions": {"python": "3.11.x", "numpy": "X.Y.Z"}
}

Rellena los null tras ejecutar.

Restricciones

  • Sin PyTorch. Por anti-objetivo §10. Solo NumPy + librería estándar.
  • Reproducible. Fija np.random.seed(42) antes de cualquier shuffle. Documéntalo en el manifest.
  • Sin fugas. Verifica que train/dev/test son disjuntos por fila.

Condiciones de parada

Estás listo cuando:

  1. dataset.py (o .npz) carga en <1 segundo.
  2. La sentencia print print(len(train_ids), len(dev_ids), len(test_ids)) funciona.
  3. manifest.json existe con todos los valores null sustituidos por números.
  4. Puedes decodificar un train_ids[i] aleatorio y leer de vuelta la fila original (english / spanish).

Escollos

  • Duplicación de <bos> / <eos>. Si accidentalmente antepones <bos> dos veces (una desde la Fase 11, otra aquí), cada estadística de n-grama está descuadrada por uno. Comprueba decodificando una sola fila y contando las ocurrencias de <bos>.
  • Drift de vocab. Si recodificas una fila de la Fase 12 que contiene un carácter o substring que el BPE de la Fase 11 no vio, te encontrarás con <unk>. Cuenta las ocurrencias de <unk>; debería ser 0 si el corpus de la Fase 12 se usó para entrenar el BPE.
  • Shuffle del split sin seed. Si la Fase 12 no fijó la semilla aleatoria para sus splits, tus splits diferirán en cada ejecución. O fijas la seed aquí, o comprueba en el manifest de la Fase 12 la seed que usó.

Cuándo consultar solutions/

Tras comprometer dataset.py y manifest.json. La solución en solutions/00-tokenize-corpus-ref.md (escrita al abrir la fase) compara tus elecciones de tokenización y números de cordura del split.


Siguiente lab: lab/01-ngram-baseline.md.