- Motor de inferência de LLM em C++/CUDA que permite executar o modelo Llama 70B em uma RTX 3090 (24 GB de VRAM) por meio de streaming da memória da GPU e E/S direta opcional com NVMe
- Usa uma estrutura de cache adaptativo em 3 camadas para dividir automaticamente entre VRAM, RAM fixa e fallback em NVMe/mmap, alcançando até 83x mais velocidade em relação ao mmap
- O backend gpu-nvme-direct transfere dados diretamente do NVMe para a GPU, contornando completamente a CPU e aproveitando ao máximo a largura de banda do PCIe
- Recursos de layer skip e self-speculative decoding reduzem computações desnecessárias e aumentam a velocidade de processamento sem perda de qualidade
- Permite rodar modelos extremamente grandes com eficiência em hardware de consumo, apontando para uma maior acessibilidade à inferência de LLMs de alto desempenho
Visão geral do NTransformer
- Motor de inferência de LLM de alta eficiência em C++/CUDA que executa o modelo Llama 70B em uma RTX 3090 (24 GB de VRAM)
- Faz streaming das camadas do modelo pela memória da GPU e, opcionalmente, usa E/S direta com NVMe para contornar completamente a CPU
- Sem dependências externas além do CUDA Toolkit; não requer PyTorch nem cuBLAS
- Suporta o formato de modelo GGUF, com quantizações Q4_0, Q8_0, Q4_K_M, Q5_K, Q6_K, F16 e F32
Desempenho e estrutura de cache
- Cache adaptativo em 3 camadas (3-Tier Adaptive Caching)
- Camadas residentes na VRAM (0 E/S)
- RAM fixa (somente para transferência H2D)
- Fallback em NVMe/mmap
- Em um ambiente com RTX 3090 + 48 GB de RAM, obteve 83x mais velocidade em relação ao mmap
- A largura de banda do PCIe Gen3 x8 (cerca de 6,5 GB/s) atua como gargalo
- A quantização Q4_K_M carrega 10 camadas a mais na VRAM (36 vs 26), reduzindo o volume de transferência
- O layer skip (baseado em similaridade de cosseno) pula 20 de 80 camadas, com perda mínima de qualidade
Principais recursos
- Streaming SLEP: sobreposição de leitura NVMe, DMA via PCIe e computação na GPU com buffer duplo
- Backend gpu-nvme-direct: lê dados do NVMe diretamente para memória fixa acessível pela GPU
- Self-speculative decoding: usa as camadas residentes na VRAM como modelo de rascunho, sem necessidade de modelo adicional
- Seleção automática do caminho de dados: residente na VRAM > RAM fixa H2D > mmap fixo >
memcpy da CPU
- Suporte à arquitetura Llama: inclui RoPE, GQA, SwiGLU, RMSNorm e cache KV
Requisitos do sistema
- Linux (Ubuntu, kernel 6.17+), CUDA Toolkit 13.1, gcc/g++ 14, CMake 3.24+
- GPU com Compute Capability 8.0+ (RTX 3090 testada)
- Para usar E/S direta com NVMe, é necessário um SSD NVMe em slot PCIe separado e a biblioteca gpu-nvme-direct
Streaming direto NVMe
- Quando o modelo não cabe na VRAM, usa-se um caminho direto NVMe → GPU, excluindo completamente a CPU
- Fluxo de dados: NVMe SSD → DMA → memória de staging fixa → PCIe H2D → buffer da GPU → computação
- O NVMe é vinculado ao VFIO para acesso direto em espaço de usuário
- Cada camada (cerca de 670 MB no caso de um 70B Q6_K) é lida em cerca de 202 ms com 670 comandos NVMe
- Leitura NVMe, DMA H2D e computação na GPU são processados em paralelo em um pipeline de buffer duplo
Configuração do sistema e avisos de risco
- O script de configuração automática (
setup_system.sh) configura em sequência GRUB, NVIDIA DKMS, cabeçalhos CUDA, VFIO e binding do NVMe
- Inclui operações de alto risco, como desativação de IOMMU, patch em módulos do kernel e binding de NVMe ao VFIO
- Configurações incorretas podem causar falha de boot, perda de dados no NVMe e instabilidade do sistema
- Nunca use a unidade de boot; é necessário um dispositivo NVMe dedicado e separado
- Todas as alterações contam com scripts de backup e restauração
Arquitetura e estrutura do código
- Principais componentes no diretório
src/
core/: tensores, alocação de memória, gerenciamento de dispositivo GPU
cuda/: kernels de GEMV, RMSNorm, RoPE, SwiGLU e softmax
memory/: motor de streaming SLEP baseado em NVMe e mmap
model/: composição do Transformer, loader GGUF, attention, FFN, normalization
inference/: tokenizador, sampler, motor
scripts/: inclui scripts de configuração do sistema, binding de NVMe e restauração
Roadmap por etapas de desenvolvimento
- Etapa 1: Llama 8B Q8_0, kernels CUDA customizados, 48,9 tok/s (concluída)
- Etapa 2: streaming SLEP, execução de 70B em uma única GPU, ganho de 33x em velocidade (concluída)
- Etapa 3: suporte a Q4_K_M/Q5_K, layer skip, self-speculative decoding, cache KV em F16 (concluída)
- Etapa 4: backend NVMe Direct, leitura NVMe guiada pela GPU a 3,35 GB/s (concluída)
- Etapa 5: otimização da inferência e API C pública (planejada)
Licença
1 comentários
Comentários do Hacker News
Acho realmente inteligente a abordagem de transferir diretamente do NVMe para a GPU, contornando a CPU
Ao rodar modelos grandes localmente, o gargalo sempre foi a hierarquia de memória, e isso basicamente trata o NVMe como uma VRAM estendida, acessada diretamente via DMA
Fico curioso sobre como isso se compararia à abordagem de memória unificada (unified memory) da série Apple M. O M4 Max consegue colocar um modelo 70B inteiro na memória, mas o throughput é menor que o de uma 3090
Seria interessante ver um benchmark comparando o desempenho nativo da 3090 com essa abordagem via NVMe e do M4 Max com base em inferência em lote (batch inference)
Com GPUdirect, é possível fazer transferência DMA direta para dispositivos de armazenamento
Fiquei pensando em como seria se o armazenamento m.2 fosse, na prática, DRAM. Ao fazer spill do modelo a partir da GPU, não há necessidade de persistência, então a RAM do sistema poderia ficar disponível para a CPU
Uma velocidade de 0.2 token/s é lenta para chat, mas suficiente para tarefas em lote/assíncronas
Eu executo pipelines de geração automática de conteúdo, com várias chamadas de LLM em paralelo. A geração de imagens é o gargalo, então o trabalho inteiro já leva uns 20 minutos de qualquer forma
Se eu pudesse rodar um modelo 70B localmente, isso economizaria custos com tokens de API e seria uma grande redução de custo
0.2 tok/s é aceitável para experimentação, mas insuficiente para uso interativo
Na maioria dos casos, modelos 8B ou 13B bem quantizados oferecem um equilíbrio melhor entre latência e qualidade
Experimento realmente interessante. Eu deveria ter tentado algo assim antes
Queria saber os números reais de throughput em relação à largura de banda teórica do PCIe. Gostaria de entender se isso é um problema de latência ou de largura de banda
É um hack muito legal, mas 0.5 tok/s em um modelo 70B é lento em comparação com os 30+ tok/s que a mesma placa entrega em um modelo 7B
Segundo pesquisas da NVIDIA, modelos abaixo de 10B já conseguem lidar com 40~70% das tarefas de agentes, e a diferença de qualidade está diminuindo rapidamente
Essa área ainda vale muito a pena para experimentação
No longo prazo, parece que o essencial será a otimização dos modelos, ou seja, pesquisar quais partes do modelo podem ser omitidas sem afetar o desempenho. No fim das contas, o modelo também é uma forma de compressão com perdas (lossy compression). Esse caminho também ajudaria na democratização da IA
Projeto realmente incrível. Fico curioso sobre que tipo de conhecimento de sistemas/hardware é necessário para ter uma ideia dessas
Eu trabalho em ambientes onde o hardware é muito abstraído, então é difícil imaginar esse tipo de abordagem. Parece exigir não só criatividade, mas também entendimento em nível de sistema
Ao tentar rodar um LLM no PS2, bati no limite de 32MB de RAM e 4MB de VRAM, então criei um método de streaming de camadas. O PS2 conseguia lidar diretamente com endereços de 32 bits na VRAM, então era muito rápido, e tentei reproduzir isso também no PC
Também estou tentando algo parecido. Estou experimentando rodar um modelo 1T usando menos da metade da VRAM
Acho que, modificando a camada de roteamento do SGLang, dá para implementar expert swap baseado em previsão JIT da Gen5 NVMe para a memória da GPU. Estou usando primitivas NVIDIA Dynamo e NIXL
Queria saber se alguém já tentou isso
Projeto muito legal. Gostaria de saber mais detalhes sobre o processo de patch DKMS em GPUs comuns. Também quero tentar
Links relacionados: RTX4090 P2P Unlock, vGPU Unlock