Skip to content
anecho.ai

Null Test v0.1: dez aprimoradores de fala, dezoito condições, e nada venceu o bruto na média agrupada

O harness, o dataset, as configs e agora os resultados. Dez engines de aprimoramento de fala (speech enhancement) pontuadas contra um controle bruto em taxa de erro de palavras (WER), decomposição de erros, detecção de atividade de voz (VAD) e custo. O bruto venceu na WER agrupada — mas pelo menos uma engine venceu o bruto em 11 das 18 condições individuais, e as inserções subiram, em vez de descer.

Anecho Engineering13 de ago. de 202616 min de leitura
nulltestbenchmarkmethodologyopen-sourcerelease

Atualização de 20 de outubro de 2026: um experimento separado agora compara o nosso v8_2 com o ai-coustics Quail VF 2.2 S em conversas ao vivo construídas: empate com o faster-whisper base.en, vantagem do v8_2 com a transcrição de entrada do Gemini Live, e a condição decidindo quem lidera. Veja conversas ao vivo. Nada neste post muda.

Atualizado em 14 de agosto de 2026: a matriz foi regenerada com cinco condições adicionais de operadora de telefonia, passando de treze para dezoito. Os números absolutos se moveram; a ordenação, não. Cada figura abaixo é citada do benchmark.json publicado.

Hoje publicamos o Null Test v0.1 — o harness, o manifesto do dataset, as configs, as regras e o primeiro conjunto completo de resultados. Ele mede o que acontece com a acurácia de speech-to-text quando você coloca uma engine de aprimoramento de fala na frente de um reconhecedor, em dezoito condições acústicas, contra um controle de hipótese nula que está autorizado a vencer.

Nos números agrupados, ele venceu — e a decomposição por condição logo abaixo disso é onde mora a engenharia de verdade.

Um null test é a medição canônica da engenharia de áudio: subtraia o sinal processado da referência e o que sobra é exatamente o que o processador fez — incluindo o dano. Essa é toda a ambição deste projeto, então esse é o nome.

Por que isto existe

As afirmações públicas são irreconciliáveis. A Krisp divulga uma redução de WER de aproximadamente 46%. A ai-coustics divulga aproximadamente 43%. Um estudo independente (arXiv:2512.17562) constatou que o áudio aprimorado pontuou pior que o bruto em todas as 40 configurações que testou — embora apenas com o MetricGAN+, em fala médica, em WER semântica. A AssemblyAI, citando-o, reportou separadamente que a saída da Krisp aproximadamente dobrou a WER quando alimentada ao STT dela, enquanto cortava os falsos disparos de VAD em cerca de 3.5x. A Deepgram publicou a posição de que o aprimoramento prejudica a acurácia, e não encontramos dados que a acompanhem. Ninguém compartilha um corpus, um conjunto de condições, uma configuração ou um controle. A versão longa desse desacordo está em A supressão de ruído realmente ajuda o speech-to-text?.

O que foi rodado

Reconhecedorfaster-whisper base.en, CTranslate2 int8 CPU, decodificação greedy
VADSilero VAD, limiar 0.5, blocos de 512 amostras
Conjunto de teste10 locutores, 180 clipes, aproximadamente 1406 segundos de áudio, seed 20260101
Palavras de referênciacerca de 190 por condição, 3420 no total por backend
Condições18
Backends12 (bruto, controle passthrough e dez aprimoradores)
HostApple M1 Max, onnxruntime 1.28.0, fixado em 1 thread intra-op

As dezoito condições: clean; ruído de banda larga a -5, 0, 5, 10 e 20 dB SNR; babble_snr5; locutor concorrente a 0 e 5 dB; reverb e reverb_snr10; e sete condições de telefonia — telephony (uma ida e volta G.711 µ-law), telephony_snr10, mais A-law, G.722, Opus a 12 kbps e perda de pacotes em rajadas a 3% e 10%.

Os dez aprimoradores: GTCRN (MIT), cinco variantes do FastEnhancer, T/S/B/M/L (MIT), DeepFilterNet3 em duas configurações (MIT ou Apache-2.0) e dois modelos da ai-coustics, Quail L e Quail VF 2.2 L, rodados através do SDK licenciado como baseline proprietária de referência.

Os nossos próprios modelos não estão nesta matriz. Chamber e Clearline serão linhas nela, sob as mesmas regras, contra o mesmo controle que acabou de vencer todo mundo. Publicar o árbitro antes do competidor era o objetivo dessa ordem.

Os resultados

Agrupado em todas as dezoito condições:

BackendWERInserçõesDeleçõesRTFLatência
Bruto (sem processamento)14.77%10160—0 ms
ai-coustics Quail L15.56%126570.12430 ms
ai-coustics Quail VF 2.2 L18.10%161750.07630 ms
GTCRN (MIT)20.26%210400.05016 ms
FastEnhancer-L (MIT)20.44%1591070.37625.8 ms
FastEnhancer-M (MIT)22.40%217830.11022 ms
FastEnhancer-T (MIT)22.46%1451090.01316 ms
DeepFilterNet335.18%3801970.133100 ms

Nenhum aprimorador venceu o bruto na WER agrupada. O melhor foi o ai-coustics Quail L, a 15.56% contra os 14.77% do bruto — cerca de oito décimos de ponto pior, o que, neste tamanho de amostra, chamaríamos de empate em vez de derrota. Tudo abaixo dele perdeu por cinco pontos ou mais, e isso não é empate.

O agrupado responde "o aprimoramento deve estar ligado por padrão" e quase nada mais; as seções por condição abaixo são as que merecem ação, e elas dizem algo diferente.

As inserções subiram, não desceram. O bruto produziu 101. O GTCRN produziu 210. O DeepFilterNet3 produziu 380. Isso é o oposto direto da alegação dos fornecedores de que o aprimoramento remove palavras alucinadas, e vale a pena se demorar nisso: uma inserção não é uma palavra distorcida, é o reconhecedor emitindo uma palavra que ninguém disse. A nossa leitura é que o que um supressor deixa para trás — ruído musical, silêncio com gate, transientes borrados — é mais decodificável-como-fala do que o ruído que ele removeu.

A decomposição do GTCRN faz o ponto: 210 inserções contra apenas 40 deleções, onde o bruto tinha 101 e 60. Ele não está comendo as suas palavras funcionais, está adicionando palavras que ninguém falou. Modos de falha opostos, e um único número de WER esconde qual deles você comprou. É por isso que cada célula publica S, D e I separadamente.

Onde a alegação dos fornecedores se sustenta

Parar no número agrupado seria fazer exatamente o que criticamos nos fornecedores. O aprimoramento ganha margens reais em condições específicas — em 11 das nossas 18, pelo menos uma engine venceu o bruto — e são as condições que você preveria: aquelas em que ruído ou uma voz concorrente está genuinamente destruindo pistas fonéticas.

A mais clara é o isolamento de locutor (speaker isolation). O ai-coustics Quail VF é um modelo Voice Focus: o trabalho dele é isolar o locutor primário e rejeitar as outras vozes. Em locutor concorrente a 5 dB, ele cortou as inserções de 19 para 10 e a WER de 26.3% para 20.5%. Em babble a 5 dB, 24.7% para 20.5%, com as inserções caindo de 10 para 7. Esses são os resultados mais fortes que qualquer aprimorador registrou aqui. Ruído de banda larga em SNR baixo mostra o mesmo formato — a 0 dB, oito das dez engines vencem o bruto, a melhor por 4.7 pontos.

As sete condições em que nada venceu o bruto são igualmente informativas: as duas reverberantes e as cinco condições de operadora de telefonia. Em quatro dessas cinco, o melhor que uma engine consegue é um empate exato com não fazer nada, o que é um tipo próprio de resposta.

O que nada disso sustenta é a alegação geral. Agrupado, o Quail VF está mais de três pontos pior que o bruto, porque ele também roda sobre material limpo, reverberante e de banda estreita, onde só pode remover informação. O aprimoramento paga onde o áudio é genuinamente ruim e te custa onde não é, e um único escalar — o nosso incluído — esconde de que lado dessa linha o seu tráfego está.

VAD: a métrica que todo mundo cita mal se move, a que importa se move muito

A mesma rodada pontuou o Silero VAD em todos os streams. F1 de VAD agrupado: 0.950 do bruto contra 0.947 do melhor stream aprimorado. Avalie o aprimoramento pelo F1 de VAD e você conclui que ele não faz nada.

A taxa de falsos alarmes é outra história, e um falso alarme é o que um barge-in espúrio realmente é:

CondiçãoTaxa de falsos alarmes, brutoAprimoradoEngine
Babble a 5 dB97.7%68.2%FastEnhancer-L
Locutor concorrente a 5 dB58.1%37.2%ai-coustics Quail VF

Sob babble a 5 dB, o stream bruto dispara um falso alarme em essencialmente todo frame sem fala — um VAD que deixou de funcionar como gate. O aprimoramento leva isso a 68.2%: ainda ruim, e trinta pontos melhor.

Então a mesma rodada diz que o aprimoramento te custa cinco pontos de WER agrupada e te compra um terço a menos de taxa de falsos alarmes. Isso não é uma contradição, é uma arquitetura: áudio aprimorado para o detector de turnos, áudio bruto para o reconhecedor. Entregamos isso como o default do SDK, e o raciocínio está em O pipeline dividido.

Telefonia: nenhum aprimorador ajudou, e vários prejudicaram muito

Na ida e volta G.711 µ-law, o bruto está em 5.8% de WER. Contra isso: ai-coustics Quail L +1.6 ponto, Quail VF +2.6, GTCRN +3.2, FastEnhancer-T +6.8, DeepFilterNet3 +9.5. Na mesma ida e volta com ruído a 10 dB, o bruto está em 10.5% e a dispersão vai de +0.5 a +9.5.

Nenhum aprimorador produziu melhora significativa em áudio de telefonia, e vários causaram degradações grandes. Duas linhas saem fracionalmente abaixo do bruto e nenhuma delas é um resultado: o FastEnhancer-S está -0.5 na linha limpa — com 190 palavras de referência, a menos de uma única palavra de não fazer nada — e +3.7 na linha com ruído; o Quail VF está -1.1 na linha com ruído e +2.6 na limpa. Empates, nas duas direções.

As cinco condições de operadora adicionadas nesta atualização dizem a mesma coisa de forma mais crua. Em A-law, G.722, Opus a 12 kbps e perda em rajadas de 3%, o melhor que qualquer engine consegue é um empate exato com o bruto; em perda de 10%, nada o alcança. As piores células são severas — o FastEnhancer-M registra 49.0% em A-law contra os 7.4% do bruto, com 61 inserções onde o bruto tem 2. Ruído de quantização de companding está fora do que esse modelo espera, e ele responde alucinando.

Isso importa porque telefonia é onde está o volume de chamadas, e o formato disso não é acidente: o DNS Challenge, a série de benchmarks contra a qual a maioria dos removedores de ruído publicados é ajustada, nunca teve uma trilha de banda estreita. A área otimizou para 16 e 48 kHz porque era isso que era pontuado.

E importa com um asterisco grande. Uma WER bruta de 5.8% na condição base de telefonia significa que ela é uma condição fácil, e não a coisa que quebra implantações telefônicas em produção — veja as ressalvas. A história completa da banda estreita, incluindo um experimento separado de 8 kHz de ponta a ponta com engines nativas de banda estreita e um controle de ida e volta de reamostragem, está em 8 kHz é onde a IA de voz realmente quebra. A versão curta: 8 kHz nativo vence o reamostrar-e-torcer por 0.7 ponto para o mesmo fornecedor, e absolutamente nada vence o áudio intocado de quem liga.

As ressalvas, por inteiro

Um resultado sem os seus limites é um anúncio. Estas acompanham cada número acima.

  • Um único reconhecedor. faster-whisper base.en. Um reconhecedor diferente dá números absolutos diferentes. O harness suporta Deepgram e AssemblyAI para que a ordenação possa ser rechecada, e gostaríamos que alguém que não confia em nós fizesse isso.
  • Cerca de 190 palavras de referência por condição, 3420 agrupadas. O suficiente para separar efeitos grandes, não o suficiente para resolver um ou dois pontos de WER: uma palavra vale aproximadamente 0.5 ponto por condição e 0.03 no agrupado. Leia a lacuna entre o bruto e o Quail L como um empate; as lacunas de cinco a vinte pontos abaixo dela, não.
  • O DeepFilterNet3 é medido através de um adaptador block-online. Nenhum export ONNX público carrega os tensores de estado recorrente, então streaming por frame é impossível com os pesos publicados. Os 35.18% dele são um limite inferior de qualidade e um limite superior de custo, e a latência de 100 ms dele está muito acima do que um runtime nativo em Rust atinge. Nunca cite o número sem esta frase. Ele também roda a 48 kHz sobre material de 16 kHz sobreamostrado para 48 kHz — a situação honesta de VoIP, não a condição para a qual foi projetado.
  • As linhas da ai-coustics são uma baseline proprietária rodada através do SDK licenciado. Um ponto de referência, nunca um caminho de código que nós colocamos em produção.
  • O licenciamento restringe o reuso. O ruído do ESC-50 é CC-BY-NC-3.0, então essas condições são apenas para avaliação. O LibriSpeech é CC-BY-4.0, e as condições de babble e de locutor concorrente são construídas apenas a partir do LibriSpeech, então não carregam restrição NC.
  • onnxruntime fixado em 1 thread intra-op, execução sequencial. A coluna de RTF é um stream em um núcleo, não um fan-out.
  • Apenas inglês, pontuação em lote, nenhum painel de escuta, nenhuma métrica em nível de turno. O aprimoramento é alimentado bloco a bloco com estado carregado entre blocos, mas o reconhecedor é pontuado em enunciados completos, e o VAD é por frame. "Menos barge-ins falsos" como métrica de produto precisa de limites de turno rotulados e de uma definição acordada.
  • As condições de telefonia estão mais realistas do que eram, e ainda não são uma chamada telefônica. Agora incluem pernas A-law e G.722, Opus a 12 kbps e perda de pacotes em rajadas de dois estados a 3% e 10% com ocultação por repetição atenuada — em vez de perda aleatória independente com preenchimento de silêncio, que, respectivamente, lisonjeia os decodificadores e exagera o dano. Ainda faltam: eco acústico com distorção não linear de alto-falante, supressão do lado do aparelho e pernas AMR-WB ou EVS. Eco é a lacuna com que mais nos importamos, porque é a deficiência por trás da parte do nosso próprio roadmap que não se fecha com um patch.
  • Estas dezoito condições são armazenadas a 16 kHz depois de uma perna de operadora a 8 kHz, então cada backend as vê na sua própria taxa nativa. O experimento genuinamente de banda estreita — 60 clipes, 8 kHz do início ao fim, nada reamostrado, engines nativas de 8 kHz incluídas — é um artefato separado, com o seu próprio limite de resolução de 1,140 palavras de referência, onde uma palavra vale 0.09 ponto.

Metodologia, em detalhe suficiente para ser atacada

O streaming é simulado honestamente. Cada aprimorador é alimentado bloco a bloco no seu tamanho de bloco declarado, carregando estado entre blocos, sem lookahead além da sua latência algorítmica declarada. Processamento offline do arquivo inteiro lisonjeia um aprimorador e não é o que um agente ao vivo recebe. A latência é reportada como latência algorítmica — frame mais lookahead — uma propriedade do modelo, não do nosso laptop.

O RTF é medido, não citado. Um único núcleo fixado, passes de aquecimento descartados, string de hardware registrada em cada linha. Um modelo que vence em WER a 4x do tempo real não é uma opção de produção, então o número de acurácia e o número de custo viajam juntos.

O ruído é misturado, não obtido pré-misturado. Fala limpa mais ruído a um SNR alvo calculado apenas sobre as regiões de fala ativa, para que o silêncio inicial e final não distorça a razão. A reverberação é convolução com respostas ao impulso de sala medidas. Telefonia é uma ida e volta real de codec — reamostrar para 8 kHz, codificar e decodificar G.711 µ-law, reamostrar de volta — em vez de um filtro passa-baixas fazendo as vezes de canal. Uma perna de codec real, e ainda assim não uma chamada telefônica real; a ressalva acima lista o que fica de fora.

A normalização de texto é fixa e publicada. A WER é (S + D + I) / N depois de um normalizador aplicado de forma idêntica a cada hipótese e referência: case folding, remoção de pontuação, expansão de números, tratamento de contrações. A normalização pode mover a WER em vários pontos, então ela é versionada no repositório e registrada em cada linha.

Determinismo, e saídas por enunciado. Seeds fixas para a seleção de ruído, o sorteio de SNR e a seleção de RIR; o manifesto do dataset é endereçado por conteúdo com SHA-256 por arquivo, verificado no download, então a mesma config no mesmo commit produz as mesmas linhas. Cada rodada também emite hipóteses e referências por enunciado junto com os agregados, para que qualquer pessoa possa recomputar, fatiar de outro jeito ou encontrar os dez arquivos que carregam um resultado. Benchmarks que publicam apenas agregados não podem ser checados, e é em boa parte assim que a área chegou aqui.

As regras que fazem dele um árbitro

  1. O controle bruto está sempre na matriz e está autorizado a vencer. No v0.1, ele venceu.
  2. Nós nos pontuamos sob as mesmas regras, nas mesmas tabelas. Chamber e Clearline serão linhas, não uma página de marketing separada.
  3. Toda célula é publicada, incluindo as que perdemos. Nenhuma condição é descartada depois que vemos o resultado.
  4. As configs estão no repositório. Se um fornecedor acredita que configuramos mal a engine dele, a correção é um pull request contra um arquivo YAML, e nós rodamos de novo e republicamos.
  5. Direito de resposta. Qualquer mantenedor ou fornecedor pode pedir uma nova rodada com uma configuração diferente. Publicamos as duas.
  6. O licenciamento é declarado por linha. Onde os termos de um fornecedor proíbem publicar resultados de benchmark, dizemos que a célula está bloqueada e nomeamos a razão, em vez de omiti-la em silêncio.

O formato de saída

O documento completo está em /benchmark. O resumo de um backend:

{
  "id": "gtcrn",
  "label": "GTCRN",
  "license": "MIT",
  "wer": 0.2026,
  "werSubstitutions": 443,
  "werInsertions": 210,
  "werDeletions": 40,
  "werRefWords": 3420,
  "vadF1": 0.9472,
  "vadFalseAlarm": 0.1638,
  "rtf": 0.0498,
  "latencyMs": 16.0
}

Cada backend também carrega um objeto conditions com a mesma decomposição por condição — onde vivem os desacordos interessantes.

Rodando você mesmo

git clone https://github.com/anecho/nulltest
cd nulltest
uv sync

# fetch and verify the dataset against the content-addressed manifest
python -m nulltest.data fetch --manifest data/manifest.json

# one condition, two backends, one recogniser — a few minutes on a laptop
python -m nulltest.run \
  --condition babble_snr5 \
  --backend gtcrn --backend raw \
  --stt faster-whisper:base.en \
  --out out/

python -m nulltest.report out/ --format md

Adicionar uma engine é um arquivo. O benchmark só conversa com esta interface:

class Enhancer(Protocol):
    id: str
    sample_rate: int
    block_size: int              # samples per process() call
    algorithmic_latency_ms: float

    def reset(self) -> None: ...

    def process(self, block: np.ndarray) -> np.ndarray:
        """block: float32 mono, shape (block_size,), range -1 to 1. Returns same shape."""

Se a sua engine implementa reset e process, ela pode estar na matriz. Gostaríamos particularmente que os fornecedores cujas alegações publicadas citamos submetessem os seus próprios adaptadores e configurações.

O que vem depois, e a parte comercial

O v0.2 adiciona métricas de endpointing em nível de turno via Onset, STT de streaming com latência até a transcrição final, um segundo e um terceiro reconhecedor para que a ordenação possa ser checada em vez de confiada, condições multilíngues e uma condição de eco com distorção não linear de alto-falante. Chamber e Clearline entram na matriz quando tiverem algo que valha a pontuação.

Sobre esse último ponto, com franqueza: uma linha aqui não é um press release, e não vamos publicar uma antes que valha a leitura. Experimentos de arquitetura e de corpus estão rodando contra as mesmas condições held-out que produziram as tabelas acima, e o Clearline entra na matriz quando merecer a linha — medido em condições de telefonia dignas do nome, contra um controle autorizado a vencê-lo.

A parte comercial, declarada uma vez e sem decoração: este benchmark não é o produto. Um benchmark não tem comprador nem retenção — ninguém renova um leaderboard. O que pretendemos vender é o Clearline, um caminho de áudio de telefonia: isolamento de locutor primário nativo em 8 kHz, supressão de eco residual, por minuto, com chave de API instantânea e sem reunião de vendas. Note exatamente o que o v0.1 nos licencia a dizer sobre isso. Ele diz que nada na prateleira ajuda em um canal de banda estreita, e que ninguém entrega isolamento de locutor a 8 kHz, ponto. Ele ainda não diz que o nosso é melhor — esse número pertence à tabela, não a um parágrafo, e vai para lá quando for medido. O Null Test é como descobrimos o que construir, e como você confere se estamos mentindo sobre isso.

Harness e issues: github.com/anecho. Matriz completa: /benchmark. Quickstart: /docs. Se você quer uma condição, uma engine ou um reconhecedor adicionados, abra uma issue — inclusive se espera que isso nos deixe mal.

A seguir
  • 24 de out. de 2026

    Alternativas à ai-coustics para agentes de voz e call centers (2026)

    Por que equipes olham além do ai-coustics Quail Voice Focus, e uma lista curta com fontes conforme listado em outubro de 2026: Krisp VIVA, AssemblyAI Voice Focus, isolamento de voz do LiveKit Cloud, NVIDIA Speaker Focus, Anecho e referências de código aberto. Comparamos a ai-coustics com o nosso próprio modelo em conversas ao vivo: empate com o faster-whisper, vantagem do v8_2 com o Gemini Live, menos barge-ins falsos para a ai-coustics, e a condição decide quem lidera.

  • 22 de out. de 2026

    Alternativas à Krisp para agentes de voz e call centers (2026)

    Por que equipes olham além do Krisp VIVA, e uma lista curta com fontes conforme listado em outubro de 2026: ai-coustics Quail Voice Focus, AssemblyAI Voice Focus, isolamento de voz do LiveKit Cloud, NVIDIA Speaker Focus, Anecho e referências de código aberto, com onde cada um roda, seu preço público e se o medimos. Não medimos a Krisp.

  • 20 de out. de 2026

    SDKs de isolamento de locutor comparados (2026): Krisp, ai-coustics, AssemblyAI, LiveKit e Anecho

    Uma comparação com fontes do isolamento de locutor para agentes de voz e call centers conforme listado em outubro de 2026: onde cada produto roda, latência declarada, taxas de amostragem, integração, preço público e licenciamento. Krisp VIVA e Anecho declaram 15 ms em CPU; a ai-coustics lista menos de 30 ms; AssemblyAI e LiveKit vendem isolamento dentro de um serviço em nuvem. Números de qualidade apenas do nosso próprio benchmark.