Ajuste fino do Laya nas suas 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 ajustado alcança 0.766 nas mesmas 2.000 decisões, acima dos 0.727 publicados do TypeSafe Jev e acima do teto de 0.735 de auto-concordância do professor. O ajuste fino é onde está a maior parte do valor, e o notebook de ajuste fino público roda todo o ciclo nas GPUs 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 sendo estruturais quando você troca os dados pelos seus próprios.
O outro exemplo completo — uma cabeça de decisão de agente de navegador em uma única GPU de 16 GB, sem API paga — está em Ajuste fino do Laya como cabeça de decisão de agente de navegador.
O que o notebook faz, em ordem
| # | etapa | o que acontece |
|---|---|---|
| 1 | Ambiente | verifica que as duas 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) viram itens tokenizados com alvos suaves, gravados em disco para as duas ranks de DDP |
| 4 | Treino | train_ddp.py sob torchrun --nproc_per_node=2, quatro épocas |
| 5 | Calibração | uma temperatura por tipo, ajustada em uma fatia reservada antes do treino (dentro do script de treino, após a última época) |
| 6 | Avaliação | a divisão oficial test respondida pelo checkpoint ajustado — 400 casos, 2.000 decisões — com latência por caso |
| 7 | Métricas | precisão, precisão suave, Brier, ECE, MAE de score, dentro de um nível, KL/TV e percentis de latência; uma tabela comparativa 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 ao Hub |
| 9 | Relatório | benchmark_report.json com a tabela de métricas e a precisão por fluxo de trabalho |
Configurações do Kaggle: Accelerator GPU T4 x2, Internet On. As saídas caem em
/kaggle/working/laya_finetuned_typed_decisions.
A receita de treino
O RLCD treina nas distribuições gold do benchmark, não em rótulos rígidos: cada item carrega a probabilidade que o professor atribuiu a cada opção, e as duas metades da perda leem esse alvo —
- um termo de gradiente de política sobre projeções de logit ruidoso amostradas (estilo GRPO: quatro amostras por item, ruído de exploração decaindo de 0.4 → 0.1), recompensado por regras de pontuação próprias (esférica 0.75, probabilidade ranqueada 1.0);
- um termo de entropia cruzada suave com peso total contra a mesma distribuição.
Os ajustes que o notebook define para um cartão de 16 GB:
| épocas | 4 |
| lote efetivo | 64 sequências (8 por micro-lote, 2 GPUs, 4 passos de acumulação) |
| taxas de aprendizado | encoder 2.5e-5, cabeça 1e-4 — AdamW, agenda de cosseno |
| memória | autocast fp16, gradient checkpointing no encoder e na cabeça, clip de norma de 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 apontá-lo aos seus dados, substitua as duas chamadas de load_dataset e mantenha o esquema das
linhas: cada caso carrega state, questions e gold (as probabilidades do professor por
pergunta), e o pré-processador os transforma em itens. Os tipos de pergunta são choice, score e
noul; qualquer coisa que você consiga expressar com eles sobre um estado vale.
A calibração faz parte da execução
Este é o passo mais provável de ser deixado de fora ao copiar o ciclo, e ele é estrutural no momento em que alguém aplica gating sobre a confiança.
O notebook tira uma fatia de calibração dos dados de treino antes de fragmentá-los entre as ranks (até 400 itens, ou 10%, com semente fixa, idêntica em toda rank). Ajustar temperaturas em itens nos quais a execução já treinou mede o ajuste, não a calibração — o modelo está quase certo e quase confiante neles, então o otimizador não tem nada para suavizar e retorna uma escala degenerada.
Depois da última época, a rank 0 ajusta uma temperatura por tipo de pergunta (choice, score,
noul) por LBFGS sobre o log da temperatura, limitada a [0.1, 10] (1.0 para uma fatia com menos
de dez itens, 1.2 se o ajuste lançar). Os valores vão para rl_agent_config.json como
temperature, e o notebook remove qualquer temperature_by_options herdada na mesma escrita:
aqueles valores antigos de bucket têm precedência na inferência e mascarariam silenciosamente o novo
ajuste.
O escalonamento por temperatura deixa o argmax — e a precisão — inalterados; o que se move é a confiança. Os checkpoints, como distribuídos, são excessivamente confiantes, então ajuste antes de confiar em qualquer limiar, e avalie o resultado em dados reservados antes de alegar uma melhoria. A regressão de persistência de config roda sem downloads nem treino:
python tests/test_calibration_persistence.py
Avaliar antes de confiar nele
A avaliação é uma passada completa sobre a divisão de teste oficial: 400 casos, 2.000 decisões em
Agent Trace Observability, Customer Service, Invoice Processing e Security Incidents. Ela calcula
precisão, precisão suave, Brier, ECE (via laya.common.ece_score), MAE de score, dentro de um nível
e percentis de latência, depois constrói uma tabela comparativa 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 |
| Teacher Self-Agreement | teto | 0.735 | — |
| Laya (checkpoint publicado) | ajustado | 0.766 | — |
A linha do Laya da sua 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 copiar: mantenha as fatias que te
importam (um idioma, um fluxo de trabalho) dentro dos dados reservados, e reporte a calibração ao lado
da precisão, porque o sinal de treino é uma distribuição, não só um rótulo. Quando você tiver
números, um post nas
Discussões do repositório é o lugar para
compartilhá-los; benchmarks e limites conhecidos ficam em BENCHMARKS.md na raiz do repositório.
Enviar para o Hub
A célula de publicação é a última milha do ciclo, e ela é deliberadamente entediante:
- Coloque um
HF_TOKENde escrita no Kaggle (Add-ons → Secrets). A célula lança as instruções exatas se ele estiver faltando. - Defina o repositório de destino — a célula distribuída usa por padrão um nome no próprio namespace do projeto, então mude-o antes de rodar.
- Rode. Ele escreve um model card cujos números vêm da tabela de comparação desta execução, depois
envia
model.safetensors,encoder/,tokenizer/,rl_agent_config.json, o card e o relatório de benchmark.
O resultado carrega 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 é sobrescrito a cada época, então um timeout ou OOM do Kaggle custa
uma época em vez da execução.
O que observar
- O ciclo é tão bom quanto os alvos. O RLCD imita a distribuição de um professor nas suas perguntas; colete as confianças do professor antes do treino (ou junto com ele), e trate a qualidade delas como o teto.
- A fatia de calibração é pequena de propósito. Até 400 itens ou 10% — o suficiente para três escalares por tipo, não o suficiente para validar contra algo. Reserve seus próprios dados de avaliação.
- Seus rótulos devem caber nas três primitivas. Se sua decisão não é um choice, uma escala ou uma probabilidade sim/não, molde-a em uma delas primeiro. Duas arestas afiadas já estão documentadas: contagens altas de opções degradam a seleção por confiança (#394), e a negação em escolha forçada pode seguir a pergunta em vez do estado (#377).
- Entregue a config, não só os pesos. A
temperature_by_optionsremovida é a parte que desfaz silenciosamente uma calibração se sobreviver em uma config copiada.