Skip to main content
Writing a recipe typically requires you to use a training algorithm, as covered in the previous page. Harmony allows you to create your own algorithms through convenient methods that give you access to models for operations such as backward or optim step. You can mix and match these methods to create your own algorithms, or copy and modify our supported algorithms in adaptive_harmony.common. In this page, we assume reasonable familiarity with reinforcement learning with LLMs.

Training primitives

TrainingModel

This is the main class through which you interact with model weights. Load models explains in detail how to a model, but to recap:
Choose the tp parameter (Tensor Parallelism) to be the smallest possible while still fitting in your GPUs. Choose the max_seq_len parameter to be larger than your expected rollout size in tokens, while still fitting in your GPUs.

Generating text

Once a TrainingModel has been loaded, you can use it straightforwardly to make async inference calls. The input and outputs are StringThread objects, corresponding to chats. Details about creation methods are given in the thread page.

Generating tokens

When training with RL, you need the raw tokens to be able to compute log-probabilities and losses. Harmony provides tokenized versions of threads called adaptive_harmony.TokenizedThread, as well as utils for tokenization and detokenization:

Logprobs

Get model logprobs like so:

Training: backward

For training we have implemented losses of the most common algorithms (cross-entropy for SFT, PPO, GRPO, DPO…) inside Harmony. You can do a backward step for each of these losses by applying the corresponding trainer function on the TrainingModel, for instance:
The list of training methods for RL policies is:
  • train_ppo
  • train_grpo
  • train_gspo
  • train_dpo
  • train_tangents
We refer the reader to harmony_client.harmony_client for definition of the parameters for these methods. Note that these methods only compute gradient contribution for the given samples, they do not change model parameters (this is performed by calling optim_step). The train_tangents method is special in that it allows you to pass arbitrary losses, allowing you to implement any RL algorithm not covered in our libraries. See the Bring your own loss functions section at the end of this file for instructions on how to use it.

Training: optim step

Once you have computed the backward pass for all samples in your batch, you need to perform a gradient descent step. We use the AdamW optimizer under the hood.

Putting it all together: simplified GRPO walkthrough

We will see how all these building blocks interact by implementing GRPO, one of the most common RL methods for LLMs. Please refer to the original paper for an in-depth explanation of the algorithm. For simplicity, we only illustrate the single-turn variant of GRPO here. Please take a look at adaptive_harmony.common.env_grpo for our multi-turn variant.

Init: defining useful variables

We will need to use the following objects in the GRPO class:
And before running the data generation, we initialize the reference model to the untrained one:

Generate data

The first phase in the algorithm is to generate self.completions_per_sample completions from a single prompt. We use a helper dataclass for sample collection:
and we proceed like so, creating several completions per prompt and grading them:

Run the algorithm

Once the data generation part is written, the entire algorithm is quite straightforward.
If you look at our actual code, you will see some added complexity from checkpointing, callbacks and logging. That’s it! Pretty simple, isn’t it?

Bring your own loss functions

We also offer a way to train with arbitrary loss functions with train_tangents, by specifying gradient values (tangents) at each token. There are two options:
  • If you have a closed-form solution of the gradient of your loss with respect to the model logprobs, you can simply compute this value with your numerical library of choice and pass it to train_tangents.
  • Otherwise, you can also use autodiff software to compute the gradient of your loss function with respect to the logprobs.
For this second option, imagine you have access to your logprobs as well as your loss loss_fn written in torch. You would do the following, for a given sample (TokenizedThread):
While slightly more technical, this option offers full customizability of your training algorithm.