O que aconteceu quando tentei adaptar um modelo de código de 7B num MacBook de 18 GB, com números reais de memória, perda e latência
English summary: A real QLoRA pilot on a 4-bit Qwen2.5-Coder 7B with MLX on an 18 GB M3 Pro: why the first runs hit the memory cutoff, the conservative configuration that passed, and what its numbers do and don't show.
Publicado: 11 de novembro de 2026
Tempo de leitura: 9 min
Série: lemon-code em 30 dias, parte 11 de 13
As primeiras tentativas de adaptar o modelo de 7B no meu MacBook pararam no meio. O MLX dizia que o pico estava abaixo de 14 GB, dentro do limite que eu tinha declarado. Mesmo assim, a memória livre do sistema caiu abaixo de 15%, e o corte de segurança matou o processo.
O piloto que passou usou metade das camadas e metade do rank do perfil planejado. Terminou em 200 segundos, com pico de 11,1 GB. Este post mostra o caminho entre as duas coisas, com os números reais do lemon-model.
Imagine um livro técnico enorme, já impresso. Você não pode reescrever as páginas, mas pode colar post-its com correções e anotações. Quem lê o livro com os post-its tem uma versão adaptada, e o livro original continua intacto.
LoRA é isso. Os pesos do modelo ficam congelados, e o treino ajusta pequenas matrizes ao lado deles: os post-its. QLoRA é a mesma ideia com o livro em letra miúda, ou seja, a base quantizada em 4 bits para caber na memória.
O rank r é o tamanho do post-it. Rank 4 é um post-it pequeno; rank 8, um maior. Quanto maior, mais capacidade de adaptação e mais memória.
Com o mlx-lm, um treino LoRA sobre uma base em 4 bits é um comando. Uma versão próxima do piloto que passou:
pip install "mlx-lm[train]"
mlx_lm.lora \
--model mlx-community/Qwen2.5-Coder-7B-Instruct-4bit \
--train --data ./data --config ./lora-config.yaml \
--batch-size 1 --num-layers 8 \
--iters 6 --learning-rate 1e-4 \
--grad-checkpoint --max-seq-length 4096 \
--adapter-path ./adapters
A pasta data precisa de train.jsonl; o arquivo valid.jsonl é opcional no mlx-lm e aparece no piloto para registrar a perda de validação. O lora-config.yaml define o rank usado pelo exemplo:
lora_parameters:
rank: 4
dropout: 0.0
scale: 20.0
O comando é um exemplo reduzido; a configuração completa do piloto também registrou os demais limites e parâmetros. Como a base já é 4 bits, esse ajuste é QLoRA.
Produtos gratuitos e pagos para transformar ideias em uma base que você consegue executar.
13 produtos disponíveisContinue explorando tópicos similares
Com 8 mil tokens de contexto, o modelo de 7B levou 88 segundos para começar a responder no meu M3 Pro. O de 1.5B levou 24. Este post mostra o benchmark completo e por que escolhi o maior mesmo assim.
Uma resposta com 'if n == 20: return 6765' passa em todos os testes de Fibonacci. No lemon-model ela recebe nota zero. Este post mostra o resto do sistema que impede hype de virar release.

Deep dive na destilação de conhecimento: como modelos chineses aprenderam com Claude/GPT-4 (e com a si mesmos, caso DeepSeek-R1), dark knowledge de Hinton, response vs logit distillation, por que treinar do zero custa $100M e como fine-tunar seu próprio modelo por $5 com QLoRA e Unsloth. Inclui pipeline completo de código e análise das polêmicas éticas/legais.
Checklist de 47 pontos para encontrar bugs, riscos de segurança e problemas de performance antes do lançamento.
Templates testados em produção, usados por desenvolvedores. Economize semanas de setup no seu próximo projeto.
O perfil planejado para o 7B era: batch 1, acumulação de gradiente 2, 16 camadas, rank 8, gradient checkpointing, teto declarado de 14 GB de pico.
O problema foi outro limite. O lemon-model tem uma trava que encerra o treino quando a memória livre do sistema cai abaixo de 15%. Num Mac de 18 GB, o sistema, o navegador e o resto também ocupam memória unificada. Duas tentativas com o 7B pararam nesse corte com o pico do MLX ainda abaixo de 14 GB.
A lição: o número que o framework reporta é só uma parte. O que derruba a máquina é a soma.
A solução foi reduzir a pressão sem mexer no resto:
| Parâmetro | Planejado | Piloto |
|---|---|---|
| camadas adaptadas | 16 | 8 |
| rank | 8 | 4 |
| batch | 1 | 1 |
| acumulação de gradiente | 2 | 2 |
| tamanho máximo de sequência | 2048 | 4096 |
| gradient checkpointing | sim | sim |
Dados: 6 exemplos de treino e 1 de validação, tirados de um conjunto curado de repositórios meus, com 14.066 tokens de treino planejados. Três exemplos acima de 4.096 tokens foram removidos inteiros, sem truncar.
Resultado registrado:
Numa comparação direta no exemplo de validação, a perda foi de 1,0660 na base para 1,0482 com o adapter.
Depois, uma expansão registrou seis treinos com sementes e configurações diferentes, todos abaixo do teto de 14 GB. Um deles, com semente 7, chegou a perda de validação de 0,883 com pico de 11,58 GB. Esses resultados continuam sendo evidência de treino em dados de desenvolvimento, não de desempenho no holdout.
Medi a mesma geração com e sem adapter: tempo até o primeiro token subiu de 8,4 s para 9,4 s, e tokens por segundo caíram 10,9% (de 30,6 para 27,3). A medição foi feita com a máquina já sob pressão de memória depois do treino, então é uma estimativa, não um número de produção.
O relatório do lemon-model é explícito, e eu repito aqui:
NOASSERTION e o conjunto de dados e o adapter permanecem privados, locais e não elegíveis para promoção.O registro mostra que este treino limitado terminou no Mac e produziu um adapter com hash registrado. Não comprova direitos liberados, testes de código aprovados, qualidade, generalização ou prontidão para produção. Qualidade é o próximo post.
Neste perfil, um treino LoRA sobre base quantizada terminou num Mac de 18 GB quando respeitei a memória do sistema inteiro, e não só a do framework. O piloto é pequeno de propósito: 8 camadas, rank 4, 6 exemplos. Ele registra uma execução, não prova que o modelo ficou melhor em código. Essa pergunta precisa de outra ferramenta.
Na sexta: evals antes de hype, e por que o lemon-model trava a promoção de qualquer modelo que não passe por elas.
Se o seu time quer adaptar modelos abertos com dados próprios sem mandar código para fora, montar esse pipeline com limites e rastreabilidade é um trabalho que faço na LEMON.DEV.