SnailText
PT

Análise técnica aprofundada

Como o whisper.cpp funciona por dentro

GGML, quantização e três backends GPU - o que torna o modelo de pesquisa da OpenAI rápido o suficiente para rodar no laptop à sua frente.

Pelo fundador da SnailText · Publicado

Versão curta

O whisper.cpp porta o Whisper da OpenAI de Python e PyTorch para um único binário C++ usando a biblioteca de tensores GGML. O GGML armazena pesos em formatos quantizados customizados (INT8, INT4) que reduzem o tamanho do modelo em 4-8x e permitem que CPUs executem inferência em velocidade real. Aceleração GPU via Metal na Apple, Vulkan cross-vendor no Windows e Linux, ou CUDA na NVIDIA reduz a latência de segundos para menos de 200ms em frases curtas.

Números reais de desempenho em produção

Números reais de desempenho em produção (verified 2026-05-25)
Modelo Hardware Backend Clipe de 10s Clipe de 30s
Whisper Tiny M2 Air (8 GB) Metal 0.18s 0.42s
Whisper Base M2 Air (8 GB) Metal 0.25s 0.58s
Whisper Small M2 Air (8 GB) Metal 0.45s 1.1s
Whisper Medium M2 Pro (16 GB) Metal 0.85s 2.0s
Whisper Tiny Intel i5-1240P CPU only 0.95s 2.8s
Whisper Base Intel i5-1240P CPU only 1.6s 4.8s
Whisper Small RTX 3060 Mobile Vulkan 0.30s 0.75s
Whisper Medium RTX 3060 Mobile Vulkan 0.55s 1.4s
Whisper Large-v3 RTX 4070 Vulkan 0.60s 1.6s
Whisper Large-v3 RTX 4070 CUDA 0.45s 1.2s

O que o whisper.cpp realmente é (e o que não é)

Quando a OpenAI lançou o Whisper em setembro de 2022, a implementação de referência era um pacote Python construído sobre PyTorch. Funcionava, mas carregava a árvore completa de dependências do PyTorch com cerca de 2 GB, precisava de CUDA para qualquer velocidade razoável e era difícil de distribuir dentro de um app desktop.

Georgi Gerganov, um engenheiro de software búlgaro com background em simulações físicas, lançou o whisper.cpp em outubro de 2022. O projeto reescreve o loop de inferência do Whisper em C++ usando uma biblioteca de tensores customizada chamada GGML. O resultado é um binário autocontido que não linka Python, PyTorch ou runtime CUDA por padrão. Roda em um Raspberry Pi 4, um iPhone, um MacBook Air de 2015 ou um Threadripper configurado ao máximo, e produz as mesmas transcrições que a referência Python da OpenAI dentro da margem de erro de arredondamento.

whisper.cpp não é um modelo diferente. A arquitetura da rede neural é idêntica: um encoder Transformer de 12 ou 24 camadas seguido de um decoder Transformer de 12 ou 24 camadas, dependendo do tamanho. O que mudou é o formato dos pesos, o runtime que executa as multiplicações de matrizes e a ausência de Python no caminho de deployment.

O efeito prático é que qualquer aplicação que queira rodar Whisper sem acesso à internet pode linkar estaticamente o whisper.cpp e distribuir um executável autocontido. O SnailText faz isso. O MacWhisper faz isso. O SuperWhisper em modo local faz isso. Três anos após o início do projeto, o whisper.cpp é rápido o suficiente para ditado em tempo real em um celular.

GGML - a biblioteca de tensores que faz a matemática de verdade

GGML é uma pequena biblioteca C (cerca de 30.000 linhas em meados de 2026) que lida com quatro coisas: um formato de arquivo para pesos de redes neurais serializados, uma representação de grafo para a sequência de operações que uma rede executa, um backend de execução CPU com kernels SIMD otimizados manualmente, e um conjunto de backends GPU (Metal, CUDA, Vulkan, ROCm, SYCL) que delegam as multiplicações de matrizes para aceleradores de hardware quando um está disponível.

O formato de arquivo - agora chamado GGUF desde agosto de 2023, substituindo o formato GGML mais antigo - é um único arquivo binário que contém os metadados da arquitetura do modelo, vocabulário e tensores de pesos quantizados em um layout projetado para acesso mapeado em memória. Quando o whisper.cpp carrega um modelo, ele não aloca gigabytes de RAM e copia os pesos. Ele chama mmap (ou o equivalente no Windows) e deixa o sistema operacional paginar os pesos na memória conforme o kernel os acessa de fato. Em um sistema com bastante RAM, o arquivo acaba sendo completamente cacheado. Em um sistema com pouca memória, o SO faz paging das camadas frias e mantém as quentes residentes. De qualquer forma, o GGML não precisa gerenciar isso sozinho.

O modelo de execução é um grafo acíclico dirigido. Antes da primeira inferência, o GGML constrói um nó de grafo para cada operação de tensor que o Whisper executa: a self-attention multi-cabeça, os MLPs feed-forward, a cross-attention entre encoder e decoder, o softmax final. O grafo é compilado uma vez. Em cada inferência, o GGML percorre o grafo, despachando cada nó para o backend que foi selecionado. O despacho acontece na granularidade de uma operação de tensor, não do grafo inteiro, o que significa que um backend GPU que não suporte alguma operação exótica pode recorrer à CPU apenas para aquela operação sem perder o restante da aceleração GPU.

GGML inference pipeline Audio enters as a 16-bit PCM buffer. GGML loads the GGUF model via mmap and builds a compute graph once. Each tensor operation is then dispatched at runtime to the active backend: CPU SIMD on any machine, Metal on Apple Silicon, CUDA on NVIDIA-only, or Vulkan cross-vendor. The result is plain text from the decoder, returned to the host application. Audio buffer 16 kHz · f32 · RAM Compute graph compiled once Backend dispatch per-op selection CPU SIMD AVX2 / NEON / SSE Metal Apple Silicon Vulkan NVIDIA · AMD · Intel CUDA NVIDIA only Text decoder
GGML compiles the inference graph once at load time. Each tensor operation is then dispatched per-op to the active backend, so a GPU backend that lacks one exotic op can fall back to CPU for that single op without losing the rest of the acceleration.

Quantização INT8 e INT4 - como um modelo de 1,5 GB vira 600 MB sem desmoronar

O modelo Whisper Large, em sua forma FP16 PyTorch original, tem cerca de 3 GB em disco. Whisper Small tem cerca de 480 MB. Whisper Tiny tem cerca de 75 MB. Esses são os números FP16 do lançamento da OpenAI.

O GGML armazena esses modelos em formatos quantizados. O padrão para uso em produção é Q5_1, o que significa que cada peso é codificado com cerca de 5,5 bits em média em vez de 16. O resultado é uma redução de cerca de 3-4x no tamanho em disco e uma redução similar no uso de RAM. Whisper Large em Q5_1 cabe em 1,2 GB. Whisper Small cabe em cerca de 250 MB. Isso é o que torna realista distribuir o Whisper como parte do instalador de um app desktop.

O truque está em como os bits são alocados. Quantização ingênua - simplesmente truncar cada peso FP16 para seu valor INT8 mais próximo - destrói a precisão. A arquitetura transformer é sensível à magnitude dos pesos, e a quantização uniforme produz erro suficiente por camada que, multiplicado por 24 camadas, o modelo simplesmente produz nonsense.

O GGML usa quantização em blocos com fatores de escala por bloco. Os pesos são divididos em pequenos blocos (tipicamente 32 pesos por bloco), o valor absoluto máximo de cada bloco é calculado, e os pesos são escalados para caber no orçamento de bits disponível. Um pequeno fator de escala em ponto flutuante é armazenado junto a cada bloco. Na dequantização, os valores inteiros são multiplicados de volta pela escala para recuperar uma aproximação do FP16 original. Para alguns formatos de quantização, um segundo valor de offset por bloco também é armazenado para lidar com pesos de distribuições assimétricas.

O formato Q5_1 usado pela maioria dos deployments whisper.cpp em produção armazena inteiros de 5 bits por peso, um zero-point de 4 bits por bloco e uma escala FP16 por bloco. Os bits efetivos por peso incluindo todo o overhead são cerca de 5,5. Para comparação, Q4_0 tem cerca de 4,5 bits por peso e Q8_0 tem cerca de 8,5 bits por peso.

O custo em precisão é mensurável mas pequeno. No conjunto de teste LibriSpeech clean, Whisper Small em FP16 registra cerca de 3,4% de word error rate (conforme o paper original do Whisper, Tabela 2). O mesmo modelo em Q5_1 registra cerca de 3,5-3,7% dependendo do build. Em Q4_0 a diferença aumenta para cerca de 0,3-0,5 pontos percentuais. Abaixo de Q4 a diferença começa a importar, e abaixo de Q3 você tem degradação perceptível em fala com sotaque.

Deployments em produção (incluindo o SnailText) quase sempre distribuem Q5_1 por padrão. É o formato com melhor equilíbrio entre tamanho e precisão para variantes Whisper de compacto a médio. Os arquivos completos do modelo Q5_1 para Whisper Tiny a Large-v3 estão disponíveis no Hugging Face em ggerganov/whisper.cpp.

Os três backends GPU, e por que todos existem

Inferência em CPU funciona em qualquer máquina mas é o caminho mais lento. Uma CPU moderna de laptop consegue rodar Whisper Small a cerca de 1,5-2x o tempo real, o que significa que uma gravação de 10 segundos transcreve em cerca de 5-7 segundos. Para ditado, onde o usuário espera ver o texto dentro de um segundo após terminar a frase, isso é lento demais.

Aceleração GPU é o caminho para latência sub-segundo, e o whisper.cpp suporta três backends GPU sérios.

Metal é a API GPU da Apple. Em qualquer Mac com Apple Silicon (M1 e posteriores), o chip série M tem uma arquitetura de memória unificada onde a GPU compartilha a mesma RAM que a CPU. Isso é incomum. Em sistemas x86 com GPUs discretas, você precisa copiar dados da RAM do sistema para a VRAM da GPU antes que ela possa tocá-los, e copiar os resultados de volta quando terminar. No Apple Silicon não há cópia. A GPU e a CPU leem as mesmas páginas de memória física. O efeito prático é que o whisper.cpp com backend Metal em um M2 ou M3 transcreve um clipe de 10 segundos em cerca de 0,4-0,8 segundos para Whisper Small. M4 é mais rápido ainda. O backend Metal foi contribuído por engenheiros da Apple e é o mais polido dos três.

CUDA é a API GPU da NVIDIA. É a plataforma original de computação GPU, datando de 2007, e continua sendo o backend mais rápido em throughput absoluto para modelos grandes em uma placa NVIDIA dedicada. Um RTX 4070 transcreve Whisper Large-v3 bem abaixo do tempo real. A desvantagem é que CUDA só roda em hardware NVIDIA (sem AMD, sem Intel, sem gráficos integrados) e requer que o usuário tenha o CUDA Toolkit instalado, que é um download de vários gigabytes e um ponto de fricção para usuários finais. O whisper.cpp suporta CUDA mas tipicamente não é o backend padrão em aplicações voltadas para consumidores.

Vulkan é a API GPU cross-vendor. Funciona em NVIDIA, AMD, Intel Arc, gráficos integrados AMD, gráficos integrados Intel e GPUs ARM Mali. O backend Vulkan no GGML e whisper.cpp foi lançado em 2024 e amadureceu rapidamente ao longo de 2025-2026. Em uma placa RTX discreta, Vulkan tem aproximadamente 70-90% da velocidade de CUDA para a mesma carga de trabalho. Em hardware AMD e Intel, onde CUDA não é uma opção, Vulkan é o único caminho significativo para aceleração. O backend Vulkan é o que o SnailText distribui no Windows porque nos permite produzir um único binário que acelera via GPU em qualquer laptop moderno sem pedir ao usuário que instale drivers.

Também existem ROCm (o equivalente CUDA da AMD) e SYCL (a stack de computação da Intel). Ambos funcionam no whisper.cpp mas têm bases de usuários consideravelmente menores.

Como os números de produção se traduzem em experiência do usuário

A tabela de benchmarks acima mostra os tempos end-to-end que medimos em configurações de hardware consumer comuns. Três observações merecem destaque.

Primeiro, Macs com chips série M atingem latência interativa (menos de um segundo para frases curtas de ditado) em todos os modelos exceto Large, mesmo sem uma GPU discreta, por causa da memória unificada. Segundo, o backend Vulkan em uma placa NVIDIA moderna está a 25-30% do CUDA, o que é próximo o suficiente para que a conveniência de não instalar CUDA ganhe em apps consumer. Terceiro, CPU-only em um laptop Intel recente é rápido o suficiente para uso ocasional mas não rápido o suficiente para parecer instantâneo.

Streaming - obtendo transcrições antes do usuário terminar de falar

Os números acima são latência end-to-end: pressionar a tecla de parar, esperar pelo resultado. Existe um segundo modo, streaming, onde o whisper.cpp transcreve o áudio em pedaços enquanto o usuário ainda está falando. O resultado aparece dentro de algumas centenas de milissegundos após o usuário parar, porque a maior parte do trabalho já está feita.

Streaming requer duas coisas. Um modelo VAD (voice activity detection) que identifica quando uma frase terminou (a maioria dos deployments em produção usa Silero VAD, um pequeno modelo ONNX que roda em milissegundos). E uma maneira de alimentar frases completas no Whisper conforme elas acontecem, sem reiniciar o modelo.

O whisper.cpp suporta ambos. O padrão padrão é: abrir o stream de áudio, rodar VAD continuamente, acumular amostras até o VAD reportar que o usuário pausou, então despachar aquele chunk para o Whisper enquanto continua gravando. Cada chunk transcreve independentemente. Quando o usuário pressiona a tecla de parar, apenas o chunk parcial do final precisa ser transcrito - os chunks anteriores já estão prontos.

O SnailText usa esse padrão onde o hardware se beneficia dele - para um ditado típico de 30 segundos em máquinas com GPU habilitada, o usuário vê o resultado em um ou dois segundos após parar, porque a maior parte da inferência aconteceu durante a própria gravação. Streaming não é gratuito, porém: adiciona overhead que compensa quando as passagens individuais de inferência são baratas, e compensa menos (ou nada) quando não são. Saber se habilitá-lo para uma dada configuração é o tipo de decisão que precisa de telemetria de produção em vez de uma regra empírica.

O problema de seleção de GPU que ninguém avisa você

Em um laptop com GPU Intel e NVIDIA, o whisper.cpp pode silenciosamente recorrer à CPU mesmo quando a GPU dedicada está disponível. O backend Vulkan é ótimo na teoria: um binário, qualquer GPU, simplesmente funciona. Na prática existe uma classe de problema que não está em nenhuma documentação, e que você só encontra ao distribuir em hardware consumer real.

Em um laptop com múltiplas GPUs - NVIDIA Optimus, AMD Switchable Graphics, integrada mais dedicada - o sistema operacional as enumera em uma ordem. As APIs gráficas as enumeram em ordens diferentes, às vezes discordando entre si e às vezes mudando dependendo do estado do driver. O backend Vulkan do whisper.cpp endereça um dispositivo escolhido por índice inteiro, e o inteiro que aponta para a placa discreta em uma API pode apontar para a GPU integrada em outra.

O sintoma é um fallback silencioso para CPU. Você acha que a GPU está sendo usada. O aplicativo reporta que a GPU está sendo usada. O monitor do sistema mostra zero atividade GPU. A inferência leva 20 segundos em vez de 2.

A classe de solução que se sustenta em face desse tipo de heterogeneidade é empírica em vez de preditiva: não tente adivinhar qual índice de dispositivo corresponde a uma GPU real, meça. Execute uma inferência de teste rápida e decida com base no desempenho observado se vai manter aquele dispositivo ou recorrer ao próximo. O diagrama abaixo esboça a forma do loop.

Probe-and-fallback GPU selection At startup the application mounts the Whisper model at the first device index, runs a short probe inference, and decides whether the measured latency is consistent with a real GPU. If yes, that device is kept. If not, the loop tears down and tries the next index, falling back to CPU if no device produces fast inference. Mount model · start Probe @ first device index short test inference latency consistent w/ GPU? YES Keep this GPU index NO Tear down · probe @ next index multi-GPU systems YES NO Continue · or fall back to CPU if no GPU passes
The shape of an empirical GPU selection loop. On single-GPU machines it confirms the obvious quickly. On laptops with NVIDIA Optimus or AMD Switchable Graphics, the loop routes to the discrete card even when system enumeration is misleading. The class of approach generalizes to any setting where the right device index cannot be predicted from metadata alone.

Em máquinas com GPU única isso apenas confirma o óbvio em uma fração de segundo na inicialização. Em laptops com múltiplas GPUs roteia a inferência para a placa discreta mesmo quando a enumeração do sistema é enganosa. Existem vários edge cases que te pegam nessa camada - entradas de enumeração duplicadas em algumas GPUs integradas, quirks de driver específicos de vendor, iGPUs de memória compartilhada que precisam de orçamentos de latência diferentes para evitar falsos negativos - e cada um deles precisa de tratamento próprio. A lição geral é que seleção de GPU em hardware Windows consumer é um problema que você só consegue resolver observando como seu build se comporta em máquinas reais e adicionando caminhos para os casos que a telemetria revela.

Nada disso está na documentação do whisper.cpp ou nas issues do repositório GGML. É o tipo de trabalho que transforma “suportamos Vulkan” em algo que um usuário não técnico não precisará pensar.

Categorias de falha que você só vê em produção

Probe-and-fallback foi um exemplo de uma categoria mais ampla — modos de falha apenas em produção que a documentação upstream não avisa você. Cada um deles precisou de telemetria de usuários reais para sequer percebermos; os listamos aqui como categorias em vez de receitas porque a solução certa em cada caso depende da sua stack específica, e o que funcionou para nós não é o único caminho válido.

1. Discordância de enumeração multi-GPU. Coberto acima. A forma: diferentes APIs gráficas na mesma máquina discordam sobre qual índice inteiro aponta para qual GPU física. A classe de solução: probing empírico em vez de seleção preditiva. A versão desse problema que você enfrenta depende de qual SO, qual estado de driver, e se a máquina tem gráficos híbridos — a classe de solução se generaliza.

2. Enumeração fantasma de GPU integrada. Em algumas configurações de GPU integrada, o Vulkan loader expõe múltiplas entradas que todas apontam para o mesmo adaptador físico subjacente. Executar inferência contra cada uma delas em sequência — que é o que o probe-and-fallback ingênuo faz — pode saturar a largura de banda de memória compartilhada de formas que não são apenas lentas mas ativamente desestabilizadoras. A classe de solução: identificar a identidade do adaptador físico antes de iterar sobre índices, para que um loop de probe nunca acidentalmente sobrecarregue o mesmo hardware múltiplas vezes.

3. Compilação cold-shader do Vulkan. A inicialização de GPU pela primeira vez em um estado de driver novo pode levar muito mais tempo do que os benchmarks de inferência em estado estável sugerem. Já vimos tempos de compilação cold-shader se estenderem de um segundo em hardware aquecido para dezenas de segundos em hardware frio. A classe de solução: tornar os timeouts adaptativos a se a GPU foi usada recentemente, não codificados para um único limiar.

4. Pressão de memória GPU sob streaming. Inferência em streaming significa múltiplas invocações do Whisper acontecendo em rápida sucessão em vez de um grande lote. Em GPUs com VRAM limitada ou compartilhada (gráficos integrados, chips NVIDIA móveis com TDR habilitado), invocações back-to-back podem disparar recuperação no nível do driver — o SO reseta a GPU achando que o app travou. A classe de solução: detectar restrições de VRAM antecipadamente e ou desabilitar streaming ou reduzir a taxa de invocação em dispositivos que não estão preparados para isso.

5. Fallback silencioso para CPU. Em todos os quatro acima, o pior modo de falha é que o whisper.cpp não loga nada errado, o app reporta a GPU como ativa, o monitor do sistema concorda, e a inferência leva dez ou vinte vezes mais do que deveria. A classe de solução é a mesma: não confie em metadados sobre se você está na GPU — meça a latência em uma carga de trabalho real e decida com base na medição.

O fio condutor é que aceleração GPU em hardware consumer é um problema que você só consegue resolver completamente ao fazer deploy para usuários reais e observar a telemetria. Nenhuma dessas categorias aparece em um ambiente de desenvolvimento local com uma stack gráfica bem conhecida. Todas elas apareceram no momento em que tivemos alguns milhares de instalações com diferentes vendors, gerações e versões de driver.

O que isso significa para quem está construindo sobre whisper.cpp hoje

Se você está avaliando whisper.cpp para um produto, a capacidade central é sólida. A precisão do modelo é boa, os formatos de quantização são bem compreendidos, e o projeto é ativamente mantido por Gerganov e uma comunidade open-source de cerca de 600 contribuidores em 2026.

A complexidade está na cauda longa. Fazer a aceleração GPU funcionar de forma confiável em toda a diversidade do hardware consumer é seu próprio projeto de engenharia. O comportamento correto de streaming depende do hardware à sua frente. Engenharia de prompt (o parâmetro initial_prompt) afeta materialmente a precisão em vocabulário específico de domínio, e tem suas próprias sutilezas dependendo de como você o usa. O comportamento em gravações longas tem edge cases que os padrões não tratam graciosamente. As configurações padrão são boas mas não são ótimas para todos os casos de uso.

Para um app de ditado desktop, tudo isso é solucionável, e o whisper.cpp continua sendo a melhor base sobre a qual resolver isso. Para um pipeline de transcrição server-side em escala, você pode olhar para faster-whisper (Python, backend CTranslate2) ou uma das APIs cloud - o perfil operacional é diferente. Para casos de uso embarcados (Raspberry Pi, mobile, dispositivos de borda), o whisper.cpp está em uma categoria própria.

A razão pela qual o projeto existe, e a razão pela qual o SnailText, MacWhisper, SuperWhisper e muitos outros constroem sobre ele, é que ele torna o Whisper genuinamente portátil. O mesmo código C++ roda em todos os SOs desktop, todos os SOs mobile modernos e uma ampla gama de alvos embarcados. O modelo em si é apenas um arquivo. O runtime é uma biblioteca estática. Sem Python, sem CUDA, sem serviço para chamar. Isso, em 2026, ainda é uma combinação rara.

Se você prefere usar o resultado em vez de construí-lo, é exatamente isso que entregamos: o SnailText roda o whisper.cpp localmente no Mac e no Windows, escolhe um modelo que cabe no seu hardware e fica offline. Baixe aqui — grátis para começar, sem conta.

SnailText é ditado por voz offline para Mac e Windows: local, privado, grátis para começar.

Baixar para Mac

Perguntas comuns

Qual é a diferença entre Whisper e whisper.cpp?

Whisper é o modelo de reconhecimento de fala open-source da OpenAI. whisper.cpp é um port C++ independente do código de inferência que executa o mesmo modelo sem Python, PyTorch ou CUDA. Mesmos pesos do modelo, mesmos resultados, runtime diferente.

O whisper.cpp é mais lento que a versão Python?

Não, geralmente é mais rápido. O runtime C++ tem menos overhead, e os modelos quantizados usam menos largura de banda de memória. No mesmo hardware, o whisper.cpp geralmente supera a referência Python na CPU e se iguala na GPU.

O que significa GGML?

GGML originalmente significava Georgi Gerganov's Machine Learning library. Desde então foi formalizado apenas como nome do projeto e é a biblioteca de tensores que está por baixo do llama.cpp, whisper.cpp e vários outros ports.

Qual é a diferença entre quantização Q4, Q5 e Q8?

O número é aproximadamente a quantidade de bits usados por peso. Q4 tem cerca de 4 bits por peso, Q5 tem cerca de 5 bits, Q8 tem cerca de 8 bits. Números menores significam arquivos menores e inferência mais rápida, mas maior perda de precisão. Q5_1 é a escolha típica em produção para deployments whisper.cpp.

Posso rodar whisper.cpp em um Raspberry Pi?

Sim. Whisper Tiny roda em tempo real no Pi 4. Whisper Base roda a aproximadamente 0.5x o tempo real. Whisper Small é lento demais para ser útil em hardware de nível Pi.

O whisper.cpp suporta GPU em placas AMD?

Sim, via Vulkan (cross-vendor) ou ROCm (específico da AMD). Vulkan é mais fácil de fazer deploy porque não requer instalação do ROCm. O SnailText usa Vulkan para suporte AMD no Windows.

O whisper.cpp é o mesmo que faster-whisper?

Não. faster-whisper é um port diferente que usa CTranslate2 como backend em vez de GGML. É baseado em Python e tipicamente usado no lado servidor. whisper.cpp é C++ e tipicamente usado em aplicações desktop e embarcadas.

Quer o whisper.cpp em um app desktop polido?

SnailText é whisper.cpp com VAD, hotkey, auto-detecção de GPU e uma UI. O plano gratuito tem ditado local ilimitado, sem necessidade de conta.