Transformers Trainer

How the Hugging Face Trainer progress bar works and how to change it

The transformers Trainer draws its bar with ProgressCallback, a tqdm.auto bar whose total is the number of optimizer steps. disable_tqdm=True swaps it for plain log lines, and loss only appears every logging_steps (default 500) steps. Since v5, report_to defaults to "none", so W&B or TensorBoard stay silent until you name them. Checked on transformers 5.22.0.

5 min readML training and GPUs

At a glance

  • The bar counts optimizer steps, so gradient_accumulation_steps=2 halves the total you see.
  • Loss lines print every 500 steps by default; lower logging_steps to see them sooner.
  • report_to defaults to "none" in transformers v5, where v4 reported to every installed integration.
  • Jupyter and Colab get NotebookProgressCallback (an HTML bar and table) instead of tqdm.

Where the Trainer progress bar comes from

When you start a training run with the Hugging Face Trainer in a terminal, it adds ProgressCallback by default. That callback creates a standard bar with tqdm(total=state.max_steps) from tqdm.auto, and only the main process draws it, so a multi-GPU run shows one bar.

That total is the number of optimizer update steps, not epochs multiplied by batches. With 64 examples, a batch size of 8, gradient_accumulation_steps=2 and 2 epochs, the bar counts to 8, not 16. When your run hits evaluation or prediction, ProgressCallback puts up a second bar for that pass.

The dictionaries scrolling above the bar come from the same callback. Every logging_steps steps, its on_log hook takes the log dictionary (loss, grad_norm, learning_rate, epoch), rounds floats to 4 significant digits and writes it above the bar with tqdm.write.

The arguments that control the bar and the logs

You control the bar and the log lines through TrainingArguments. These are the arguments that touch progress output, with their defaults in transformers 5.22.0.

ArgumentDefaultWhat it changes
disable_tqdmNot set: bar on, unless the transformers logger is above WARNINGTrue replaces ProgressCallback with PrinterCallback.
logging_strategy"steps"Log by step count, at the end of each epoch ("epoch") or never ("no").
logging_steps500Optimizer steps between log lines when the strategy is "steps".
logging_first_stepFalseLog at step 1 instead of waiting for the first interval.
report_to"none"Integrations that receive the logs, like "wandb", "tensorboard" or "mlflow".
log_level"passive"Logger level on the main process. Setting it does not hide the bar.

Turn the bar off

To hide the progress bar, pass disable_tqdm=True. If you leave it unset, the Trainer decides when TrainingArguments is created: the bar is off only if the transformers logger is above WARNING at that moment, for example after transformers.logging.set_verbosity_error(). Passing log_level="error" alone keeps the bar, because that level is applied later.

Python
from transformers import TrainingArguments

args = TrainingArguments(
    output_dir="out",
    disable_tqdm=True,
    logging_steps=50,
)

Turning the bar off doesn't leave your terminal silent. With disable_tqdm=True the Trainer uses PrinterCallback, which prints each log dictionary as a plain line on the main process. That's handy when you write output to a log file, where a redrawing bar turns into noise.

Log more or less often

By default you won't see a single loss value until the optimizer has taken 500 update steps. On a small dataset or a quick test, training can finish before the first line appears.

Set logging_steps lower to print more often, and logging_first_step=True to get a line at step 1, so you know logging works before the first full interval.

Python
args = TrainingArguments(
    output_dir="out",
    logging_strategy="steps",
    logging_steps=10,
    logging_first_step=True,
    report_to="tensorboard",
)

The same settings control how often metrics reach your experiment tracker, which brings up a breaking change in the v5.0.0 release notes. In transformers v4, leaving report_to unset sent logs to every installed integration. In v5 the default is "none", so after upgrading, W&B or TensorBoard log nothing until you pass report_to="wandb" or a list of integrations yourself.

Replace the bar with your own callback

If neither callback prints what you want, subclass TrainerCallback. It gives you hooks such as on_train_begin, on_step_end, on_log, on_evaluate and on_train_end.

You manage callbacks on a trainer with add_callback(), remove_callback() and pop_callback(). To replace the default bar, remove ProgressCallback and add a callback that implements on_log.

Python
from transformers import ProgressCallback, Trainer, TrainerCallback


class LossPrinter(TrainerCallback):
    def on_log(self, args, state, control, logs=None, **kwargs):
        if state.is_world_process_zero and logs and "loss" in logs:
            print(f"step {state.global_step}/{state.max_steps} loss {logs['loss']:.4f}")


trainer = Trainer(model=model, args=args, train_dataset=train_dataset)
trainer.remove_callback(ProgressCallback)
trainer.add_callback(LossPrinter())
trainer.train()

Notebook versus terminal

Which callback the Trainer registers depends on where Python runs. In a terminal you get ProgressCallback and its tqdm bar. In Jupyter or Colab the Trainer uses NotebookProgressCallback, which draws an HTML bar and a metrics table that update in place.

Keep that in mind when you strip out the default bar. In a notebook, trainer.remove_callback(ProgressCallback) silently does nothing, because the active callback there is NotebookProgressCallback from transformers.utils.notebook.

Watch a Trainer run from your phone

Because the Trainer's terminal bar is a standard tqdm bar, Runpeek can stream it. We ran a short Trainer job on transformers 5.22.0 with the patch below, and the link showed the bar counting to its 8 optimizer steps and the run closing as finished with exit code 0.

Call patch() before training starts. It hooks the terminal bar, not the HTML bar that NotebookProgressCallback draws in a notebook. Evaluation draws its own bar, so it counts as progress; set the stall window a little longer than your slowest silent step, such as a checkpoint save, and keep it at 30 minutes or less. The links expire 30 minutes after the last update.

FAQ

How do I disable the progress bar in the Hugging Face Trainer?

Pass disable_tqdm=True to TrainingArguments. The Trainer then swaps ProgressCallback for PrinterCallback, which prints each log dictionary as a plain line instead of drawing a bar. Setting log_level="error" does not hide the bar.

Why does the Trainer bar show fewer steps than my number of batches?

The bar counts optimizer update steps. With gradient accumulation, several batches make one step, so 16 batches with gradient_accumulation_steps=2 show as 8 steps. Multiple GPUs shrink the count too, since each step covers one batch per device.

Why is the Trainer not logging the loss?

logging_steps defaults to 500, so a short run can finish before the first log line. Set logging_steps=10 and logging_first_step=True to see the loss early, and check that logging_strategy isn't "no".

Why did W&B stop logging after I upgraded to transformers v5?

In v5, report_to defaults to "none". In v4, leaving it unset reported to every installed integration. Pass report_to="wandb" or a list such as ["wandb", "tensorboard"] to TrainingArguments.

Does the Trainer progress bar work in Jupyter and Colab?

Yes, but it's a different one. In notebooks the Trainer uses NotebookProgressCallback, which draws an HTML bar with a metrics table instead of tqdm. Code that removes or patches the tqdm bar does not affect it.

Check on long runs from your phone

Change one import and every tqdm bar prints a link you can open on any device. Get a Discord or Slack message when the run finishes, fails or stalls.

Get a live linkpip install tqdm-live

Sources