Agendamento de GPU e gestão de recursos no Ollama: otimização de VRAM e balanceamento entre várias GPUs

Com uma placa de 8 GB de VRAM, você finalmente consegue carregar um modelo 13B. Depois de algumas inferências, porém, tudo trava de repente e a tela mostra o erro “CUDA out of memory”.
Ou você investe em duas GPUs, esperando enfim executar modelos maiores, abre o nvidia-smi e descobre que apenas uma placa está trabalhando enquanto a outra continua ociosa.
Encontrei todos esses problemas quando comecei a usar o Ollama: VRAM insuficiente, várias GPUs sem uso e uma velocidade de inferência que oscilava sem explicação. Aos poucos, entendi a lógica de agendamento de GPU por trás do Ollama. Muita coisa não funciona só porque foi configurada; é preciso compreender o que os parâmetros realmente controlam.
Reuni aqui o que aprendi para resolver alguns problemas práticos:
- Como executar um modelo 13B com estabilidade em 8 GB de VRAM, sem OOM inesperado
- Como configurar várias GPUs para que elas sejam realmente utilizadas, com uma solução completa de balanceamento de carga
- Quais parâmetros ajustar quando falta VRAM, em ordem de prioridade
- O que é GPU offloading e como ele funciona internamente no llama.cpp
Um aviso antes de começar: o conteúdo é um pouco mais avançado e pressupõe alguma familiaridade com GPU, CUDA e as operações básicas do Ollama. Se você começou a usar o Ollama agora, vale ler primeiro os textos anteriores da série, especialmente o sexto, sobre fundamentos de otimização de desempenho. Com esse contexto, esta explicação fica bem mais fácil de acompanhar.
1. Como funciona a gestão de memória da GPU: todos os parâmetros
O agendamento de GPU do Ollama depende principalmente de alguns parâmetros que controlam como as camadas do modelo são distribuídas entre GPU e CPU. Entender esses parâmetros ajuda a explicar por que às vezes ocorre um erro mesmo quando a VRAM parece suficiente, ou por que a inferência fica lenta sem um motivo aparente.
1.1 Os principais parâmetros em detalhes
Estes são os parâmetros mais importantes, organizados em uma tabela para facilitar a consulta:
| Parâmetro | Função | Valor padrão | Quando ajustar |
|---|---|---|---|
num_gpu | Quantas camadas do modelo são executadas na GPU | Detecção automática | Reduza quando faltar VRAM |
main_gpu | Número da GPU principal | 0 | Defina qual placa usar em uma configuração com várias GPUs |
low_vram | Ativa o modo de pouca VRAM | false | Recomendado para placas com menos de 8 GB |
num_batch | Tamanho do lote | 512 | Reduza para 256 quando a VRAM estiver no limite |
num_ctx | Tamanho do contexto | 4096 | Em conversas curtas, 2048 economiza bastante VRAM |
Entre esses parâmetros, num_gpu é o que mais causa confusão. Ele não representa a quantidade de GPUs instaladas, mas quantas camadas do modelo serão processadas na GPU.
Por exemplo, o Llama 2 7B tem 32 camadas. Ao configurar num_gpu: 32, todas as 32 camadas são executadas na GPU. Se a VRAM não for suficiente, você pode usar num_gpu: 20: 20 camadas ficam na GPU e as outras 12 são calculadas pela CPU, o que naturalmente reduz a velocidade.
O parâmetro low_vram é interessante. Quando ele está ativo, o Ollama usa algumas técnicas para economizar VRAM, como colocar o KV cache na memória da CPU em vez de mantê-lo na GPU. A inferência fica um pouco mais lenta, mas pelo menos o processo não trava.
1.2 Fluxo de alocação da VRAM
Quando o Ollama carrega um modelo, a alocação de VRAM segue este fluxo:
- Detecção da VRAM: primeiro, verifica quanta memória livre existe na GPU
- Cálculo das camadas: com base no tamanho do modelo e na VRAM disponível, calcula quantas camadas cabem na GPU
- Alocação do KV cache: reserva espaço para o cache usado na inferência, que também ocupa VRAM
- Início da inferência: o uso dinâmico da VRAM varia durante a execução
O ponto crítico está na segunda etapa: o Ollama calcula automaticamente a melhor distribuição de camadas. Esse cálculo nem sempre é preciso, principalmente quando a VRAM fica exatamente no limite, como ao executar um modelo 13B em uma placa de 8 GB. Nesses casos, é necessário definir num_gpu manualmente.
Para descobrir quantas camadas do modelo atual usam GPU offloading, execute:
ollama run llama3 --verbose
Na saída, você verá uma linha parecida com llama_model_load: model loaded - layers: 40/40 on GPU, indicando que todas as 40 camadas estão na GPU.
1.3 Como funciona o backend llama.cpp
O Ollama usa o llama.cpp como mecanismo de inferência. Ao entender a lógica de GPU offloading do llama.cpp, fica mais claro por que alguns ajustes de parâmetros produzem pouco efeito.
Decisão de GPU offloading
O llama.cpp faz aproximadamente este cálculo:
VRAM disponível = VRAM total da GPU - reserva do sistema (algumas centenas de MB)
Tamanho por camada = parâmetros do modelo / número de camadas
Camadas que cabem = min(total de camadas, VRAM disponível / tamanho por camada)
Há uma armadilha nesse cálculo: ele considera apenas a VRAM ocupada pelo modelo e não inclui o KV cache. Esse cache é usado durante a inferência e aumenta conforme a conversa fica mais longa. Por isso, às vezes o modelo carrega corretamente, mas, após algumas inferências, o KV cache esgota a VRAM e o processo trava.
Arquitetura de cálculo híbrido
GPU e CPU não trabalham de forma totalmente separada. Em linhas gerais:
- A GPU cuida de: cálculos de matrizes e operações de attention, que exigem mais processamento
- A CPU cuida de: operações de embedding e normalization, que exigem menos processamento
- Transferência de dados: os dados precisam circular entre GPU e CPU, o que gera custo adicional
Quando apenas parte das camadas fica na GPU, o custo da transferência aumenta. Ao terminar uma camada, se a próxima estiver no outro dispositivo, o resultado precisa ser transferido antes que o cálculo continue. É por isso que o GPU offloading parcial pode reduzir bastante a velocidade de inferência.
Mapeamento de memória com mmap
Por padrão, o llama.cpp usa mmap para carregar o arquivo do modelo. As vantagens são:
- Não é necessário ler o modelo inteiro para a memória; o sistema operacional carrega os dados sob demanda
- Vários processos podem compartilhar a mesma região de memória
- O consumo de memória é menor
Se você quiser desativar o mmap, pois ele pode causar problemas em algumas situações, configure no Modelfile:
PARAMETER use_mmap false
2. Configuração com várias GPUs: arquitetura completa de balanceamento de carga
Para quem tem duas ou mais GPUs, a principal dúvida é: como fazer o Ollama usar todas elas?
Primeiro, uma limitação importante: o Ollama não oferece paralelismo de modelo. Isso significa que não é possível dividir um modelo em duas partes, processando uma na GPU 0 e outra na GPU 1. Cada modelo só pode ser vinculado a uma GPU.
Então, para que servem várias GPUs? Há duas possibilidades:
- Executar instâncias de modelos diferentes: a GPU 0 executa o llama3 e a GPU 1 executa o mistral
- Executar várias instâncias do mesmo modelo: útil para balancear a carga e aumentar a vazão
2.1 Uma instância com várias GPUs: limitações e configuração
Se você só precisa que o Ollama reconheça várias GPUs, a forma mais simples é usar a variável de ambiente CUDA_VISIBLE_DEVICES:
# Permitir que o Ollama use apenas a GPU 0 e a GPU 1
CUDA_VISIBLE_DEVICES=0,1 ollama serve
Essa configuração, porém, tem um problema: por padrão, o Ollama coloca o modelo apenas na GPU 0, enquanto a GPU 1 continua ociosa. Você pode indicar a GPU principal com o parâmetro main_gpu:
# Modelfile
FROM llama3
PARAMETER main_gpu 1 # Definir a GPU 1 como principal
Na prática, essa solução tem utilidade limitada: você apenas trocou a placa que executa o modelo, sem aproveitar de fato a capacidade das duas GPUs.
2.2 Balanceamento entre várias instâncias: solução recomendada
A forma de realmente aproveitar várias GPUs é executar várias instâncias do Ollama, vincular cada uma a uma placa e distribuir as solicitações com um balanceador de carga.
A arquitetura fica assim:
┌─────────┐
│ Cliente │ Envia solicitações de inferência
└────┬────┘
│
┌────▼────────────────────┐
│ Nginx (balanceador) │ Estratégia least_conn
│ Porta: 8080 │
└────┬─────────┬──────────┘
│ │
┌────▼───┐ ┌──▼────┐
│Ollama 1│ │Ollama 2│
│GPU 0 │ │GPU 1 │ Cada instância usa uma GPU exclusiva
│Porta │ │Porta │
│11434 │ │11435 │
└────────┘ └────────┘
Etapa 1: iniciar várias instâncias do Ollama
# Instância 1: vinculada à GPU 0, porta 11434
CUDA_VISIBLE_DEVICES=0 OLLAMA_HOST=127.0.0.1:11434 ollama serve &
# Instância 2: vinculada à GPU 1, porta 11435
CUDA_VISIBLE_DEVICES=1 OLLAMA_HOST=127.0.0.1:11435 ollama serve &
Observação: o diretório de dados padrão do Ollama é ~/.ollama, e as duas instâncias compartilham o mesmo armazenamento de modelos. Isso não é um problema, pois o mapeamento de memória com mmap permite que vários processos compartilhem o mesmo arquivo do modelo.
Etapa 2: configurar o balanceamento de carga no Nginx
# /etc/nginx/conf.d/ollama.conf
upstream ollama_cluster {
least_conn; # Priorizar a instância com menos conexões
server 127.0.0.1:11434;
server 127.0.0.1:11435;
}
server {
listen 8080;
location / {
proxy_pass http://ollama_cluster;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
# Suporte a respostas em streaming
proxy_buffering off;
proxy_cache off;
}
}
A estratégia least_conn envia cada nova solicitação para a instância com o menor número de conexões ativas. Assim, a carga fica mais bem distribuída entre as duas GPUs.
Etapa 3: chamar pelo cliente
O cliente precisa se conectar apenas à porta do Nginx:
# Chamada pelo Nginx, distribuída automaticamente para uma das instâncias
curl http://localhost:8080/api/generate -d '{
"model": "llama3",
"prompt": "Olá"
}'
Outra opção é alterar o endereço padrão do cliente Ollama:
export OLLAMA_HOST=http://localhost:8080
ollama run llama3
2.3 Comparação das estratégias de balanceamento
O Nginx oferece diferentes estratégias de balanceamento de carga, cada uma adequada a um cenário:
| Estratégia | Como funciona | Cenário indicado |
|---|---|---|
| Round-robin (padrão) | Envia solicitações alternadamente para cada instância | Cenários simples, com modelos do mesmo tamanho |
Menos conexões (least_conn) | Envia para a instância menos ocupada | Recomendado para serviços de inferência |
| IP Hash | Um mesmo IP sempre é enviado à mesma instância | Cenários que exigem persistência de sessão |
As solicitações de um serviço de inferência têm duração imprevisível: algumas retornam em segundos, enquanto outras levam vários minutos. Com round-robin, uma instância pode ficar sobrecarregada enquanto outra permanece ociosa. least_conn evita esse desequilíbrio.
Se você quiser distribuir as solicitações de maneira uniforme e permitir uma troca automática quando uma instância falhar, adicione uma verificação de integridade:
upstream ollama_cluster {
least_conn;
server 127.0.0.1:11434 max_fails=3 fail_timeout=30s;
server 127.0.0.1:11435 max_fails=3 fail_timeout=30s;
}
Depois de três falhas consecutivas, o Nginx retira temporariamente a instância do cluster e tenta usá-la novamente após 30 segundos.
3. Estratégias para otimizar a VRAM: quantização, contexto e processamento em lote
Quando falta VRAM, ajuste os parâmetros nesta ordem: quantização > tamanho do contexto > tamanho do lote > número de camadas na GPU.
Por que essa ordem? Porque a quantização produz o maior impacto. Para o mesmo modelo, Q4 pode usar 75% menos VRAM que FP16. Alterar o número de camadas na GPU apenas transfere o cálculo para a CPU: economiza VRAM, mas reduz a velocidade.
3.1 Escolha do nível de quantização
Quantizar significa armazenar os parâmetros do modelo com menos bits. FP16 usa 16 bits por parâmetro, enquanto Q4 usa apenas 4. A redução de bits naturalmente causa alguma perda de precisão, mas, nos testes práticos, a perda do Q4 fica em torno de 2% a 3%, aceitável para a maioria dos cenários.
Comparação entre níveis de quantização:
| Quantização | Uso de VRAM em relação ao FP16 | Perda de precisão | Cenário indicado |
|---|---|---|---|
| Q4_K_M | Cerca de 25% | 2% a 3% | Recomendado: equilíbrio entre desempenho e qualidade |
| Q5_K_M | Cerca de 33% | 1% a 2% | Cenários que exigem um pouco mais de precisão |
| Q8_0 | Cerca de 50% | 0,5% | Qualidade próxima da precisão original |
| FP16 | 100% | Nenhuma | Pesquisa e testes de benchmark |
Dados práticos de referência para o Llama 2 13B:
- FP16: cerca de 26 GB de VRAM
- Q4_K_M: cerca de 8 GB de VRAM
- Q8_0: cerca de 13 GB de VRAM
Portanto, um modelo 13B Q4 cabe por pouco em 8 GB de VRAM. O problema é que o KV cache ainda precisa de espaço e pode esgotar a memória durante a inferência.
Uma recomendação ao escolher o nível de quantização: para uso cotidiano, Q4_K_M é suficiente. Em tarefas que exigem maior precisão, como tradução e geração de código, vale considerar Q5_K_M ou Q8_0.
Por padrão, o Ollama baixa a versão quantizada em Q4. Para usar outra quantização, adicione o sufixo ao nome do modelo:
# Quantização Q4 (padrão)
ollama pull llama3
# Quantização Q8
ollama pull llama3:8b-q8_0
3.2 Otimização do tamanho do contexto
O KV cache armazena o histórico anterior da conversa durante a inferência. Seu uso de VRAM está diretamente ligado ao tamanho do contexto.
Fórmula aproximada e simplificada:
VRAM do KV cache ≈ num_ctx × num_layers × hidden_dim × 2 bytes
Considere o Llama 2 7B como exemplo:
- num_layers = 32
- hidden_dim = 4096
- num_ctx = 4096
O KV cache fica em torno de 2 GB. Se o ctx aumentar para 8192, ele passa a ocupar 4 GB. Ao dobrar o contexto, você também dobra a VRAM do KV cache.
Estratégias de otimização:
-
Conversas curtas: use
num_ctx: 2048- Economiza metade da VRAM do KV cache
- É suficiente para perguntas e respostas cotidianas e tarefas simples
-
Processamento de documentos longos: não defina diretamente o ctx como 16000 ou mais; use uma estratégia de chunking
- Divida o documento em trechos menores e processe um de cada vez
- É mais estável e controlável do que enviar tudo de uma vez
Defina o tamanho do contexto no Modelfile:
FROM llama3
PARAMETER num_ctx 2048 # Reduzir o tamanho do contexto
É importante desfazer um equívoco comum: muita gente acredita que reduzir o ctx prejudica a qualidade da saída. Não é assim. O ctx determina apenas quanto da conversa anterior o modelo consegue “lembrar”. Se a conversa tem poucas rodadas, usar 2048 ou 4096 produz o mesmo resultado.
3.3 Otimização de lotes e concorrência
O parâmetro num_batch controla quantos tokens são processados de uma vez. O valor padrão é 512, ou seja, o Ollama processa 512 tokens de inferência por lote.
Qual é a vantagem de um lote grande? Maior eficiência no processamento paralelo. O custo é um pico mais alto no uso de VRAM.
Quando a memória está no limite, reduzir o lote ajuda a diminuir esse pico:
FROM llama3
PARAMETER num_batch 256 # Reduzir de 512 para 256
Nos testes práticos, reduzir o batch de 512 para 256 diminuiu o pico de VRAM em cerca de 20%. A inferência fica um pouco mais lenta, mas a queda não é tão grande quanto ao reduzir o número de camadas na GPU.
O problema das solicitações simultâneas
Por padrão, o Ollama processa as solicitações em série: termina uma antes de iniciar a próxima. Se várias forem enviadas ao mesmo tempo, elas ficam na fila.
Há duas formas de aumentar a capacidade concorrente:
- Implantar várias instâncias: use a solução de balanceamento entre várias GPUs descrita acima; cada instância processa solicitações de forma independente
- Usar um sistema de filas: adicione uma fila na camada da aplicação, como Redis Queue, e gerencie a distribuição das solicitações
A segunda opção é mais adequada quando você não tem várias GPUs. No código da aplicação, o fluxo pode ser assim:
import redis
from queue import Queue
# Usar o Redis como fila
r = redis.Redis()
r.lpush('ollama_queue', request_data)
# O worker em segundo plano retira solicitações da fila para processá-las
request = r.rpop('ollama_queue')
ollama.generate(request)
4. Casos práticos: três situações reais
Depois da teoria, estes são alguns problemas reais e as soluções aplicadas.
4.1 Cenário 1: executar um modelo 13B com estabilidade em 8 GB de VRAM
Problema
O usuário tem uma RTX 3060 com 8 GB de VRAM e quer executar o modelo Llama 2 13B Q4. O próprio modelo precisa de cerca de 8 GB e cabe por pouco. Depois de algumas inferências, porém, começam os erros de OOM porque o KV cache esgota a memória.
Solução
A ideia central é reduzir o uso do KV cache e o pico de VRAM.
FROM llama2:13b-q4
PARAMETER num_gpu 30 # O modelo 13B tem 40 camadas; colocar apenas 30 na GPU
PARAMETER low_vram true # Ativar o modo de pouca VRAM e colocar o KV cache na memória da CPU
PARAMETER num_ctx 2048 # Reduzir o contexto pela metade e também diminuir o KV cache pela metade
PARAMETER num_batch 256 # Reduzir o lote para diminuir o pico de memória
Com esses parâmetros combinados, o uso de VRAM se mantém estável em torno de 6 GB, deixando 2 GB de margem para oscilações.
Resultado
- Uso de VRAM: caiu de cerca de 8 GB para aproximadamente 6 GB, com execução estável
- Velocidade de inferência: cerca de 8 tokens/s, mais lenta que o uso integral da GPU, mas muito mais rápida que apenas CPU
- Estabilidade: os travamentos por OOM deixaram de ocorrer
O custo é uma inferência um pouco mais lenta. Dez camadas precisam ser processadas pela CPU, e toda passagem entre GPU e CPU gera transferência de dados. Ainda assim, a configuração se torna utilizável e deixa de travar inesperadamente.
4.2 Cenário 2: aumentar a vazão com balanceamento entre duas GPUs
Problema
O usuário tem duas RTX 3090, cada uma com 24 GB de VRAM, e implantou o Ollama como um serviço de API externo. Uma única instância processa apenas uma solicitação por vez, a concorrência é baixa e, nos horários de pico, a fila cresce bastante.
O nvidia-smi mostra uma grande diferença de utilização entre as placas: uma fica constantemente acima de 70%, enquanto a outra permanece perto de 20%.
Solução
Usar várias instâncias com balanceamento de carga no Nginx, como explicado em detalhes na seção 2. Este é o script completo de inicialização:
#!/bin/bash
# start_ollama_cluster.sh
# Instância 1: GPU 0
CUDA_VISIBLE_DEVICES=0 \
OLLAMA_HOST=127.0.0.1:11434 \
OLLAMA_MODELS=/home/user/.ollama \
nohup ollama serve > ollama1.log 2>&1 &
# Instância 2: GPU 1
CUDA_VISIBLE_DEVICES=1 \
OLLAMA_HOST=127.0.0.1:11435 \
OLLAMA_MODELS=/home/user/.ollama \
nohup ollama serve > ollama2.log 2>&1 &
# Pré-carregar o modelo nas duas instâncias
sleep 5
curl http://127.0.0.1:11434/api/pull -d '{"name": "llama3"}'
curl http://127.0.0.1:11435/api/pull -d '{"name": "llama3"}'
echo "Cluster do Ollama iniciado nas portas 11434 e 11435"
A configuração do Nginx usa least_conn para distribuir as solicitações de maneira uniforme.
Resultado
- Vazão total: aumento de cerca de 80% ao passar de uma instância em série para duas em paralelo
- Utilização por GPU: passou de uma média de 40% para 80%, com as duas placas trabalhando
- Latência de resposta: redução de cerca de 50% nos horários de pico, pois as solicitações deixaram de esperar na fila
Nos testes práticos, uma única instância levou cerca de 10 minutos para processar 100 solicitações; com duas instâncias balanceadas, o tempo caiu para pouco mais de 5 minutos.
4.3 Cenário 3: automatizar a alocação dinâmica de VRAM
Problema
O usuário trabalha com vários modelos de tamanhos diferentes e precisa ajustar manualmente a quantidade de camadas na GPU a cada troca. Quando esquece de mudar a configuração, o processo trava. É possível automatizar isso?
Solução
Criar um script que escolha automaticamente a configuração adequada do Modelfile com base na VRAM disponível.
#!/bin/bash
# auto_offload.sh - Configuração automática de GPU offloading
# Obter a VRAM livre atual da GPU, em MB
GPU_MEM_FREE=$(nvidia-smi --query-gpu=memory.free --format=csv,noheader,nounits | head -1)
# Referência de tamanho dos modelos, em MB
declare -A MODEL_SIZES
MODEL_SIZES["llama3:8b-q4"]=5000
MODEL_SIZES["llama3:70b-q4"]=40000
MODEL_SIZES["mistral:7b-q4"]=4500
MODEL_NAME=$1
if [ -z "$MODEL_NAME" ]; then
echo "Uso: $0 <nome_do_modelo>"
exit 1
fi
MODEL_SIZE=${MODEL_SIZES[$MODEL_NAME]}
if [ -z "$MODEL_SIZE" ]; then
echo "Tamanho desconhecido para o modelo $MODEL_NAME"
exit 1
fi
# Verificar se há VRAM suficiente para usar apenas a GPU
if [ $GPU_MEM_FREE -gt $MODEL_SIZE ]; then
# Offloading completo para GPU
echo "Usando offloading completo para GPU (memória suficiente)"
cat > /tmp/modelfile_temp <<EOF
FROM $MODEL_NAME
PARAMETER num_gpu -1 # -1 indica uso integral da GPU
PARAMETER low_vram false
EOF
else
# GPU parcial: calcular a proporção adequada de camadas
OFFLOAD_RATIO=$((GPU_MEM_FREE * 100 / MODEL_SIZE))
echo "Usando offloading parcial para GPU ($OFFLOAD_RATIO%)"
cat > /tmp/modelfile_temp <<EOF
FROM $MODEL_NAME
PARAMETER num_gpu $OFFLOAD_RATIO
PARAMETER low_vram true
PARAMETER num_ctx 2048
EOF
fi
# Criar o modelo
ollama create "${MODEL_NAME}-auto" -f /tmp/modelfile_temp
echo "Modelo ${MODEL_NAME}-auto criado com configuração automática"
Como usar:
# Executar o script para criar automaticamente uma configuração adequada
./auto_offload.sh llama3:70b-q4
Resultado
- Adaptação automática às mudanças na VRAM disponível
- Menos erros de configuração manual
- Troca de modelo sem precisar ajustar os parâmetros toda vez
O script ainda pode ser ampliado. É possível adicionar monitoramento para mudar automaticamente para o modo de pouca VRAM quando faltar memória, ou combinar a solução com uma tarefa agendada que pré-carrega o modelo durante a madrugada, quando não há usuários.
5. Boas práticas e monitoramento: configurações recomendadas, ferramentas e problemas comuns
5.1 Configurações recomendadas por quantidade de VRAM
Esta tabela de consulta rápida ajuda a escolher uma configuração adequada ao seu hardware:
| VRAM | Modelo recomendado | Quantização | Camadas na GPU | Outros parâmetros |
|---|---|---|---|---|
| 6 GB | Modelo 7B | Q4 | Parcial, cerca de 50% | low_vram=true, ctx=2048 |
| 8 GB | Modelo 7B | Q4 | GPU completa | ctx=2048, por segurança |
| 8 GB | Modelo 13B | Q4 | Parcial, cerca de 75% | low_vram=true, ctx=2048, batch=256 |
| 12 GB | Modelo 13B | Q4 | GPU completa | É possível usar ctx=4096 |
| 16 GB | Modelo 13B | Q8 ou Q5 | GPU completa | ctx=4096 |
| 16 GB | Modelo 70B | Q4 | Parcial, cerca de 50% | low_vram=true |
| 24 GB | Modelo 70B | Q4 | GPU completa | É possível usar ctx=4096 |
| 48 GB, duas placas | Modelo 70B | Q4 | GPU completa | Balanceamento entre várias instâncias |
Observação: estas são estimativas conservadoras. Na prática, também é preciso considerar o KV cache e o espaço reservado pelo sistema. Em conversas longas, com contexto maior, uma configuração mais conservadora tende a ser mais estável.
5.2 Ferramentas para monitorar a VRAM
Monitoramento em tempo real com nvidia-smi
A forma mais simples é:
# Atualizar a cada segundo
nvidia-smi -l 1
# Exibir apenas o uso da VRAM
nvidia-smi --query-gpu=memory.used,memory.free --format=csv -l 1
A saída mostra o uso de memória de cada placa. Ao observar os valores durante a inferência, você consegue identificar como a VRAM aumenta.
Logs detalhados do Ollama
ollama run llama3 --verbose
A saída mostra informações detalhadas sobre o carregamento do modelo, incluindo:
- Número de camadas com GPU offloading
- Uso de memória do modelo
- Se o mmap está ativo
- Alocação do KV cache
Ao ver uma mensagem como GPU offloading: 40/40 layers, você sabe que todas as camadas do modelo estão na GPU.
Exemplo de script de monitoramento
Para acompanhar o uso da VRAM por períodos mais longos, você pode criar um script que registre os dados em um log:
#!/bin/bash
# monitor_gpu.sh
LOG_FILE="gpu_memory.log"
while true; do
TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
GPU_MEM=$(nvidia-smi --query-gpu=memory.used,memory.free --format=csv,noheader)
echo "$TIMESTAMP $GPU_MEM" >> $LOG_FILE
sleep 5
done
Deixe o script rodando em segundo plano para consultar os dados históricos quando necessário.
5.3 Solução de problemas comuns
Problema 1: OOM durante a inferência
Siga estas etapas:
- Verifique o
nvidia-smipara confirmar que a VRAM realmente acabou - Confira a configuração atual:
- A quantização é Q4? Se não for, mude para Q4
- O tamanho do contexto está grande demais? Reduza para 2048
- O lote está grande demais? Reduza para 256
- Todas as camadas estão na GPU? Retire algumas delas
- Se os ajustes anteriores não resolverem, ative
low_vram=true
Ordem de prioridade: quantização > ctx > batch > número de camadas na GPU > low_vram
Problema 2: inferência lenta
Primeiro, confirme se o número de camadas com GPU offloading é insuficiente:
ollama run your_model --verbose | grep "GPU offloading"
Se a saída mostrar GPU offloading: 20/40 layers, metade das camadas está sendo calculada pela CPU, e a lentidão é esperada.
Solução: reduza o nível de quantização, passando de Q4 para Q8, ou use uma placa com mais VRAM. Se nenhuma opção for possível, será necessário aceitar essa velocidade.
Problema 3: a VRAM oscila muito e fica instável
A principal causa das oscilações é o KV cache. Quanto mais longa a conversa, maior o cache.
Solução: limite o tamanho do contexto ou controle o histórico na camada da aplicação, mantendo, por exemplo, apenas as dez rodadas mais recentes.
Problema 4: depois de configurar várias GPUs, apenas uma é usada
Verifique se a configuração do Nginx entrou em vigor:
curl http://localhost:8080/api/tags
Se a resposta mostrar apenas um modelo, isso indica que as solicitações estão sendo distribuídas.
Se houver grande diferença de utilização entre as duas placas, as causas possíveis são:
- A estratégia
least_connnão foi configurada - Uma das instâncias apresentou problema; verifique os logs
- O modelo foi carregado em apenas uma das instâncias
Resumo
Depois de todos esses detalhes, os pontos principais são:
- Quando faltar VRAM, ajuste primeiro a quantização: Q4 usa 75% menos memória que FP16 e causa pouca perda de qualidade
- Observe o uso do KV cache: o tamanho do contexto afeta diretamente o cache, e conversas longas pressionam mais a VRAM
- Use balanceamento para várias GPUs: uma única instância tem utilidade limitada; várias instâncias com Nginx são a solução adequada
- Entenda o funcionamento do llama.cpp: GPU offloading não é mágica, mas um cálculo dividido por camadas que gera custo de transferência de dados
Estas são algumas configurações prontas para uso:
Configuração estável para 8 GB de VRAM:
PARAMETER num_gpu 30
PARAMETER low_vram true
PARAMETER num_ctx 2048
PARAMETER num_batch 256
Inicialização com balanceamento entre duas GPUs:
CUDA_VISIBLE_DEVICES=0 OLLAMA_HOST=127.0.0.1:11434 ollama serve &
CUDA_VISIBLE_DEVICES=1 OLLAMA_HOST=127.0.0.1:11435 ollama serve &
Se este conteúdo foi útil, confira os outros textos da série. O sexto explica os fundamentos de quantização e processamento em lote; este aprofunda a parte de GPU. O oitavo aborda a implantação paralela de vários modelos e aplica a configuração com várias GPUs a cenários mais complexos.
Em caso de dúvida, procure no GitHub Discussions do Ollama, onde a comunidade já discutiu muitos problemas práticos. Você também pode deixar um comentário; responderei quando vir.
FAQ
O Ollama consegue dividir um modelo entre várias GPUs para fazer cálculos em paralelo?
Por que o modelo carrega corretamente, mas apresenta OOM depois de algumas inferências?
• Reduza o tamanho do contexto (num_ctx)
• Ative o modo low_vram
• Encurte o histórico da conversa
Qual parâmetro devo ajustar primeiro quando falta VRAM?
O parâmetro num_gpu indica quantas GPUs eu tenho?
Qual estratégia usar para balancear a carga entre várias GPUs?
Que tamanho de modelo cabe em 8 GB de VRAM?
• 7B Q4: tudo na GPU, ctx=2048
• 13B Q4: GPU parcial (cerca de 75%), com low_vram + ctx=2048 + batch=256
• Modelos maiores exigem mais VRAM ou offloading para CPU
21 min de leitura · Publicado em: 11 abr 2026 · Atualizado em: 4 set 2026
Guia Ollama LLM local
Se você chegou pela busca, o caminho mais rápido é ir para o post anterior ou próximo desta série.
Anterior
Ollama Modelfile: parâmetros e modelos personalizados
Entenda os 10 principais parâmetros do Ollama Modelfile, ajuste temperature e num_ctx e use quatro modelos prontos para criar versões personalizadas.
Parte 3 de 13
Próximo
Otimização de desempenho do Ollama na prática: guia de quantização, lotes e memória
Veja como escolher entre quantizações Q4, Q5 e Q8 no Ollama, ajustar num_batch para aumentar a vazão e gerenciar a memória da GPU para evitar erros de OOM.
Parte 5 de 13



Comentários
Entre com GitHub para comentar