Phase 06 - Lesson 05
Whisper — Arquitectura y Fine-Tuning
Whisper es un encoder-decoder transformer con ventana de 30 segundos, entrenado con 680 mil horas de pares audio-texto multilingües con supervisión débil. Una sola arquitectura, múltiples tareas, robusto en 99 idiomas. El ASR de referencia en 2026.
Tipo: Build Lenguajes: Python Prerrequisitos: Fase 6 · 04 (ASR), Fase 5 · 10 (Atención), Fase 7 · 05 (Transformer Completo) Tiempo: ~75 minutos
El Problema
Whisper, lanzado por OpenAI en septiembre de 2022, fue el primer modelo de ASR en llegar como un commodity: pega el audio, obtén el texto, 99 idiomas, robusto al ruido, corre en una laptop. Para 2024 OpenAI ya había lanzado las variantes Large-v3 y Turbo; para 2026, Whisper es el baseline por defecto para todo, desde la transcripción de podcasts hasta los asistentes de voz y los subtítulos de YouTube.
Pero Whisper no es un pipeline que puedas tratar como una caja negra para siempre. El domain shift lo destruye — jerga técnica, acentos de los hablantes, nombres propios, clips cortos, silencio. Necesitas saber:
- Qué es realmente por dentro.
- Cómo entregarle audio en chunks, en streaming o de formato largo de la manera correcta.
- Cuándo hacer fine-tune y cómo.
El Concepto
Arquitectura. Encoder-decoder transformer estándar.
- Entrada: espectrograma log-mel de 30 segundos, 80 mels, hop de 10 ms → 3000 frames. Los clips más cortos reciben zero-padding, los clips más largos se dividen en chunks.
- Encoder: conv-downsample (stride 2) +
Nbloques transformer. Para Large-v3: 32 capas, 1280 dimensiones, 20 cabezas. - Decoder:
Nbloques transformer con self-attn causal + cross-attn a la salida del encoder. Del mismo tamaño que el encoder. - Salida: tokens BPE sobre un vocabulario de 51.865 tokens.
Large-v3 tiene 1,55 mil millones de parámetros. Turbo usa un decoder de 4 capas (en vez de 32), reduciendo la latencia en 8× con una pérdida de WER inferior al 1%.
El formato del prompt. Whisper es un modelo multitarea guiado por tokens especiales en el prompt del decoder:
<|startoftranscript|><|en|><|transcribe|><|notimestamps|> Hello world.<|endoftext|>
<|en|>— etiqueta de idioma; fuerza el comportamiento de traducción vs. transcripción.<|transcribe|>o<|translate|>— traducir la salida al inglés a partir de una entrada en cualquier idioma, o transcribir textualmente.<|notimestamps|>— omitir los timestamps a nivel de palabra (más rápido).
El prompt es lo que permite a un solo modelo realizar muchas tareas. Cambia <|en|> por <|fr|> y transcribe francés.
Ventana de 30 segundos. Todo está fijado a 30 segundos. Los clips más largos necesitan chunking; los clips más cortos reciben padding. Las ventanas no se procesan en streaming de forma nativa — por eso existen WhisperX, Whisper-Streaming y faster-whisper.
Normalización log-mel. (log_mel - mean) / std, donde las estadísticas provienen del propio corpus de entrenamiento de Whisper. Debes usar el preprocesamiento de Whisper (whisper.audio.log_mel_spectrogram), no librosa.feature.melspectrogram.
Variantes en 2026
| Variante | Parámetros | Latencia (A100) | WER (LibriSpeech-clean) |
|---|---|---|---|
| Tiny | 39M | 1× tiempo real | 5,4% |
| Base | 74M | 1× | 4,1% |
| Small | 244M | 1× | 3,0% |
| Medium | 769M | 1× | 2,7% |
| Large-v3 | 1,55B | 2× | 1,8% |
| Large-v3-turbo | 809M | 8× | 1,58% |
| Whisper-Streaming (2024) | 1,55B | streaming | 2,0% |
Fine-tuning
Flujo de trabajo canónico en 2026:
- Recolecta de 10 a 100 horas de audio del dominio objetivo con transcripciones alineadas.
- Ejecuta
transformers.Seq2SeqTrainercon el callbackgenerate_with_loss. - Eficiente en parámetros: LoRA en
q_proj,k_proj,v_projde las capas de atención reduce la memoria de GPU en 4× con un costo de WER inferior a 0,3. - Congela el encoder si tienes menos de 10 horas. Ajusta solo el decoder.
- Usa el propio tokenizer y formato de prompt de Whisper; nunca cambies el tokenizer.
Resultados de la comunidad: hacer fine-tune de Medium con 20 horas de dictado médico reduce el WER del 12% al 4,5% en vocabulario médico. Hacer fine-tune de Turbo con 4 horas de islandés reduce el WER del 18% al 6%.
Constrúyelo
Paso 1: ejecuta Whisper sin ajustes
import whisper
model = whisper.load_model("large-v3-turbo")
result = model.transcribe(
"clip.wav",
language="en",
task="transcribe",
temperature=0.0,
condition_on_previous_text=False, # prevents runaway repetition
)
print(result["text"])
for seg in result["segments"]:
print(f"[{seg['start']:.2f}–{seg['end']:.2f}] {seg['text']}")
Valores por defecto importantes que siempre debes sobrescribir: temperature=0.0 (el muestreo usa por defecto la cadena de fallback 0.0 → 0.2 → 0.4 …), condition_on_previous_text=False (previene el problema de alucinación en cascada) y no_speech_threshold=0.6 (detección de silencio).
Paso 2: formato largo en chunks
# whisperx is the 2026 reference for long-form with word-level timestamps
import whisperx
model = whisperx.load_model("large-v3-turbo", device="cuda", compute_type="float16")
segments = model.transcribe("1hour.mp3", batch_size=16, chunk_size=30)
WhisperX agrega (1) gating mediante VAD Silero, (2) alineación a nivel de palabra vía wav2vec 2.0, (3) diarización vía pyannote.audio. El caballo de batalla de 2026 para transcripción en producción.
Paso 3: fine-tune con LoRA
from transformers import WhisperForConditionalGeneration, WhisperProcessor
from peft import LoraConfig, get_peft_model
model = WhisperForConditionalGeneration.from_pretrained("openai/whisper-large-v3-turbo")
lora = LoraConfig(
r=16, lora_alpha=32, target_modules=["q_proj", "v_proj"],
lora_dropout=0.1, bias="none", task_type="SEQ_2_SEQ_LM",
)
model = get_peft_model(model, lora)
# model.print_trainable_parameters() -> ~3M trainable / 809M total
Luego el loop estándar del Trainer. Haz checkpoint cada 1000 pasos. Evalúa con WER en un conjunto de validación separado.
Paso 4: inspecciona lo que aprende cada capa
# Grab cross-attention weights during decode to see what the decoder attends to.
with torch.inference_mode():
out = model.generate(
input_features=features,
return_dict_in_generate=True,
output_attentions=True,
)
# out.cross_attentions: layer × head × step × src_len
Visualiza con un heatmap — verás la alineación diagonal a medida que los pasos del decoder recorren los frames del encoder. Esa diagonal es la noción de timestamps de palabras de Whisper.
Úsalo
El stack de 2026:
| Situación | Elección |
|---|---|
| Inglés general, offline | Large-v3-turbo vía whisperx |
| Mobile / edge | Whisper-Tiny cuantizado (int8) o Moonshine |
| Formato largo multilingüe | Large-v3 vía whisperx + diarización |
| Idioma de pocos recursos | Fine-tune de Medium o Turbo con LoRA |
| Streaming (2 s de latencia) | Whisper-Streaming o Parakeet-TDT |
| Timestamps a nivel de palabra | WhisperX (alineación forzada vía wav2vec 2.0) |
faster-whisper (backend CTranslate2) es el runtime de inferencia CPU+GPU más rápido en 2026 — 4× más rápido que el original con salida idéntica.
Trampas que todavía aparecen en 2026
- Texto alucinado en el silencio. Whisper se entrenó con subtítulos que incluyen "Thanks for watching!", "Subscribe!", letras de canciones. Aplica siempre gating por VAD antes de llamar.
- Cascada de
condition_on_previous_text. Una alucinación contamina las ventanas siguientes. Configúralo enFalsea menos que necesites fluidez entre los chunks. - Padding de clip corto. Un clip de 2 segundos rellenado hasta 30 segundos puede alucinar en el silencio final. Usa
pad=Falseo gating por VAD. - Estadísticas de mel incorrectas. Usar los mels de librosa en vez de los de Whisper produce una salida casi aleatoria. Usa
whisper.audio.log_mel_spectrogram.
Entrégalo
Guárdalo como outputs/skill-whisper-tuner.md. Diseña un pipeline de fine-tune o de inferencia de Whisper para un dominio específico.
Ejercicios
- Fácil. Ejecuta
code/main.py. Tokeniza un prompt al estilo Whisper, calcula los presupuestos de shape decodificado e imprime el cronograma de chunks para un clip de 10 minutos. - Medio. Instala
faster-whisper, transcribe un podcast de 10 minutos y compara el WER con una transcripción humana. Pruebalanguage="auto"vs.language="en"forzado. - Difícil. Usando
datasetsde HF, elige un idioma en el que Whisper tiene dificultades (por ejemplo, urdu), haz fine-tune de Medium con LoRA durante 2 epochs con 2 horas y reporta el delta de WER.
Términos Clave
| Término | Lo que dice la gente | Lo que realmente significa |
|---|---|---|
| Ventana de 30 s | El límite de Whisper | Tope rígido de entrada; divide el audio más largo en chunks. |
| SOT | Start-of-transcript | `< |
| Token de timestamps | Alineación temporal | Cada offset de 0,02 s es un token especial en el vocabulario de 51k. |
| Turbo | La variante rápida | Decoder de 4 capas, 8× más rápido, regresión de WER <1%. |
| WhisperX | El wrapper para formato largo | VAD + Whisper + alineación wav2vec + diarización. |
| Fine-tune con LoRA | Ajuste eficiente | Agrega adaptadores de bajo rango a la atención; entrena ~0,3% de los parámetros. |
| Alucinación | La falla silenciosa | Whisper produce inglés fluido a partir de ruido/silencio. |
Lecturas Adicionales
- Radford et al. (2022). Artículo de Whisper — la arquitectura original y la receta de entrenamiento.
- OpenAI (2024). Lanzamiento de Whisper Large-v3-turbo — decoder de 4 capas, 8× más rápido.
- Bain et al. (2023). WhisperX — formato largo, alineado por palabra, diarizado.
- Systran — repositorio de faster-whisper — backend CTranslate2, 4× más rápido.
- HuggingFace — tutorial de fine-tune de Whisper — recorrido canónico de LoRA / full-FT.