# Recursos do Trainer

Cada receita abaixo demonstra um recurso específico do [Trainer](/docs/transformers/main/pt/main_classes/trainer#transformers.Trainer): funções de perda personalizadas, avaliação eficiente em memória, estratégias de checkpointing e muito mais.

> [!TIP]
> Abra uma [issue](https://github.com/huggingface/transformers/issues/new/choose) se houver um recurso ou fluxo de trabalho que você gostaria de ver aqui.

## Função de perda personalizada

Passe [compute_loss_func](/docs/transformers/main/pt/main_classes/trainer#transformers.Trainer.compute_loss_func) para [Trainer](/docs/transformers/main/pt/main_classes/trainer#transformers.Trainer) para substituir a função de perda padrão. A função é executada *após* o forward pass e define apenas como a perda é calculada a partir das saídas. Para modificar o próprio forward pass, [crie uma subclasse](./trainer_customize#compute-loss) de [compute_loss()](/docs/transformers/main/pt/main_classes/trainer#transformers.Trainer.compute_loss) em vez disso.

A função de perda personalizada deve ter a seguinte assinatura:

```py
import torch.nn.functional as F

def my_loss_fn(outputs, labels, num_items_in_batch):
    logits = outputs["logits"]
    loss = F.cross_entropy(logits, labels, reduction="sum")
    return loss / num_items_in_batch
```

- `outputs` é a saída bruta do modelo (`outputs.logits` tem a forma `(batch, seq_len, vocab_size)`).
- `labels` são os ids de tokens removidos do lote de entrada pelo [Trainer](/docs/transformers/main/pt/main_classes/trainer#transformers.Trainer) antes da passagem para frente.
- `num_items_in_batch` é o número de alvos de previsão em todo o lote acumulado. Para modelos de LM causal, ele conta os rótulos deslocados (`labels[..., 1:]`), pois o deslocamento dos rótulos deixa a posição 0 de cada sequência sem um alvo. Consulte [Escala da perda](./grad_accumulation#loss-scaling) para mais detalhes. O [Trainer](/docs/transformers/main/pt/main_classes/trainer#transformers.Trainer) ignora a normalização automática da perda quando uma função de perda personalizada é fornecida, portanto, sua função deve tratar a normalização diretamente.

```py
trainer = Trainer(
    model=model,
    args=TrainingArguments(...),
    train_dataset=train_dataset,
    compute_loss_func=my_loss_fn,
)
trainer.train()
```

> [!NOTE]
> Consulte o [guia de subclasseamento](./trainer_customize#compute-loss) para mais exemplos de como sobrescrever [compute_loss()](/docs/transformers/main/pt/main_classes/trainer#transformers.Trainer.compute_loss).

## Avaliando no início

Defina `eval_on_start=True` para executar uma passagem completa de avaliação antes do primeiro passo de treinamento. Uma avaliação pré-treinamento revela problemas no pipeline de avaliação precocemente, especialmente durante execuções longas.

`eval_on_start` requer um `eval_strategy` válido (como `"epoch"`) e um conjunto de dados de avaliação.

```py
from transformers import Trainer, TrainingArguments

trainer = Trainer(
    model=model,
    args=TrainingArguments(
        output_dir="out",
        eval_strategy="epoch",
        eval_on_start=True,
    ),
    train_dataset=train_dataset,
    eval_dataset=eval_dataset,
    compute_metrics=compute_metrics,
)
trainer.train()
```

Uma avaliação completa adiciona tempo, portanto, é mais útil em execuções iniciais ou após modificar `compute_metrics`.

## Avaliações com uso eficiente de memória

Durante a avaliação, o [Trainer](/docs/transformers/main/pt/main_classes/trainer#transformers.Trainer) executa uma passagem direta em cada lote e concatena os logits em um único tensor na GPU. Assim que o conjunto de dados de avaliação é totalmente processado, o [Trainer](/docs/transformers/main/pt/main_classes/trainer#transformers.Trainer) move os logits concatenados para a CPU e chama `compute_metrics`. Para modelos grandes ou conjuntos de avaliação extensos, os logits acumulados podem esgotar a memória da GPU, mesmo quando o treinamento no mesmo hardware funciona normalmente, pois o treinamento retém apenas um lote de ativações por vez.

### eval_accumulation_steps

Desloque as previsões acumuladas da GPU para a CPU a cada *n* lotes. Valores menores reduzem a memória da GPU, mas aumentam a frequência das transferências para a CPU.

```py
from transformers import Trainer, TrainingArguments

trainer = Trainer(
    model=model,
    args=TrainingArguments(
        output_dir="out",
        eval_strategy="epoch",
        eval_accumulation_steps=16,   # move predictions to CPU every 16 batches
    ),
    eval_dataset=eval_dataset,
    compute_metrics=compute_metrics,
)
trainer.train()
```

### preprocess_logits_for_metrics

Chamado uma vez por lote de avaliação na GPU, imediatamente após a passagem para frente e antes da acumulação de logits. O valor retornado substitui os logits em `eval_pred.predictions`. Executar o cálculo no nível do lote reduz o tamanho do tensor por lote e fornece a `eval_accumulation_steps` um tensor menor para descarregar.

```py
import evaluate
from transformers import Trainer, TrainingArguments

metric = evaluate.load("accuracy")

def preprocess_logits_for_metrics(logits, labels):
    if isinstance(logits, tuple):
        logits = logits[0]
    return logits.argmax(dim=-1)

def compute_metrics(eval_preds):
    preds, labels = eval_preds
    labels = labels[:, 1:].reshape(-1)
    preds = preds[:, :-1].reshape(-1)
    return metric.compute(predictions=preds, references=labels)

trainer = Trainer(
    model=model,
    args=TrainingArguments(
        output_dir="out",
        eval_strategy="epoch",
        eval_accumulation_steps=16,
    ),
    eval_dataset=eval_dataset,
    compute_metrics=compute_metrics,
    preprocess_logits_for_metrics=preprocess_logits_for_metrics,
)
trainer.train()
```

## Desempenho do Dataloader

Por padrão, o [Trainer](/docs/transformers/main/pt/main_classes/trainer#transformers.Trainer) cria um dataloader com `dataloader_num_workers=0`. Os dados são carregados no processo principal enquanto a GPU fica ociosa, o que se manifesta como baixa utilização da GPU entre os lotes.

Tanto `dataloader_persistent_workers` quanto `dataloader_prefetch_factor` exigem `dataloader_num_workers > 0`.

- `dataloader_persistent_workers` mantém os subprocessos de workers ativos entre épocas para evitar a reinitialização do zero, ao custo de maior uso de memória.
- `dataloader_prefetch_factor` controla quantos lotes cada worker prepara antecipadamente. Com `dataloader_prefetch_factor=2` e `num_workers=4`, até 8 lotes ficam na memória enquanto a GPU treina com o lote atual.

```py
from transformers import TrainingArguments

args = TrainingArguments(
    output_dir="out",
    dataloader_num_workers=4,            # spawn 4 worker subprocesses
    dataloader_persistent_workers=True,  # keep them alive between epochs
    dataloader_prefetch_factor=2,        # each worker preloads 2 batches ahead
)
```

## Agrupar amostras por comprimento

Use `train_sampling_strategy="group_by_length"` para agrupar exemplos com comprimentos semelhantes e reduzir o padding. Quando você não fornece comprimentos pré-computados, o [Trainer](/docs/transformers/main/pt/main_classes/trainer#transformers.Trainer) os infere a partir da primeira entrada do modelo em cada item do dataset. Isso também funciona quando datasets multimodais baseados em processadores retornam objetos [BatchFeature](/docs/transformers/main/pt/main_classes/feature_extractor#transformers.BatchFeature), pois eles são contêineres de recursos semelhantes a mapeamentos.

```py
from transformers import TrainingArguments

training_args = TrainingArguments(
    output_dir="qwen3-vl-finetuned",
    train_sampling_strategy="group_by_length",
)
```

Se um [Dataset](https://huggingface.co/docs/datasets/main/en/package_reference/main_classes#datasets.Dataset) já possui uma coluna de comprimento pré-computada, o [Trainer](/docs/transformers/main/pt/main_classes/trainer#transformers.Trainer) usa essa coluna. O nome padrão da coluna é `length`. Defina `length_column_name` quando o seu conjunto de dados usar outro nome. Essa estratégia requer um conjunto de dados com comprimento conhecido e é ignorado para [IterableDataset](https://huggingface.co/docs/datasets/main/en/package_reference/main_classes#datasets.IterableDataset).

## Amostragem de reequilíbrio por lote

Em conjuntos de dados de comprimento variável, o desequilíbrio dentro de um micro-lote e entre dispositivos faz com que os dispositivos desperdicem tempo com preenchimento e fiquem ociosos nas etapas de sincronização de gradientes.

Defina `train_sampling_strategy="batch_rebalance"` em [TrainingArguments](/docs/transformers/main/pt/main_classes/trainer#transformers.TrainingArguments) para reduzir ambos os efeitos. Para cada passo do otimizador, o amostrador:

1. Ordena as amostras do lote por comprimento.
2. Distribui o lote ordenado entre os dispositivos de modo que o custo dos tokens de preenchimento de cada micro-lote seja equilibrado. Micro-lotes com amostras longas recebem menos amostras, e micro-lotes com amostras curtas recebem mais.

Isso reduz o padding dentro de cada micro-lote, e cada dispositivo finaliza um micro-lote em aproximadamente o mesmo tempo, o que reduz o tempo ocioso na sincronização e mantém a memória de pico menor do que com `"group_by_length"`. Essa estratégia é suportada apenas para treinamento paralelo de dados por enquanto (o paralelismo de tensor ainda não é suportado).

```py
from transformers import Trainer, TrainingArguments

trainer = Trainer(
    model=model,
    args=TrainingArguments(
        output_dir="out",
        train_sampling_strategy="batch_rebalance",  # balance padding cost across devices
        per_device_train_batch_size=8,              # average samples per micro-batch
        length_column_name="length",                # optional: dataset column with precomputed lengths
    ),
    train_dataset=train_dataset,
)
trainer.train()
```

`per_device_train_batch_size` é uma média aqui, em vez de uma contagem exata por etapa: alguns micro-lotes têm menos amostras e outros têm mais, mas o número total de amostras treinadas por etapa permanece o mesmo que com uma estratégia de amostragem distribuída normal.

O sampler precisa do comprimento de cada amostra para ordenar e equilibrar os lotes. Por padrão, o [Trainer](/docs/transformers/main/pt/main_classes/trainer#transformers.Trainer) varre o conjunto de dados completo uma vez no início do treinamento para calcular esses comprimentos. Para pular essa varredura, pré-compute os comprimentos em uma coluna do conjunto de dados (por exemplo, durante o pré-processamento) e passe seu nome como `length_column_name` (padrão: `"length"`).

## NEFTune

[NEFTune](https://hf.co/papers/2310.05914) adiciona ruído aleatório aos embeddings de tokens durante a passagem direta. O ruído atua como regularização e pode melhorar o desempenho no ajuste fino por instrução.

Ative o NEFTune definindo `neftune_noise_alpha` em [TrainingArguments](/docs/transformers/main/pt/main_classes/trainer#transformers.TrainingArguments). Os valores típicos de alpha variam de 5 a 15.

```py
from transformers import Trainer, TrainingArguments

trainer = Trainer(
    model=model,
    args=TrainingArguments(
        output_dir="out",
        num_train_epochs=3,
        neftune_noise_alpha=5,
    ),
    train_dataset=train_dataset,
)
trainer.train()
```

O NEFTune afeta apenas o treinamento, e a camada de incorporação original é restaurada após o treinamento.

## Registro

Controle quando e onde o [Trainer](/docs/transformers/main/pt/main_classes/trainer#transformers.Trainer) grava as entradas de log com `logging_strategy`, `logging_steps` e `report_to`.

- `logging_strategy="steps"` registra a cada `logging_steps()` atualizações do otimizador. Use `"epoch"` para registrar no final de cada epoch, em vez disso.
- `report_to` envia logs para um rastreador de experimentos como Trackio.

```py
from transformers import Trainer, TrainingArguments

trainer = Trainer(
    model=model,
    args=TrainingArguments(
        output_dir="out",
        logging_strategy="steps",
        logging_steps=50,               # write a log entry every 50 optimizer updates
        report_to="trackio",            # stream to Trackio (or "wandb", "tensorboard", …)
        run_name="model-experiment-v1", # display name in the tracker
    ),
    train_dataset=train_dataset,
)
trainer.train()
```

## Checkpointing

O [Trainer](/docs/transformers/main/pt/main_classes/trainer#transformers.Trainer) salva um checkpoint a cada `save_steps()` atualização do otimizador e mantém todos eles (ou os mais recentes `~TrainingArguments.save_total_limit`).

`save_strategy="best"` mantém apenas o único melhor checkpoint de acordo com uma métrica. Um novo checkpoint é salvo somente quando a métrica monitorada melhora, o que economiza espaço em disco e evita o acúmulo de checkpoints obsoletos.

```py
from transformers import Trainer, TrainingArguments

trainer = Trainer(
    model=model,
    args=TrainingArguments(
        output_dir="out",
        eval_strategy="epoch",
        save_strategy="best",
        metric_for_best_model="perplexity",   # save when eval perplexity improves
        greater_is_better=False,              # lower perplexity is better
        load_best_model_at_end=True,          # load the best weights after training finishes
    ),
    train_dataset=train_dataset,
    eval_dataset=eval_dataset,
    compute_metrics=compute_metrics,          # must return {"perplexity": ...}
)
trainer.train()
```

### Retomar o treinamento

Pass `resume_from_checkpoint=True` para [train()](/docs/transformers/main/pt/main_classes/trainer#transformers.Trainer.train) se o treinamento foi interrompido e você deseja retomar sem perder o progresso. O treinamento será retomado a partir do checkpoint mais recente em `output_dir`.

```py
trainer.train(resume_from_checkpoint=True)
```

Especifique um caminho de checkpoint para retomar de um ponto específico.

```py
trainer.train(resume_from_checkpoint="out/checkpoint-1000")
```

Ao retomar, o [Trainer](/docs/transformers/main/pt/main_classes/trainer#transformers.Trainer) restaura o estado do otimizador, o estado do agendador e o estado do RNG.

O retomar de checkpoints requer os arquivos de estado do otimizador e do agendador no diretório do checkpoint. Se esses arquivos estiverem ausentes (por exemplo, quando `save_only_model=True`), o otimizador será reiniciado do zero.

### Checkpointing JIT

Com o checkpointing periódico (save_strategy="steps" ou "epoch"), você perde todo o progresso de treinamento entre o último checkpoint salvo e uma interrupção. Em clusters compartilhados com cargas de trabalho preemptíveis, como [Kueue](https://kueue.sigs.k8s.io/), os jobs podem ser encerrados a qualquer momento, de modo que esse intervalo pode significar horas de computação desperdiçada.

JIT O checkpointing (Just-In-Time) fecha essa lacuna. Quando o trainer recebe um sinal SIGTERM, ele salva um checkpoint no ponto exato em que o treinamento foi interrompido, para que você retome com perda mínima de progresso. Ele funciona em conjunto com o checkpointing periódico. As salvaguardas periódicas protegem contra falhas e problemas de hardware, enquanto as salvaguardas JIT protegem contra preempção e desligamentos controlados.

Ative-o definindo `enable_jit_checkpoint=True` em [TrainingArguments](/docs/transformers/main/pt/main_classes/trainer#transformers.TrainingArguments).

```py
from transformers import TrainingArguments

training_args = TrainingArguments(
    output_dir="your-model",
    enable_jit_checkpoint=True,
)
```

Quando o SIGTERM é recebido, o [Trainer](/docs/transformers/main/pt/main_classes/trainer#transformers.Trainer) aguarda a conclusão da etapa de treinamento atual, salva um checkpoint e interrompe o treinamento de forma graciosa. Um arquivo sentinela (`checkpoint-is-incomplete.txt`) é escrito quando o salvamento começa e removido assim que o checkpoint é totalmente gravado. Se um diretório de checkpoint ainda contiver esse arquivo, o salvamento foi interrompido antes de ser concluído. O [Trainer](/docs/transformers/main/pt/main_classes/trainer#transformers.Trainer) não verifica isso automaticamente, portanto, inspecione-o você mesmo antes de retomar.

Retome do checkpoint JIT da mesma forma que qualquer outro checkpoint.

```py
trainer.train(resume_from_checkpoint=True)
```

> [!WARNING]
> Você deve configurar seu orquestrador para permitir tempo suficiente para que o checkpoint seja concluído. O período padrão de desligamento gracioso do Kubernetes é de apenas 30 segundos, o que geralmente não é suficiente para modelos maiores.

Defina `terminationGracePeriodSeconds` na especificação do seu Pod ou Job. A localização exata do campo varia conforme o trainer (Kubeflow Training Operator, Ray, etc.).

```yaml
spec:
  template:
    spec:
      terminationGracePeriodSeconds: 300
```

Use `--signal=TERM@<seconds>` no seu script sbatch para enviar SIGTERM antes do limite de tempo do job expirar.

```bash
#SBATCH --signal=TERM@300
```

Calcule o período de tolerância necessário como o tempo máximo possível de um passo de treinamento mais o tempo de salvamento do checkpoint, mais o atraso de 3 segundos de `kill_wait` antes do início do checkpoint. Por exemplo, se um passo de treinamento levar até 2 minutos e o salvamento de um checkpoint levar 2 minutos, defina pelo menos 243 segundos de tempo de tolerância.

