DPO Customization
Learn how to use the NeMo Platform 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 Platform. DPO here is full-weight (no LoRA/adapter); the output is a full model entity.
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 the NeMo Platform and Python SDK.
- Installed the Python SDK (PyPI wrapper:
pip install "nemo-platform[all,nemo-rl-plugin]"soRlJobInputis available; source checkout: runmake bootstrapfrom the repository root).nemo-platform[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-sideNMP_RL_MULTINODE_SHARED_STORAGE_PATH. - A Hugging Face token with access to the gated base model (this tutorial uses
meta-llama/Llama-3.2-1B-Instruct). Export it asHF_TOKEN. - 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 needs your NeMo Platform server URL. By default http://localhost:8080 is used; set NMP_BASE_URL to override:
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 (meta-llama/Llama-3.2-1B-Instruct) is gated, so 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.
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. We poll the top-level job status and surface the training step’s progress.
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 the NeMo Platform 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.