PEFT & RL Alignment Training
Parameter-efficient fine-tuning (12 methods), reinforcement learning alignment (9 trainers), mixed-precision training, knowledge distillation, and dataset curation
Deeplearning4j 1.0.0-rewrite adds a complete suite of tools for fine-tuning large pretrained models without retraining all parameters, aligning language model outputs using reinforcement learning feedback, training with reduced numerical precision, and curating datasets for domain adaptation.
1. Overview
The following capability groups are covered in this page:
PEFT
PeftModel, PeftModelFactory, LoraLayer
13 adapter types; freeze base weights, train only adapter parameters
RL Alignment
GRPOTrainer, DPOTrainer, PPOTrainer, and 7 more
Human-preference and reward-signal alignment
Training Pipelines
SFTTrainingPipeline, RLAlignmentPipeline
End-to-end supervised and RLHF workflows
Mixed Precision
FP8ScaleManager, LossScaler
FP8 forward/backward, dynamic loss scaling
8-bit Adam
Adam8bit, Adam8bitUpdater
~4x optimizer-state memory reduction
Knowledge Distillation
DistillationTrainer
Teacher/student training with KL, attention, and feature losses
Dataset Curation
TextDeduplicator, SequencePacker, and 18 more
Deduplication, contamination removal, curriculum, bin-packing
Transfer Learning
TransferLearning, TransferLearningHelper
Layer freezing and head replacement on existing models
All SameDiff models gain these extension methods automatically:
sd.applyPeft(PeftConfig config);
sd.getTrainableParameters();
sd.printTrainableParameters();
sd.distillFrom(SameDiff teacher, DistillationConfig config);
sd.fitGRPO(GRPOConfig config, MultiDataSetIterator data);
sd.saveAdapters(Path dir);
sd.loadAdapters(Path dir);2. Maven Dependencies
3. PEFT Methods
3.1 PeftType Enum
Every PEFT method is identified by a PeftType constant:
LORA
Low-Rank Adaptation — low-rank A/B matrices added to linear projections
QLORA
LoRA on NF4-quantized base weights
DORA
Weight-Decomposed LoRA with learned magnitude vector
LOHA
Low-rank Hadamard product adaptation
LOKR
Low-rank Kronecker product adaptation
IA3
Infused Adapter by Inhibiting and Amplifying Inner Activations
VERA
Vector-based Random Matrix Adaptation
PREFIX_TUNING
Trainable key/value prefix tokens prepended to each layer
PROMPT_TUNING
Soft prompt tokens prepended to the input embedding
ADAPTER
Small bottleneck feed-forward modules inserted between layers
LOFTQ
LoRA initialized to minimize NF4 quantization error
ADALORA
Adaptive rank allocation across layers
DYLORA
Dynamic rank search during training
3.2 PeftModel
PeftModel wraps an existing SameDiff base model and injects adapter layers without modifying the base graph:
Key PeftModel capabilities:
printTrainableParameters()
Logs trainable vs total parameter count and percentage
getTrainableParameterCount()
Returns the count of adapter (non-frozen) parameters
addAdapter(String name, PeftConfig config)
Inject an additional named adapter onto the same base model
setActiveAdapter(String name)
Switch which adapter is active for inference
mergeAndUnload()
Merge adapter weights into base weights and return a plain SameDiff
saveAdapters(Path dir)
Serialize only adapter weights (small files)
loadAdapters(Path dir)
Restore previously saved adapter weights
Base model parameters are automatically frozen when PeftModel is created. Only the adapter parameters listed in targetModules are in the computation graph as trainable variables.
3.3 PeftModelFactory
PeftModelFactory.fromConfig(SameDiff baseSd, PeftConfig config) inspects config.getPeftType() and dispatches to the correct adapter injection strategy:
3.4 LoraLayer
LoraLayer is the core adapter unit for all LoRA variants. It wraps an existing linear op (matrix multiply) with low-rank side-path A and B matrices:
Fields tracked per layer:
r
Rank of the factorization
alpha
Scaling factor; effective scale = alpha / r
dropout
Dropout probability applied to the adapter path
mergeWeights() adds (lora_B @ lora_A) * (alpha / r) directly into the base weight matrix, eliminating the side path and returning a standard linear op with no inference overhead.
3.5 LoraAdapterCache
LoraAdapterCache provides thread-safe, LRU-evicted in-memory caching of adapter weights for multi-adapter serving scenarios:
The LRU policy evicts the least-recently-used adapter when the cache is full, making it suitable for serving many fine-tuned variants from a single base model without loading all adapters into GPU memory simultaneously.
3.6 LoftQInitializer
LoftQInitializer produces LoRA A/B initializations that specifically minimize the error introduced by NF4 quantization:
Use initLoraWeights(InitLoraWeights.LOFTQ) in LoraConfig to apply this automatically via PeftModelFactory.
4. LoRA Deep Dive
4.1 LoraConfig
biasMode controls which bias vectors receive gradients:
NONE
No bias vectors are trained (default)
ALL
All bias vectors (base + adapter layers) are trained
LORA_ONLY
Only bias vectors in LoRA-targeted layers are trained
4.2 QLoraConfig
QLoraConfig extends LoraConfig and adds NF4 quantization of the base weights. The base model loads in 4-bit and stays frozen; only the LoRA adapter trains in full precision:
4.3 AdaLoraConfig — Adaptive Rank Allocation
AdaLoRA starts all adapters at initR and iteratively prunes ranks toward targetR using singular value decomposition-based importance scoring. Orthogonal regularization keeps the A/B decomposition valid:
4.4 DyLoraConfig — Dynamic Rank
DyLoRA trains a single adapter that can serve any rank in [minR, maxR] by randomly sampling a rank each forward pass. This produces an adapter where you pick the serving rank at inference time based on latency vs. quality trade-offs:
4.5 Other Adapter Configs
DoraConfig
useDoraDecomposition, magnitudeLr (learning rate for the magnitude vector)
LohaConfig
Hadamard rank r, lohaAlpha, targetModules
LokrConfig
Kronecker factor sizes, alpha, targetModules
IA3Config
targetModulesForFeedforward, scales feedforward activations only
VeraConfig
projectionRank, per-layer scaling vectors; shared random projection matrices are not stored per-layer
LoftQConfig
numBits, numIter for quantization error minimization
PrefixTuningConfig
numVirtualTokens, encoderHiddenSize
PromptTuningConfig
numVirtualTokens, promptTuningInit (RANDOM or TEXT)
AdapterConfig
bottleneckDim, nonLinearity, placement (AFTER_ATTN, AFTER_FF, BOTH)
4.6 VeRA — Vector-based Random Matrix Adaptation
VeRA (ADR 0077) shares a single pair of frozen random projection matrices across all targeted layers. Only per-layer learned scaling vectors d and b are trained, making it dramatically more parameter-efficient than standard LoRA.
The update formula per layer is:
where A_shared and B_shared are the same frozen random matrices for every layer. Only d and b (one scalar per row/column) are trainable.
VeRA requires orders of magnitude fewer trainable parameters than LoRA at the same rank, making it well suited for scenarios where adapter storage or communication is a bottleneck.
4.7 DyLoRA — Dynamic Rank Training
DyLoRA (ADR 0077) trains a single adapter with a rank range [minRank, maxR]. During each forward pass a rank is sampled uniformly from the range. After training, the same adapter checkpoint can be served at any rank in the range, letting you trade quality against latency at deployment time.
4.8 LoRA+ — Differential Learning Rates
LoRA+ (ADR 0077) applies a higher learning rate to the B matrix than to the A matrix. The B matrix lies closer to the output and benefits from faster updates; keeping A at the base learning rate stabilises training. Set loraLrRatioB in LoraConfig and register the multiplier in TrainingConfig:
4.9 PiSSA and OLoRA Initialization
Both PiSSA and OLoRA (ADR 0077) produce better starting points for LoRA adapters than random initialization by exploiting the structure of the base weight matrix.
PiSSA (Principal Singular-value and Singular-vector Adaptation) runs a truncated SVD on the base weight and initialises A and B from the top-r singular triplets. The base weight is then replaced by its residual W_residual = W - B @ A, so the adapter begins training with zero initial error.
OLoRA performs the same residual correction but uses QR decomposition instead of SVD, which is cheaper for wide matrices.
Select either via initLoraWeights:
Because the base weight is modified in place during initialization, mergeAndUnload() is mandatory before saving if you want a standalone model file. The residual base weight and the adapter must be kept together.
4.10 BitFit — Bias-Only Fine-Tuning
BitFit (ADR 0077) is the simplest PEFT method: every parameter in the base model is frozen except the bias vectors. It is implemented as a method on PeftModel rather than a separate config:
BitFit is appropriate for small datasets where larger adapters overfit, and for establishing a low-cost baseline before committing to a full PEFT experiment.
4.11 Multi-Adapter Serving
Multiple adapters may be attached to the same base model simultaneously. Switch between them without reloading the base weights:
LoraAdapterCache manages hot-swapping in multi-tenant serving: the cache holds pre-loaded adapter weight maps and swaps them into the model graph on demand with LRU eviction.
4.12 Merge and Unload
After training, merge the adapter into the base weights to get a standard model with no inference overhead:
Under the hood, mergeAndUnload() calls LoraLayer.mergeWeights() on every adapted layer, which adds (B @ A) * (alpha / r) to the base weight in place, then removes the adapter variables from the graph.
5. RL Alignment Trainers
All RL alignment trainers operate on a SameDiff policy model and are configured with builder-pattern config objects. They implement a common interface that exposes a train(MultiDataSetIterator) method.
5.1 GRPOTrainer — Group Relative Policy Optimization
For each prompt, GRPO generates groupSize completions, scores them with a reward function, computes z-score normalized advantages within the group, and optimizes a clipped surrogate objective:
where ratio = pi(token) / pi_old(token).
SameDiff placeholders used by GRPOTrainer:
_grpo_tokens
[batch, seq]
Token IDs for generated completions
_grpo_old_log_probs
[batch, seq]
Log probabilities from the old policy
_grpo_advantages
[batch]
Z-score normalized group advantages
_grpo_ref_log_probs
[batch, seq]
Log probabilities from the frozen reference model
5.2 DPOTrainer — Direct Preference Optimization
DPO eliminates the need for a separate reward model by directly optimizing on preference pairs (chosen vs. rejected):
5.3 PPOTrainer — Proximal Policy Optimization
PPO uses a value network to estimate baselines and clips the policy update ratio:
5.4 DAPOTrainer — Decoupled Clip and Dynamic Sampling Policy Optimization
DAPO decouples the clip range for chosen vs. rejected samples and uses dynamic sampling to focus the rollout budget on difficult prompts:
5.5 DrGRPOTrainer — Variance-Reduced GRPO
DrGRPO adds advantage whitening (zero mean, unit variance across the full batch rather than per-group) to reduce gradient variance:
5.6 KTOTrainer — Kahneman-Tversky Optimization
KTO applies prospect theory loss functions that model asymmetric human preferences (losses are felt more strongly than gains):
5.7 ORPOTrainer — Odds Ratio Preference Optimization
ORPO eliminates the reference model by adding an odds-ratio penalty directly to the SFT cross-entropy loss:
5.8 SimPOTrainer — Simple Preference Optimization
SimPO removes the reference model and uses length-normalized rewards to avoid verbosity bias:
5.9 GSPOTrainer — Grouped Sampling Policy Optimization
GSPO uses sampling-based grouping of completions and optimizes group-level preference signals:
5.10 VlmGRPOTrainer — GRPO for Vision-Language Models
VlmGRPOTrainer extends GRPO for multimodal models. The reward function receives both the generated text and the conditioning image:
5.11 RewardModelTrainer
RewardModelTrainer trains a scalar reward model from preference data. It supports three reward function implementations:
CompositeRewardFunction
Weighted sum of multiple reward signals
RuleBasedRewardFunction
Hand-crafted heuristics (format compliance, length penalties)
SameDiffRewardFunction
Trainable neural reward model implemented as a SameDiff graph
6. Training Pipelines
6.1 SFTTrainingPipeline
SFTTrainingPipeline handles the full supervised fine-tuning loop: data loading, loss computation, gradient accumulation, optimizer stepping, checkpointing, and optional evaluation:
Internally, SFTTrainingPipeline uses GradientAccumulator to split each logical batch into micro-batches, accumulating gradients across accumulationSteps calls to SameDiff.execBackwards() before applying the optimizer update.
6.2 RLAlignmentPipeline
RLAlignmentPipeline coordinates the full RLHF loop:
Freeze reference model (copy of base policy before RL training)
Rollout generation — sample completions from current policy
Reward scoring — score with
RewardModelTraineror aRewardFunctionAdvantage computation — normalize per group or globally
Trainer update — call the configured RL trainer (GRPO, PPO, DPO, etc.)
6.3 GradientAccumulator
6.4 CheckpointManager
6.5 ContinuedPretrainingWorkflow
For domain-specific continued pretraining, ContinuedPretrainingWorkflow mixes a domain dataset with a general-purpose dataset at a configurable ratio:
7. Mixed Precision Training
7.1 FP8ScaleManager
FP8ScaleManager tracks per-tensor absolute maximums and updates dynamic scales for FP8 forward and backward passes:
Forward activations
E4M3
448.0
Backward gradients
E5M2
57344.0
7.2 LossScaler — Dynamic Loss Scaling
LossScaler prevents underflow in FP16/BF16 training by scaling the loss up before the backward pass and scaling gradients back down before the optimizer step:
7.3 Gradient Checkpointing
Gradient checkpointing trades compute for memory by not storing all intermediate activations during the forward pass. Activations are recomputed during the backward pass as needed:
7.4 LossScaleConfig — TrainingConfig Integration (ADR 0057)
The core of the mixed precision system is LossScaleConfig, which is embedded directly in TrainingConfig. Three modes are available:
NONE
No loss scaling (default; pure FP32 training)
STATIC
Fixed scale factor; use when you already know a safe scale for your model
DYNAMIC
Adaptive scaling that automatically grows on stable steps and backs off on overflow
TrainingConfig carries two additional data-type fields:
computeDataType— the dtype used for forward and backward passes (e.g.,FLOAT16orBFLOAT16)masterWeightDataType— the dtype used to store the authoritative weight copy (almost alwaysFLOAT)
For a known-stable scale (e.g., after a dry-run sweep), use static mode:
A convenience factory method covers the most common case:
7.5 Gradient Accumulation via TrainingConfig (ADR 0057)
Gradient accumulation is configured directly on TrainingConfig via gradientAccumulationSteps. Gradients are always accumulated in FP32 regardless of computeDataType, which prevents precision loss when summing many small gradients:
The GradientAccumulator (see section 6.3) is used by SFTTrainingPipeline internally when gradientAccumulationSteps > 1. It stores accumulated gradients per named variable and averages them before applying the optimizer update. You may also use it directly in a custom training loop (see section 6.3).
Data type memory tradeoffs (for reference):
Weights
W bytes
W/2 (FP16) + W (master FP32) = 1.5W
Gradients
W bytes
W/2 bytes
Optimizer state (Adam)
2W bytes
2W bytes
Activations
A bytes
A/2 bytes
For models where activations dominate GPU memory (most large transformers), mixed precision provides a significant net reduction despite the FP32 master weight copy.
8. 8-bit Adam Optimizer
Adam8bit stores the first and second moment vectors (m and v) in INT8 with per-block absolute maximum quantization, reducing optimizer state memory by approximately 4x:
BF16 Adam (standard)
~56 GB optimizer state
Adam8bit
~14 GB optimizer state
Default block size is 2048 elements per quantization block (DEFAULT_BLOCK_SIZE = 2048).
Internally, Adam8bitUpdater performs per-block updates:
Dequantize INT8
mandvblocks to float using stored absmax valuesApply the standard Adam moment update in float
Compute the parameter update
Requantize updated
mandvback to INT8
BlockQuantizationUtils provides the low-level INT8 quantize/dequantize operations used by the updater.
9. Knowledge Distillation
DistillationTrainer trains a smaller student model to mimic a larger teacher model. Three loss components are available and can be combined:
DistillationKLLoss
KL divergence between teacher and student output distributions at temperature T
AttentionDistillationLoss
MSE between teacher and student attention weight matrices
FeatureDistillationLoss
MSE between intermediate hidden state representations
The temperature parameter scales logits before the softmax: higher values produce softer probability distributions that expose more information about inter-class similarities.
Alternatively, use the SameDiff extension:
9.1 Native Distillation Loss Ops (ADR 0077)
Each of the three Java loss classes is backed by a C++ op (CPU and CUDA) registered in libnd4j. You can invoke them directly via SameDiff if you want to compose a custom distillation loss:
distillation_kl_loss
sd.math.distillationKLLoss(student, teacher, labels, T, alpha)
alpha * T^2 * KL(softmax(s/T) || softmax(t/T)) + (1-alpha) * CE(s, labels)
feature_distillation_loss
sd.math.featureDistillationLoss(studentHidden, teacherHidden)
MSE(projection(studentHidden), teacherHidden)
attention_distillation_loss
sd.math.attentionDistillationLoss(studentAttn, teacherAttn)
MSE(studentAttn, teacherAttn) with head-count alignment
Each op ships with a gradient (backward) implementation so they participate automatically in sd.execBackwards().
Example — custom combined loss in a SameDiff graph:
9.2 Self-Distillation with EMA Teacher
DistillationTrainer also supports self-distillation, where the teacher is an Exponential Moving Average (EMA) of the student's own weights. This stabilises training when no external large teacher is available:
10. Dataset Curation Toolkit
The dataset curation package provides 20 utilities for preparing high-quality training data.
10.1 Deduplication
TextDeduplicator uses MinHash Locality-Sensitive Hashing to detect and remove near-duplicate documents efficiently:
10.2 Benchmark Contamination Removal
NGramDecontaminator removes documents containing n-gram overlaps with benchmark evaluation sets:
10.3 Quality Filtering
TextQualityFilter applies heuristics to remove low-quality text:
10.4 Curriculum Learning
CurriculumIterator wraps a dataset iterator and yields examples in order of difficulty, starting with easier examples and progressing to harder ones:
10.5 Sequence Packing
SequencePacker bin-packs variable-length sequences into fixed-size windows, minimizing padding tokens and maximizing GPU utilization:
10.6 Domain Mixing
WeightedDataMixer samples from multiple domain iterators with configurable weights:
10.7 Padding-Free Batching
LengthBucketingIterator groups sequences into length buckets before batching, reducing within-batch padding. PaddingFreeBatch represents a batch where all padding has been eliminated by packing:
10.8 Instruction Formatting and Chat Templates
InstructionDataFormatter and ChatTemplate apply model-specific chat templates to raw instruction datasets:
10.9 Stratified Splitting
StratifiedSplitter creates train/validation/test splits that preserve category distributions:
10.10 Package Reference and Full Class List
All curation classes live under org.nd4j.linalg.dataset.curation in the nd4j-api artifact, not org.deeplearning4j.data. Use these imports in your code:
.dedup
MinHasher, TextDeduplicator
.decontamination
NGramDecontaminator, DecontaminationResult
.curriculum
CurriculumIterator, DifficultyScorer
.packing
SequencePacker, PackedSequence
.mixing
WeightedDataMixer
.batching
LengthBucketingIterator, PaddingFreeBatch, PaddingFreeBatchCollator
.filtering
TextQualityFilter, FilterResult
.format
ChatTemplate, InstructionDataFormatter, ConversationTurn, ConversationExtension, FormattedExample
.splitting
StratifiedSplitter, SplitResult
(top-level)
RawTextDatasetIterator, TokenizedTextDataIterator
The correct imports for the examples in sections 10.1–10.9 follow this pattern:
MinHasher constructor signature (exact from source):
NGramDecontaminator works in two steps — index benchmarks first, then decontaminate:
CurriculumIterator API (exact from source):
SequencePacker uses First-Fit Decreasing bin packing and produces block-diagonal attention masks (one block per packed document) to prevent cross-document attention leakage:
WeightedDataMixer is a generic Iterator<T> that accepts any Iterator<T> sources. It supports optional temperature scaling (values < 1 sharpen the distribution toward the highest-weight source; values > 1 flatten it):
11. Transfer Learning API
The classical transfer learning API (TransferLearning / TransferLearningHelper) applies to MultiLayerNetwork and ComputationGraph models. For large generative models, prefer the PeftModel API described in sections 3–4.
11.1 Freeze Layers by Name Pattern
11.2 SameDiff-Based Freezing
For SameDiff models, freeze parameters by converting them to constants:
11.3 TransferLearningHelper — Pre-computed Feature Cache
For large frozen feature extractors, pre-computing activations at the freeze boundary dramatically reduces training time:
12. Configuration Reference
LoraConfig
r
int
8
Adapter rank
loraAlpha
int
16
Scaling numerator; effective_scale = loraAlpha / r
loraDropout
double
0.0
Dropout on adapter input
targetModules
List<String>
[]
Layer name substrings to target
bias
String
"none"
Which bias vectors to train: "none", "all", "lora_only"
initLoraWeights
String
"kaiming_uniform"
Init strategy: "kaiming_uniform", "gaussian", "pissa", "olora"
loraLrRatioB
double
1.0
LR multiplier for B matrix relative to A matrix (LoRA+ feature)
useRsLora
boolean
false
Use rank-stabilized scaling α/√r instead of α/r
VeraConfig
projectionRank
int
64
Rank of the shared random projection matrices
targetModules
List<String>
[]
Layer name substrings to target
loraDropout
double
0.0
Dropout applied to the adapter path
DyLoraConfig
r
int
16
Maximum rank (upper bound of dynamic range)
minRank
int
1
Minimum rank sampled during training
loraAlpha
int
16
Scaling factor
targetModules
List<String>
[]
Layer name substrings to target
LossScaleConfig
mode
Mode
NONE
NONE, STATIC, or DYNAMIC
initialScale
double
65536.0
Starting loss scale (2^16)
minScale
double
1.0
Floor for dynamic scaling
maxScale
double
65536.0
Ceiling for dynamic scaling
growthFactor
double
2.0
Multiplier applied to scale after stable run
backoffFactor
double
0.5
Multiplier applied to scale on overflow
growthInterval
int
2000
Consecutive finite-gradient steps before scale grows
GRPOConfig
groupSize
int
8
Completions generated per prompt
clipEpsilon
double
0.2
Policy ratio clipping threshold
klCoeff
double
0.04
KL divergence penalty weight
maxNewTokens
int
256
Maximum tokens generated per completion
temperature
double
1.0
Sampling temperature
SFTConfig
maxSeqLength
int
2048
Maximum input sequence length
batchSize
int
8
Micro-batch size per step
gradientAccumulationSteps
int
1
Steps before optimizer update
numEpochs
int
3
Training epochs
learningRate
double
2e-4
Peak learning rate
warmupSteps
int
0
Linear warmup steps
saveEveryNSteps
int
500
Checkpoint frequency
FP8ScaleManager
rollingWindowSize
int
16
Steps in the rolling absmax window
forwardFormat
FP8Format
E4M3
FP8 format for forward activations
backwardFormat
FP8Format
E5M2
FP8 format for backward gradients
forwardMaxValue
double
448.0
Saturation value for E4M3
backwardMaxValue
double
57344.0
Saturation value for E5M2
LossScaler
initialScale
double
65536.0
Starting loss scale
scaleWindow
int
2000
Steps before doubling the scale
scaleFactor
double
2.0
Factor used to halve (on overflow) or double
Adam8bit
lr
double
1e-3
Learning rate
beta1
double
0.9
First moment decay
beta2
double
0.999
Second moment decay
epsilon
double
1e-8
Numerical stability constant
blockSize
int
2048
Elements per quantization block
DistillationConfig
temperature
double
4.0
Softmax temperature for teacher logits
klLossWeight
double
1.0
Weight for KL divergence loss component
attentionLossWeight
double
0.0
Weight for attention map distillation
featureLossWeight
double
0.0
Weight for hidden state distillation
hardLabelWeight
double
0.0
Weight for ground-truth cross-entropy
See Also
SameDiff Training — base training loop and
TrainingConfigTransfer Learning —
TransferLearning.BuilderforMultiLayerNetwork/ComputationGraphOmniHub Model Hub — downloading pretrained base models to fine-tune
SameDiff Serialization — saving and loading models and adapter weights
Last updated
Was this helpful?