Voz e IA — Módulo 2: reconocimiento de voz (ASR) — de audio a texto
Segundo módulo del Curso de Voz e IA en tiempo real: cómo una máquina convierte audio en texto. Del enfoque clásico (fonemas y modelos ocultos de Markov) al fin de la era con CTC y los modelos encoder-decoder, cómo funciona Whisper por dentro, y por qué el ASR moderno es, en el fondo, un problema de secuencia a secuencia.
☰ Índice del contenido
- La tesis del módulo
- Cómo se hacía antes (y por qué era frágil)
- El problema del alineamiento
- CTC: alinear sumando sobre todos los alineamientos
- Encoder-decoder: el ASR como traducción
- Whisper por dentro
- El código: transcribir en la práctica
- CTC vs encoder-decoder: ¿cuál uso?
- Errores comunes
- La frase para llevarse
- Qué viene
- Material relacionado
En el módulo 1 dejamos el audio convertido en algo que una red neuronal puede digerir: el mel-espectrograma (una imagen del sonido donde el eje horizontal es el tiempo, el vertical es la frecuencia en escala mel —la que imita cómo oye el oído humano— y el color es la energía). Salimos de la onda cruda y llegamos a una matriz de números. Ahora empieza el trabajo de verdad: convertir esa matriz en texto. Ese es el problema del ASR (Automatic Speech Recognition, reconocimiento automático de voz), y este módulo cuenta cómo se resolvió, por qué la solución de hace veinte años era frágil, y por qué la de hoy —la que usa Whisper— es, en el fondo, el mismo tipo de modelo que traduce idiomas.
La tesis del módulo
El reconocimiento de voz moderno no busca fonemas en un diccionario: es un modelo de secuencia a secuencia que mapea un espectrograma a una cadena de texto, entrenado a gran escala. Por eso un mismo modelo transcribe decenas de idiomas sin que nadie le programe las reglas de ninguno: no aprendió español ni japonés, aprendió a mapear sonido a texto, y el idioma es solo una parte más de lo que sale por el otro lado.
Cómo se hacía antes (y por qué era frágil)
Durante décadas el ASR fue un sistema de piezas separadas, cada una entrenada aparte y encadenada a mano. Vale la pena entenderlo porque explica de qué nos liberó el deep learning.
El enfoque clásico tenía tres bloques:
- Extracción de features con MFCC (Mel-Frequency Cepstral Coefficients, coeficientes cepstrales en frecuencia mel: una compresión del espectro de cada ventana de audio en ~13 números que resumen la “forma” del sonido). Es un pariente pobre del mel-espectrograma del módulo 1: menos información, pensado para que los modelos estadísticos chicos de la época pudieran con él.
- Un modelo acústico con HMM. El HMM (Hidden Markov Model, modelo oculto de Markov: un modelo estadístico de estados que no vemos —los sonidos— que van cambiando en el tiempo y emiten lo que sí vemos —los features—) modelaba cada fonema (la unidad mínima de sonido de un idioma: la /s/, la /a/, la /rr/) como una secuencia de estados. El sistema tenía un diccionario de pronunciación que decía cómo se descompone cada palabra en fonemas, y el HMM buscaba la secuencia de fonemas más probable dado el audio.
- Un modelo de lenguaje aparte, que reordenaba las hipótesis según qué palabras suelen ir juntas (“a ver” es más probable que “haber” en cierto contexto).
El problema no era que no funcionara —funcionaba, con esfuerzo—, sino su fragilidad. Cada bloque se entrenaba con un objetivo distinto y los errores se acumulaban en cascada: un diccionario de pronunciación incompleto rompía palabras nuevas, el HMM asumía que cada frame de audio dependía solo del estado actual (una simplificación que la voz real no respeta), y adaptar el sistema a otro idioma o a otro acento significaba rehacer el diccionario y reentrenar los modelos acústicos. Era ingeniería artesanal, cara y quebradiza.
El salto del deep learning fue reemplazar toda esa cadena por una sola red neuronal entrenada de punta a punta (end-to-end: una función que va directo del audio al texto, sin bloques intermedios que se entrenen por separado). Pero para entrenar esa red apareció un problema nuevo, y resolverlo es lo interesante.
El problema del alineamiento
Tienes un espectrograma con, digamos, 300 frames (columnas de tiempo) y la transcripción correcta: “hola”. Cuatro letras, 300 frames. ¿Qué frame corresponde a la “h”? ¿Cuántos frames dura la “o”? No lo sabes. El hablante pudo arrastrar la “o” durante 80 frames o soltarla en 10. En los datos de entrenamiento nadie marcó, frame por frame, qué letra sonaba en cada instante —hacerlo a mano para miles de horas es inviable.
Ese es el problema del alineamiento: la entrada (frames de audio) y la salida (caracteres) tienen largos distintos y no sabemos cuál se corresponde con cuál. El enfoque clásico lo resolvía con el diccionario de pronunciación y el HMM. El deep learning necesitaba otra idea. Hay dos, y son las dos grandes familias del ASR moderno.
CTC: alinear sumando sobre todos los alineamientos
CTC (Connectionist Temporal Classification, clasificación temporal conexionista) es la primera idea y la más elegante. En lugar de exigir un alineamiento, los considera todos a la vez.
La red mira el espectrograma y, para cada frame, emite una distribución de probabilidad sobre el alfabeto. La clave es que ese alfabeto tiene un carácter extra: el token blank (en blanco, que se escribe - y significa “en este frame no emito ninguna letra nueva”). Con ese token, la red puede alinear como quiera: puede repetir una letra en varios frames y puede rellenar los silencios con blanks.
La magia está en la regla de colapso. Para pasar de la tira de frames a la palabra final: primero se juntan las letras repetidas consecutivas, luego se borran los blanks. Así, para la palabra “hola”, muchas tiras distintas dan el mismo resultado:
COLAPSO CTC: MUCHAS TIRAS ► UNA PALABRA
h h - o o o l - l a ► (junta repes) ► h-ol-la
(borra blank) ► holla MAL
h - o o - l - l - a ► h-o-l-l-a
borra blank ► holla MAL
h - o o - l l - - a ► h-o-l--a
borra blank ► hola OK
- h - o - l - a - - ► -h-o-l-a--
borra blank ► hola OK
Fíjate en el detalle del blank entre las dos “l”: sin un blank en medio, dos letras iguales seguidas se colapsarían en una. El blank es lo que permite escribir “carro” (con dos “r”) sin que se fusionen. Ese es su segundo trabajo, más allá de marcar silencio.
Durante el entrenamiento, CTC no elige un alineamiento: calcula la probabilidad de la palabra correcta sumando la probabilidad de todas las tiras que colapsan a ella. Si “hola” es la respuesta, su score es la suma de las probabilidades de h-ol--a, hho-l-a, -h-o-l-a y todas las demás tiras válidas. Esa suma tendría millones de términos si se calculara ingenuamente, pero se resuelve eficientemente con programación dinámica (una técnica que reutiliza cálculos parciales para no repetir trabajo). La red aprende a subir esa probabilidad total, y en el camino descubre sola qué frame va con qué letra, sin que nadie se lo marcara.
Ojo: CTC hace una suposición fuerte —que cada frame es independiente de los demás dado el audio—. Eso significa que, por sí solo, no modela bien que después de “q” casi siempre viene “u”. Los sistemas CTC serios se apoyan en un modelo de lenguaje externo en el momento de decodificar para arreglar esto. No es un end-to-end tan puro como parece.
La ventaja enorme de CTC: como emite una decisión por frame y de izquierda a derecha, sirve para streaming (transcribir mientras el audio va llegando, sin esperar a que termine la frase). Volveremos a esto en la tabla comparativa.
Encoder-decoder: el ASR como traducción
La segunda familia —la de Whisper— ataca el alineamiento de otra manera: no lo resuelve explícitamente, deja que el modelo lo aprenda con atención. Es la arquitectura encoder-decoder (codificador-decodificador), y es exactamente un Transformer, la misma arquitectura que vimos en detalle en la arquitectura completa del Transformer.
La idea es tratar la transcripción como una traducción: traducir de “idioma espectrograma” a “idioma texto”. Dos piezas:
- El encoder (codificador) lee el espectrograma completo y lo convierte en una representación interna rica —una secuencia de vectores que resumen qué se dijo, con contexto de toda la frase, no frame por frame aislado.
- El decoder (decodificador) genera el texto autorregresivamente (autoregressive: produce un token a la vez, y cada token nuevo se agrega a la entrada para predecir el siguiente, como cuando un LLM escribe palabra por palabra). En cada paso, el mecanismo de atención (attention: el decoder decide a qué partes del espectrograma “mirar” para producir el token actual) resuelve el alineamiento de forma implícita: al generar la palabra “hola”, la atención se concentra sola en los frames donde sonó.
PIPELINE ASR ENCODER-DECODER (WHISPER)
audio ──► ┌───────────┐
│ mel- │ (módulo 1)
│ espectro │
└─────┬─────┘
▼
┌───────────┐ lee todo el espectro
│ ENCODER │ ► representación
│Transformer│ interna con contexto
└─────┬─────┘
▼
┌───────────┐──┐ genera 1 token,
│ DECODER │ │ mira el encoder
│ autorreg │◄─┘ con atención y
└─────┬─────┘ realimenta (ciclo)
▼
texto: "hola"
Ese ciclo del decoder es la diferencia de fondo con CTC. CTC decide todo de una pasada, en paralelo. El decoder encoder-decoder va token por token, y cada token puede depender de los anteriores —por eso “sabe” que después de “q” viene “u” sin ayuda externa: el modelo de lenguaje está incorporado en el decoder. A cambio, esa dependencia secuencial hace que no sea naturalmente apto para streaming: para dar el primer token bien, típicamente le conviene haber visto todo el audio.
Whisper por dentro
Whisper es el modelo de ASR de OpenAI (open source, 2022) que popularizó este enfoque. Vale la pena mirarlo porque encarna la tesis del módulo. Lo que lo hace especial no es la arquitectura —es un encoder-decoder Transformer bastante estándar— sino cómo y con qué se entrenó:
- ~680.000 horas de audio recogidas de internet con sus transcripciones, de forma débilmente supervisada (weakly supervised: las transcripciones venían “de la calle” —subtítulos, transcripciones de dudosa calidad— en vez de audio etiquetado a mano en laboratorio). Cantidad y variedad por encima de pureza. De esas horas, ~117.000 son multilingües y cubren decenas de idiomas.
- Entrada estandarizada: trocea el audio en ventanas de 30 segundos, cada una convertida en un log-mel-espectrograma (de 80 canales mel en las versiones clásicas). Todo lo que entra al encoder tiene ese formato fijo.
- Multitarea vía tokens especiales. Aquí está lo ingenioso. El decoder no solo transcribe: el mismo modelo hace transcripción, traducción al inglés, detección de idioma y timestamps (marcas de tiempo). ¿Cómo elige la tarea? Con tokens especiales al inicio de la secuencia que el decoder lee como instrucción: algo como
<|es|>(idioma español)<|transcribe|>(o<|translate|>)<|notimestamps|>. Cambiar esos tokens cambia lo que el modelo hace, sin tocar los pesos. Es la misma idea de “prompt” que en los LLM, aplicada a audio. - Familia de tamaños:
tiny,base,small,medium,large(y variantes turbo posteriores). Más grande = más preciso y más lento. La elección de tamaño es una decisión de producto, y la veremos en detalle en el módulo 3.
Sus fortalezas: robustez frente a ruido, acentos y audio de baja calidad (fruto directo de haberse entrenado con datos “sucios” de internet), y cobertura multilingüe en un solo modelo.
Sus debilidades, que hay que conocer antes de ponerlo en producción:
- Alucinaciones en el silencio. Como es un modelo generativo autorregresivo, en tramos sin voz (silencio, música, ruido) a veces “inventa” texto plausible: repite la frase anterior, mete un “gracias por ver el video” heredado de sus datos de YouTube. No falla en blanco, falla inventando.
- No diariza. Diarizar es responder “¿quién habló?” —separar y etiquetar a los distintos hablantes. Whisper transcribe qué se dijo, no quién lo dijo; para diarización hace falta otro sistema encima.
- Latencia por ser batch. Batch (por lotes) es lo opuesto a streaming: procesa el audio en bloques de 30 segundos ya grabados. No está pensado para transcribir en vivo mientras la persona habla —justo la limitación que hace que el streaming sea un tema aparte, y central para un curso “en tiempo real”.
El código: transcribir en la práctica
Dos formas de llamar a Whisper. La primera, con la librería oficial openai-whisper:
# pip install -U openai-whisper (requiere ffmpeg instalado en el sistema)
import whisper
# Carga uno de los tamaños: tiny, base, small, medium, large.
# La primera vez descarga los pesos; luego quedan en caché local.
model = whisper.load_model("base")
# transcribe() hace TODO el pipeline del módulo:
# lee el archivo, lo trocea en ventanas de 30s, saca el mel-espectro,
# corre encoder+decoder y devuelve el texto ya reensamblado.
result = model.transcribe("entrevista.mp3")
print(result["text"]) # transcripción completa como string
for seg in result["segments"]: # y también segmentada con timestamps
print(f"[{seg['start']:.1f}s → {seg['end']:.1f}s] {seg['text']}")
La segunda, con la librería transformers de Hugging Face, útil si ya trabajas en ese ecosistema o quieres una variante concreta del modelo (por ejemplo large-v3):
# pip install -U transformers torch
from transformers import pipeline
# El pipeline "automatic-speech-recognition" arma solo el modelo,
# el extractor de features (el mel) y el tokenizer, todos compatibles.
asr = pipeline(
task="automatic-speech-recognition",
model="openai/whisper-large-v3-turbo",
device=0, # 0 = primera GPU; usa "cpu" si no tienes GPU
)
salida = asr("entrevista.mp3")
print(salida["text"])
Ambas hacen exactamente lo que dibujó el diagrama: audio → mel → encoder → decoder → texto. La diferencia son detalles de ergonomía, no de fondo.
CTC vs encoder-decoder: ¿cuál uso?
| CTC | Encoder-decoder (seq2seq) | |
|---|---|---|
| Cómo alinea | Explícito, con blank y suma sobre alineamientos | Implícito, con atención |
| Cómo emite | Una decisión por frame, en paralelo | Un token a la vez, autorregresivo |
| Modelo de lenguaje | Externo (hay que sumarlo al decodificar) | Incorporado en el decoder |
| Streaming | Natural (decide izquierda a derecha) | Difícil (le conviene ver todo el audio) |
| Calidad / robustez | Buena, algo por debajo en frases complejas | Mejor, sobre todo con acentos y ruido |
| Alucinaciones en silencio | Casi no (no es generativo) | Sí (es generativo) |
| Ejemplo típico | ASR en vivo, dictado con baja latencia | Whisper, transcripción por lotes |
La regla práctica: si necesitas transcribir en vivo con la mínima latencia posible (subtítulos en directo, un asistente de voz que responde mientras hablas), CTC o híbridos basados en CTC son el camino natural. Si necesitas máxima calidad sobre audio ya grabado y en muchos idiomas, un encoder-decoder tipo Whisper gana. Muchos sistemas de producción combinan las dos ideas.
Errores comunes
- Creer que Whisper “entiende” idiomas. No aprendió gramática de ninguno: aprendió a mapear sonido a texto sobre 680k horas. Que transcriba japonés no significa que lo “sepa”; significa que vio suficiente japonés en el entrenamiento.
- Esperar que CTC modele el lenguaje solo. Por su suposición de independencia entre frames, CTC puro produce ortografía rara sin un modelo de lenguaje externo al decodificar. No es opcional en sistemas serios.
- Confundir el blank de CTC con un silencio. El blank es un token técnico que habilita el alineamiento y separa letras repetidas. A veces coincide con silencio, pero su función no es “marcar que no hay voz”.
- Usar Whisper para transcripción en vivo tal cual. Es batch: procesa bloques de 30s. Forzarlo a streaming ingenuamente da latencia y errores en los bordes de cada bloque. El streaming es un problema de diseño aparte.
- Ignorar las alucinaciones en silencio. En producción, pasar audio con tramos largos sin voz a Whisper sin un filtro previo de actividad de voz produce texto inventado. Hay que detectar y recortar el silencio antes.
- Pedirle a Whisper que diga quién habló. No diariza. Si necesitas separar hablantes, es otro sistema encima de la transcripción, no un parámetro de Whisper.
La frase para llevarse
“El ASR moderno dejó de buscar fonemas en un diccionario y empezó a traducir: de idioma espectrograma a idioma texto. Por eso un solo modelo transcribe medio mundo —no aprendió idiomas, aprendió a mapear sonido a letras.”
Qué viene
Módulo 3: Whisper en la práctica. Ya sabes qué hace por dentro; ahora viene el detalle operativo que decide si sirve en tu producto. Qué tamaño elegir según tu presupuesto de latencia y GPU, por qué faster-whisper (una reimplementación optimizada) corre varias veces más rápido con la misma calidad, cómo sacar timestamps a nivel de palabra para subtitular, y cómo manejar las alucinaciones en silencio con detección de actividad de voz antes de transcribir. Del “cómo funciona” al “cómo se corre bien”.
Material relacionado
Preguntas sobre este curso
Regístrate gratis para hacer preguntas y guardar tu progreso.
✉ Entérate de lo nuevo
Recibe un aviso cuando publique nuevos cursos, workshops o investigaciones. Sin spam.