· 19 min de leitura · ...

O laboratório de IA de $900: rodando modelos 70B em hardware consumer

Montei um setup de $900 com RTX 3060 Ti e rodei modelos de 8B a 70B parâmetros. Os dados revelaram um fenômeno que ninguém documentou: o GPU Offloading Cliff.

IALLMshardwareinferênciaopen-source
Indice

Eu queria rodar um modelo de 70 bilhões de parâmetros na minha própria máquina. Sem cloud, sem API, sem mandar meus dados pra ninguém. O problema? Todo benchmark que eu encontrava usava hardware de $10.000 ou mais. A100, H100, placas que custam mais do que eu ganho em meses.

Então fiz o que qualquer pessoa teimosa faria: montei um setup de $900 e testei eu mesmo. Uma RTX 3060 Ti de $300, um i7 usado, 32GB de RAM e um SSD. Setup de estudante. Setup de quem mora em país onde A100 não é opção.

E funciona? Funciona. Mas não do jeito que eu esperava. Achei que bastava jogar mais camadas na GPU e a velocidade ia subindo proporcionalmente. Errado. Os benchmarks revelaram um fenômeno que a literatura acadêmica não documentou, otimizações que não fazem diferença nenhuma quando você acha que deveriam fazer, e uma única técnica que realmente muda o jogo.

Esse post é o registro completo dos experimentos: dados reais, tabelas, configs de terminal, e zero hype. Se você já pensou em rodar LLMs localmente e não sabe se vale a pena, esses números vão te dar a resposta.

O setup: o que $900 compra em 2026

Antes de mostrar os números, preciso ser transparente sobre o hardware. Não é um PC gamer de última geração. É o tipo de máquina que um desenvolvedor ou estudante monta com orçamento apertado.

ComponenteEspecificaçãoCusto (USD)
GPUNVIDIA GeForce RTX 3060 Ti~$300
VRAM8 GB GDDR6X(inclusa)
CPUIntel Core i7-9700F @ 3.00GHz~$200
RAM32 GB DDR4 2666 MHz (2x16GB)~$70
StorageNVMe SSD 512GB~$50
Placa-mãe + Fonte + GabineteATX padrão~$280
Total~$900

Software: Ubuntu 24.04, NVIDIA Driver 580, CUDA 13.0, llama.cpp v8763. Tudo open-source, tudo gratuito.

Os modelos testados

Testei quatro modelos cobrindo de 8B a 70B parâmetros, todos quantizados para caber na memória disponível:

ModeloParâmetrosQuantizaçãoTamanho (GiB)CamadasCabe na VRAM?
Llama 3.1 8B Instruct8.03BQ4_K_M4.5833100%
Mistral Nemo 12B Instruct12.25BQ4_K_M6.9641100%
Qwen 2.5 14B Instruct14.77BQ4_K_M8.3740~100%*
Llama 3.1 70B Instruct70.55BQ2_K24.568025%

O 70B é o caso mais interessante. Com quantização Q2_K (2 bits), ele comprime de ~140GB (FP16) para ~25GB. Não cabe inteiro na GPU (8GB), mas cabe na RAM do sistema (32GB).

Se você não é da área: quantização é como comprimir uma foto. Você reduz o tamanho do arquivo, mas perde um pouco de detalhe. Q2_K significa que cada peso do modelo usa apenas 2 bits em vez de 16. O modelo fica 7x menor, com alguma perda de qualidade nas respostas.

O llama.cpp permite distribuir as camadas do modelo entre GPU e CPU usando o parâmetro ngl (number of GPU layers). Pense assim: o modelo tem 80 camadas, e você escolhe quantas delas rodam na GPU (rápida) vs na CPU (lenta). E é exatamente aqui que a história fica interessante.

O GPU Offloading Cliff: o fenômeno que ninguém documentou

A ideia por trás do GPU offloading parece simples: quanto mais camadas do modelo você coloca na GPU, mais rápido ele roda. Faz sentido intuitivamente, certo? A literatura acadêmica também trata assim: uma relação gradual, mais ou menos proporcional.

Eu esperava ver exatamente isso nos meus benchmarks. Não foi o que aconteceu.

Meus dados mostram que essa suposição está errada.

Rodei benchmarks sintéticos com o llama-bench (ferramenta nativa do llama.cpp), variando o ngl de 0 (tudo na CPU) até o máximo que a VRAM permite. Os resultados por modelo:

Llama 3.1 8B Q4_K_M (4.58 GiB, 33 camadas)

nglGPU %pp512 (tok/s)tg128 (tok/s)Speedup
00%744.99 ± 11.167.00 ± 0.021.0x
1648%1127.81 ± 12.0312.77 ± 0.011.8x
33100%2525.68 ± 24.7376.25 ± 0.0210.9x

Mistral Nemo 12B Q4_K_M (6.96 GiB, 41 camadas)

nglGPU %pp512 (tok/s)tg128 (tok/s)Speedup
00%508.86 ± 6.564.59 ± 0.011.0x
2049%769.65 ± 7.908.66 ± 0.011.9x
41100%1690.74 ± 10.3450.85 ± 0.0111.1x

Qwen 2.5 14B Q4_K_M (8.37 GiB, 40 camadas)

nglGPU %pp256 (tok/s)tg64 (tok/s)Speedup
00%258.66 ± 4.323.73 ± 0.021.0x
2050%386.39 ± 5.076.21 ± 0.031.7x
40100%759.44 ± 9.4114.84 ± 0.064.0x

Llama 3.1 70B Q2_K (24.56 GiB, 80 camadas)

nglGPU %pp128 (tok/s)tg32 (tok/s)Speedup
00%42.991.201.0x
1012.5%49.851.371.14x
1518.7%52.861.471.22x
2025%56.151.551.29x

Agora olhe para esses números com atenção. O padrão é claro:

Speedup (geração)
  12x |                                                          * 8B (10.9x)
      |                                                    * 12B (11.1x)
  10x |
      |
   8x |
      |
   6x |
      |                                              * 14B (4.0x)
   4x |
      |
   2x |         *** (todos os modelos ~1.3-1.9x)
      |   ****
   1x |***
      +--+------+------+------+------+------+------+------+--
         0%    12%    25%    37%    50%    62%    75%   100%
                        % de camadas na GPU

Veja o que acontece: existe uma transição de fase por volta de 50% de camadas na GPU. Abaixo desse ponto, o overhead de transferência de dados entre CPU e GPU a cada fronteira de camada domina o tempo de execução. O speedup é marginal: 1.0x a 1.9x, independente do modelo. Acima de 50%, a computação se torna o bottleneck (e a GPU é excelente nisso), e o ganho explode para 4.0x a 11.1x.

Analogia: imagine uma esteira de fábrica onde cada peça precisa ser transportada entre dois prédios. Se mais da metade das máquinas está no prédio A, o tempo de transporte domina e não importa quão rápidas as máquinas são. Mas quando você concentra a maioria no mesmo prédio, a velocidade das máquinas finalmente importa.

Eu chamo isso de GPU Offloading Cliff porque é exatamente o que os dados mostram: não é uma rampa, é um penhasco. E a implicação prática é direta. Se você não consegue colocar pelo menos metade das camadas do modelo na GPU, o ganho de ter uma GPU é quase irrelevante. Para o 70B no meu setup, o máximo que consigo é 25% das camadas (ngl=20). Estou no lado errado do penhasco. E confesso que demorei pra aceitar isso.

Por que isso importa

A literatura acadêmica (FlexGen, PowerInfer) trata a relação entre GPU layers e performance como um tradeoff gradual. Os schedulers de offloading assumem que cada layer adicional na GPU dá um ganho proporcional. Meus dados mostram que essa suposição está errada. O ganho é não-linear com transição de fase. E isso tem implicações concretas para quem decide quanto investir em VRAM: se sua GPU não tem VRAM suficiente para passar do threshold de 50%, o investimento tem retorno marginal.

ModeloAbaixo de 50% GPUAcima de 50% GPUCliff Ratio
Llama 8B1.8x (48%)10.9x (100%)6.0x
Mistral 12B1.9x (49%)11.1x (100%)5.8x
Qwen 14B1.7x (50%)4.0x (100%)2.4x
Llama 70B1.3x (25%)N/A (não cabe)N/A

Zonas de viabilidade: quando rodar local faz sentido?

Com os benchmarks em mãos, criei um framework prático para decidir quando inferência local é viável. Três zonas, definidas pela velocidade de geração:

ZonaVelocidade% GPU LayersCenárioExemplos
A: Interativo>10 tok/s>80%Chat, IDE copilot, APIs real-time8B Q4 ngl=33, 12B Q4 ngl=41
B: Batch1-10 tok/s25-80%Sumarização, pipelines offline, análise14B Q4 ngl=40, 70B Q2 + speculative
C: ImpraticávelAbaixo de 1 tok/sAbaixo de 15%Custo de espera excede custo de API70B Q2 ngl=0

Zona A é onde o usuário percebe streaming quase instantâneo. O 8B a 76 tok/s e o 12B a 51 tok/s vivem aqui confortavelmente. Dá pra usar como copilot de código, chatbot, API de produção.

Zona B é viável para processamento automatizado. Uma resposta de 200 tokens leva de 30 a 130 segundos. Não serve pra chat interativo, mas funciona bem pra pipelines de sumarização, extração de entidades, tradução em lote.

Zona C é economicamente irracional. O tempo que o desenvolvedor gasta esperando custa mais do que pagar uma API cloud.

Cenários reais com o 70B (ngl=20, Zona B)

Para validar as zonas, rodei sete tarefas de NLP do mundo real usando a API HTTP do llama-server (compatível com OpenAI):

Cenáriotok/sTTFT (s)Latência (s)Tokens (in/out)Zona
Sumarização de texto1.541.67131.5484 / 200B
Geração de código1.611.1724.1158 / 37B
Tradução (EN→PT)1.561.3485.2223 / 131B
Extração de entidades (JSON)1.571.3179.7218 / 123B
Raciocínio lógico1.581.2356.5184 / 88B
Classificação de sentimento1.551.2633.7206 / 51B
QA com contexto longo1.601.5023.5387 / 35B

Dois insights saltam dos dados:

  1. A velocidade de geração é notavelmente consistente entre tarefas (1.54 a 1.62 tok/s). O bottleneck é puramente computacional, não depende do tipo de tarefa.

  2. O TTFT (time-to-first-token) é desacoplado da geração. O primeiro token chega em 1.17 a 1.67 segundos, muito rápido em relação à velocidade de geração. Para tarefas com output curto (classificação: 51 tokens, QA: 35 tokens), o TTFT domina a latência total. Isso torna essas tarefas mais viáveis do que o tok/s sozinho sugeriria.

A caçada por performance: o que funciona e o que não funciona

Com o 70B preso na Zona B a 1.57 tok/s, eu não queria aceitar. Tinha que ter um jeito de melhorar isso com software. Parti pra testar toda otimização disponível, uma por uma, com a esperança de encontrar algum ganho significativo. Spoiler: a maioria decepcionou.

Flash Attention

Teoria: computação de atenção IO-aware que reduz o bottleneck de bandwidth de memória. Performance grátis, sem impacto na qualidade.

Resultado: +0.6% (1.57 → 1.58 tok/s). Irrelevante.

KV Cache Quantization

Teoria: comprimir o cache de key-value de FP16 para Q4_0 ou Q8_0, liberando VRAM para mais camadas na GPU.

Resultado com Q8_0: 0% de ganho. Com Q4_0 tentando subir para ngl=25 ou ngl=30: OOM (out of memory). A VRAM de 8GB simplesmente não comporta.

Mais GPU layers (ngl > 20)

Resultado: impossível. ngl=20 é o máximo absoluto para o 70B Q2_K em 8GB de VRAM, mesmo com KV cache quantizado.

O stack completo de otimizações

Otimizaçãongltg (tok/s)vs BaselineNota
Baseline201.571.0xreferência
+ Flash Attention201.581.01xnegligível
+ FA + KV Cache Q8_0201.571.00xzero ganho
+ FA + KV Q4_0 + ngl=2525OOMN/Anão cabe
+ FA + KV Q4_0 + ngl=3030OOMN/Anão cabe
Speculative Decoding15+draft~3.452.2xúnico ganho real

Achado crítico: em hardware com VRAM severamente limitada (menos de 25% das camadas na GPU), otimizações de software que atacam eficiência de compute (flash attention) ou compressão de cache (KV quantization) não produzem melhoria mensurável. O bottleneck é a bandwidth de memória entre CPU e GPU nas fronteiras de camada, não o compute da GPU nem o tamanho do KV cache.

Speculative decoding: a única saída

Depois de tanta frustração com otimizações que não deram resultado, essa foi a técnica que mudou tudo.

Speculative decoding funciona com uma ideia elegante: um modelo pequeno e rápido (o “draft”) gera vários tokens candidatos, e o modelo grande (o “target”) verifica todos de uma vez num único forward pass em batch. É como ter um estagiário escrevendo rascunhos rápidos e o sênior apenas revisando, em vez do sênior escrever cada palavra do zero. Tokens aceitos pelo sênior são produzidos a custo marginal quase zero.

No meu setup, usei o Llama 3.2 1B Q4_K_M (771 MB) como draft model. Ele cabe inteiro na GPU e roda a 317 tok/s. O target (70B) verifica os candidatos em batch, e o resultado efetivo é 3.45 tok/s. Um ganho de 2.2x sobre o baseline.

Mas aqui vem o plot twist: para caber o draft model na GPU, preciso sacrificar 5 camadas do target (de ngl=20 para ngl=15). Essa perda isolada custa ~6% de performance (1.57 → 1.47 tok/s). Mas o ganho do speculative compensa com folga.

# Config otimizada com speculative decoding
llama-cli -m llama-70b-q2_k.gguf \
  -md llama-3.2-1b-q4_0.gguf \
  -ngl 15 -ngld 99 -fa -ctk q4_0 -ctv q4_0 \
  -c 2048 --mlock --draft-max 8

O trade-off de alocação de VRAM

Esse é o achado que mais me surpreendeu. Em hardware com VRAM limitada, speculative decoding cria um dilema de alocação: dedicar VRAM ao modelo principal (mais GPU layers) ou ao draft model (ganhos do speculative)?

ConfiguraçãoTarget nglDrafttok/sEfeito
Sem speculative20nenhum1.57baseline
Speculative (ngl=20)201B (GPU)OOMfalha
Speculative (ngl=15)151B (GPU)3.45+2.2x

A resposta é contraintuitiva: a alocação ótima de VRAM não é “maximizar layers do modelo principal”. É reservar VRAM para um draft model rápido, aceitando menos layers do target. Sacrificar 5 layers do 70B (perda de ~6%) para alocar o draft model inteiro dá ganho líquido de 2.2x.

Esse trade-off tem implicações diretas para schedulers de offloading automático em frameworks de inferência. Nenhum paper publicado que eu conheça analisou essa decisão de alocação entre target e draft model em hardware consumer.

Quanto custa de verdade: local vs cloud

TCO do hardware

ComponenteCusto (USD)Amortização (3 anos)Mensal
Sistema completo$90036 meses$25/mês
Eletricidade (~200W)$0.12/kWhcontínuo~$17/mês
Total mensal$42/mês

Custo por token: local vs cloud

ProvedorModeloCusto por 1M tokens de output
OpenAI GPT-4o200B+ (est.)$15.00
Anthropic Claude SonnetN/A$15.00
Anthropic Claude OpusN/A$75.00
Local RTX 3060 TiLlama 70B Q2~$0.02
Local RTX 3060 TiLlama 8B Q4~$0.001

A diferença é brutal: local custa 750x menos que GPT-4o por token de output. Mas velocidade importa. A 1.57 tok/s (70B), o sistema gera ~4.9M tokens por mês rodando 24/7.

Break-even: quando local compensa?

Padrão de usoTokens/mêsCusto cloud (GPT-4o)Custo localCompensa?
Leve (50 req/dia, 200 tok)300K$4.50$42Não
Médio (500 req/dia)3M$45.00$42Sim, mês 1
Pesado (2000 req/dia)12M$180.00$42Sim, mês 1
Pipeline batch (24/7)4.9M$73.50$42Sim, mês 1

Para uso leve, cloud é mais econômico. A partir de ~500 requisições por dia, local já compensa no primeiro mês. E tem fatores que não aparecem na planilha:

FatorLocalCloud API
Privacidade de dadosTotal: nada sai do dispositivoDados enviados a terceiros
Disponibilidade24/7, sem rate limitsRate limits, outages
Consistência de latênciaDeterminísticaVariável (rede, fila)
CustomizaçãoControle total (fine-tuning, system prompts)Limitado
Dependência de internetNenhumaObrigatória

Quando o 70B compensa sobre o 8B?

Uma pergunta natural: se o 8B roda a 76 tok/s (Zona A) e o 70B a 1.57 tok/s (Zona B), por que usar o 70B?

A resposta está na qualidade das respostas, não na velocidade:

Raciocínio complexo: modelos 70B superam os 8B substancialmente em raciocínio multi-step, resolução de problemas matemáticos e instruções complexas.

Qualidade multilíngue: traduções e geração em múltiplos idiomas são significativamente melhores no 70B.

Output estruturado: extração de entidades e geração de JSON são mais confiáveis com modelos maiores.

O framework de decisão é direto: use 8B para tarefas interativas sensíveis a velocidade, 70B para tarefas batch sensíveis a qualidade.

O que aprendi: lições para quem quer montar o próprio lab

Depois de dezenas de benchmarks, configs testadas e OOMs enfrentados, estas são as lições que eu gostaria de ter recebido antes de começar:

1. VRAM é o recurso mais precioso. Não é clock speed, não é CUDA cores, não é bandwidth de memória. É quanto VRAM sua GPU tem. Ela determina quantas camadas do modelo cabem na GPU, e isso determina de qual lado do cliff você está.

2. Se menos de 50% das camadas cabem na GPU, o ganho é marginal. Não compre uma GPU de 6GB achando que vai ter “algum ganho”. O cliff effect garante que abaixo de 50%, o retorno é mínimo (1.0x a 1.9x). Se puder, invista nos 8GB extras que te colocam do outro lado do penhasco.

3. Otimizações de software não resolvem limitação de hardware. Flash attention, KV cache quantization: são técnicas válidas, mas inúteis quando o bottleneck é bandwidth de memória entre CPU e GPU. Não perca tempo otimizando compute quando o problema é transferência de dados.

4. Speculative decoding é a exceção. É a única técnica que muda o paradigma de inferência (de geração sequencial para verificação em batch) e, por isso, é a única que dá ganho real em hardware limitado.

5. 32GB de RAM é o mínimo para modelos 70B. O modelo Q2_K ocupa ~25GB. Com overhead do sistema operacional e do KV cache, 32GB fica apertado. 64GB daria mais margem.

6. Quantização Q2_K funciona, mas tem custo de qualidade. Comprimir de 16 bits para 2 bits inevitavelmente perde informação. Para tarefas onde precisão máxima importa (matemática, código complexo), considere modelos menores com quantização mais alta (14B Q4) em vez de modelos maiores com quantização agressiva (70B Q2).

Conclusão: o lab de $900 é real

Rodei um modelo de 70 bilhões de parâmetros numa máquina de $900. Não é rápido o suficiente pra chat interativo (1.57 tok/s baseline, 3.45 tok/s com speculative decoding), mas é perfeitamente viável para processamento batch, pipelines de NLP, e qualquer cenário onde qualidade importa mais que latência.

O achado mais importante não foi a velocidade em si. Foi o GPU Offloading Cliff: a descoberta de que a relação entre camadas na GPU e performance não é gradual, e sim uma transição de fase. Abaixo de 50%, ganho marginal. Acima de 50%, o speedup explode. Esse fenômeno tem implicações diretas para decisões de compra de hardware e para o design de schedulers de offloading automático.

Para um estudante no Brasil, na Índia ou na Nigéria, onde uma A100 custa mais do que muita gente ganha em um ano, $900 é a diferença entre ter acesso a modelos frontier ou não. E o que os dados mostram é que, com as técnicas certas (speculative decoding, quantização agressiva, zonas de viabilidade bem definidas), esse acesso é real. Limitado, mas real.

O hardware consumer não substitui o datacenter. Mas democratiza o acesso ao que antes era exclusivo de quem tinha $10.000+ pra gastar em GPU. E num mundo onde IA está se tornando infraestrutura básica, garantir que qualquer pessoa possa experimentar, aprender e construir com modelos frontier, mesmo que devagar, é mais do que uma questão técnica. É uma questão de acesso.

E pra mim, isso vale cada tok/s.


Referências

  1. Frantar, E., et al. “GPTQ: Accurate Post-Training Quantization for Generative Pre-Trained Transformers.” ICLR 2023.
  2. Lin, J., et al. “AWQ: Activation-aware Weight Quantization for LLM Compression and Acceleration.” MLSys 2024.
  3. Sheng, Y., et al. “FlexGen: High-Throughput Generative Inference of Large Language Models with a Single GPU.” ICML 2023.
  4. Song, Y., et al. “PowerInfer: Fast Large Language Model Serving with a Consumer-grade GPU.” SOSP 2024.
  5. Leviathan, Y., et al. “Fast Inference from Transformers via Speculative Decoding.” ICML 2023.
  6. Chen, C., et al. “Accelerating Large Language Model Decoding with Speculative Sampling.” 2023.
  7. Dao, T. “FlashAttention-2: Faster Attention with Better Parallelism and Work Partitioning.” 2023.
  8. Dettmers, T., et al. “QLoRA: Efficient Finetuning of Quantized LLMs.” NeurIPS 2023.
  9. Kwon, W., et al. “Efficient Memory Management for Large Language Model Serving with PagedAttention.” SOSP 2023.
  10. Alizadeh, K., et al. “LLM in a Flash: Efficient Large Language Model Inference with Limited Memory.” Apple ML Research, 2023.

Fique por dentro

Receba artigos sobre arquitetura de software, IA e projetos open source direto no seu e-mail.