3 pontos por GN⁺ 3 시간 전 | 1 comentários | Compartilhar no WhatsApp
  • Ferramenta alternativa ao Tiktoken e ao HuggingFace Tokenizers, com suporte a vários CPUs e tokenizadores amplamente usados, processando texto em GB/s
  • Otimiza com SIMD a pré-tokenização normalmente feita por motores de regex, reduz ramificações, comunicação entre threads e interação com Python, além de fazer cache eficiente do mapeamento de tokens de palavras já vistas
  • No benchmark de 11,9GB do OpenWebText, a vazão do GPT-2 chegou a 24.53GB/s em um AMD EPYC 9565, 8.79GB/s em um Apple M4 Max e 6.27GB/s em um Ryzen 7 9800X3D
  • O modo de compatibilidade com HuggingFace e Tiktoken mantém quase todo o código existente intacto, mas perde desempenho pelo custo de reproduzir exatamente a mesma saída; a API do Gigatoken, em que o Rust lê os arquivos diretamente, oferece o maior paralelismo e a maior velocidade
  • Ainda não há suporte a WordPiece nem saída para arquivo, e faltam otimizações para SentencePiece e validação no Windows, então no momento ele é mais adequado para tokenizadores BPE em Linux, macOS ou WSL

Escopo de suporte e modo de uso

  • Gigatoken é um tokenizador de alta velocidade para modelos de linguagem, voltado a CPUs x86 e ARM modernas e a quase todos os tokenizadores comuns
  • A instalação é feita com pip install gigatoken, e ele oferece sua própria API e um modo de compatibilidade com HuggingFace Tokenizers e Tiktoken
  • O modo de compatibilidade encapsula tokenizadores existentes e os converte com .as_hf() ou .as_tiktoken(), respectivamente
    • Aplica bastante trabalho para que a saída corresponda exatamente à do HuggingFace Tokenizers
    • Esse processamento de compatibilidade tem um custo de desempenho nada desprezível, então não chega ao ganho de cerca de 1.000x da API própria, mas ainda assim é mais rápido que as implementações existentes no geral
  • A API própria recebe nomes de modelos do HuggingFace como "Qwen/Qwen3-8B" e TextFileSource, codificando arquivos diretamente
    • A implementação em Rust lê os dados diretamente, evitando overhead desnecessário e maximizando o paralelismo
    • Ao passar estruturas de dados do Python, o custo de leitura dos dados no Python continua existindo

Implementação para aumentar a velocidade

  • O maior ganho vem da reimplementação altamente otimizada, com base em SIMD, da pré-tokenização que normalmente é deixada a cargo do motor de regex
  • O foco também foi minimizar ramificações e otimizar intensivamente o cache de mapeamento de pré-tokens, que busca os tokens codificados de palavras já vistas
    • O cache cresce rapidamente e a distribuição dos pré-tokens tem cauda longa, o que dificulta seu tratamento
  • Reduzir a interação com Python e a comunicação entre threads também trouxe ganho adicional de desempenho
  • Não é uma implementação ajustada para um único CPU ou tokenizador específico: houve otimização para combinações de vários tokenizadores com CPUs x86 e ARM modernas, e os resultados se mantêm consistentes entre CPUs e tokenizadores

Benchmark de 11,9GB do OpenWebText

  • Em um ambiente com AMD EPYC 9565 de 144 núcleos, a vazão do GPT-2 chegou a 24.53GB/s, sendo 989x mais rápida que os 24.8MB/s do HuggingFace Tokenizers e 681x mais rápida que os 36.0MB/s do Tiktoken
    • As principais variantes de BPE ficaram em geral entre cerca de 15.49~24.00GB/s
    • Itens baseados em SentencePiece foram relativamente mais lentos, com cerca de 2.51~4.82GB/s
  • No Apple M4 Max de 16 núcleos, o GPT-2 chegou a 8.79GB/s, sendo 1.268x mais rápido que o HuggingFace e 140x mais rápido que o Tiktoken
    • OLMo 2/3 registrou 1.299x em relação ao HuggingFace, e Qwen 2/2.5 registrou 1.105x
  • No AMD Ryzen 7 9800X3D de 16 núcleos, o GPT-2 chegou a 6.27GB/s, sendo 106x mais rápido que o HuggingFace e 68x mais rápido que o Tiktoken
    • As principais variantes de BPE ficaram em cerca de 4.21~6.09GB/s, enquanto variantes relativamente menos otimizadas ficaram em cerca de 1.12~2.84GB/s

Condições de medição e interpretação

  • O OWT (OpenWebText) foi escolhido como dado de benchmark por representar aproximadamente o texto obtido após extrair documentos do Common Crawl
  • O Gigatoken processa o arquivo inteiro sem dividi-lo previamente, então ele próprio executa a busca de limites de divisão e o paralelismo automático
  • Os comparativos processam dados previamente divididos com base em <|endoftext|>
    • O HuggingFace encode_batch_fast usa os primeiros 100MB
    • O Tiktoken encode_ordinary_batch usa o primeiro 1GB
    • Como nenhuma das duas implementações usa cache e a velocidade tende a permanecer estável ao longo do processamento, essas condições de comparação foram adotadas
  • Os resultados do Tiktoken incluem apenas tokenizadores oficialmente suportados
  • Cada linha representa um único tokenizador distinto com o mesmo vocabulário, merges e pré-tokenizador
    • Várias versões e modelos derivados das famílias Llama, Qwen, DeepSeek, GLM, Nemotron, Kimi, Phi e Gemma foram agrupados na mesma linha de tokenizador
  • O item mais lento é o tokenizador baseado em SentencePiece, que ainda não foi suficientemente otimizado no Gigatoken

Validação de suporte e processamento em larga escala

  • Sem instalar nada, é possível validar a tokenização de repositórios de modelos do HuggingFace e medir o tempo com o comando uvx --with tokenizers gigatoken bench
  • No exemplo de validação do GPT-2, a saída bateu em 20.401 documentos
    • No Apple M4 Max, processou 11,920.51MB em 1.432s, a 8,327.05MB/s, ficando 1,353.13x mais rápido que o HuggingFace
    • No AMD EPYC 9565, processou os mesmos dados em 0.486s, a 24,532.45MB/s, ficando 989.21x mais rápido
  • Nessa taxa do EPYC, seria possível tokenizar todo o Common Crawl, na escala de 130 trilhões de tokens, em menos de 6,5 horas
  • O exemplo usa o sample OWT do Stanford CS336, e por padrão a CLI usa os primeiros 100MB do arquivo para validação e comparação com o HuggingFace
  • Na primeira execução no macOS, o código Rust pode ficar mais lento por causa da verificação de segurança, então pode ser necessário rodar o comando duas vezes para uma medição precisa
  • Casos de divergência na saída ou lentidão devem ser reportados em GitHub Issue

Limitações conhecidas

  • O processamento iterativo em Python é executado em Rust, mas usa ABI3, que é mais lento que as APIs internas do CPython específicas por versão
    • Há planos para especialização por versão do Python, e experimentos iniciais mostraram 2x de ganho em casos dominados por overhead
  • A API do Gigatoken ainda não implementa um sink de saída para arquivo
  • WordPiece não é suportado
  • A tokenização baseada em SentencePiece tem um nível de otimização inferior ao BPE comum
    • A prioridade atual também é baixa, principalmente porque é mais usada por modelos do Google e da família BERT
  • Como os testes no Windows ainda não são suficientes, no momento o recomendado é usar WSL

Escopo do uso de IA

  • A maior parte do codebase foi escrita diretamente, sem IA, e isso pode ser verificado no histórico de commits do projeto
  • Na fase final do projeto, a IA foi usada nas seguintes tarefas
    • implementação da API para usuários
    • generalização, portabilidade e ampliação da compatibilidade do pré-tokenizador para mais tokenizadores
    • suporte a padding, truncamento e normalização Unicode
    • portabilidade das estratégias SIMD entre AVX512, AVX2 e NEON
    • ganho final de cerca de 4x de desempenho com remoção de ramificações e melhorias na hierarquia de cache de pré-tokens
    • refatoração e melhoria do reuso de código

1 comentários

 
GN⁺ 3 시간 전
Opiniões no Hacker News
  • Como “a maior parte do código foi escrita diretamente, sem IA, e isso pode ser verificado no histórico do Git”, a declaração de que a programação humana acabou perde força

  • Não se trata de otimizar excessivamente uma CPU específica e um único tokenizer, mas sim de obter desempenho consistente ao otimizar todo o conjunto de combinações entre x86·ARM modernos e vários tokenizers
    A pré-tokenização, normalmente deixada para mecanismos de expressões regulares, foi otimizada diretamente com SIMD e com o mínimo de ramificações; também melhoraram o cache de mapeamento de tokens do vocabulário para encontrar rapidamente o resultado da codificação de palavras já vistas. Nessa área, os caches crescem rápido e têm caudas longas na distribuição, o que os torna difíceis de lidar
    A interação com Python e a comunicação entre threads também foram minimizadas

  • Lembra o simdjson, que atinge velocidades difíceis de acreditar com programação criativa. Se for amplamente adotado, pode reduzir bastante energia, custos e emissões de carbono, então seria bom publicar também um crate em Rust; se necessário, eu mesmo gostaria de ajudar

    • Tokenização quase nunca foi um gargalo relevante, e a serialização de JSON em geral também não. Gasta-se muito mais energia com entrada/saída e armazenamento do que com serialização e tokenização
      Pensando em economia e meio ambiente, processamento em lote de requisições tem um efeito maior. O problema mais caro é a baixa utilização da GPU; ao adaptar o trabalho ao formato de processamento em lote, hoje já é possível economizar 50% até na OAI. Se nem todas as respostas precisam ser imediatas, algumas podem esperar alguns dias; chamadas de ferramentas não expiram, e para o próprio LLM não existe tempo de relógio de parede
  • Clonei o repositório e dei uma olhada: a substituição das expressões regulares de pré-tokenização e a otimização de cache são abordagens úteis de forma geral. É um trabalho excelente, a ponto de toda a comunidade de tokenização querer aprender o segredo desse ganho de velocidade

    • Em breve, o projeto terá uma explicação técnica e um artigo, além de um vídeo de apresentação, que também serão compartilhados no Discord
    • Isso é muito valioso não só para inferência, mas também para treinamento com datasets proprietários, e também impressiona o fato de uma única pessoa ter feito tudo isso
  • É uma conquista ótima, mas a tokenização normalmente representa menos de 0,1% do tempo total de inferência. Ainda assim, será muito útil para aplicações que precisam da tokenização em si

    • Dependendo da forma de inferência, a fatia da tokenização também pode ser significativa. Em medições iniciais rodando um Qwen3 8B em uma única B200, trocar para o gigatoken reduziu o tempo até o primeiro token (TTFT) em média 5,5% com entrada de 2.048 tokens, 8,4% com 8.192 e 7,8% com 32.768
      O efeito aumenta com modelos menores ou GPUs mais rápidas, e ainda é preciso validação adicional antes de incluir isso no README. A origem do benchmark é fastokens
    • Em plataformas de IA, é preciso tokenizar rapidamente no início da requisição para decidir depois coisas como roteamento e rate limiting. Mesmo que a proporção no tempo total da requisição seja pequena, a eficiência é importante
    • Como a tokenização é em grande parte serial, se o prompt inicial for grande ela pode representar uma fatia importante do tempo de processamento da entrada. Isso porque, depois de passar para a inferência do modelo, todos os tokens podem ser processados em paralelo
    • Mesmo 1/1.000 das operações de inferência fica difícil de ignorar quando a escala aumenta. Como a Gartner estimou os gastos com inferência em 2026 em cerca de US$ 28 bilhões, aplicando a suposição anterior isso dá US$ 28 milhões por ano
      Fonte: https://www.gartner.com/en/newsroom/press-releases/2026-07-2...
    • Especialmente em modelos pequenos, isso pode reduzir muito a latência até o primeiro token. Para provedores de inferência como Groq ou Cerebras, a latência é tão importante quanto a vazão total
  • Parece mais útil na preparação offline de dados de pré-treinamento do que no momento da inferência. Ao tokenizar vários terabytes de texto para o corpus de treinamento, pode economizar tempo e custo, além de encurtar o ciclo de iteração ao ajustar datasets

  • Dedicar capacidade de engenharia para tornar 1.000 vezes mais rápida uma parte que representa 0,1% do tempo total de execução é exatamente o tipo de comportamento mais típico de desenvolvedor de software

    • Fiz em Rust uma nuvem de palavras em alta resolução em cerca de 100 ms e, com otimizações adicionais, reduzi para cerca de 16 ms. O mundo não precisa de um gerador de nuvem de palavras tão rápido, mas, se é para fazer, que seja o mais rápido possível
    • “A busca pela excelência não precisa de justificativa”
      https://x.com/mitchellh/status/2074225453217505494
    • Depende do fluxo de trabalho. Também existem usos em que se faz apenas tokenização, sem enviar imediatamente o texto para o modelo
    • Mesmo em um subcomponente, uma melhoria de 1.000 vezes pode viabilizar recursos qualitativamente novos. Muitas vezes, o motivo de aquela parte ser só 0,1% do total é justamente a repetição, ao longo do projeto, da atitude de “por que fazer direito se não afeta o desempenho total?”
      LLMs estão muito mais perto do limite de melhorias de 1.000 vezes, mas é comum operações básicas do PyTorch serem 2 vezes mais lentas que uma simples reescrita, e algoritmos de escalonamento melhores às vezes trazem ganhos de 5 a 10 vezes. Tokenização rápida também pode abrir espaço para outras funcionalidades que até agora eram ignoradas por parecerem inviáveis
    • Se a tokenização for feita para executar um modelo de linguagem pequeno (SLM) de roteamento, sua proporção pode ser muito maior que 0,1%. Isso é como pensar que “como o PC passa a maior parte do tempo parado na área de trabalho, otimizar o driver da GPU não importa”
  • É um desempenho difícil de acreditar, a ponto de eu ter ficado um bom tempo olhando para os números do gráfico tentando entendê-los

  • É exatamente a funcionalidade de que o ClickHouse precisa, então pretendo testá-la em https://github.com/ClickHouse/ClickHouse/issues/108247
    Seria bom se o README destacasse mais o desempenho por núcleo, e fico curioso se, no algoritmo real, correspondência com tabela hash perfeita ajudaria

  • Então fica a dúvida: quantas oportunidades de otimização de 1.000 vezes ainda restam em outras partes do pipeline de inferência?

    • Diferente da camada de tokenização, em outras mudanças de inferência é difícil simplesmente determinar se estão corretas ou não
    • Há muitas, e quase todo componente tem equipes e pesquisas dedicadas. É bem provável que ainda venham muitos grandes avanços
    • Nas partes que ocupam uma fatia maior do tempo de inferência, muito mais esforço de otimização já deve ter sido investido