Treinar um pequeno modelo de linguagem (Qwen2.5-0.5B) para gerar descrições comerciais atrativas e concisas de produtos a partir de nomes e características de produtos. Este projeto integra todos os conceitos aprendidos: carregamento de modelo QLoRA, configuração LoRA, preparação de conjunto de dados, treinamento SFTTrainer, avaliação e salvamento de adaptador.
Criar um conjunto de dados sintético de 50 exemplos em formato Alpaca:
import json
dataset = [
{
"instruction": "Escreva uma descrição comercial atrativa para um produto tecnológico.",
"input": "Nome: Drone dobrável 4K. Características: Câmera estabilizada, 30 min de tempo de voo, controle por app, modo de rastreamento automático. Preço: $349,99.",
"output": "Capture o mundo de cima com nosso Drone dobrável 4K! Leve, potente e pronto para viajar. Desfrute de vídeo ultra nítido graças à sua câmera estabilizada, voe até 30 minutos sem preocupações e controle tudo do seu smartphone. Com modo de rastreamento automático, nunca perca de vista a ação. Tecnologia profissional ao alcance da sua mão. Apenas $349,99."
},
{
"instruction": "Escreva uma descrição comercial atrativa para um produto tecnológico.",
"input": "Nome: Teclado Mecânico RGB. Características: Interruptores táteis, iluminação personalizável, design ergonômico, anti-ghosting. Preço: $89,99.",
"output": "Domine cada jogo ou projeto com nosso Teclado Mecânico RGB. Projetado para quem exige precisão e estilo. Interruptores táteis que respondem ao seu toque, iluminação RGB que permite criar seu ambiente ideal e um design ergonômico que protege suas mãos durante longas sessões. Anti-ghosting assegura que cada pressionamento conte. Desempenho e elegância em um único dispositivo. Apenas $89,99."
},
# ... 48 exemplos mais
]
# Salvar como JSON
with open("product_descriptions_dataset.json", "w") as f:
json.dump(dataset, f, indent=2)
# --- Importações ---
import torch
from transformers import (
AutoModelForCausalLM,
AutoTokenizer,
BitsAndBytesConfig,
TrainingArguments
)
from peft import LoraConfig, get_peft_model, PeftModel
from trl import SFTTrainer
from datasets import Dataset
import json
import wandb
# --- Configuração Inicial ---
wandb.login() # Opcional
# --- Carregar Conjunto de Dados ---
with open("product_descriptions_dataset.json", "r") as f:
raw_data = json.load(f)
dataset = Dataset.from_list(raw_data)
# --- Carregar Modelo e Tokenizer com QLoRA ---
model_name = "Qwen/Qwen2.5-0.5B-Instruct"
bnb_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_quant_type="nf4",
bnb_4bit_compute_dtype=torch.bfloat16,
bnb_4bit_use_double_quant=True,
)
model = AutoModelForCausalLM.from_pretrained(
model_name,
quantization_config=bnb_config,
device_map="auto",
trust_remote_code=True
)
tokenizer = AutoTokenizer.from_pretrained(model_name, trust_remote_code=True)
tokenizer.pad_token = tokenizer.eos_token # Requerido para padding
# --- Configurar LoRA ---
lora_config = LoraConfig(
r=8,
lora_alpha=16,
target_modules=["q_proj", "v_proj"],
lora_dropout=0.05,
bias="none",
task_type="CAUSAL_LM"
)
model = get_peft_model(model, lora_config)
model.print_trainable_parameters()
# --- Função de Formatação ---
def formatting_prompts_func(examples):
instructions = examples["instruction"]
inputs = examples["input"]
outputs = examples["output"]
texts = []
for instruction, input_text, output in zip(instructions, inputs, outputs):
text = f"### Instrução:\n{instruction}\n\n### Entrada:\n{input_text}\n\n### Resposta:\n{output}"
texts.append(text)
return texts
# --- Configuração de Treinamento ---
training_args = TrainingArguments(
output_dir="./product_desc_results",
num_train_epochs=5,
per_device_train_batch_size=2,
gradient_accumulation_steps=8,
optim="paged_adamw_8bit",
save_steps=100,
logging_steps=25,
learning_rate=2e-4,
weight_decay=0.01,
fp16=True,
max_grad_norm=0.3,
warmup_ratio=0.03,
lr_scheduler_type="cosine",
report_to="wandb",
evaluation_strategy="no", # Pular avaliação para simplificar
save_total_limit=2,
)
# --- Criar e Executar Trainer ---
trainer = SFTTrainer(
model=model,
args=training_args,
train_dataset=dataset,
formatting_func=formatting_prompts_func,
max_seq_length=512,
tokenizer=tokenizer,
packing=False,
)
trainer.train()
# --- Salvar Adaptador ---
model.save_pretrained("./product_desc_adapter")
tokenizer.save_pretrained("./product_desc_adapter")
# --- Opcionalmente Fundir e Salvar Modelo Completo ---
# model = model.merge_and_unload()
# model.save_pretrained("./product_desc_merged")
# tokenizer.save_pretrained("./product_desc_merged")
Após o treinamento, teste o modelo em novos produtos:
def generate_product_description(product_name, features, price):
instruction = "Escreva uma descrição comercial atrativa para um produto tecnológico."
input_text = f"Nome: {product_name}. Características: {features}. Preço: ${price}."
prompt = f"### Instrução:\n{instruction}\n\n### Entrada:\n{input_text}\n\n### Resposta:\n"
inputs = tokenizer(prompt, return_tensors="pt").to(model.device)
outputs = model.generate(
**inputs,
max_new_tokens=200,
temperature=0.7,
top_p=0.9,
do_sample=True
)
full_text = tokenizer.decode(outputs[0], skip_special_tokens=True)
response = full_text.split("### Resposta:")[-1].strip()
return response
# Testar
desc = generate_product_description(
"Alto-falante Bluetooth à Prova d'Água",
"20W de potência, 15 horas de bateria, conexão multi-ponto, design portátil",
"79,99"
)
print(desc)
Saída Esperada (Exemplo):
*"Leve a festa a qualquer lugar com nosso Alto-falante Bluetooth à Prova d'Água. Pura potência de 20W que enche qualquer espaço com som imersivo. Desfrute até 15 horas de música ininterrupta, conecte dois dispositivos simultaneamente e leve-o à praia, piscina ou montanha com seu design resistente e portátil. Diversão sem restrições onde quer que você vá. Apenas $79,99."