Transdutor RNN (RNN-T)
Visão geral
RNN Transducer (RNN‑T) é uma arquitetura neural e um critério de treinamento amplamente usados para reconhecimento automático de fala (automatic speech recognition, ASR) em fluxo (streaming) de baixa latência (low‑latency). Ele foi projetado para mapear uma sequência de quadros de características acústicas (áudio) para uma sequência de tokens de saída (caracteres, subpalavras ou palavras) sem exigir alinhamentos em nível de quadro (frame‑level alignments).
O RNN‑T é especialmente popular em ASR no dispositivo (on-device) e em tempo real (real-time) porque ele pode:
- Processar áudio incrementalmente conforme ele chega (em fluxo)
- Produzir hipóteses parciais com baixa latência
- Aprender alinhamentos internamente, evitando alinhamentos forçados (forced alignments) durante o treinamento
- Combinar modelagem acústica e um componente leve “semelhante a modelo de linguagem” em um único sistema ponta a ponta (end-to-end)
Conceitualmente, o RNN‑T pode ser visto como uma alternativa amigável ao processamento em fluxo para ASR com codificador–decodificador (encoder–decoder) baseado em atenção (attention-based), e uma alternativa mais expressiva à Classificação Temporal Conexionista (Connectionist Temporal Classification, CTC).
O problema central: alinhamentos desconhecidos entre quadros de áudio e tokens
Na fala, a entrada é uma sequência longa de quadros (por exemplo, passos de 10 ms), enquanto a saída é uma sequência muito mais curta de tokens (por exemplo, subpalavras). A parte difícil é que normalmente não sabemos qual quadro de áudio corresponde a qual token.
Pipelines tradicionais de ASR usavam componentes separados (modelo acústico + léxico de pronúncia + modelo de linguagem) e dependiam de mecanismos de alinhamento como estados de HMM. Modelos ponta a ponta como o RNN‑T, em vez disso, tratam o alinhamento como uma variável latente (latent variable) e o aprendem por meio de um objetivo diferenciável (differentiable objective).
O RNN‑T faz isso construindo uma distribuição de probabilidade sobre todos os alinhamentos válidos que mapeiam quadros de entrada para tokens de saída, incluindo um símbolo em branco (blank) especial que significa “não emitir nada neste passo de tempo”.
Arquitetura do RNN‑T
Um modelo RNN‑T tem três partes principais:
- Codificador (encoder) (também chamado de rede de transcrição): mapeia quadros acústicos para representações de alto nível
- Rede de predição (prediction network): consome tokens emitidos anteriormente para produzir uma representação do histórico de saída
- Rede conjunta (joint network): combina as representações do codificador e da rede de predição para produzir uma distribuição sobre os próximos tokens (incluindo o símbolo em branco)
Esses três componentes, em conjunto, definem probabilidades sobre sequências de tokens enquanto permitem inferência em fluxo (streaming inference).
Codificador: modelagem acústica para streaming
O codificador recebe características acústicas (x_{1:T}) (por exemplo, log-Mel filterbanks) e produz vetores codificados (h_{1:T'}):
[ h_t = \mathrm{Encoder}(x_{1:t}) \quad \text{(streaming/causal)} ]
Pontos-chave:
- Em ASR em fluxo, o codificador é causal (não olha para o áudio futuro) ou usa contexto em blocos (chunked) (antecipação limitada).
- (T') pode ser menor que (T) devido à subamostragem (subsampling) (por exemplo, empilhamento de quadros ou convoluções com stride), o que reduz computação e melhora a latência.
- Escolhas comuns de codificador:
- LSTM/GRU (Redes Neurais Recorrentes (Recurrent Neural Networks))
- Híbridos de convolução + RNN
- Variantes de Conformer/Transformer adaptadas para streaming (Arquitetura Transformer (Transformer Architecture))
Nota prática: Muitos sistemas modernos de “RNN‑T” usam um codificador Transformer/Conformer; o nome “RNN” é histórico, vindo dos primeiros projetos.
Rede de predição: modelagem do histórico de tokens
A rede de predição consome os tokens não brancos emitidos anteriormente (y_{1:u-1}) e produz um estado (g_u):
[ g_u = \mathrm{PredNet}(y_{1:u-1}) ]
Isso se comporta de forma semelhante a um pequeno modelo de linguagem neural, mas é treinado conjuntamente com o codificador em dados pareados de áudio-texto.
Características importantes:
- Ela não consome quadros acústicos.
- Ela só é atualizada quando o modelo emite um token não branco.
- Arquiteturas típicas: uma camada de embeddings + uma LSTM/GRU ou um Transformer pequeno.
Rede conjunta: combinando áudio e histórico
Em qualquer ponto, o RNN‑T considera um par de índices:
- (t): posição na sequência de áudio codificada (h_{1:T'})
- (u): posição na sequência de tokens de saída (y_{1:U}) (quantos rótulos já foram emitidos)
A rede conjunta combina (h_t) e (g_u) para produzir valores de logit (logits) sobre o vocabulário mais o símbolo em branco:
[ z_{t,u} = \mathrm{Joint}(h_t, g_u) ] [ p(k \mid t,u) = \mathrm{softmax}(z_{t,u}) \quad k \in \mathcal{V} \cup {\varnothing} ]
Onde (\varnothing) é o símbolo em branco.
Uma rede conjunta comum é:
- projeção linear de (h_t) e (g_u)
- soma + não linearidade (por exemplo, tanh)
- camada linear final até o tamanho do vocabulário
Essa estrutura produz uma grade 2D (frequentemente chamada de treliça (lattice) do RNN‑T) sobre ((t,u)).
Como os alinhamentos funcionam: símbolos em branco e “movimentos” em uma treliça
O RNN‑T define uma distribuição sobre alinhamentos permitindo dois tipos de transições a partir do estado ((t,u)):
Emitir símbolo em branco (\varnothing): avança o tempo, mantém o mesmo comprimento de saída
((t,u) \rightarrow (t+1, u))Emitir um token (y_u): avança o comprimento de saída, mantém o mesmo tempo
((t,u) \rightarrow (t, u+1))
Esta é a ideia central amigável ao streaming:
- Símbolos em branco significam “nenhum token emitido ainda; consuma mais áudio.”
- Símbolos não brancos significam “emita um token agora; permaneça no mesmo passo de áudio.”
Um pequeno exemplo de alinhamento
Suponha que a saída-alvo seja as subpalavras: ["he", "llo"] (U=2). Conforme o áudio chega ao longo dos quadros (t=1..T'), um alinhamento possível poderia ser:
- Em (t=1): símbolo em branco
- Em (t=2): emitir
"he" - Ainda em (t=2): símbolo em branco (ou emitir o próximo token imediatamente; depende do modelo)
- Em (t=3): símbolo em branco
- Em (t=4): emitir
"llo" - Depois, símbolos em branco até o fim
Existem muitos alinhamentos válidos que produzem a mesma sequência de saída. O treinamento do RNN‑T soma sobre todos eles.
Objetivo de treinamento: maximizar a probabilidade da sequência sem rótulos por quadro
Dada a entrada (x) e os tokens-alvo (y), o RNN‑T define:
[ P(y \mid x) = \sum_{a \in \mathcal{A}(x,y)} P(a \mid x) ]
Onde:
- (a) é um caminho de alinhamento através da treliça ((t,u))
- (\mathcal{A}(x,y)) é o conjunto de todos os alinhamentos consistentes com (y)
O treinamento minimiza a log-verossimilhança negativa (negative log-likelihood):
[ \mathcal{L} = -\log P(y \mid x) ]
Forward-backward (programação dinâmica)
Somar diretamente sobre todos os alinhamentos é exponencial, então o RNN‑T usa um algoritmo de avanço-retrocesso (forward-backward algorithm) (como em HMMs e CTC) sobre a treliça:
- Variável forward (\alpha(t,u)): probabilidade de alcançar ((t,u))
- Variável backward (\beta(t,u)): probabilidade de completar a partir de ((t,u))
Em cada célula da treliça ((t,u)), as probabilidades vêm de:
- transição de símbolo em branco a partir de ((t-1,u))
- transição de rótulo a partir de ((t,u-1))
Isso produz gradientes exatos para a perda do RNN‑T via Retropropagação (Backpropagation), implementada de forma eficiente nos principais frameworks.
Detalhes práticos de treinamento
Escolhas e truques comuns em sistemas reais:
- Subamostragem no codificador para reduzir (T') (crítico para memória/compute)
- Vocabulário como subpalavras (equilibra flexibilidade e comprimento da sequência)
- Regularização: dropout, suavização de rótulos (label smoothing), SpecAugment
- Treinamento com lotes grandes + otimização distribuída (Descida do Gradiente (Gradient Descent))
Decodificação: gulosa e busca em feixe em um cenário de streaming
No tempo de inferência, queremos:
[ \hat{y} = \arg\max_y P(y \mid x) ]
A busca exata é intratável, então a decodificação prática usa aproximações.
Decodificação gulosa (greedy decoding) (mais rápida)
Uma abordagem gulosa simples em streaming, a cada passo de tempo:
- Calcular a distribuição (p(\cdot \mid t,u))
- Se o argmax for símbolo em branco: avançar (t)
- Caso contrário, emitir o token, avançar (u) e atualizar o estado da rede de predição
A decodificação gulosa é de baixa latência e barata, mas pode reduzir a acurácia em comparação com a busca em feixe, especialmente para áudio ambíguo.
Decodificação com busca em feixe (beam search) (comum em produção)
A busca em feixe (beam search) mantém múltiplas hipóteses parciais (prefixos) e as expande. Para RNN‑T, a busca em feixe deve lidar com o comportamento especial do símbolo em branco e com o fato de que emitir rótulos não avança o tempo.
Uma busca em feixe típica para RNN‑T itera sobre passos de tempo (t) e, dentro de cada passo de tempo, realiza um número limitado de expansões de rótulos.
Ingredientes-chave:
- Largura do feixe (beam width): número de hipóteses mantidas (por exemplo, 4–16 no dispositivo; maior no servidor)
- Poda (pruning): descartar hipóteses de baixa probabilidade para ganhar velocidade
- Fusão rasa (shallow fusion) opcional com modelo de linguagem externo: combinar a pontuação do RNN‑T com a do modelo de linguagem (veja abaixo)
Abaixo está um pseudocódigo simplificado (ilustrativo, não pronto para produção):
def rnnt_beam_search(encoded_frames, pred_net, joint, beam_size=8, max_sym_per_t=2):
# Each hypothesis: (tokens, pred_state, logp)
beam = [([], pred_net.init_state(), 0.0)]
for h_t in encoded_frames:
new_beam = beam
# Allow limited label emissions at this time step
for _ in range(max_sym_per_t):
candidates = []
for tokens, state, logp in new_beam:
logits = joint(h_t, pred_net.output(state))
probs = softmax(logits)
# Blank: advance time (handled by carrying hypothesis forward)
candidates.append((tokens, state, logp + log(probs["<blank>"])))
# Non-blank expansions: emit token, update pred state
for tok in top_k_tokens(probs, k=beam_size):
if tok == "<blank>":
continue
next_state = pred_net.step(state, tok)
candidates.append((tokens + [tok], next_state, logp + log(probs[tok])))
new_beam = prune_to_top_k(candidates, beam_size)
beam = new_beam
return best_hypothesis(beam)
Decodificadores reais adicionam otimizações como cache de estados (state caching), mesclagem de prefixos (prefix merging) e computações conjuntas em lote (batched joint computations).
O papel do símbolo em branco durante a decodificação
O símbolo em branco não é exibido ao usuário. Ele serve a dois propósitos:
- Permite que o modelo espere até ter evidência acústica suficiente
- Habilita flexibilidade de alinhamento e streaming estável
Um modelo que emite símbolos em branco demais pode ser excessivamente conservador (maior latência); poucos símbolos em branco podem causar saídas prematuras ou instáveis. Sistemas em produção frequentemente ajustam parâmetros de decodificação e, às vezes, aplicam técnicas como escalonamento do símbolo em branco (blank scaling) ou heurísticas de detecção de término (endpointing).
Por que o RNN‑T é adequado para ASR em streaming de baixa latência
O RNN‑T se alinha naturalmente às restrições do reconhecimento de fala em tempo real:
1) Processamento incremental sem contexto completo do enunciado
Ao contrário de ASR sequência a sequência (sequence-to-sequence, seq2seq) baseado em atenção e não em streaming (que frequentemente aplica atenção sobre todo o enunciado codificado), o RNN‑T pode operar com:
- um codificador causal/em blocos
- uma rede de predição que depende apenas de tokens passados
Isso permite hipóteses parciais conforme o áudio chega.
2) Modelagem conjunta de acústica e histórico
A rede de predição dá ao modelo uma noção forte de “quais tokens são prováveis a seguir”, o que frequentemente melhora a acurácia em relação a suposições de independência condicional no estilo CTC puro.
3) Implantação eficiente no dispositivo
O RNN‑T pode ser projetado para ser:
- de baixa memória (rede de predição pequena, codificador subamostrado)
- de baixo custo computacional por quadro
- estável sob restrições de streaming (antecipação limitada)
Por isso o RNN‑T é comum em assistentes de voz, ditado e legendas ao vivo em dispositivos móveis.
Relação com outras abordagens de ASR
RNN‑T vs CTC
Tanto RNN‑T quanto Classificação Temporal Conexionista (CTC) usam um símbolo em branco e somam sobre alinhamentos. A principal diferença:
- CTC assume que as saídas em diferentes passos de tempo são condicionalmente independentes dado o input (sem um modelo explícito de histórico de rótulos).
- RNN‑T condiciona tanto no input quanto nas saídas não brancas anteriores via a rede de predição.
Consequências práticas:
- O RNN‑T frequentemente obtém melhor acurácia, especialmente em contextos mais longos e vocabulários mais ricos.
- A decodificação do CTC é mais simples; a do RNN‑T é mais envolvida.
RNN‑T vs codificador–decodificador baseado em atenção
ASR baseado em atenção (por exemplo, LAS) pode ser altamente preciso, mas frequentemente é menos direto para streaming porque a atenção pode exigir contexto do enunciado completo (embora existam variantes de atenção em streaming).
O RNN‑T é uma “escolha padrão” quando você precisa de:
- limites estritos de latência
- saídas incrementais estáveis
- comportamento robusto em streaming
Sistemas híbridos e modelos de linguagem externos
Embora a rede de predição se comporte como um modelo de linguagem interno, muitos sistemas melhoram a acurácia ao integrar um modelo de linguagem (language model, LM) externo usando fusão rasa:
[ \log P_{\text{total}} = \log P_{\text{RNNT}} + \lambda \log P_{\text{LM}} + \gamma \cdot \text{coverage/length terms} ]
Isso pode ajudar com palavras raras, nomes ou adaptação a domínios.
Conceito relacionado: Busca em Feixe.
Considerações práticas de implantação
Escolha de vocabulário
Tokenizações comuns:
- Caracteres: simples, mas sequências longas
- Subpalavras (BPE/unigram): ótimo equilíbrio para ASR
- Palavras: vocabulário grande, problemas de fora do vocabulário (out-of-vocabulary, OOV) a menos que sejam tratados com cuidado
Subpalavras são comuns em sistemas RNN‑T de produção.
Projeto do codificador para streaming
Para manter a latência baixa:
- Use convoluções causais ou autoatenção em blocos
- Limite o contexto à direita (antecipação) a uma janela pequena
- Subamostre cedo para reduzir a taxa de quadros
Um alvo comum de projeto é manter a latência algorítmica (da antecipação do modelo + buffering) dentro de dezenas de milissegundos, dependendo das restrições do produto.
Endpointing e resultados parciais
ASR em streaming precisa decidir:
- quando emitir transcrições parciais (“resultados intermediários”)
- quando um enunciado terminou (“detecção de fim de fala (endpointing)”)
O RNN‑T fornece probabilidades de emissão de tokens, mas a detecção de fim de fala frequentemente também usa:
- heurísticas de comprimento de sequência de símbolos em branco (blank run-length heuristics)
- um modelo separado de detecção de fim (endpointer model)
- sinais de detecção de atividade de voz (voice activity detection, VAD)
Quantização e aceleração (no dispositivo)
Para mobile/embarcados:
- quantização de pesos (quantization) (por exemplo, int8)
- fusão de operadores (operator fusion)
- cache de computações de predição/conjunta por hipótese
- larguras de feixe pequenas com ajuste cuidadoso
Esses passos de engenharia frequentemente importam tanto quanto a arquitetura do modelo para desempenho em tempo real.
Armadilhas comuns e comportamentos do modelo
- Trade-off entre deleção e inserção: ajustar o tamanho do feixe, o viés de símbolo em branco ou a fusão com modelo de linguagem pode deslocar o comportamento entre palavras ausentes (deleções) e palavras alucinadas (inserções).
- Exposição a texto de domínio: como a rede de predição do RNN‑T é treinada com áudio-texto pareado, ela pode ter desempenho inferior em frases raras de um domínio específico, a menos que seja adaptada ou fundida com um modelo de linguagem externo.
- Áudio de longa duração: streaming ajuda, mas contextos longos ainda podem ser desafiadores; alguns sistemas usam segmentação, reavaliação (rescoring) ou viés contextual (contextual biasing).
Onde o RNN‑T é usado
Aplicações típicas incluem:
- Assistentes de voz: reconhecimento rápido após palavra de ativação (wake-word)
- Ditado móvel: entrada de texto com baixa latência
- Legendas ao vivo: transcrição em streaming para reuniões/mídia
- Transcrição em call centers: assistência ao agente em tempo real
- Wearables e dispositivos embarcados: orçamentos de computação apertados, restrições de privacidade
O RNN‑T é especialmente atraente quando você precisa de saída em tempo real e não pode arcar com idas e voltas ao servidor, tornando-o uma arquitetura-chave para ASR no dispositivo.
Resumo
O RNN‑T é uma arquitetura fundamental para ASR em streaming porque:
- Modela fala-para-texto com alinhamentos latentes usando um símbolo em branco
- Combina um codificador (acústica), rede de predição (histórico de tokens) e rede conjunta (fusão) para prever o próximo símbolo
- Treina ponta a ponta via programação dinâmica de avanço-retrocesso em uma treliça 2D
- Suporta decodificação em streaming eficiente com decodificação gulosa ou busca em feixe
- Se ajusta melhor a restrições de baixa latência e no dispositivo do que muitas abordagens sequência a sequência não em streaming
Para conceitos adjacentes, veja Classificação Temporal Conexionista (CTC), Busca em Feixe, Redes Neurais Recorrentes e Arquitetura Transformer.