Neste guia técnico, vamos microajustar o modelo DeepSeek-R1-Distill-Llama-8B para tarefas de raciocínio clínico, utilizando um conjunto de dados de cadeia de pensamento médico do Hugging Face. O DeepSeek-R1 é um modelo de raciocínio de código aberto que oferece desempenho comparável a modelos proprietários, e sua versão destilada mantém capacidades avançadas em um pacote mais eficiente.
Conceitos Fundamentais do DeepSeek R1
O DeepSeek-R1-Zero foi treinado exclusivamente com aprendizado por reforço em larga escala, permitindo que o modelo desenvolvesse raciocínio autônomo de cadeia de pensamento. No entanto, apresentava desafios como repetição de etapas e legibilidade reduzida. A versão DeepSeek-R1 aprimorada introduz dados de inicialização a frio antes do treinamento por reforço, melhorando a coerência e a eficiência em tarefas de lógica e diagnóstico.
Os modelos destilados do DeepSeek, com parâmetros variando de 1.5B a 70B, retêm fortes capacidades de raciocínio. Por exemplo, o DeepSeek-R1-Distill-Qwen-32B supera modelos comparáveis em benchmarks específicos, demonstrando a eficácia da destilação.
Passos para Microajustamento
1. Configuração do Ambiente
Utilizaremos uma plataforma com GPU, como Kaggle, e o framework Unsloth para microajustamento eficiente. Comece instalando as dependências necessárias:
!pip install unsloth
!pip install --upgrade --no-cache-dir git+https://github.com/unslothai/unsloth.git
Autentique-se no Hugging Face Hub e no Weights & Biases para gerenciar modelos e experimentos:
from huggingface_hub import login
from kaggle_secrets import UserSecretsClient
segredos = UserSecretsClient()
token_hf = segredos.get_secret("HUGGINGFACE_TOKEN")
login(token_hf)
import wandb
token_wb = segredos.get_secret("wandb")
wandb.login(key=token_wb)
execucao = wandb.init(project='Microajustamento-DeepSeek-R1-Medico', job_type="training")
2. Carregamento do Modelo e Tokenizer
Carregue a versão Unsloth do modelo com quantização de 4 bits para otimizar memória:
from unsloth import FastLanguageModel
comprimento_max_seq = 2048
tipo_dado = None
carregar_em_4bit = True
modelo, tokenizador = FastLanguageModel.from_pretrained(
model_name="unsloth/DeepSeek-R1-Distill-Llama-8B",
max_seq_length=comprimento_max_seq,
dtype=tipo_dado,
load_in_4bit=carregar_em_4bit,
token=token_hf,
)
3. Inferência Pré-microajustamento
Defina um modelo de prompt para guiar o raciocínio do modelo. Este prompt instrui o modelo a pensar passo a passo antes de responder:
modelo_prompt = """
Abaixo está uma instrução que descreve uma tarefa, acompanhada de uma entrada com contexto adicional.
Escreva uma resposta que complete adequadamente a solicitação.
Antes de responder, considere cuidadosamente a questão e crie uma cadeia de pensamentos passo a passo para garantir uma resposta lógica e precisa.
### Instrução:
Você é um especialista médico com conhecimento avançado em raciocínio clínico, diagnósticos e planejamento de tratamento.
Por favor, responda à seguinte questão médica.
### Questão:
{}
### Resposta:
{}
"""
Execute uma inferência de teste com uma questão médica para verificar o comportamento inicial do modelo:
questao = "Uma mulher de 61 anos com histórico de perda urinária involuntária durante atividades como tosse ou espirro, mas sem vazamentos noturnos, passa por exame ginecológico e teste de Q-tip. Com base nesses achados, o que a cistometria provavelmente revelaria sobre seu volume residual e contrações do detrusor?"
FastLanguageModel.for_inference(modelo)
entradas = tokenizador([modelo_prompt.format(questao, "")], return_tensors="pt").to("cuda")
saidas = modelo.generate(
input_ids=entradas.input_ids,
attention_mask=entradas.attention_mask,
max_new_tokens=1200,
use_cache=True,
)
resposta = tokenizador.batch_decode(saidas)
print(resposta[0].split("### Resposta:")[1])
O modelo gera uma cadeia de raciocínio, mas a resposta pode ser verbosa. O microajustamento visará refinar a precisão e a concisão.
4. Preparação do Conjunto de Dados
Adapte o modelo de prompt para incluir uma seção de cadeia de pensamento complexa durante o treinamento:
modelo_prompt_treino = """
Abaixo está uma instrução que descreve uma tarefa, acompanhada de uma entrada com contexto adicional.
Escreva uma resposta que complete adequadamente a solicitação.
Antes de responder, considere cuidadosamente a questão e crie uma cadeia de pensamentos passo a passo para garantir uma resposta lógica e precisa.
### Instrução:
Você é um especialista médico com conhecimento avançado em raciocínio clínico, diagnósticos e planejamento de tratamento.
Por favor, responda à seguinte questão médica.
### Questão:
{}
### Resposta:
{}
{}
"""
Crie uma função para formatar o conjunto de dados, preenchendo os placeholders com questões, cadeias de pensamento e respostas:
TOKEN_FIM = tokenizador.eos_token
def formatar_exemplos(exemplos):
entradas = exemplos["Question"]
raciocinios = exemplos["Complex_CoT"]
saidas = exemplos["Response"]
textos = []
for entrada, raciocinio, saida in zip(entradas, raciocinios, saidas):
texto = modelo_prompt_treino.format(entrada, raciocinio, saida) + TOKEN_FIM
textos.append(texto)
return {"text": textos}
Carregue um subconjunto do conjunto de dados médico do Hugging Face e aplique a formatação:
from datasets import load_dataset
conjunto_dados = load_dataset("FreedomIntelligence/medical-o1-reasoning-SFT", split="train[:500]")
conjunto_dados = conjunto_dados.map(formatar_exemplos, batched=True)
5. Configuração do Modelo para Treinamento
Aplicação de LoRA (Adaptadores de Baixa Classe) para microajustamento eficiente:
modelo = FastLanguageModel.get_peft_model(
modelo,
r=16,
target_modules=["q_proj", "k_proj", "v_proj", "o_proj", "gate_proj", "up_proj", "down_proj"],
lora_alpha=16,
lora_dropout=0,
bias="none",
use_gradient_checkpointing="unsloth",
random_state=3407,
)
Configure os argumentos de treinamento e o treinador:
from trl import SFTTrainer
from transformers import TrainingArguments
from unsloth import is_bfloat16_supported
treinador = SFTTrainer(
model=modelo,
tokenizer=tokenizador,
train_dataset=conjunto_dados,
dataset_text_field="text",
max_seq_length=comprimento_max_seq,
args=TrainingArguments(
per_device_train_batch_size=2,
gradient_accumulation_steps=4,
warmup_steps=5,
max_steps=60,
learning_rate=2e-4,
fp16=not is_bfloat16_supported(),
bf16=is_bfloat16_supported(),
logging_steps=10,
optim="adamw_8bit",
weight_decay=0.01,
lr_scheduler_type="linear",
seed=3407,
output_dir="resultados",
),
)
6. Execução do Treinamento
Inicie o processo de treinamento e monitore a perda através do Weights & Biases:
estatisticas_treinamento = treinador.train()
7. Inferência Pós-microajustamento
Teste o modelo microajustado com a mesma questão médica para avaliar melhorias:
FastLanguageModel.for_inference(modelo)
entradas = tokenizador([modelo_prompt.format(questao, "")], return_tensors="pt").to("cuda")
saidas = modelo.generate(
input_ids=entradas.input_ids,
attention_mask=entradas.attention_mask,
max_new_tokens=1200,
use_cache=True,
)
resposta_final = tokenizador.batch_decode(saidas)
print(resposta_final[0].split("### Resposta:")[1])
A resposta microajustada deve ser mais concisa e precisa, com uma cadeia de raciocínio simplificada.
8. Persistência do Modelo
Salve o modelo, tokenizer e adaptadores localmente:
nome_modelo_local = "DeepSeek-R1-Medico-OT"
modelo.save_pretrained(nome_modelo_local)
tokenizador.save_pretrained(nome_modelo_local)
modelo.save_pretrained_merged(nome_modelo_local, tokenizador, save_method="merged_16bit")
Faça o upload para o Hugging Face Hub para compartilhamento:
nome_modelo_online = "seu_usuario/DeepSeek-R1-Medico-OT"
modelo.push_to_hub(nome_modelo_online)
tokenizador.push_to_hub(nome_modelo_online)
modelo.push_to_hub_merged(nome_modelo_online, tokenizador, save_method="merged_16bit")