Ajuste fino de um LLM com as suas anotações
Treine um LLM por SFT ou DPO, um modelo de recompensa ou um modelo de recompensa por processo com os rótulos do próprio estudo, avalie cada um em itens reservados e publique no Hub.
Novo na v2.14.0
Este tutorial treina quatro tipos de modelo de linguagem com as respostas que um estudo do Potato coleta. O treinador llm-sft ajusta um LLM com respostas escritas ou traços de agente corrigidos, llm-dpo ajusta um LLM com escolhas em pares, reward-model ajusta um modelo de recompensa escalar com comparações e prm-reward ajusta um modelo de recompensa por processo com avaliações de passos. A página é escrita para equipes que já coletam dados de preferência ou de traços no Potato e querem um primeiro modelo a partir desses rótulos sem exportar os dados para um script de treinamento separado. Cada seção nomeia o esquema que produz os dados, apresenta uma configuração que passa no validador do Potato, lista os parâmetros que vale a pena mudar e diz o que a pontuação em itens reservados mede e se as predições voltam aos anotadores como pré-rótulos. A visão geral do treinamento de modelos cobre a página Training, e Treine seu primeiro modelo percorre o ciclo inteiro com um classificador que dispensa GPU.
Treinadores por esquema de anotação
Todo treinador desta página aprende com um esquema de anotação por execução, e a página Training oferece um treinador apenas para os esquemas que o treinador consegue aprender. A tabela abaixo lista os esquemas com que cada treinador aprende:
| Treinador | Esquema | O que o modelo aprende | Pontuação principal em itens reservados | Mostrado aos anotadores |
|---|---|---|---|---|
llm-sft | text | a escrever a resposta que os anotadores escreveram | F1 de tokens | sim, a resposta gerada preenche a caixa de texto |
llm-sft | trajectory_edit | a reescrever os passos de um agente nos passos corrigidos | closer_to_correction | não, apenas armazenado e avaliado |
llm-dpo | pairwise no modo binary | a preferir a resposta que os anotadores escolheram | acurácia, sem contar empates | sim, o cartão da resposta preferida fica selecionado |
llm-dpo | trajectory_edit | a preferir os passos corrigidos aos originais | closer_to_correction | não, apenas armazenado e avaliado |
reward-model | pairwise (binary e scale), ranking, bws | uma pontuação por resposta | acurácia, acurácia de direção, tau de Kendall ou acurácia de melhor-pior | sim, como a própria resposta do esquema |
prm-reward | process_reward | uma avaliação de correto, neutro ou errado para cada passo | step_macro_f1 | oferecido pelo botão "AI pre-label steps" |
Antes de começar
Os extras de treinamento do Potato instalam PyTorch, Transformers e PEFT para os quatro treinadores:
pip install "potato-annotation[train-llm]"
pip install "potato-annotation[train-text]"O primeiro extra cobre llm-sft e llm-dpo, e o segundo cobre reward-model e prm-reward. pip install "potato-annotation[train]" instala todos os extras de treinamento de uma vez. Um treinador cujos pacotes estão ausentes aparece na página Training como "not installed", com o comando que instala os pacotes.
Cada treinador se recusa a ajustar com menos de 20 itens na divisão train (o parâmetro min_instances). A divisão padrão põe 70% dos itens rotulados em train, 15% em val e 15% em test, então planeje cerca de 30 itens rotulados antes da primeira execução. Os itens val e test ficam fora do treinamento e avaliam o modelo.
llm-sft e llm-dpo partem de Qwen/Qwen2.5-0.5B-Instruct, reward-model parte de distilbert/distilroberta-base e prm-reward parte de answerdotai/ModernBERT-base. Os treinadores de LLM foram feitos para rodar em GPU. Quando a máquina que executa o Potato não tem GPU, o treinamento remoto envia as execuções a um servidor com GPU por ssh ou a um cluster SLURM.
Um estudo que coleta preferências e reescritas
A primeira configuração faz duas perguntas sobre cada prompt de suporte ao cliente. Os anotadores escolhem a melhor de duas respostas e escrevem a resposta que um anotador gostaria de receber do assistente. A escolha treina llm-dpo e reward-model, e a resposta escrita treina llm-sft. Cada linha de data/answers.jsonl contém um prompt e as duas respostas:
{"id": "q001", "prompt": "How do I reset my router to factory settings?", "responses": ["Hold the reset button on the back for 10 seconds until the lights blink, then wait two minutes for the router to restart.", "Routers can be reset. Check the manual."]}A configuração mostra o prompt como o texto do item e as duas respostas como os cartões A e B:
annotation_task_name: "Support answers: preferences and rewrites"
task_dir: .
data_files:
- data/answers.jsonl
item_properties:
id_key: id
text_key: prompt
output_annotation_dir: annotation_output
user_config:
allow_all_users: true
annotation_schemes:
- annotation_type: pairwise
name: preferred
description: "Which response answers the question better?"
mode: binary
items_key: responses
allow_tie: true
tie_label: "No preference"
- annotation_type: text
name: rewrite
description: "Write the answer you would want the assistant to give."
multiline: true
rows: 4
model_training:
enabled: true
writeback:
schemas: [preferred]
min_confidence: 0.7text_key: prompt importa duas vezes, porque o prompt é o que os anotadores leem e o que llm-sft coloca depois da pergunta. items_key: responses nomeia a lista de onde vêm os cartões do esquema pairwise, na ordem dos dados, então A é a primeira resposta. writeback.schemas lista apenas preferred, de modo que os anotadores veem a escolha do modelo e não uma reescrita gerada. Os pré-rótulos ancoram os anotadores, então só acrescente rewrite à lista quando a pontuação em itens reservados da execução de llm-sft justificar mostrar o texto do modelo. min_confidence: 0.7 mantém fora da página as predições de que o modelo está menos seguro, mas ainda armazena essas predições. Verifique a configuração com o validador do Potato antes de iniciar o servidor:
python -m potato.validate_cli config.yaml --strictInicie o Potato, rotule pelo menos 30 prompts e abra /admin/training como administrador. As execuções abaixo também podem ser iniciadas pela API, com o admin_api_key da configuração em $KEY.
Ajuste fino supervisionado com llm-sft
llm-sft transforma cada item rotulado em um exemplo de treinamento. O prompt é a description do esquema (a pergunta que os anotadores viram) seguida do texto do item, e o alvo é a resposta que o anotador escreveu. A perda cobre apenas os tokens da resposta, de modo que o modelo aprende a responder em vez de repetir o prompt. Por padrão, treina-se um adaptador LoRA em vez de todos os pesos.
Escolha llm-sft e o esquema rewrite na página Training e clique em Train now, ou inicie a mesma execução pela API:
curl -X POST -H "X-API-Key: $KEY" -H "Content-Type: application/json" \
http://localhost:8000/admin/training/api/runs \
-d '{"trainer": "llm-sft", "schemas": ["rewrite"], "params": {"max_new_tokens": 256}}'A maioria das execuções muda apenas os parâmetros desta tabela:
| Parâmetro | Padrão | Significado |
|---|---|---|
model_name | Qwen/Qwen2.5-0.5B-Instruct | Um modelo de linguagem causal no Hugging Face Hub, ou um diretório local. |
lora | true | false treina todos os pesos e precisa de várias vezes mais memória. {quantize: 4bit} carrega o modelo base em 4 bits (veja QLoRA). |
max_length | 1024 | Tokens por exemplo. Um prompt longo perde tokens do início, e a resposta é mantida. |
max_new_tokens | 256 | A resposta mais longa que o modelo gera. |
instruction | a description do esquema | Texto colocado antes do texto de cada item. |
system_prompt | nenhum | Uma mensagem de sistema para modelos com template de chat. |
gradient_checkpointing | false | Economiza memória de ativações ao custo de cerca de um terço a mais de tempo. |
learning_rate | 2e-4 com LoRA, 1e-5 sem |
A execução mantém o checkpoint com a menor perda em val. Como a execução escolheu o checkpoint em val, a pontuação em itens reservados é lida em test. A pontuação é o F1 de tokens, a sobreposição de palavras entre a resposta gerada e a escrita, independentemente da ordem, com a correspondência exata informada ao lado da pontuação. O F1 de tokens dá crédito a uma resposta que usa as palavras certas nos lugares errados, então leia as duas métricas juntas.
O modelo gera uma resposta de forma gulosa para todos os itens val e test. Com writeback.include_unlabeled: true, o modelo também responde aos itens que ninguém rotulou. A confiança de uma predição é a probabilidade média que o modelo atribuiu aos tokens que gerou, e a fila de revisão de modelos ordena por essa confiança. Com rewrite em writeback.schemas, a resposta gerada preenche a caixa de texto quando um anotador abre o item.
Texto livre combina mal com vários anotadores por item. A configuração aggregation resolve várias respostas em uma comparando as respostas palavra por palavra, e duas respostas escritas raramente coincidem palavra por palavra. Para llm-sft em um esquema text, um redator por item evita a comparação palavra por palavra.
Ajuste por preferências com llm-dpo
A Direct Preference Optimization (DPO) treina um LLM para aumentar a probabilidade da resposta preferida em relação à outra resposta, medida contra uma cópia de referência congelada do modelo inicial. llm-dpo monta um exemplo a partir de cada item respondido com A ou B. O prompt é o campo prompt do item, ou o primeiro entre question, instruction, query, input e context que o item tiver. Itens respondidos com a opção de empate ficam de fora, já que um empate não marca nenhuma das respostas como melhor.
Escolha llm-dpo e o esquema preferred, ou envie a mesma requisição de cima com "trainer": "llm-dpo" e "schemas": ["preferred"]. Com o adaptador LoRA padrão, o modelo de referência é o mesmo modelo com o adaptador desligado, então nenhuma segunda cópia fica na memória. lora: false treina todos os pesos e mantém uma cópia congelada como referência, e a cópia congelada dobra a memória.
| Parâmetro | Padrão | Significado |
|---|---|---|
model_name | Qwen/Qwen2.5-0.5B-Instruct | Um modelo de linguagem causal. |
beta | 0.1 | Quanto o modelo pode se afastar da referência. Um valor menor deixa o modelo se afastar mais. |
epochs | 2 | |
learning_rate | 5e-5 com LoRA, 5e-7 sem | |
max_length | 1024 | Tokens por prompt e resposta. |
instruction | nenhum | Texto colocado antes do prompt de cada item. |
A execução mantém o checkpoint com a menor perda DPO em val, e o log da execução informa com que frequência o modelo prefere a escolha dos anotadores em val. A pontuação em itens reservados é a acurácia em test, sobre os itens não respondidos como empate, com o F1 macro ao lado da acurácia. Uma predição é a resposta que o modelo treinado prefere, com a probabilidade dessa preferência como confiança. Como pré-rótulo, o cartão da resposta preferida fica selecionado quando o anotador abre o item. Com randomize_order no esquema, a seleção acompanha a resposta até onde o anotador a vê. O adaptador salvo também é uma política e gera texto quando carregado com o PEFT. Para o contexto da coleta dos próprios dados de preferência, veja Coletando dados de RLHF e de preferência e Comparação em pares.
Um modelo de recompensa com reward-model
Um modelo de recompensa mapeia uma resposta a um número, para RLHF, para amostragem best-of-n ou para ordenar novas saídas. reward-model treina um transformer com uma única saída de modo que a resposta que os anotadores preferiram receba pontuação maior. A perda é a perda de Bradley–Terry, -log sigmoid(r_winner - r_loser), a perda de modelagem de recompensa do InstructGPT. O esquema preferred acima treina reward-model sem nenhuma mudança na configuração. Cada esquema comparativo dá um sinal de treinamento diferente:
| Esquema | Sinal de treinamento | Pontuação principal em itens reservados |
|---|---|---|
pairwise, binary | A resposta escolhida vence a outra. Empates são ignorados. | acurácia |
pairwise, scale | Vence o lado para o qual o controle deslizante pende, ponderado pelo quanto o controle pende. O ponto médio é ignorado. | acurácia de direção |
ranking | A ordem inteira, pela perda de Plackett-Luce, ou todos os pares da ordem com ranking_loss: pairs. | tau de Kendall |
bws | O melhor item vence todos os outros itens da tupla, e todos os outros itens vencem o pior. | acurácia de melhor-pior |
Quando um item tem um campo de prompt, cada recompensa é a da resposta dado o prompt. As opções de um ranking são os rótulos do esquema, cada um pontuado dado o texto do item. O servidor monta as tuplas de BWS a partir de bws_config, então uma execução com os dados do próprio servidor já tem as tuplas, e os arquivos de dados não precisam delas.
| Parâmetro | Padrão | Significado |
|---|---|---|
model_name | distilbert/distilroberta-base | Um encoder, ou um LLM com lora. |
ranking_loss | plackett_luce | Apenas esquemas ranking: plackett_luce ou pairs. |
max_length | 512 | Tokens por texto pontuado, prompt e resposta juntos. |
learning_rate | 2e-5, ou 2e-4 com LoRA |
As predições respondem à própria pergunta do esquema, então as predições são avaliadas e gravadas de volta como as de qualquer outro esquema. O pré-rótulo é o cartão selecionado em uma escolha binária, a posição do controle deslizante em uma escala, a ordem da lista em um ranking e o melhor e o pior selecionados em BWS. Toda predição também armazena os rewards de que a predição veio. Apenas as diferenças entre recompensas têm significado. Comparação em pares e Best-Worst Scaling compara os formatos comparativos para coletar os dados.
Um estudo que coleta avaliações de passos e correções
A segunda configuração trabalha com traços de agentes. Os anotadores avaliam cada passo do traço e depois corrigem os passos errados. As avaliações de passos treinam prm-reward, e as correções treinam llm-sft ou llm-dpo. Cada linha de data/traces.jsonl contém a tarefa, os passos do agente e a resposta final:
{"id": "traj_001", "task_description": "Find the current weather in San Francisco and report the temperature.", "steps": [{"thought": "I should look up the current weather.", "action": "web_search(queyr='San Francisco weather')"}, {"thought": "Open the first result.", "action": "open_url(results[0])"}, {"thought": "Read the temperature from the page.", "action": "extract_text('.temp')"}], "final_answer": "It is sunny."}Os treinadores leem a tarefa do campo task_description, task ou text do item, nessa ordem:
annotation_task_name: "Agent traces: step ratings and corrections"
task_dir: .
data_files:
- data/traces.jsonl
item_properties:
id_key: id
text_key: task_description
output_annotation_dir: annotation_output
user_config:
allow_all_users: true
annotation_schemes:
- annotation_type: process_reward
name: step_quality
description: "Rate each step of the agent's trace"
steps_key: steps
step_text_key: action
mode: per_step
allow_neutral: true
ai_prelabel: true
- annotation_type: trajectory_edit
name: corrected_trace
description: "Fix the wrong steps, then correct the final answer"
steps_key: steps
step_text_key: action
editable_fields: [action]
show_diff: true
edit_final_answer: true
final_answer_key: final_answer
model_training:
enabled: true
writeback:
schemas: [step_quality]
include_unlabeled: truemode: per_step com allow_neutral: true dá as três avaliações que prm-reward aprende. ai_prelabel: true põe o botão "AI pre-label steps" no esquema, e as avaliações treinadas aparecem por esse botão. writeback.schemas nomeia apenas step_quality. Listar corrected_trace ali impede o servidor de iniciar, e o validador dá o motivo:
model_training.writeback.schemas names 'corrected_trace', a trajectory_edit scheme, which has no prelabel display: its predictions are stored and scored but annotators would never see them. Leave it out of writeback.schemas.Reparando traços com llm-sft e llm-dpo
Uma resposta trajectory_edit é um par de traços, os passos originais do agente e os passos depois das correções do anotador. Edição de trajetórias para SFT/DPO cobre o editor, e o post sobre edição de trajetórias cobre como os pares viram dados de treinamento. Os dois treinadores deixam de fora os traços que ninguém editou.
llm-sfttoma a tarefa e os passos originais como prompt e os passos corrigidos como alvo, de modo que o modelo aprende a reparar um traço. Cada passo é escrito comoStep Nseguido dos campos do passo (action: ...,thought: ...), e a resposta final vem depois do último passo quando o esquema temfinal_answer_key.llm-dpotoma a tarefa como prompt, os passos corrigidos como a resposta preferida e os passos originais como a outra resposta. Uma predição diz se o modelo prefere a correção (A) ou o original (B), e é feita apenas para traços reservados que têm uma correção.
As duas execuções informam closer_to_correction como pontuação em itens reservados. Para llm-dpo, a pontuação é a fração dos traços reservados em que o modelo prefere a correção. Para llm-sft, a pontuação é a fração em que os passos escritos ficam mais próximos da correção do que do original pelo F1 de tokens, com o token_f1 contra a correção informado ao lado da pontuação.
As predições de uma execução trajectory_edit são armazenadas e avaliadas, e os anotadores nunca as veem. O editor sempre começa do traço original do agente, então a página não tem lugar para mostrar uma reescrita prevista. Leia as predições na página da execução ou em artifacts/predictions.jsonl no diretório da execução.
Avaliações de passos com prm-reward
Um modelo de recompensa por processo avalia os passos de um traço em vez de apenas a resposta final, como no PRM800K. prm-reward alimenta um encoder transformer com o traço inteiro como uma única entrada, a tarefa seguida de Step 1, Step 2 e assim por diante. O encoder aprende uma avaliação de três classes no último token de cada passo, de modo que cada avaliação é feita com os passos anteriores ao passo à vista. Passos que ninguém avaliou ficam de fora da perda. O modelo padrão, answerdotai/ModernBERT-base, foi escolhido pelo contexto de 8.192 tokens.
| Parâmetro | Padrão | Significado |
|---|---|---|
model_name | answerdotai/ModernBERT-base | Um encoder com um tokenizador rápido. |
max_length | 1024 | Tokens por traço. |
epochs | 6 | |
batch_size | 8 | Traços por passo de otimização. |
learning_rate | 5e-5, ou 3e-4 com LoRA |
Traços longos perdem os últimos passos. Um traço mais longo que max_length tokens é cortado pelo fim, e os passos depois do corte não são nem treinados nem avaliados. O log da execução conta os passos perdidos. Quando max_length é maior do que o modelo comporta, a execução reduz max_length ao limite do modelo com um aviso, e o limite é de 512 tokens para a maioria dos encoders da classe BERT. Quando o log da execução informa passos perdidos, aumente max_length e escolha um modelo cujo contexto comporte os traços mais longos.
A pontuação em itens reservados é step_macro_f1, o F1 macro sobre as três avaliações em todos os passos avaliados. A maioria dos passos na maioria dos traços está correta, então a acurácia favoreceria um modelo que nunca diz "errado". A execução também informa step_accuracy e first_error_accuracy, a fração de traços em que o primeiro passo errado do modelo é o primeiro passo errado dos anotadores.
Uma predição avalia todos os passos que cabem em max_length, com a probabilidade de cada avaliação como a confiança da avaliação e o passo menos confiável como a confiança do traço. Com o esquema em writeback.schemas e ai_prelabel: true, o botão "AI pre-label steps" oferece as avaliações treinadas para o anotador verificar. Um juiz LLM configurado em ai_support não é chamado para um item que tem avaliações treinadas. Anotação de recompensa por processo cobre o esquema, e o guia de modelos de recompensa por processo cobre os dados.
Ajustar um modelo maior com QLoRA
O QLoRA carrega os pesos do modelo base em 4 bits e treina um adaptador LoRA por cima. llm-sft, llm-dpo, hf-text-classification, vlm-sft e reward-model aceitam lora: {quantize: 4bit}, e prm-reward recusa a configuração antes de carregar o modelo. Planeje a memória a partir da linha "Peak GPU memory" que toda execução de transformer registra no final. A seção sobre QLoRA da referência de configuração descreve como os pesos base são carregados e a opção de 8 bits.
Adicione este bloco à configuração acima para definir o QLoRA como padrão de llm-sft:
model_training:
enabled: true
trainer_params:
llm-sft:
model_name: Qwen/Qwen2.5-7B-Instruct
lora: {quantize: 4bit}
gradient_checkpointing: trueO QLoRA precisa de uma GPU CUDA e de uma versão do bitsandbytes para o CUDA dessa máquina, instalada com pip install bitsandbytes. Sem uma GPU ou uma versão que funcione, a execução para na validação antes de carregar o modelo.
Publicando uma execução no Hugging Face Hub
Uma execução bem-sucedida cujo modelo está no servidor do Potato tem Publish to the Hugging Face Hub na página da execução. O envio carrega o modelo e um model card README.md escrito a partir da execução, com o treinador, o modelo base e o adaptador, os esquemas e rótulos, os tamanhos das divisões, a pontuação em itens reservados e aquilo em que a pontuação foi medida, e os ids da execução e do pacote. Uma execução com LoRA salvou apenas o adaptador, então o repositório no Hub contém o adaptador, e o card nomeia o modelo base sobre o qual carregar o adaptador.
O token fica fora do navegador. Crie um token de escrita nas suas configurações do Hugging Face e ponha o token no ambiente do servidor antes de iniciar o Potato:
export HF_TOKEN=hf_your_write_token
potato start config.yamlO formulário nomeia a variável de ambiente, HF_TOKEN por padrão, pede o nome do repositório duas vezes e mantém Private marcado por padrão. Publicando no Hugging Face Hub lista os arquivos que sobem, as verificações antes de um envio e a licença no model card. O mesmo envio pela API:
curl -X POST -H "X-API-Key: $KEY" -H "Content-Type: application/json" \
http://localhost:8000/admin/training/api/runs/RUN_ID/push-to-hub \
-d '{"repo_id": "your-org/support-dpo", "confirm_repo_id": "your-org/support-dpo", "private": true, "licence": "apache-2.0"}'A rota retorna 201 com o commit. Um modelo deixado em um host remoto com fetch_artifacts: false não pode ser enviado a partir do servidor do Potato, e a página da execução diz onde o modelo está. Para passar de um modelo publicado a um ciclo de aprendizado ativo, continue com Modelo no ciclo.
Leitura complementar
- Configuração do treinamento de modelos: todas as chaves de
model_training, as pontuações em itens reservados, a gravação de volta e as rotas. - Treinadores: os 38 treinadores, agrupados por tarefa.
- Treinamento remoto: servidores com GPU por ssh, clusters SLURM e o agente de polling.
- Anotação de trajetórias de agentes: coleta de dados de traços no Potato.
- Seções de referência do projeto original para
llm-sft,llm-dpo, traços de agentes,prm-reward,reward-model, QLoRA e publicação no Hub.
Referências
- Dettmers, T., Pagnoni, A., Holtzman, A., and Zettlemoyer, L. (2023). QLoRA: Efficient Finetuning of Quantized LLMs. arXiv:2305.14314. arxiv.org/abs/2305.14314
- Hu, E. J., Shen, Y., Wallis, P., Allen-Zhu, Z., Li, Y., Wang, S., Wang, L., and Chen, W. (2021). LoRA: Low-Rank Adaptation of Large Language Models. arXiv:2106.09685. arxiv.org/abs/2106.09685
- Lightman, H., Kosaraju, V., Burda, Y., Edwards, H., Baker, B., Lee, T., Leike, J., Schulman, J., Sutskever, I., and Cobbe, K. (2023). Let's Verify Step by Step. arXiv:2305.20050. arxiv.org/abs/2305.20050
- Ouyang, L., Wu, J., Jiang, X., Almeida, D., Wainwright, C. L., Mishkin, P., Zhang, C., Agarwal, S., Slama, K., Ray, A., Schulman, J., Hilton, J., Kelton, F., Miller, L., Simens, M., Askell, A., Welinder, P., Christiano, P., Leike, J., and Lowe, R. (2022). Training Language Models to Follow Instructions with Human Feedback. arXiv:2203.02155. arxiv.org/abs/2203.02155
- Rafailov, R., Sharma, A., Mitchell, E., Ermon, S., Manning, C. D., and Finn, C. (2023). Direct Preference Optimization: Your Language Model is Secretly a Reward Model. arXiv:2305.18290. arxiv.org/abs/2305.18290