DPO Customization
Learn how to use NeMo Helix to align a model with DPO (Direct Preference Optimization) on a preference dataset. For each prompt, DPO trains on a chosen (preferred) and a rejected response so the model prefers the chosen style — no separate reward model required.
This tutorial uses the rl customization backend (powered by NVIDIA NeMo-RL), which runs DPO on a Ray cluster. Unlike the SFT and LoRA tutorials (Docker GPU jobs), rl requires a Kubernetes-backed NeMo Helix deployment. DPO here is full-weight (no LoRA/adapter); the output is a full model entity. Full-weight DPO keeps a policy and a reference model in memory, so this tutorial uses Qwen/Qwen3-0.6B to fit on one GPU.
Time to complete: approximately 45-60 minutes. Job duration increases with model and dataset size.
Prerequisites
Before starting this tutorial, ensure you have:
- Completed the Quickstart to install NeMo Helix and Python SDK.
- Installed the Python SDK (PyPI wrapper:
pip install "nemo-helix[all,nemo-rl-plugin]"soRlJobInputis available; source checkout: runmake bootstrapfrom the repository root).nemo-helix[all]does not include the RL plugin. - Installed the
datasetspackage:pip install datasets. - A platform configured with
platform.runtime: kubernetes. Therl(DPO) backend provisions a Ray cluster and has no local Docker fallback —submitfails fast on a Docker-runtime platform. Multi-node jobs (parallelism.num_nodes > 1) additionally require the platform-sideNHX_RL_MULTINODE_SHARED_STORAGE_PATH. - Optional: a Hugging Face token, exported as
HF_TOKEN, if you substitute a gated base model. This tutorial’sQwen/Qwen3-0.6Bis public. - At least one GPU with CUDA 13+ and a GPU execution profile (
nemo jobs list-execution-profiles).
Quick Start
1. Initialize the SDK
The SDK connects to the deployment in your current CLI context, using its base URL, default workspace, and credentials. To connect to another deployment, refer to Connect with CLI Contexts. These examples use the default workspace. If your current CLI context uses a different workspace, run nemo config set --workspace default first.
In environments without a CLI configuration file, such as Google Colab, set NHX_BASE_URL (and NHX_ACCESS_TOKEN for an authenticated deployment) before you create the client. NemoClient.from_config() reads both:
2. Prepare the Preference Dataset
DPO trains on preference data. The rl backend takes a single dataset fileset that holds both training.jsonl and validation.jsonl, and auto-detects the row schema from the first line. Three preference formats are supported (see the platform’s BinaryPreferenceDatasetItemSchema / HelpSteer3DatasetItemSchema / Tulu3PreferenceDatasetItemSchema):
Binary Preference Format
Simple prompt / chosen / rejected (the prompt may be a string or a list of chat messages):
HelpSteer3 Format (used here)
A conversation context (string or chat messages), two candidate response1 / response2, and a signed overall_preference in -3..3 — negative means response 1 is preferred, positive means response 2, 0 is a tie. This is the raw schema of nvidia/HelpSteer3, so no conversion is needed:
Tulu3 Preference Format
Full chat conversations for both the chosen and rejected branches (each a list of messages ending with the assistant turn):
Download nvidia/HelpSteer3
We use nvidia/HelpSteer3 (the preference subset), NVIDIA’s open preference dataset. It ships native train and validation splits and matches the HelpSteer3 schema above, so we upload the rows as-is — the platform’s HelpSteer3Dataset loader handles the overall_preference semantics (including ties) at training time.
3. Create FileSet and Upload Preference Data
Upload both JSONL files to a single FileSet so the DPO job can read them.
4. Secrets Setup
The base model (Qwen/Qwen3-0.6B) is public, so the token is optional. For a gated model, store your Hugging Face token as a platform secret named hf-token and reference it on the model fileset.
5. Create Base Model FileSet and Model Entity
DPO starts from an instruction-tuned base model. The model entity’s spec is inferred asynchronously after creation.
6. Create the DPO Customization Job
Submit a DPO job to the rl backend with RlJobInput. Note the DPO-specific shape:
modelis a string ref to the model entity;datasetis a single string ref to the preference fileset (holding both files).- The training method is
{"type": "dpo", ...}— full-weight, nofinetuning_type/LoRA. ref_policy_kl_penaltyis β (DPO paper): how strongly the policy stays tied to the reference model.rlauto-generates the job id (rl-<hex>); read it back from the response.
The learning rate, β, and weight decay follow the NeMo-RL reference config dpo.yaml. max_seq_length is raised to 4096 so long HelpSteer3 conversations fit.
Other configurable knobs: optimizer_type, adam_eps, activation_checkpointing, keep_top_k, val_at_end, preference_loss_weight, sft_loss_weight. Run nemo customization rl explain for the live schema.
7. Track Training Progress
The DPO job runs four steps: download -> dpo-training (Ray) -> upload -> model-entity. Each update shows the current step, how much of that step is done, and the latest loss. Once the backend reports a loss history, the cell charts loss by step.
Interpreting DPO training metrics (in status_details.metrics):
loss— the DPO loss; should trend down as the policy learns to separate chosen from rejected.- Reward margin (chosen minus rejected reward) — should trend up: the model increasingly prefers chosen responses.
- Validation
loss— watch for divergence from training loss (overfitting). Raiseref_policy_kl_penalty(β) or addsft_loss_weightif the policy drifts too far from the reference.
8. Validate the Output Model
DPO produces a full-weight model entity (not an adapter). Confirm it was registered.
9. Deploy and Evaluate (optional)
The DPO output is a full model, so it deploys like any full-weight checkpoint (see the Full SFT tutorial for details). We deploy with vLLM and send a chat completion.
Conclusion
You aligned a base model with DPO on NeMo Helix using the rl backend:
- Uploaded a HelpSteer3 preference dataset as-is (the platform detects the schema natively).
- Submitted a full-weight DPO job that ran on a Ray cluster via the Kubernetes executor.
- Registered the output as a full model entity and (optionally) deployed it for inference.
Next steps: tune the alignment strength with ref_policy_kl_penalty (β), add sft_loss_weight to anchor the policy to the chosen responses, enable activation_checkpointing for memory headroom, or scale up with parallelism. See the Training Configuration reference for the full hyperparameter set.