Full SFT Customization
Learn how to fine-tune all model weights using supervised fine-tuning (SFT) to customize LLM behavior for your specific tasks.
About
Supervised Fine-Tuning (SFT) customizes model behavior, injects new knowledge, and optimizes performance for specific domains and tasks. Full SFT modifies all model weights during training, providing maximum customization flexibility.
What you can achieve with SFT:
- 🎯 Specialize for domains: Fine-tune models on legal texts, medical records, or financial data
- 💡 Inject knowledge: Add new information not present in the base model
- 📈 Improve accuracy: Optimize for specific tasks like sentiment analysis, summarization, or code generation
SFT vs LoRA: Understanding the Trade-offs
Full SFT trains all model parameters (for example, all 30 billion weights in Nemotron 3.5 Lightning 30B-A3B):
- ✅ Maximum model adaptation and knowledge injection
- ✅ Can fundamentally change model behavior
- ✅ Best for significant domain shifts or specialized tasks
- ❌ Requires substantial GPU resources (4-8x more than LoRA)
- ❌ Produces a full BF16 checkpoint (~66 GB for Nemotron 3.5 Lightning 30B-A3B); peak job disk usage can reach approximately 3× the downloaded base checkpoint size
- ❌ Longer training time
LoRA trains only ~1% of weights by adding thin matrices to existing weights:
- ✅ 75-95% less memory required
- ✅ Faster training (2-4x speedup)
- ✅ Produces small adapter files (~100-500MB)
- ✅ Multiple adapters can share one base model
- ❌ Limited adaptation capability compared to full fine-tuning
When to choose Full SFT:
- Training small models (1B-8B) where resource cost is manageable
- Need fundamental behavior changes (for example, medical diagnosis, legal reasoning)
- Injecting substantial new knowledge not in the base model
When to choose LoRA: Refer to the LoRA tutorial for most use cases, especially with large models (30B+) or limited GPU resources.
This tutorial uses Qwen/Qwen3-0.6B so that full SFT fits on a single GPU. Full SFT of Nemotron 3.5 Lightning 30B-A3B needs 8× 80 GB GPUs; see the Automodel reference recipe customizer_nemotron_nano_full_sft.yaml.
Prerequisites
Before starting this tutorial, ensure you have:
- Completed the Quickstart to install and deploy NeMo Helix locally
- Installed the Python SDK (PyPI wrapper:
pip install "nemo-helix[all]"; source checkout: runmake bootstrapfrom the repository root) - At least one GPU with CUDA 13+
Quick Start
1. Initialize 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 Dataset
Create your data in JSONL format—one JSON object per line. The platform auto-detects your data format. Supported dataset formats are listed below.
Flexible Data Setup:
- No validation file? The platform automatically creates a 10% validation split
- Multiple files? Upload to
training/orvalidation/subdirectories—they will be automatically merged - Format detection: Your data format is auto-detected at training time
In this tutorial the following dataset directory structure will be used:
Simple Prompt/Completion Format
The simplest format with input prompt and expected completion:
prompt: The input prompt for the modelcompletion: The expected output response
Chat Format (for conversational models)
For multi-turn conversations, use the messages format:
messages: List of message objects withroleandcontentfields- Roles:
system,user,assistant
Custom Format (specify columns in job)
You can use custom field names and map them during job creation:
- Define your own field names
- Map them to prompt/completion in the job configuration
3. Create Dataset FileSet and Upload Training Data
Install huggingface datasets package to download public rajpurkar/squad dataset if it is not installed in your Python environment:
Download rajpurkar/squad Dataset
SQuAD (Stanford Question Answering Dataset) is a reading comprehension dataset consisting of questions posed on Wikipedia articles, where the answer is a segment of text from the corresponding passage.
We convert each example to the chat messages format. The user turn is the same prompt the evaluation step sends, so the model is trained and queried through the same chat template, including the end-of-turn token that stops generation.
4. Secrets Setup
If you plan to use NGC or Hugging Face models, you will need to configure authentication:
- NGC models (
ngc://URIs): Requires NGC API key - Hugging Face models (
hf://URIs): Requires HF token for gated/private models
Configure these as secrets in your platform. Refer to Managing Secrets for detailed instructions.
Get your credentials to access base models:
- NGC API Key (Setup → Generate API Key)
- Hugging Face Token (Create token with Read access)
Quick Setup Example
In this tutorial we are going to work with the Qwen/Qwen3-0.6B model from Hugging Face. It is public, so the Hugging Face token is optional.
Hugging Face Authentication:
- For gated models, you must provide a Hugging Face token via the
token_secretparameter - Get your token from Hugging Face Settings (requires Read access)
- Accept the model’s terms on the Hugging Face model page before using it
- For public models, you can omit the
token_secretparameter when creating a fileset for model in the next step
5. Create Base Model FileSet and Model Entity
Create a fileset pointing to the Qwen/Qwen3-0.6B model in Hugging Face that we will train with SFT. Then create a Model Entity that references this fileset. Model downloading will take place at training time.
The fileset sets token_secret only when you created the hf-token secret. Gated models require it.
6. Create SFT Fine-Tuning Job
Create a customization job to fine-tune all model weights using the Automodel backend and AutomodelJobInput. The learning rate, weight decay, and micro batch come from the Automodel reference recipe qwen3_0p6b_hellaswag.yaml.
GPU Requirements:
- 1B models: 1 GPU (24GB+ VRAM)
- 3B models: 1-2 GPUs
- 8B models: 2-4 GPUs
- 30B MoE models (Nemotron 3.5 Lightning 30B-A3B): 8 GPUs with
expert_parallel_size=8 - 70B models: 8+ GPUs
Adjust num_gpus_per_node based on your model size.
7. Track Training Progress
Poll until the job finishes. 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 SFT Training Metrics:
Monitor the relationship between training and validation loss curves:
Note: Training metrics measure optimization progress, not final model quality. Always evaluate the deployed model on your specific use case.
8. Deploy Fine-Tuned Model
After training completes, deploy using the Deployment Management Service:
The deployment service automatically:
- Downloads model weights from the Files service
- Provisions storage (PVC) for the weights
- Configures and starts the vLLM container
Multi-GPU Deployment:
For larger models requiring multiple GPUs, increase gpu in executor_config. vLLM computes tensor parallelism from the GPU count and model architecture:
Single-Node Constraint: Model deployments are limited to a single node. The maximum gpu value depends on the total GPUs available on a single node in your cluster. Multi-node deployments are not supported.
Track Deployment Status
9. Evaluate Your Model
After training, evaluate whether your model meets your requirements:
Quick Manual Evaluation
Evaluation Best Practices
Manual Evaluation (Recommended)
- Test with real-world examples from your use case
- Compare responses to base model and expected outputs
- Verify the model exhibits desired behavior changes
- Check edge cases and error handling
What to look for:
- ✅ Model follows your desired output format
- ✅ Applies domain knowledge correctly
- ✅ Maintains general language capabilities
- ✅ Avoids unwanted behaviors or biases
- ❌ Doesn’t hallucinate facts not in training data
- ❌ Doesn’t produce repetitive or nonsensical outputs
Hyperparameters
For detailed information on all available hyperparameters, recommended values, and tuning guidance, refer to the Hyperparameter Reference.
Troubleshooting
Job fails during model download:
- Verify authentication secrets are configured (refer to Managing Secrets)
- For gated Hugging Face models, accept the license on the model page
- Confirm the model fileset uses
token_secret=hf_secret.namefor gated models - Check
AutomodelJobInputreferences use theworkspace/nameformat:model=f"default/{MODEL_NAME}"anddataset={"training": f"default/{DATASET_NAME}"}(for example,default/qwen3-0.6b,default/sft-dataset) - Verify the model entity points at the fileset:
fileset=f"default/{MODEL_NAME}" - Check job status:
client.jobs.get_job_status(name=job.job.name).data()
Job fails with OOM (Out of Memory) error:
- First try: Reduce
global_batch_sizefrom 64 to 32 or 16 inbatch={...} - Still OOM: Reduce
micro_batch_sizefrom 8 to 4 or 1 - Still OOM: Reduce
max_seq_lengthfrom 2048 to 1024 or 512 intraining={...} - Last resort: Set
"activation_checkpointing": Trueintraining={...}, or add GPUs withnum_gpus_per_nodeinparallelism={...}. Dense models can also raisetensor_parallel_size. MoE models that useexpert_parallel_sizeneedtensor_parallel_size1, so raiseexpert_parallel_sizewith the GPU count instead.
Loss curves not decreasing (underfitting):
- Increase training duration: raise
epochsfrom 2 to 3-5 inschedule={...} - Adjust learning rate: try
2e-5or5e-6instead of the default1e-5inoptimizer={...} - Check data quality: Verify formatting, remove duplicates, ensure diversity
Training loss decreases but validation loss increases (overfitting):
- Reduce
epochsfrom 2 to 1 inschedule={...} - Lower
learning_ratefrom1e-5to5e-6inoptimizer={...} - Increase dataset size and diversity
- Verify train/validation split has no data leakage
Model output quality is poor despite good training metrics:
- Training metrics optimize for loss, not your actual task—evaluate on real use cases
- Review data quality, format, and diversity—metrics can be misleading with poor data
- Try a different base model size or architecture
- Adjust
learning_rateandglobal_batch_size - Compare to baseline: Test base model to ensure fine-tuning improved performance
Deployment fails:
- Verify output model exists:
client.models.get_model(name=OUTPUT_NAME) - Check job logs:
client.jobs.list_job_logs(name=job.job.name).items() - Check deployment status:
client.models.get_deployment(name=deployment.name) - Ensure sufficient GPU resources for
executor_config={"gpu": 1, ...} - Verify the deployment config matches this tutorial:
engine="vllm"withdocker.io/vllm/vllm-openai:v0.22.1
Next Steps
- Monitor training metrics in detail
- Evaluate your fine-tuned model using the Evals service
- Learn about LoRA customization for resource-efficient fine-tuning