Fine-tuning com Ollama: Guia Prático para LLMs Locais

11 min de leitura Inteligência Artificial
Fine-tuning com Ollama: Guia Prático para LLMs Locais

A ascensão dos Modelos de Linguagem de Grande Escala (LLMs) auto-hospedados transformou a maneira como empresas e desenvolvedores lidam com inteligência artificial. Ferramentas como Ollama, LM Studio e interfaces como Open WebUI democratizaram o acesso a potências computacionais como Llama 3, Qwen e DeepSeek diretamente em ambientes locais ou em VPS dedicadas. No entanto, usar um modelo base "cru" nem sempre atende às necessidades específicas de negócios, jargões técnicos ou fluxos de trabalho proprietários.

Aqui entra o conceito de fine-tuning. Diferente do RAG (Retrieval-Augmented Generation), que consulta documentos externos em tempo real, o fine-tuning ajusta os pesos internos do modelo para internalizar conhecimento e comportamentos específicos. Neste tutorial técnico, vamos explorar como realizar um fine-tuning prático utilizando o Ollama, preparando seu ambiente Linux para treinar modelos leves e eficientes.

1. Entendendo a Abordagem: LoRA vs. Fine-Tuning Completo

Antes de executar qualquer comando, é crucial entender que refazer todo o treinamento de um modelo como Llama 3 ou Qwen é computacionalmente inviável para a maioria dos profissionais de TI independentes ou pequenas equipes. O fine-tuning completo exige centenas de GPUs e meses de processamento.

A solução moderna e eficiente é o Low-Rank Adaptation (LoRA). O LoRA congela os pesos do modelo pré-treinado e injeta uma pequena rede de camadas treináveis. Isso resulta em arquivos de ajuste minúsculos (geralmente entre 100MB e 500MB) que podem ser carregados dinamicamente pelo Ollama, mantendo a inteligência geral do modelo base enquanto adicionam especialização.

O processo que realizaremos neste guia segue a metodologia QLoRA (Quantized LoRA), que utiliza quantização de 4-bit para reduzir o uso de memória RAM/VRAM sem perda significativa de precisão. Isso permite treinar modelos robustos até em hardware consumer ou VPS de entrada.

2. Preparação do Ambiente e Dependências

O Ollama é, nativamente, uma ferramenta de inferência (execução). Para realizar o treinamento, precisamos integrar ao ecossistema de ferramentas open-source que suportam a geração de datasets e a aplicação de LoRA. A biblioteca padrão da indústria para essa tarefa é o unsloth, otimizada para velocidade e eficiência de memória, ou o axolotl.

Para este tutorial, focaremos em uma stack leve e direta, utilizando Python virtual environments para evitar conflitos de bibliotecas. Supondo que você já tenha o Ollama instalado na sua VPS Linux (Ubuntu/Debian), siga os passos abaixo.

  1. Crie um diretório de trabalho:
mkdir ~/ollama-finetune && cd ~/ollama-finetune
  1. Crie e ative um ambiente virtual Python:
python3 -m venv venv
source venv/bin/activate
  1. Instale as dependências principais. Você precisará do unsloth (ou trl e peft), transformers, datasets e bitsandbytes.
pip install unsloth transformers datasets bitsandbytes accelerate

Nota técnica: Se estiver utilizando uma GPU NVIDIA, certifique-se de que os drivers estão atualizados. O bitsandbytes requer CUDA compatível. Para CPUs ou GPUs AMD, a instalação pode variar, mas o foco deste guia é em hardware com aceleração GPU para viabilizar o treinamento em tempo razoável.

3. Estruturação do Dataset de Treinamento

O sucesso de um fine-tuning depende 80% da qualidade dos dados. O modelo não "aprende" apenas fatos; ele aprende padrões de instrução e resposta. Para que o Ollama reconheça o novo comportamento, o dataset deve estar em formato JSONL (JSON Lines), onde cada linha é um objeto JSON válido.

O formato ideal para modelos instruct como Llama 3, Qwen e DeepSeek segue a estrutura de conversação:

{
  "messages": [
    { "role": "system", "content": "Você é um assistente especializado em direito tributário brasileiro." },
    { "role": "user", "content": "Qual a alíquota do ICMS para importação?" },
    { "role": "assistant", "content": "A alíquota depende do estado de origem e destino, mas geralmente segue a tabela nacional..." }
  ]
}

Crie um arquivo chamado dataset.jsonl na raiz do seu projeto. Para testes funcionais, você pode começar com um dataset pequeno (cerca de 50 a 100 exemplos bem escritos). Modelos menores respondem bem a poucos dados de alta qualidade; modelos maiores exigem milhares.

Dica de Pro: Use o AnythingLLM ou interfaces similares para exportar conversas históricas de alta qualidade que já funcionaram bem, formatando-as para este padrão JSON. Isso garante que o modelo aprenda com interações reais e validadas.

4. Script de Treinamento LoRA

Agora, vamos escrever o script Python que orquestrará o treinamento. Este script utilizará a API do unsloth para maximizar a velocidade. O código abaixo configura a quantização 4-bit, define os hiperparâmetros de treinamento e aplica o LoRA.

Crie um arquivo chamado train.py:

from unsloth import FastLanguageModel
import torch
from datasets import load_dataset
from trl import SFTTrainer
from transformers import TrainingArguments
from unsloth import is_bfloat16_supported

# Configurações
MAX_SEQ_LENGTH = 2048
DEVICES = [0] # Use ["cpu"] se não tiver GPU, mas será lento
NUM_EPOCHS = 3
BATCH_SIZE = 2
GRADIENT_ACCUMULATION_STEPS = 4
LR = 2e-4

# Carregar o modelo base (ex: Llama 3.1 8B Instruct)
# Ajuste o nome do modelo conforme necessário
MODEL_NAME = "unsloth/Llama-3.1-8B-Instruct-bnb-4bit"

print("Carregando modelo...")
model, tokenizer = FastLanguageModel.from_pretrained(
    model_name=MODEL_NAME,
    max_seq_length=MAX_SEQ_LENGTH,
    dtype=None,
    load_in_4bit=True,
)

# Aplicar LoRA
model = FastLanguageModel.get_peft_model(
    model,
    r=16,
    target_modules=["q_proj", "k_proj", "v_proj", "o_proj",
                    "gate_proj", "up_proj", "down_proj"],
    lora_alpha=16,
    lora_dropout=0, # Suporte para dropout zero
    bias="none",
    use_gradient_checkpointing="unsloth",
    random_state=3407,
)

# Preparar dados
dataset = load_dataset("json", data_files="dataset.jsonl", split="train")

def formatting_prompts_func(examples):
    convos = examples["messages"]
    texts = [tokenizer.apply_chat_template(convo, tokenize=False) for convo in convos]
    return {"text": texts}

dataset = dataset.map(formatting_prompts_func, batched=True)

# Configurar Treinador
trainer = SFTTrainer(
    model=model,
    tokenizer=tokenizer,
    train_dataset=dataset,
    dataset_text_field="text",
    max_seq_length=MAX_SEQ_LENGTH,
    args=TrainingArguments(
        per_device_train_batch_size=BATCH_SIZE,
        gradient_accumulation_steps=GRADIENT_ACCUMULATION_STEPS,
        warmup_steps=5,
        num_train_epochs=NUM_EPOCHS,
        learning_rate=LR,
        fp16=not is_bfloat16_supported(),
        bf16=is_bfloat16_supported(),
        logging_steps=1,
        optim="adamw_8bit",
        weight_decay=0.01,
        lr_scheduler_type="linear",
        seed=3407,
    ),
)

# Iniciar treinamento
print("Iniciando fine-tuning...")
trainer_stats = trainer.train()

# Salvar o modelo ajustado
output_model_name = "meu-modelo-finetuned"
model.save_pretrained(output_model_name)
tokenizer.save_pretrained(output_model_name)
print(f"Treinamento concluído. Modelo salvo em {output_model_name}")

Análise do Código:

  • r=16: Define a dimensão da matriz de rank do LoRA. Valores entre 8 e 32 são comuns para equilibrar capacidade e tamanho.
  • target_modules: Especifica quais camadas da rede neural serão ajustadas. Para LLMs modernos, ajustar as projeções Q, K, V e as camadas MLP (gate, up, down) é essencial para adaptação eficaz.
  • gradient_accumulation_steps: Como a memória VRAM é limitada, simulamos batches maiores acumulando gradientes. Se tiver pouca RAM, aumente este número.

5. Execução e Monitoramento

Com o script salvo, execute o treinamento. Dependendo da potência da sua VPS (GPU), isso pode levar de minutos a horas.

python train.py

Durante a execução, monitore o uso de memória e GPU. O log deve mostrar a perda (loss) decrescendo a cada epoch. Se a loss não diminuir, seu dataset pode ter ruídos ou o learning rate está muito alto.

6. Convertendo para Formato GGUF e Usando no Ollama

O modelo treinado foi salvo em formato PyTorch (.pt). Para usá-lo no Ollama, precisamos convertê-lo para o formato GGUF, que é o padrão de carga eficiente do Ollama.

  1. Instale o utilitário de conversão:
pip install llama.cpp
  1. Exporte os pesos LoRA para GGUF: O processo envolve fundir o LoRA ao modelo base ou carregá-los separadamente. A maneira mais limpa no ecossistema atual é criar um arquivo Modelfile que instrua o Ollama a carregar o base e aplicar o LoRA.

Crie um arquivo chamado Modelfile:

FROM /caminho/para/meu-modelo-finetuned

# Ou, se preferir fundir os pesos antes:
# FROM /caminho/para/Llama-3.1-8B-Instruct-bnb-4bit.gguf
# ADAPTER /caminho/para/meu-modelo-finetuned/lora.safetensors

No entanto, a abordagem mais moderna com Ollama recente permite que você exporte o modelo completo já fundido. Se você preferir uma conversão direta para um único arquivo GGUF autossuficiente:

# Exemplo usando llama.cpp para converter e aplicar LoRA
python convert.py \
    --model-dir meu-modelo-finetuned \
    --output-file modelo-final.gguf \
    --outtype f16

Nota: O comando exato varia dependendo da versão do llama.cpp. A documentação oficial do Unsloth recomenda salvar o modelo e usar o script de conversão fornecido na pasta do repositório.

7. Criando a Imagem no Ollama

Depois de ter seu arquivo .gguf, crie um novo "Modelo" no Ollama para que ele apareça na lista de modelos disponíveis e possa ser chamado via API ou CLI.

  1. Crie o Modelfile:
FROM ./modelo-final.gguf

PARAMETER temperature 0.7
SYSTEM "Você é um assistente especializado em direito tributário brasileiro, baseado no treinamento fornecido."
  1. Crie a imagem do modelo:
ollama create meu-tributario -f Modelfile
  1. Teste o modelo:
ollama run meu-tributario

Faça perguntas ao modelo. Se o treinamento foi bem-sucedido, você notará uma mudança no estilo de resposta e na precisão das informações relacionadas ao domínio específico (neste caso, tributário) em comparação com o modelo base genérico.

8. Integração com RAG e Aplicações Práticas

O fine-tuning não substitui o RAG; ele o complementa. Enquanto o RAG traz dados atualizados e específicos de documentos, o fine-tuning ajusta a "personalidade" e a capacidade do modelo de seguir instruções complexas.

Para profissionais que utilizam AnythingLLM ou construções customizadas com LangChain, o fluxo ideal é:

  1. Treinar o modelo para entender a terminologia da empresa e o tom de voz.
  2. Hospedar o modelo fine-tuned no Ollama em sua VPS.
  3. Configurar o RAG para buscar documentos atualizados na base de conhecimento.
  4. Combinar no prompt: "Use o contexto fornecido e responda seguindo as diretrizes de estilo aprendidas."

Isso resulta em uma IA corporativa que não apenas sabe a resposta correta, mas responde exatamente como um funcionário experiente faria.

Considerações Finais sobre Hardware e Escalabilidade

Ao realizar fine-tuning local, o gargalo é sempre o hardware. Modelos como Llama 3 e Qwen são poderosos, mas exigem VRAM significativa para treinamento em 4-bit.

  • VPS com GPU: Procure instâncias com NVIDIA A10G ou L4. Elas oferecem bom custo-benefício para treinos de LoRA.
  • Máquinas Locais: Um MacBook M1/M2/M3 com 32GB+ de RAM unificada é surpreendentemente capaz de fine-tunar modelos até 7B-8B parâmetros usando a biblioteca Unsloth, aproveitando a memória unificada como VRAM.
  • CPU Only: É possível treinar em CPU, mas o tempo será exorbitante. Não recomendado para produção ou iterações rápidas.

O fine-tuning com Ollama abre um leque enorme de possibilidades para a autonomia digital. Ao dominar essas técnicas, você deixa de ser um consumidor passivo de APIs de IA e se torna um arquiteto de inteligência artificial proprietária, segura e adaptada às reais necessidades do seu negócio.

Compartilhar: Link copiado!
Esse tutorial foi útil?

Comentários (0)

Seja o primeiro a comentar.

Deixe seu comentário

Seu comentário será analisado antes de ser publicado.

0/2000