Pular para o conteúdo principal

Ajuste fino de Qwen3: Um guia passo a passo

Um guia passo a passo para fazer o ajuste fino do modelo Qwen3-32B no conjunto de dados de raciocínio médico em uma hora.
· 8 min leer

Explore com IA

Com base no sucesso do QwQ e do Qwen2.5o Qwen3 representa um grande avanço em termos de raciocínio, criatividade e recursos de conversação. Com acesso aberto a modelos densos e modelos Mixture-of-Experts (MoE)com parâmetros que variam de 0,6B a 235B-A22B, o Qwen3 foi projetado para se destacar em uma ampla gama de tarefas.

Neste tutorial, faremos o ajuste fino do modelo Qwen3-32B em um conjunto de dados de raciocínio médico. O objetivo é otimizar a capacidade do modelo de raciocinar e responder com precisão às consultas dos pacientes, garantindo que ele adote uma abordagem precisa e eficiente para responder a perguntas médicas. 

Mantemos nossos leitores atualizados sobre as últimas novidades em IA enviando o The Median, nosso boletim informativo gratuito de sexta-feira que detalha as principais histórias da semana. Inscreva-se e fique atento em apenas alguns minutos por semana:

Se você quiser saber mais sobre o Qwen 3 e como ele se comporta, consulte nosso guia de introdução ao modelo, Qwen 3: Recursos, comparação do DeepSeek-R1, acesso e muito mais.

Ajuste fino das imagens de recursos do Qwen3

Imagem do autor

1. Configuração

Vá para seu RunPod e verifique se você tem um mínimo de US$ 5 em sua conta. Em seguida, escolha o modelo A100 SXM e selecione a versão mais recente do PyTorch. Por fim, clique no botão "Deploy On-Demand" para iniciar seu Pod.

Configuração do pod Runpod

Fonte: Meus pods

Modifique as configurações do Pod e ajuste o tamanho do disco do contêiner para 100 GB. Além disso, inclua seu token de acesso ao Hugging Face como uma variável de ambiente.

Alterando o armazenamento e definindo a variável de ambiente

Fonte: Meus pods

Depois que as configurações forem aplicadas, clique em "Connect" (Conectar) para iniciar o Jupyter Lab. 

Runpod, o pod está funcionando

Fonte: Meus pods

O Jupyter Lab vem pré-instalado com os pacotes e extensões necessários, permitindo que você inicie o treinamento sem configurações adicionais.

Runpod, Jupyter Notebook.

Fonte: Meus pods

Antes de continuar, verifique se todos os pacotes Python necessários estão instalados e atualizados. 

Execute os seguintes comandos em uma célula do Jupyter Notebook:

%%capture
%pip install -U accelerate 
%pip install -U peft 
%pip install -U trl 
%pip install -U bitsandbytes
%pip install -U transformers

Use o token de acesso Hugging Face que você salvou anteriormente para fazer login no Hugging Face Hub. 

from huggingface_hub import login
import os

hf_token = os.environ.get("HF_TOKEN")
login(hf_token)

2. Carregando o modelo e o tokenizador

Embora tenhamos 80 GB de VRAM, carregaremos o modelo Qwen3 usando quantização de 4 bits. quantização de 4 bits. Isso nos permitirá ajustar facilmente o modelo na GPU e fazer o ajuste fino sem problemas. 

Baixe e carregue o modelo Qwen3-32B e o tokenizador do Hugging Face Hub.

from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig
import torch

bnb_config = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_use_double_quant=False,
    bnb_4bit_quant_type="nf4",
    bnb_4bit_compute_dtype=torch.bfloat16,
)

model_dir = "Qwen/Qwen3-32B"
tokenizer = AutoTokenizer.from_pretrained(model_dir, use_fast=True)
model = AutoModelForCausalLM.from_pretrained(
    model_dir,
    quantization_config=bnb_config,   
    device_map="auto",  
    torch_dtype=torch.bfloat16,
    trust_remote_code=True             
)

model.config.use_cache = False
model.config.pretraining_tp = 1

Baixando o modelo e o tokenizador3. Carregamento e processamento do conjunto de dados

Nesta seção, vamos nos concentrar no desenvolvimento de um estilo de prompt que incentive o modelo a se envolver no pensamento crítico. Criaremos uma estrutura de prompt que inclui um prompt de sistema com espaços reservados para a pergunta, uma cadeia de pensamento e a resposta final. 

train_prompt_style = """Below is an instruction that describes a task, paired with an input that provides further context. 
Write a response that appropriately completes the request. 
Before answering, think carefully about the question and create a step-by-step chain of thoughts to ensure a logical and accurate response.

### Instruction:
You are a medical expert with advanced knowledge in clinical reasoning, diagnostics, and treatment planning. 
Please answer the following medical question. 

### Question:
{}

### Response:
<think>
{}
</think>
{}"""

Em seguida, criaremos a função Python que usará o estilo de prompt de trem e aplicará o respectivo valor a ele para criar a coluna "text".

EOS_TOKEN = tokenizer.eos_token  # Must add EOS_TOKEN

def formatting_prompts_func(examples):
    inputs = examples["Question"]
    complex_cots = examples["Complex_CoT"]
    outputs = examples["Response"]
    texts = []
    for question, cot, response in zip(inputs, complex_cots, outputs):
        # Append the EOS token to the response if it's not already there
        if not response.endswith(tokenizer.eos_token):
            response += tokenizer.eos_token
        text = train_prompt_style.format(question, cot, response)
        texts.append(text)
    return {"text": texts}

Em seguida, carregaremos as primeiras 2.000 amostras do arquivo FreedomIntelligence/medical-o1-reasoning-SFT e, em seguida, aplicaremos a função formatting_prompts_func para criar a coluna "text".

from datasets import load_dataset

dataset = load_dataset(
    "FreedomIntelligence/medical-o1-reasoning-SFT",
    "en",
    split="train[0:2000]",
    trust_remote_code=True,
)
dataset = dataset.map(
    formatting_prompts_func,
    batched=True,
)
dataset["text"][10]

Como você pode ver, a coluna de texto contém o prompt do sistema, as instruções, as perguntas, a cadeia de raciocínio e as respostas à pergunta.

11ª amostra do conjunto de dados

O novo instrutor do STF não aceita o tokenizador, portanto, converteremos o tokenizador em um coletor de dados usando a função de transformação simples.

from transformers import DataCollatorForLanguageModeling

data_collator = DataCollatorForLanguageModeling(
    tokenizer=tokenizer,
    mlm=False
)

4. Inferência de modelo antes do ajuste fino

O estilo do prompt de inferência é diferente do prompt de trem. Ele inclui tudo do estilo de prompt de treinamento, exceto a cadeia de pensamento e a resposta.

inference_prompt_style = """Below is an instruction that describes a task, paired with an input that provides further context. 
Write a response that appropriately completes the request. 
Before answering, think carefully about the question and create a step-by-step chain of thoughts to ensure a logical and accurate response.

### Instruction:
You are a medical expert with advanced knowledge in clinical reasoning, diagnostics, and treatment planning. 
Please answer the following medical question. 

### Question:
{}

### Response:
<think>

"""

Para testar o desempenho do modelo antes do ajuste fino, pegaremos a 11ª amostra do conjunto de dados e a forneceremos ao modelo após a formatação e a conversão em tokens.

question = dataset[10]['Question']
inputs = tokenizer(
    [inference_prompt_style.format(question) + tokenizer.eos_token],
    return_tensors="pt"
).to("cuda")

outputs = model.generate(
    input_ids=inputs.input_ids,
    attention_mask=inputs.attention_mask,
    max_new_tokens=1200,
    eos_token_id=tokenizer.eos_token_id,
    use_cache=True,
)
response = tokenizer.batch_decode(outputs, skip_special_tokens=True)
print(response[0].split("### Response:")[1])

Como resultado, recebemos um longo período de reflexão e nenhuma resposta, mesmo depois dos 1.200 novos tokens. Isso é bem diferente do conjunto de dados, que é curto e conciso.

Inferência de modelo antes do ajuste fino

5. Configuração do modelo

Agora vamos implementar LoRA (Low-Rank Adaptation). O LoRA funciona congelando a maioria dos parâmetros do modelo e introduzindo um pequeno conjunto de parâmetros treináveis, que são adicionados em um formato de decomposição de baixa classificação. Isso permite que o modelo se adapte a novas tarefas sem a necessidade de atualizar ou armazenar o conjunto completo de pesos do modelo.

Essa abordagem é eficiente em termos de memória, mais rápida e econômica e, ao mesmo tempo, atinge uma precisão comparável ao ajuste fino completo.

from peft import LoraConfig, get_peft_model

# LoRA config
peft_config = LoraConfig(
    lora_alpha=16,                           # Scaling factor for LoRA
    lora_dropout=0.05,                       # Add slight dropout for regularization
    r=64,                                    # Rank of the LoRA update matrices
    bias="none",                             # No bias reparameterization
    task_type="CAUSAL_LM",                   # Task type: Causal Language Modeling
    target_modules=[
        "q_proj",
        "k_proj",
        "v_proj",
        "o_proj",
        "gate_proj",
        "up_proj",
        "down_proj",
    ],  # Target modules for LoRA
)

model = get_peft_model(model, peft_config)

Agora vamos configurar e inicializar o SFTTrainer (Supervised Fine-Tuning Trainer), uma abstração de alto nível fornecida pelas bibliotecas de transformadores e trl da Hugging Face. O SFTTrainer simplifica o processo de ajuste fino ao integrar os principais componentes, como conjunto de dados, modelo, agrupador de dados, argumentos de treinamento e configuração de LoRA, em um único fluxo de trabalho otimizado. 

from trl import SFTTrainer
from transformers import TrainingArguments


# Training Arguments
training_arguments = TrainingArguments(
    output_dir="output",
    per_device_train_batch_size=1,
    per_device_eval_batch_size=1,
    gradient_accumulation_steps=2,
    optim="paged_adamw_32bit",
    num_train_epochs=1,
    logging_steps=0.2,
    warmup_steps=10,
    logging_strategy="steps",
    learning_rate=2e-4,
    fp16=False,
    bf16=False,
    group_by_length=True,
    report_to="none"
)

# Initialize the Trainer
trainer = SFTTrainer(
    model=model,
    args=training_arguments,
    train_dataset=dataset,
    peft_config=peft_config,
    data_collator=data_collator,
)

6. Treinamento de modelos

Antes de iniciarmos o treinamento, limparemos o cache e liberaremos um pouco de RAM e VRAM da GPU para evitar problemas de falta de memória (OOM) durante o processo de treinamento. Veja como podemos fazer isso:

import gc, torch
gc.collect()
torch.cuda.empty_cache()
model.config.use_cache = False
trainer.train()

Quando o treinamento começar, você perceberá que o pod está usando 100% da GPU e 85% da VRAM da GPU. Isso indica que atingimos o ponto ideal.

Utilização da memória e da computação da GPU

O tempo de treinamento levou 42 minutos para ser concluído e, como você pode ver, a perda de treinamento diminuiu gradualmente.

Perda de treinamento

7. Inferência de modelos após o ajuste fino

Agora, testaremos o modelo ajustado na mesma amostra de antes e compararemos os resultados.

question = dataset[10]['Question']
inputs = tokenizer(
    [inference_prompt_style.format(question) + tokenizer.eos_token],
    return_tensors="pt"
).to("cuda")

outputs = model.generate(
    input_ids=inputs.input_ids,
    attention_mask=inputs.attention_mask,
    max_new_tokens=1200,
    eos_token_id=tokenizer.eos_token_id,
    use_cache=True,
)
response = tokenizer.batch_decode(outputs, skip_special_tokens=True)
print(response[0].split("### Response:")[1])

Reduzimos a seção de raciocínio e a resposta precisa, o que se alinha com o conjunto de dados. Esse é um resultado incrível.

Inferência de modelo após o ajuste fino

Vamos testar o desempenho do Qwen3 ajustado em outra amostra do conjunto de dados.

question = dataset[100]['Question']
inputs = tokenizer(
    [inference_prompt_style.format(question) + tokenizer.eos_token],
    return_tensors="pt"
).to("cuda")

outputs = model.generate(
    input_ids=inputs.input_ids,
    attention_mask=inputs.attention_mask,
    max_new_tokens=1200,
    eos_token_id=tokenizer.eos_token_id,
    use_cache=True,
)
response = tokenizer.batch_decode(outputs, skip_special_tokens=True)
print(response[0].split("### Response:")[1])

Mais uma vez, o processo de raciocínio foi preciso e curto, e a resposta foi precisa, semelhante ao conjunto de dados.

Inferência de modelo após o ajuste fino

Se você estiver tendo problemas para fazer o ajuste fino do seu modelo Qwen3, consulte o notebook complementar: ajuste fino-qwen-3.

8. Salvando o modelo 

A etapa final é salvar o modelo e o tokenizador e carregá-los no hub Hugging Face, o que nos permite criar um aplicativo ou compartilhar o modelo com a comunidade de código aberto. 

new_model_name = "Qwen-3-32B-Medical-Reasoning"
model.push_to_hub(new_model_name)
tokenizer.push_to_hub(new_model_name)

Depois que o modelo e o tokenizador forem carregados, será gerado um link para o repositório. Por exemplo: kingabzpro/Qwen-3-32B-Medical-Reasoning - Hugging Face

kingabzpro/Qwen-3-32B-Medical-Reasoning Mode repositório no Hugging Face

Fonte: kingabzpro/Qwen-3-32B-Medical-Reasoning

O repositório de modelos tem as tags apropriadas, uma descrição, um notebook complementar e todos os arquivos necessários para você carregar e testar.

Conclusão

O Qwen-3 representa outro passo significativo em direção à democratização da IA. Você pode baixar facilmente o Qwen-3, executá-lo em seu PC (sem acesso à Internet), ajustá-lo ou até mesmo hospedá-lo em seu servidor local. Na verdade, o Qwen-3 incorpora os princípios da IA aberta.

Neste tutorial, aprendemos a fazer o ajuste fino do modelo Qwen-3 em um conjunto de dados de raciocínio médico usando a plataforma Runpod. Notavelmente, todo o processo custou menos de US$ 3. Para melhorar ainda mais o desempenho do ajuste fino, você pode treinar o modelo no conjunto de dados completo por pelo menos 3 épocas.

Você pode saber mais sobre o modelo Qwen 3 em nosso guia, Qwen 3: Recursos, comparação do DeepSeek-R1, acesso e muito mais. Você também pode ver nossos guias sobre Como usar o Qwen 2.4-VL localmente e Ajuste fino do DeepSeek R1 (modelo de raciocínio).

Abid Ali Awan

Autor

Abid Ali Awan

Sou um cientista de dados certificado que gosta de criar aplicativos de aprendizado de máquina e escrever blogs sobre ciência de dados. No momento, estou me concentrando na criação e edição de conteúdo e no trabalho com modelos de linguagem de grande porte.

Temas

Relacionado

Tutorial

Como fazer o ajuste fino do GPT 3.5: Liberando todo o potencial da IA