Ajuste fino do Laya nas tuas próprias decisões
No benchmark typed-decisions, os checkpoints base pontuam perto do acaso zero-shot — 0.36 e 0.35 contra uma linha de base aleatória de 0.318 — enquanto o checkpoint com ajuste fino atinge 0.766 nas mesmas 2,000 decisões, acima do 0.727 publicado do TypeSafe Jev e acima do teto de auto-concordância de 0.735 do professor. É no ajuste fino que está a maior parte do valor, e o notebook público de ajuste fino corre o ciclo completo nas 2xT4 gratuitas do Kaggle: construir o conjunto de dados, treinar com RLCD, ajustar as temperaturas de calibração, avaliar e enviar o resultado para o Hub. Esta página percorre esse notebook e aponta as partes que continuam a ser essenciais quando trocas os dados pelos teus.
O outro exemplo trabalhado — uma cabeça de decisão de agente de navegador numa única GPU de 16 GB sem API paga — está em Ajuste fino do Laya como cabeça de decisão de um agente de navegador.
O que o notebook faz, por ordem
| # | passo | o que acontece |
|---|---|---|
| 1 | Ambiente | verifica que ambas as GPUs T4 estão visíveis e alocadas |
| 2 | Instalação | laya, transformers, datasets e as dependências de treino |
| 3 | Pré-processamento | os 1,200 casos de treino (6,000 decisões tipadas) tornam-se itens tokenizados com alvos suaves, escritos em disco para ambos os ranks DDP |
| 4 | Treino | train_ddp.py sob torchrun --nproc_per_node=2, quatro épocas |
| 5 | Calibração | uma temperatura por tipo, ajustada numa fatia reservada antes do treino (dentro do script de treino, após a última época) |
| 6 | Avaliação | a partição oficial test, respondida pelo checkpoint com ajuste fino — 400 casos, 2,000 decisões — com latência por caso |
| 7 | Métricas | precisão, precisão suave, Brier, ECE, MAE de score, within-one-level e percentis KL/TV e de latência; uma tabela de comparação direta contra o Jev e o teto do professor |
| 8 | Publicação | (opcional) um model card construído a partir dos próprios números da execução, pasta enviada para o Hub |
| 9 | Relatório | benchmark_report.json com a tabela de métricas e a precisão por fluxo de trabalho |
Definições do Kaggle: Accelerator GPU T4 x2, Internet On. Os resultados ficam em
/kaggle/working/laya_finetuned_typed_decisions.
A receita de treino
O RLCD treina sobre as distribuições gold do benchmark, e não sobre etiquetas rígidas: cada item transporta a probabilidade que o professor atribuiu a cada opção, e ambas as metades da perda leem esse alvo —
- um termo de gradiente de política sobre projeções de logits ruidosas amostradas (estilo GRPO: quatro amostras por item, ruído de exploração com anneal de 0.4 → 0.1), recompensado por regras de pontuação próprias (spherical 0.75, ranked probability 1.0);
- um termo de entropia cruzada suave com peso total contra a mesma distribuição.
Os parâmetros que o notebook define para uma placa de 16 GB:
| épocas | 4 |
| lote efetivo | 64 sequências (8 por micro-lote, 2 GPUs, 4 passos de acumulação) |
| taxas de aprendizagem | encoder 2.5e-5, head 1e-4 — AdamW, agendamento cosseno |
| memória | autocast fp16, gradient checkpointing no encoder e na cabeça, recorte da norma do gradiente 1.0 |
| orçamento de sequência | max_len 1024, head_max_len 256, max_tokens_per_batch 4096 |
O tempo de execução em 2xT4 é de minutos para a demonstração e de horas para dados reais: cerca de 4–6 minutos para as 6,000 decisões da demonstração, e aproximadamente 4–5 horas para quatro épocas sobre ~30k perguntas.
Para o apontar aos teus dados, substitui as duas chamadas a load_dataset e mantém o esquema das
linhas: cada caso transporta state, questions e gold (as probabilidades do professor por
pergunta), e o pré-processador transforma-os em itens. Os tipos de pergunta são choice, score e
noul; tudo o que consigas expressar com eles sobre um estado serve.
A calibração faz parte da execução
É o passo com maior probabilidade de ser esquecido ao copiar o ciclo, e torna-se essencial no momento em que alguém aplica gating com base na confiança.
O notebook retira uma fatia de calibração dos dados de treino antes de os fragmentar entre os ranks (até 400 itens, ou 10%, com uma semente fixa, idêntica em todos os ranks). Ajustar temperaturas sobre itens em que a execução já treinou mede o ajuste, e não a calibração — o modelo está quase certo e quase correto neles, por isso o otimizador não tem nada para suavizar e devolve uma escala degenerada.
Após a última época, o rank 0 ajusta uma temperatura por tipo de pergunta (choice, score,
noul) por LBFGS sobre o logaritmo da temperatura, limitada a [0.1, 10] (1.0 para uma fatia
com menos de dez itens, 1.2 se o ajuste levantar uma exceção). Os valores vão para
rl_agent_config.json como temperature, e o notebook remove qualquer temperature_by_options
herdado na mesma escrita: esses valores antigos por balde têm precedência na inferência e
mascaram silenciosamente o novo ajuste.
A escala de temperatura deixa o argmax — e a precisão — inalterados; o que muda é a confiança. Os checkpoints como são distribuídos são demasiado confiantes, por isso ajusta antes de confiar em qualquer limiar, e avalia o resultado em dados reservados antes de reivindicares uma melhoria. A regressão de persistência da configuração corre sem downloads nem treino:
python tests/test_calibration_persistence.py
Avaliar antes de confiar
A avaliação é uma passagem completa pela partição oficial de teste: 400 casos, 2,000 decisões em
Agent Trace Observability, Customer Service, Invoice Processing e Security Incidents. Calcula a
precisão, a precisão suave, o Brier, o ECE (via laya.common.ece_score), o MAE de score, o
within-one-level e os percentis de latência, e depois constrói uma tabela de comparação direta
cujas linhas de referência são fixas:
| modelo | tipo | precisão | ECE |
|---|---|---|---|
| TypeSafe Jev 1.13.0 | geral | 0.727 | 0.144 |
| ModernBERT-base (149M) | especialista | 0.646 | 0.179 |
| Auto-concordância do professor | teto | 0.735 | — |
| Laya (checkpoint publicado) | ajuste fino | 0.766 | — |
A linha do Laya da tua própria execução é calculada da mesma forma — o notebook reconstrói a
tabela a partir dos próprios números da execução. Dois hábitos que vale a pena copiar: mantém as
fatias que te interessam (um idioma, um fluxo de trabalho) dentro dos dados reservados, e reporta a
calibração ao lado da precisão, porque o sinal de treino é uma distribuição, e não apenas uma
etiqueta. Quando tiveres números, um post nas
Discussions do repositório é o sítio para os
partilhar; os benchmarks e os limites conhecidos vivem em BENCHMARKS.md na raiz do repositório.
Enviar para o Hub
A célula de publicação é a última milha do ciclo, e é deliberadamente aborrecida:
- Coloca um
HF_TOKENde escrita no Kaggle (Add-ons → Secrets). A célula levanta uma exceção com as instruções exatas se ele faltar. - Define o repositório de destino — a célula distribuída aponta por predefinição para um nome no namespace do próprio projeto, por isso altera-o antes de correr.
- Corre-a. Escreve um model card cujos números vêm da tabela de comparação desta execução, e depois
envia
model.safetensors,encoder/,tokenizer/,rl_agent_config.json, o card e o relatório de benchmark.
O resultado carrega-se como qualquer outro checkpoint — não há uma API específica de ajuste fino:
import laya
agent = laya.load("your-org/your-checkpoint") # the repo you just pushed
result = agent.predict(state, questions)
Um checkpoint_latest/ rotativo é substituído após cada época, por isso um timeout ou OOM no Kaggle
custa uma época, e não a execução.
O que vigiar
- O ciclo é tão bom quanto os alvos. O RLCD imita a distribuição de um professor nas tuas perguntas; recolhe as confianças do professor antes (ou a par) do treino, e trata a sua qualidade como o teto.
- A fatia de calibração é pequena de propósito. Até 400 itens ou 10% — suficiente para três escalares por tipo, insuficiente para validar. Reserva os teus próprios dados de avaliação.
- As tuas etiquetas têm de caber nas três primitivas. Se a tua decisão não for um choice, uma escala ou uma probabilidade de sim/não, molda-a numa delas primeiro. Já estão documentadas duas arestas afiadas: contagens elevadas de opções degradam a seleção por confiança (#394), e a negação forçada de escolha pode seguir a pergunta em vez do estado (#377).
- Distribui a configuração, não só os pesos. O
temperature_by_optionsremovido é a parte que desfaz silenciosamente uma calibração se sobreviver numa configuração copiada.