Concepts / Implementing the Modified Training Function

Implementing the Modified Training Function

Linear warmup gradually increases the learning rate from initial_lr to peak_lr during the first warmup_steps batches of training.

  • Programming

Why a Model Needs a Training Function

A language model does not become useful on its own. It has to be trained, and the work of training is organized around a function. A training function is a function you write to train a model: it takes a model and training data and returns the model in a trained state.

The phrase implementing a training function points to the fact that training is not automatic. Someone has to decide how the training process is organized and write it as a function. Once it exists as a function, the same procedure can be called again whenever the model needs to be trained, which keeps the process consistent and easy to repeat.

This article follows one idea from the chapter on training and evaluating large language models: how a training function is structured, and in particular how its learning rate is computed. The central question to keep in mind is this: what goes into a training function, and what state does the model hold when the function finishes? The source for this topic is brief, so the focus here is on the core mechanism and what it means for structuring your code.

Inputs, Outputs, and the Model's State

The easiest way to build intuition for a training function is to follow the model's state from start to finish. Before training, the model is in its initial condition. During training, the function repeatedly processes data and updates the model. After training, the model is in a new condition that reflects the data it was trained on. Each stage is a snapshot of the same model at a different point in time.

Modelinitial conditionTraining functionrepeats updatesTrained modelstate after trainingTraining databatchesmodel indata inmodel out
What data goes into the training function, what comes out, and which part of the model changes?

The diagram shows the shape of the idea. The training data and the model both go into the training function, and what comes back is the model after training. The model's internal state is the part that changes, which is why the trained model is the changed element. Practically, this means you should check after the call that the model's state actually changed, because a function that returns without updating the model has not trained anything.

Where Pretraining Fits

The source names two linked ideas: implementing a training function, and pretraining the LLM. Pretraining is the stage where a large language model is trained on its base data, and the training function is the code that carries out that stage. In other words, the function is the mechanism, and pretraining is the job it is used for.

The Learning Rate Changes on Every Step

A learning rate controls how large a change the optimizer makes to a model's weights on each update. In many simple training loops it stays at one value for the entire run. The training function in this article does something different: it recalculates the learning rate on every step of the loop, and it uses one rule for the early steps and another rule for the rest of training. The two rules are called the warmup phase and the cosine annealing phase.

The word linear describes the shape of the warmup change. The learning rate rises by the same amount on every step, so plotted against steps it forms a straight line. The increment is a fixed quantity computed once, before the training loop begins. The learning rate itself is recalculated inside the innermost loop, once per batch, because the step counter changes once per batch.

Computing the Warmup Increment

The increment added on each warmup step is the total rise divided by the number of warmup steps. The total rise is the distance from initial_lr up to peak_lr, and the number of warmup steps spreads that rise evenly across the warmup period.

Formula, step by step
  1. 1
    Start with the peak learning rate, which the function reads from the optimizer.
  2. 2
    Subtract initial_lr to get the total rise that warmup must cover.
  3. 3
    Divide by warmup_steps to get the fixed amount the learning rate rises on each warmup step.
  4. 4
    This quotient is computed once, before the epoch loop starts, and reused on every warmup step.

Once the increment is known, the learning rate at any warmup step follows directly. The step counter global_step counts the steps taken so far, so the learning rate is the starting value plus global_step times the increment.

Rule

Worked example

Computing the increment and the learning rate at step 2

Suppose initial_lr is 0.1, peak_lr is 0.5, and warmup_steps is 4. What is the warmup increment, and what is the learning rate when global_step is 2?

  1. 1
    Find the total rise

    peak_lr minus initial_lr is 0.5 minus 0.1, which is 0.4.

  2. 2
    Find the increment

    Divide the total rise by warmup_steps: 0.4 divided by 4 gives 0.1.

  3. 3
    Apply the warmup formula

    With global_step equal to 2, the learning rate is initial_lr plus 2 times 0.1, which is 0.1 plus 0.2.

  4. 4
    Check the branch

    global_step 2 is less than warmup_steps 4, so the linear warmup branch applies.

Result

The increment is 0.1, and the learning rate at global_step 2 is 0.3.

Watching Warmup Climb Batch by Batch

What do you think happens?

Using the same values (initial_lr 0.1, peak_lr 0.5, warmup_steps 4), what is the learning rate at global_step 2?

  • 0.2

  • 0.3

  • 0.4

  • 0.5

Reveal answer
Answer:

0.3

The increment is 0.1, and 0.1 plus 2 times 0.1 equals 0.3. Each warmup step adds the same fixed amount, so the rise is a straight line.

global_step 0lr 0.1global_step 1lr 0.2global_step 2lr 0.3global_step 3lr 0.4global_step 4lr 0.5, cosine begins+ 0.1+ 0.1+ 0.1+ 0.1
How does the learning rate change batch by batch during warmup, and where does it end up?

The diagram shows the warmup rising in equal steps of 0.1. Each batch adds the same amount, so the learning rate climbs in a straight line. When global_step reaches 4, which equals warmup_steps, the warmup branch no longer applies and the learning rate is taken from the cosine schedule, which starts from the peak.

Switching to Cosine Annealing

The branch that handles warmup begins with the condition global_step < warmup_steps. When that condition is true, the code uses the linear formula. When it is false, the code uses the cosine formula. Once global_step reaches warmup_steps, the training function stops using the linear rule and starts using cosine annealing, a technique used to adjust the learning rate after the warmup phase.

global_step <warmup_steps?checked every batchLinear warmupinitial_lr + global_step *lr_incrementLearning rate forthis stepused for the weight updateCosine annealingstarts at peak_lr, lowerstoward min_lrtruefalse
What condition causes the training loop to leave warmup, and what does the learning rate schedule do after that point?

The two phases are connected through the same step counter and the same peak_lr. Warmup climbs toward the peak, and cosine annealing starts from that peak and decreases toward the minimum. The variable progress measures how far training has moved through the post-warmup period. The source defines it as the number of steps completed after warmup divided by the number of steps remaining after warmup, which is the total number of training steps minus warmup_steps. Because progress is measured from the end of warmup, the cosine schedule begins from the peak learning rate and moves toward min_lr as training continues.

Locating an Unexpected Learning Rate

When a learning rate looks wrong during training, the fastest path to the cause is to ask three questions in order. First, which branch applied at that step: was global_step below warmup_steps? Second, what were the values of initial_lr, peak_lr, and warmup_steps that fed into the increment? Third, for a cosine step, what were total_training_steps and warmup_steps that defined progress? Each question points to one line of the training function, so the divergence can be located rather than guessed.

python
Notes on the code
  • lr_increment is computed once, before the epoch loop starts
  • the condition decides which phase applies at this step
  • the warmup line is where a warmup learning rate value originates
  • the cosine branch is where progress determines the value

The snippet is an illustration of the structure described in the source, not a complete training function. The lines that matter for debugging are the increment line, the branch condition, and the warmup assignment. If a warmup value is wrong, check whether the increment was computed from the values you expected. If the value is wrong only after warmup ends, check the cosine branch and the progress inputs.

Mistakes When Structuring a Training Function

Structural choiceIncorrect versionCorrect version
Where the increment is computedRecalculated inside the batch loop on every stepComputed once, before the epoch loop starts
Where the learning rate is computedComputed once and held fixed for the whole runRecalculated inside the innermost loop, once per batch
Where the peak comes fromPassed in as an argument the function does not expectRead from the optimizer's first parameter group
Whether the model is checkedFunction returns without confirming the model changedModel state is confirmed to have changed after the call

Structural choices that separate a sound training function from a fragile one

  • Common mistake

    Treating the learning rate as a single fixed value for the whole run

    Why it fails

    The training function in this article recalculates the learning rate on every step and switches rules, so a fixed value would skip warmup and cosine annealing entirely.

    Do this instead

    Compute the learning rate inside the per-batch loop, using the phase that applies at that step.

  • Common mistake

    Recomputing the warmup increment inside the batch loop

    Why it fails

    The increment depends only on peak_lr, initial_lr, and warmup_steps, which do not change during the run, so recomputing it wastes work and invites inconsistent inputs.

    Do this instead

    Compute lr_increment once, before the epoch loop starts.

  • Common mistake

    Passing the peak learning rate as an argument

    Why it fails

    The source says the function does not receive a peak learning rate as an argument and reads it from the optimizer instead.

    Do this instead

    Read the peak from the optimizer's first parameter group, and understand that this assumes the optimizer's starting learning rate is the peak.

  • Common mistake

    Assuming the function trains the model just because it was called

    Why it fails

    A function can run and still leave the model unchanged, so calling it does not guarantee training happened.

    Do this instead

    Confirm that the model's state actually changed after the call.

  • Common mistake

    Confusing the step counter global_step with the epoch number when checking which phase applies

Practice: Trace a Learning Rate Back to Its Line

EASY

Using initial_lr 0.1, peak_lr 0.5, and warmup_steps 4, a training run logs a learning rate of 0.25 at some step during warmup. Using the three debugging questions, determine which branch applied, what the increment should be, and which line would produce the value you need to check. Then state what the learning rate should be at global_step 3.

Hints
  • Start by asking whether global_step was below warmup_steps at the logged step.
  • The increment is peak_lr minus initial_lr, divided by warmup_steps.
  • At global_step 3, the warmup formula gives initial_lr plus 3 times the increment.

Key Takeaways

  • A training function takes a model and training data and returns the model in a trained state, and its usefulness depends on the model's state actually changing after the call.
  • Linear warmup raises the learning rate by a fixed increment, (peak_lr minus initial_lr) divided by warmup_steps, computed once before the epoch loop and applied through initial_lr plus global_step times the increment.
  • The training loop switches from warmup to cosine annealing when global_step is no longer less than warmup_steps, and the cosine schedule starts from the peak and lowers toward min_lr using progress.
  • When a learning rate looks wrong, identify the branch that applied, trace the increment inputs, and check the cosine progress inputs to locate the responsible line.
  • Pretraining a large language model is the job, and the training function is the mechanism used to carry it out.

Related concepts

More concepts starting with I