Embedding Model Fine-Tuning Recipe#
Adapt an embedding model to your domain-specific data, then evaluate and deploy it with this complete six-stage pipeline.
Overview#
This recipe fine-tunes the Nemotron 3 Embed checkpoint for domain-specific retrieval and deploys the resulting checkpoint with Retriever NIM or vLLM.
Why Fine-Tune Embedding Models?#
Pre-trained embedding models work well for general-purpose retrieval, but may underperform on specialized domains with unique terminology, document structures, or query patterns. Fine-tuning adapts the model to:
Understand domain-specific vocabulary and concepts
Better match the types of queries your users will ask
Improve retrieval accuracy on your specific document corpus
Training Pipeline#
A large language model (LLM) generates synthetic question-and-answer pairs in Stage 0.
┌─────────────────────────────────────────────────────────────────────────────┐
│ YOUR DOCUMENT CORPUS │
│ (Text files: .txt, .md, and other supported formats) │
└──────────────────────────────────┬──────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ STAGE 0: SYNTHETIC DATA GENERATION (retrieval SDG plugin) │
│ ┌─────────────────┐ ┌─────────────────┐ ┌──────────────────────────┐ │
│ │ Document Chunks │ → │ LLM Generation │ → │ Q&A Pairs + Evaluations │ │
│ │ │ │ (NVIDIA API) │ │ │ │
│ └─────────────────┘ └─────────────────┘ └──────────────────────────┘ │
└──────────────────────────────────┬──────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ STAGE 1: TRAINING DATA PREPARATION │
│ ┌─────────────────┐ ┌─────────────────┐ ┌──────────────────────────┐ │
│ │ Train/Val/Test │ → │ Hard Negative │ → │ Multi-hop Unrolling │ │
│ │ Split │ │ Mining │ │ │ │
│ └─────────────────┘ └─────────────────┘ └──────────────────────────┘ │
└──────────────────────────────────┬──────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ STAGE 2: MODEL FINE-TUNING (Automodel) │
│ ┌─────────────────────────────────────────────────────────────────────────┐│
│ │ Contrastive Learning: Query → Positive Documents vs Hard Negatives ││
│ └─────────────────────────────────────────────────────────────────────────┘│
└──────────────────────────────────┬──────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ STAGE 3: EVALUATION (BEIR) │
│ ┌─────────────────────────────────────────────────────────────────────────┐│
│ │ Compare Base vs Fine-tuned Model on IR Metrics (nDCG, Recall) ││
│ └─────────────────────────────────────────────────────────────────────────┘│
└──────────────────────────────────┬──────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ STAGE 4: EXPORT (WHEN REQUIRED) │
│ ┌─────────────────────────────────────────────────────────────────────────┐│
│ │ Export models that require a deployment artifact; otherwise skip ││
│ └─────────────────────────────────────────────────────────────────────────┘│
└──────────────────────────────────┬──────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ STAGE 5: DEPLOY │
│ ┌─────────────────────────────────────────────────────────────────────────┐│
│ │ Launch NIM or vLLM from the selected artifact ││
│ └─────────────────────────────────────────────────────────────────────────┘│
└─────────────────────────────────────────────────────────────────────────────┘
Stage |
Command |
Description |
Output |
|---|---|---|---|
Stage 0: SDG |
|
Validate corpus, generate synthetic Q&A pairs from documents |
Q&A pairs with quality scores |
Stage 1: Data Prep |
|
Convert, mine hard negatives, unroll |
Training-ready data |
Stage 2: Finetune |
|
Fine-tune embedding model |
Model checkpoint |
Stage 3: Eval |
|
Evaluate on retrieval metrics |
Metrics comparison |
Stage 4: Export |
|
Export when required by the selected profile |
Exported model or skipped |
Stage 5: Deploy |
|
Deploy the selected model artifact with NIM or vLLM |
Running inference service |
Installation#
1. Install the uv Package Manager#
This project requires the uv package manager. It automatically creates and manages a virtual environment under the repository root, and each pipeline stage uses an isolated environment. Do not use pip install. The project relies on uv workspaces and per-stage dependency isolation.
curl -LsSf https://astral.sh/uv/install.sh | sh
2. Clone and Install Nemotron#
# Clone the repository
git clone https://github.com/NVIDIA-NeMo/Nemotron.git
cd Nemotron
# uv creates a virtual environment at .venv/ and installs all dependencies
uv sync --all-extras
3. Get Your NVIDIA API Credential#
Stage 0 sends synthetic-data-generation requests to Data Designer’s built-in
NVIDIA endpoint unless the generic NVIDIA_API_BASE_URL environment variable
is set. Use the credential for the selected endpoint:
export NVIDIA_API_KEY=your_key_here
4. Optional: Configure Execution Profiles#
For Docker or Slurm execution, create env.toml in the repository root directory.
Minimal configuration (local execution only):
[wandb]
project = "my-embedding-project"
entity = "my-username"
Full configuration with Docker and Slurm support: Refer to Execution Profiles.
Preparing Your Corpus#
Supported Formats#
Any text files, default: .txt, .md, .text, and files with no extension
Documents should be UTF-8 encoded
Files are processed recursively from the corpus directory
Corpus Size Recommendations#
Corpus Size |
Documents |
Expected Results |
|---|---|---|
Minimum |
50–100 documents (approximately 50,000 tokens) |
Basic domain adaptation |
Recommended |
500 or more documents |
Good domain coverage |
Optimal |
1,000 or more documents |
Best performance |
Document Organization#
Organize your documents in a directory structure:
data/corpus/
├── doc1.txt
├── doc2.md
└── subdirectory/
└── doc3.txt
All files matching the file_extensions config (default: .txt,.md) will be processed recursively.
Document Quality Tips#
Length: Aim for 200–2,000 tokens per document
Content: Ensure documents are representative of your domain
Diversity: Include various document types/topics from your domain
Quality: Clean, well-formatted text yields better synthetic Q&A pairs
Prerequisites#
Hardware Requirements#
GPU: An NVIDIA GPU with at least 80 GB of VRAM, such as an A100 or H100
Stage 0 uses the NVIDIA API and does not require a GPU.
Stages 1–3 and Stage 5 require a GPU for model inference, training, or serving.
Stage 4 requires a GPU only for profiles, such as
llama, that enable export.
CPU: Modern multicore processor (16 or more cores recommended)
Memory: 128 GB or more RAM recommended
Storage: Approximately 50 GB of free disk space for outputs, models, and containers
Software Requirements#
Python: 3.12 or later
uv: Package manager (installation instructions above)
NVIDIA API Key: Required for synthetic data generation
NVIDIA GPU Drivers: Latest drivers for your GPU
Docker (optional): For containerized execution
Slurm (optional): For cluster execution
Expected Runtime and Resources#
Stage |
GPU VRAM |
CPU |
Notes |
|---|---|---|---|
Stage 0 (SDG) |
N/A |
8 or more cores |
Uses API (no local GPU); runtime varies by dataset size |
Stage 1 (Data Prep) |
40 GB |
16 or more cores |
Hard-negative mining on GPU; runtime varies by dataset size |
Stage 2 (Finetune) |
80 GB |
16 or more cores |
Runtime varies by dataset size and epochs |
Stage 3 (Eval) |
40 GB |
8 or more cores |
Evaluation metrics computation; runtime varies by dataset size |
Stage 4 (Export) |
N/A for default; 40 GB for |
8 or more cores |
Default is a no-op; TensorRT export requires an NGC container |
Stage 5 (Deploy) |
40 GB |
4 or more cores |
Inference container initialization |
Total disk space: Approximately 50 GB for outputs, model checkpoints, and containers
Runtime: Runtime depends on dataset size. Larger corpora and more training epochs take longer.
For a small dataset, such as
nv_pp_randomwith approximately 70 input files, Stage 0 (SDG) can take about 30 minutes with the default setup. Changing LLM endpoints or tuningmax_parallel_requests_for_gencan affect runtime, rate-limit behavior, and generation quality. Stage 2 (Finetune) can take 10–20 minutes with the default setup.For a large dataset, such as 10,000 or more input files, Stage 0 (SDG) can take tens of hours or 1–2 days, and Stage 2 (Finetune) can take 5–10 hours. Changing model endpoints, GPU type and count, and other fine-tuning parameters can affect runtime.
Large Language Model (LLM) API Usage (Stage 0)#
Stage 0 uses LLM APIs for synthetic data generation. By default, it uses NVIDIA’s hosted LLMs:
Default endpoint: Data Designer built-in, optionally overridden with
NVIDIA_API_BASE_URLDefault generation/judge model:
nvidia/nemotron-3-ultra-550b-a55bUsage: ~4 API calls per document (artifact extraction, QA generation, dedup, quality eval)
Access and limits: Depend on the selected NVIDIA endpoint and credential
Progress: Built-in progress logging shows completion %, records/second, and ETA per stage
Other providers: NeMo Data Designer supports multiple providers, such as OpenAI and OpenRouter.
Customize provider settings in the config file
See default provider settings for configuration options
Resuming Stage 0#
Data Designer writes a durable checkpoint after each buffer_size records in every
resume mode. The resume setting controls whether a later invocation reuses checkpoints
stored under the same artifact_path and dataset_name:
Mode |
Behavior |
Use when |
|---|---|---|
|
Start a fresh generation run. Existing artifacts are left in place and a timestamped dataset directory is used when needed. |
Intentionally generating a new stochastic dataset. |
|
Require a compatible prior run and continue from its completed checkpoints. Fail if no prior dataset exists or its configuration is incompatible. |
Explicitly recovering an interrupted run. |
|
Continue a compatible prior run; otherwise start a fresh run. |
A job may be retried automatically from either a clean or interrupted state. |
To continue an interrupted run, keep artifact_path, dataset_name, and buffer_size
unchanged:
nemotron embed sdg -c default corpus_dir=/path/to/your/docs resume=always
Resume compatibility uses Data Designer’s configuration fingerprint; it does not hash
the contents of corpus files. Use always or if_possible only when the input corpus
has not changed in place. The default is never so that an ordinary repeated recipe
invocation generates new data instead of silently reusing a completed dataset.
After each successful non-preview run, Stage 0 writes generation_result.json
next to the exported JSONL file. This manifest identifies the exact output from
the run, including a timestamped file from a repeated resume=never invocation.
By default, Stage 1 resolves the manifest before preparing the data. To select
another input, set sdg_input_path to a data file or an existing SDG output
directory.
Earlier recipe versions exposed batch_size, start_batch_index, and
end_batch_index for manually partitioning the corpus into independent runs. Those
settings have been removed with the manual batching implementation. Use buffer_size
to control checkpoint/write granularity; it does not partition the corpus or produce
separate batch outputs. Manual start/end ranges have no direct replacement. Use a
stable dataset_name with resume=always to continue an interrupted run.
Quick Start#
Default Profile#
The default profile loads nvidia/Nemotron-3-Embed-1B-BF16 from
Hugging Face for mining, fine-tuning, and base-model evaluation. Stage 5 can
mount the consolidated Stage 2 checkpoint directly into Retriever NIM 2.x or
serve it with vLLM:
export LD_LIBRARY_PATH=""
export NVIDIA_API_KEY=your_endpoint_credential
# Optional: override Data Designer's built-in NVIDIA endpoint.
export NVIDIA_API_BASE_URL=https://your-authorized-endpoint.example/v1
nemotron embed sdg -c default corpus_dir=/path/to/your/docs
nemotron embed prep -c default
nemotron embed finetune -c default
nemotron embed eval -c default
# Stage 4 is an intentional no-op for this profile.
nemotron embed export -c default
# Option A: deploy with the default Retriever NIM 2.2 image.
nemotron embed deploy -c default detach=true
nemotron embed eval -c default eval_nim=true eval_base=false eval_finetuned=true \
output_dir=./output/embed/nemotron-3-1b/stage3_eval_nim_comparison
docker stop nemotron-embed
# Option B: deploy with the checked-in vLLM backend.
nemotron embed deploy -c default backend=vllm detach=true
nemotron embed eval -c default eval_nim=true eval_base=false eval_finetuned=true \
embedding_api_backend=vllm \
output_dir=./output/embed/nemotron-3-1b/stage3_eval_vllm_comparison
docker stop nemotron-embed
Stage 0 uses nvidia/nemotron-3-ultra-550b-a55b through Data
Designer’s built-in endpoint or the optional NVIDIA_API_BASE_URL override.
Model-dependent artifacts are isolated
under output/embed/nemotron-3-1b/. Both deploy backends mount
stage2_finetune/checkpoints/LATEST/model/consolidated read-only at /model
without ONNX or TensorRT conversion. NIM selects it through
NIM_MODEL_PATH=/model; vLLM runs vllm serve /model and detects the
checkpoint’s embedding configuration automatically.
Because the artifact is already local, neither path forwards NGC_API_KEY
into the container.
The deploy preflight requires a checkpoint with this supported fingerprint: hidden size 2,048; 16 layers; 24 attention heads; 8 key/value heads; intermediate size 6,144; and vocabulary size 131,072.
NIM uses the selected image’s default runtime limit and automatically selects
the compatible pipeline for the detected GPU. To apply a smaller serving limit,
set max_seq_len; to troubleshoot a specific NIM pipeline, set
NEMOTRON3_EMBED_NIM_PIPELINE_ID. vLLM derives
the checkpoint’s sequence length, pooling, activation, and prompt behavior
automatically. The evaluator uses vLLM’s /v2/embed endpoint and passes
input_type (query or document) without adding text prefixes. For null or
nonfinite endpoint responses, the evaluator retries up to 32 times per affected
input. Treat every retry warning as a serving-reliability defect.
Stage 2 uses a commit-pinned Automodel source with Transformers 5.12.1 to write the deployable checkpoint. Stages 1 and 3 retain Transformers 5.1 through 5.5 for the original checkpoint path.
The preceding served-endpoint evaluation commands evaluate the fine-tuned
checkpoint and served endpoint in one process. They record endpoint, model, and
dimension diagnostics and write results to a separate output directory. The
reported metric deltas compare aggregate retrieval behavior; they do not prove
artifact identity. The deploy mount and fingerprint checks establish which local
artifact was selected. Set fail_on_nim_metric_drift=true only when the
configured tolerances should gate the run.
Use NEMOTRON3_EMBED_DEPLOY_CHECKPOINT to override the default checkpoint
directory for either backend. Use NEMOTRON3_EMBED_NIM_MODEL to set the model
alias advertised by NIM or passed to vLLM as --served-model-name.
Dry Run#
nemotron embed finetune -c default --dry-run
Pipeline Flexibility#
Stages are designed to run sequentially, but you can start from any stage if you have the required inputs:
Start From |
Requirement |
Use Case |
|---|---|---|
Stage 0 |
Document corpus |
Full pipeline from scratch |
Stage 1 |
Q&A pairs (JSON/JSONL/Parquet) |
Skip SDG if you have labeled data or use NVIDIA’s pre-generated dataset |
Stage 2 |
Training data (Automodel format) |
Skip data prep if data is ready |
Stage 3 |
Model checkpoint |
Evaluate existing checkpoint |
Stage 4 |
Model checkpoint |
Export existing model when the selected profile requires it |
Stage 5 |
Model checkpoint or exported artifact |
Deploy existing model |
The default profile loads the Stage 2 Hugging Face-style PyTorch checkpoint
directly through NIM_MODEL_PATH, so Stage 4 is an explicit no-op.
For stage-specific input requirements and options, run nemotron embed <stage> --help. In a source checkout, inspect the corresponding config/default.yaml file for default paths and settings.
Using NVIDIA’s Pre-Generated Dataset#
NVIDIA provides a ready-to-use synthetic retrieval dataset on Hugging Face: Retrieval-Synthetic-NVDocs-v1. This dataset was generated from NVIDIA’s publicly available content using the same SDG pipeline (Stage 0) in this recipe, and contains ~15K documents with 105K+ question-answer pairs across multiple reasoning types.
If you want to fine-tune an embedding model on NVIDIA-related content, you can skip Stage 0 entirely and start directly from Stage 1:
# Download the pre-generated dataset
python -c "
from datasets import load_dataset
ds = load_dataset('nvidia/Retrieval-Synthetic-NVDocs-v1', split='train')
ds.to_json('./output/embed/stage0_sdg/nv_docs_sdg.jsonl')
"
# `datasets.to_json()` writes JSONL; pass the exact file to avoid mixed-directory ambiguity.
# Start from Stage 1 (data preparation) using the downloaded data
nemotron embed prep -c default sdg_input_path=./output/embed/stage0_sdg/nv_docs_sdg.jsonl
# Continue with the rest of the pipeline
nemotron embed finetune -c default
nemotron embed eval -c default
This is useful for quickly getting started with the recipe or benchmarking the pipeline without needing an NVIDIA API key for synthetic data generation.
Execution Modes#
The embed recipe supports multiple execution modes for flexibility between local development and production cluster runs.
Local Execution (Default)#
Run directly on your local machine with GPU:
nemotron embed finetune -c default
nemotron embed eval -c default
Docker Execution#
Run inside a Docker container with GPU passthrough using --run local-docker:
# Runs the command inside a Docker container with GPU access
nemotron embed finetune -c default --run local-docker
# All stages support Docker execution
nemotron embed sdg -c default --run local-docker
nemotron embed prep -c default --run local-docker
nemotron embed eval -c default --run local-docker
Note: Requires the
local-dockerprofile inenv.toml(refer to Execution Profiles).
Slurm Batch Execution#
Submit jobs to a Slurm cluster for production workloads:
# Attached execution (waits for completion, streams logs via SSH)
nemotron embed finetune -c default --run my-cluster
# Detached execution (submits job and exits immediately)
nemotron embed finetune -c default --batch my-cluster
# Run full pipeline on cluster
nemotron embed sdg -c default --batch my-cluster
nemotron embed prep -c default --batch my-cluster
nemotron embed finetune -c default --batch my-cluster
nemotron embed eval -c default --batch my-cluster
Execution Profiles#
Execution profiles are defined in env.toml in the repository root directory.
Example env.toml for local and cluster execution:
# Weights & Biases configuration (optional but recommended)
[wandb]
project = "my-embedding-project"
entity = "my-team"
# Local Docker execution profile
[local-docker]
executor = "docker"
runtime = "nvidia" # Enable GPU passthrough
ipc_mode = "host"
shm_size = "16g"
mounts = [
"./data:/workspace/data",
"./output:/workspace/output"
]
# Slurm cluster execution profile
[my-cluster]
executor = "slurm"
account = "my-account"
partition = "interactive"
batch_partition = "batch"
tunnel = "ssh"
host = "cluster.example.com"
user = "username"
remote_job_dir = "/shared/path/to/jobs"
mounts = ["/shared:/shared"]
These shared profiles intentionally omit container_image, so each stage uses
the compatible image in its checked-in configuration. Stage 2 defaults to the
NeMo Automodel 26.06
container
(nvcr.io/nvidia/nemo-automodel:26.06). Set container_image only in an
execution profile dedicated to a stage that is compatible with that image.
Runtime Overrides#
Override execution settings on the command line:
# Use more GPUs
nemotron embed finetune -c default --run my-cluster run.env.gpus_per_node=4
# Use different partition
nemotron embed finetune -c default --batch my-cluster run.env.partition=batch
# Override time limit
nemotron embed finetune -c default --batch my-cluster run.env.time=08:00:00
Interactive Debugging#
Stage files to the cluster for interactive debugging:
# Stage files without executing
nemotron embed finetune -c default --run my-cluster --stage
# Then SSH to cluster and run manually
ssh cluster.example.com
cd /path/to/staged/files
./run.sh
Configuration#
Each stage’s default.yaml config derives its paths from the profile-wide
artifact_root, which defaults to ./output/embed/nemotron-3-1b. Override it
once for an entire pipeline run:
nemotron embed run -c default --to eval artifact_root=./output/embed/experiments/domain-a
Changing artifact_root only relocates artifacts. A future model profile such
as nemotron-3-8b must also set its own base model, runtime settings, NIM
identity and fingerprint, and any model-specific dependencies.
Default Model Settings#
# Stage 0
# Set NVIDIA_API_BASE_URL to override Data Designer's built-in endpoint.
# Stage 1-3
base_model: nvidia/Nemotron-3-Embed-1B-BF16
trust_remote_code: true
# Stage 4
enabled: false
# Stage 5
backend: nim # Override with backend=vllm
vllm_image: nvcr.io/nvidia/vllm:26.06-py3
model_dir: ./output/embed/nemotron-3-1b/stage2_finetune/checkpoints/LATEST/model/consolidated
model_path_env: NIM_MODEL_PATH
container_model_path: /model
max_seq_len: null # Use the NIM image default; vLLM reads checkpoint metadata
All ordinary fields can still be overridden on the command line:
nemotron embed finetune -c default num_epochs=1 learning_rate=2e-5
Sequence length#
Mining, training, and evaluation use 512 tokens. The default NIM profile uses
the selected image’s runtime limit. Set max_seq_len: 512 to enforce the same
served limit; changing local training lengths alone does not expand it.
Longer sequences increase GPU memory use substantially; reduce batch sizes when necessary.
CLI Commands#
# Inspect the recipe
nemotron embed info
# Default direct-checkpoint path
nemotron embed run -c default --to eval
nemotron embed deploy -c default detach=true
nemotron embed eval -c default eval_nim=true eval_base=false eval_finetuned=true \
output_dir=./output/embed/nemotron-3-1b/stage3_eval_nim_comparison
# Stop the default container
docker stop nemotron-embed
Output Structure#
output/embed/
└── nemotron-3-1b/
│ ├── stage0_sdg/
│ ├── stage1_data_prep/
│ ├── stage2_finetune/checkpoints/LATEST/model/consolidated/
│ └── stage3_eval/eval_results.json
Evaluation Metrics#
The evaluation stage computes standard information retrieval metrics using the BEIR framework.
Metric |
Description |
Range |
|---|---|---|
nDCG@k |
Normalized Discounted Cumulative Gain (ranking quality) |
0.0–1.0 |
Recall@k |
Fraction of relevant documents in top-k results |
0.0–1.0 |
Precision@k |
Fraction of retrieved documents that are relevant |
0.0–1.0 |
MAP@k |
Mean Average Precision |
0.0–1.0 |
Higher scores indicate better retrieval performance.
Interpreting Results#
Good fine-tuning results typically show:
nDCG@10 and Recall@10 improvement of 15% over base model
Consistent improvements across all k values
Example successful evaluation:
Model: base
- nDCG@10: 0.42
- Recall@10: 0.65
- Precision@10: 0.38
Model: fine-tuned
- nDCG@10: 0.51 (+21%) ✓
- Recall@10: 0.78 (+20%) ✓
- Precision@10: 0.45 (+18%) ✓
Warning signs:
No improvement: May need more training data or higher quality Q&A pairs
Worse performance: Check for data quality issues or training hyperparameters
Overfitting: Good training metrics but poor validation metrics
Key Components#
Component |
Purpose |
Repository |
|---|---|---|
Data Designer retrieval SDG plugin |
Generate synthetic question-and-answer pairs and convert them to training data |
|
Automodel |
Embedding model training framework |
|
BEIR |
Evaluation framework for information retrieval |
|
NeMo Export-Deploy |
ONNX/TensorRT export for optimized inference |
|
NVIDIA NIM |
Production inference microservice with custom model support |
Default Model Profile#
Property |
Value |
|---|---|
Model |
Nemotron 3 Embed |
Model locator |
|
Embedding dimension |
2048 |
Recipe sequence length |
512 |
Deployment backend |
Retriever NIM or vLLM |
Serving input artifact |
Hugging Face PyTorch/safetensors checkpoint |
NIM selector |
|
Stage 4 |
Skipped for the default profile |
Troubleshooting#
Installation Issues#
Error: uv: command not found
# Install the uv package manager
curl -LsSf https://astral.sh/uv/install.sh | sh
# Add to PATH
export PATH="$HOME/.cargo/bin:$PATH"
Error: nemotron: command not found
# Make sure you're in the Nemotron directory
cd /path/to/Nemotron
# Run with uv
uv run nemotron embed info
Stage 0: SDG Issues#
Error: NVIDIA_API_KEY not set
# Use the credential for the built-in endpoint or NVIDIA_API_BASE_URL.
export NVIDIA_API_KEY=your_key_here
Error: API rate limiting
Solution: Reduce batch size in config or add delays between API calls
Alternative: Contact NVIDIA for increased rate limits for production use
Error: Poor Q&A quality scores
Solution: Check document quality - ensure clean, well-formatted text
Solution: Adjust
sentences_per_chunkin config (default: 5 sentences per chunk)
Stage 1: Data Preparation Issues#
Error: CUDA out of memory during hard negative mining
# Reduce mining batch size in config
nemotron embed prep -c default mining_batch_size=64
Error: No valid Q&A pairs after quality filtering
Solution: Lower quality_threshold (default: 7.0)
Solution: Check SDG output quality scores
Error: Import errors for nemo_automodel
# Ensure dependencies are installed
cd /path/to/Nemotron
uv sync --all-extras
Stage 2: Training Issues#
Error: Train Loss not decreasing
Solution: Try adjusting learning rate (default: 1e-5; try 5e-6 or 2e-5)
Solution: Lower
global_batch_sizeto increase the number of gradient update stepsSolution: Check training data quality
Error: Train Loss is NaN
Solution: Reduce learning rate significantly
Solution: Check for data quality issues (missing values, corrupted entries)
Error: CUDA out of memory during training
# Reduce local batch size
nemotron embed finetune -c default local_batch_size=2
Error: Training very slow
Check: GPU utilization with
nvidia-smiSolution: Increase batch size if GPU not fully utilized
Solution: Enable mixed precision training (usually enabled by default)
Stage 3: Evaluation Issues#
Error: Model checkpoint not found
# Check checkpoint path
ls -la output/embed/nemotron-3-1b/stage2_finetune/checkpoints/LATEST/model/consolidated/
# Specify custom path
nemotron embed eval -c default finetuned_model_path=/path/to/checkpoint
Error: BEIR evaluation fails
Solution: Ensure eval_beir data was created in Stage 1
Solution: Check that corpus.jsonl and queries.jsonl exist
Stage 5: Deployment Issues#
Override the default NIM image
export NEMOTRON3_EMBED_NIM_IMAGE=nvcr.io/your-compatible-embedding-nim:tag
nemotron embed deploy -c default
Alternatively, use the checked-in vLLM backend:
nemotron embed deploy -c default backend=vllm
Error: Serving container fails to start
# Authenticate to NGC when required for the selected image.
docker login nvcr.io
# Check if port is already in use
sudo lsof -i :8000
# Use different port
nemotron embed deploy -c default backend=vllm host_port=8002
Error: Served accuracy differs from checkpoint
Solution: For vLLM evaluation, set
embedding_api_backend=vllm; it uses/v2/embedand sendsinput_type=queryorinput_type=documentwithout manually prefixing text.Solution: Let vLLM detect pooling, activation, normalization, and sequence length from the checkpoint. Do not add overrides unless you are deliberately testing a different serving contract.
Solution: Verify model files are complete and not corrupted
CUDA Library Errors#
Error: nvJitLink or CUDA symbol errors
# Clear LD_LIBRARY_PATH to avoid conflicts
export LD_LIBRARY_PATH=""
Error: HybridCache import errors
# Clear HuggingFace cache
rm -rf ~/.cache/huggingface/modules/transformers_modules/nvidia/
Docker Issues#
Error: Container has no GPU access
# Verify NVIDIA runtime is installed
docker run --rm --gpus all nvidia/cuda:12.1.0-base-ubuntu22.04 nvidia-smi
# Check docker daemon.json includes nvidia runtime
cat /etc/docker/daemon.json
Slurm Issues#
Error: Job submission fails
# Check Slurm is configured in env.toml
cat env.toml
# Verify SSH access to cluster
ssh cluster.example.com
# Check Slurm partition exists
sinfo -p interactive
Error: Job stays in pending state
# Check job queue
squeue -u $USER
# Check job reason
squeue -j <job-id> -o "%.18i %.9P %.8j %.8u %.2t %.10M %.6D %R"
Debugging Slurm jobs
# Check job status
squeue -u $USER
# View job logs
cat /path/to/job/logs/stdout.txt
cat /path/to/job/logs/stderr.txt
# Cancel stuck job
scancel <job-id>
# View job details
scontrol show job <job-id>
General Debugging#
Enable verbose logging
# Add --verbose flag (if available)
nemotron embed finetune -c default --verbose
# Check logs in output directory
cat output/embed/stage2_finetune/logs/*.log
Dry run to preview
# Preview command without executing
nemotron embed finetune -c default --dry-run
Monitoring Training#
Weights & Biases Integration#
Training automatically logs to Weights & Biases if configured in env.toml:
[wandb]
project = "my-embedding-project"
entity = "my-team"
AutoModel creates one W&B run from distributed rank zero and records training loss, learning rate, gradient norm, memory, step timing, and validation metrics. Slurm run names include the Slurm job ID. Sensitive Slurm environment variables are delivered through a private mode-0600 file rather than being embedded in generated executor or sbatch files.
Monitor training progress at: https://wandb.ai/<entity>/<project>
Local Monitoring#
Check training logs:
tail -f output/embed/stage2_finetune/logs/train.log
GPU utilization:
watch -n 1 nvidia-smi
Checkpoint progress:
ls -lh output/embed/stage2_finetune/checkpoints/
Best Practices#
Data Quality#
Use clean, well-formatted documents
Ensure documents represent your target domain
Aim for diverse document types and topics
Start with small corpus to test pipeline, then scale up
Training#
Start with default hyperparameters (1-2 epochs, LR 1e-5, batch size 128)
Monitor validation metrics to avoid overfitting
Attention implementation is auto-detected (flash_attention_2 if available, else sdpa)
Checkpoint frequency: if
ckpt_every_stepsis omitted, defaults to once per epoch for map-style datasets or twice during training for iterable datasets
Key hyperparameters to tune:
Parameter |
Default |
Notes |
|---|---|---|
Epochs |
3 |
Default is tuned for the small example dataset; for real-world data, 1–2 epochs is usually sufficient. 3 epochs risks overfitting on most datasets. Refer to epoch guidance in the FAQ. |
Learning rate |
1e-5 |
Try double and half of the default value |
Learning rate warmup steps |
5 |
Set to 5-10% of total steps of finetune to have better early training stability |
Sequence length |
512 |
Set |
Evaluation#
Always compare against base model
Test on held-out test set (not used in training)
Evaluate on realistic queries from your domain
Consider multiple metrics (nDCG, Recall, Precision)
Deployment#
Test exported models thoroughly before production
Verify NIM accuracy matches checkpoint
Monitor inference latency and throughput
Set up proper logging and monitoring
FAQ#
Synthetic Data Generation (SDG)#
How much does SDG model quality impact final embedding accuracy, and when is it worth upgrading the SDG model?
The SDG model directly determines the quality of synthetic queries and answers used to train the embedding model, so it has a first-order effect on final retrieval accuracy. The recipe uses nvidia/nemotron-3-ultra-550b-a55b to prioritize generation and judging quality. Consider changing the SDG model when: (1) quality scores from the SDG quality judge are consistently low (median below 7/10), (2) generated queries are shallow or miss the reasoning patterns users need, or (3) cost and latency are too high for the corpus size. You can select models per task—for example, keep a stronger qa_generation_model while using a smaller approved model for artifact extraction and judging. Run a small pilot (50–100 docs) and compare downstream Stage 3 metrics on the same held-out set before adopting a different model.
How should SDG prompts be designed to reliably capture rare words and domain-specific identifiers (bug IDs, product IDs, versions) that matter for retrieval accuracy?
The built-in SDG pipeline extracts structured artifacts from each document chunk — including entities, technical terms, key concepts, and relationships — before generating QA pairs. These artifacts are injected into the QA generation prompt, which biases the LLM toward producing queries that reference specific identifiers. To improve coverage of rare tokens: (1) ensure your source documents contain the identifiers in context (the LLM can only reference what it sees in the chunk), (2) increase max_artifacts_per_type (default: 2) so more entities and technical terms are extracted per chunk, and (3) increase num_pairs to generate more QA pairs per document, raising the chance that niche identifiers appear in at least some queries. If identifiers span multiple chunks, for example, a bug ID mentioned in one section and its resolution in another, enable multi-document bundling (multi_doc: true) so the LLM sees cross-chunk context. After SDG, spot-check a sample of generated queries for identifier coverage before proceeding to training.
Tailor prompts to the document type, such as a bug report, ticket, or technical manual, to optimize Q&A generation.
Data Volume and Saturation#
What is the optimal number of source documents (or QA pairs) needed before embedding fine-tuning accuracy saturates?
There is no universal threshold — saturation depends on domain complexity, vocabulary diversity, and document heterogeneity. As a rough guide:
Corpus Size |
Typical Outcome |
|---|---|
100 or more documents |
Basic domain adaptation |
500–1,000 documents |
Good domain coverage for enterprise corpora |
5,000 or more documents |
Strong and reliable adaptation |
After SDG and quality filtering (default threshold 7.0), the effective training set is typically smaller than the raw document count. Monitor Stage 3 eval metrics (nDCG@10, Recall@10) across runs with increasing data to find your domain’s saturation point.
How can you reliably detect saturation of the embedding model as you scale data volume?
Run the pipeline at two or three data scales, for example, 25%, 50%, and 100% of your corpus, with identical hyperparameters and compare Stage 3 eval metrics. Saturation is reached when doubling the data yields less than approximately 1–2 absolute points of nDCG@10 improvement. Use a fixed held-out evaluation set across all runs to ensure comparability. Refer to the evaluation questions below.
Should you prioritize adding more documents or generating more queries per document to improve accuracy?
In general, more documents with diverse content have a larger impact than more queries per document because new documents introduce new vocabulary, concepts, and retrieval patterns. More queries per document (using num_pairs) primarily help the model see the same content from different query angles, which has diminishing returns after the core semantics are covered. Prioritize adding documents first. After your corpus is representative, increase num_pairs (default: 7) to improve query diversity for chunks that cover complex or multifaceted topics.
Using Existing Vector-DB Chunks#
Would using real production vector-DB chunks as positives (instead of synthetic chunks) improve embedding accuracy?
Yes, this can improve accuracy. If your production chunks reflect the actual retrieval units that you query against, training on them aligns the embedding space more closely with your deployment setup. The recipe supports this: you can skip Stage 0 entirely and start from Stage 1 by supplying your own QA pairs with real chunks as positives. Refer to the Pipeline Flexibility table. Format your data as JSON with query–positive-passage pairs and feed it to nemotron embed prep. The main risk is that real chunks without synthetic queries may lack query diversity. Consider generating synthetic queries against your real chunks, as described in the next question, to get the best of both approaches.
Is it recommended to generate multiple synthetic queries per real chunk to better shape the embedding space?
Yes. Generating multiple diverse queries per chunk teaches the model that many different phrasings should map to the same passage. You can do this by running Stage 0 with your real chunks as input documents and increasing num_pairs. The SDG pipeline generates varied query types, such as factual, relational, inferential, and procedural queries, with different complexity levels for each chunk. This is especially valuable for chunks that cover dense or multifaceted content where a single query captures only one retrieval intent.
Should training-time chunking exactly match production chunking to maximize retrieval accuracy, or is approximate alignment sufficient?
Exact matching is ideal, but approximate alignment is usually sufficient. Keep training and production chunks similar in length and boundary style. For example, if production chunks contain about 500 tokens and use sentence-boundary splitting, train on chunks with a similar length and boundary style. The embedding model learns semantic similarity at the passage level, not memorized chunk boundaries.
Large mismatches can reduce accuracy. For example, training on five-sentence chunks (the Stage 0 default, typically about 100–150 tokens) while deploying with 2,000-token chunks creates a distribution gap. To reduce the gap, either feed your real production chunks directly as positives or adjust sentences_per_chunk in Stage 0 and passage_max_length in Stages 1–3 to approximate your production chunk size. Set passage_max_length consistently across stages so tokenization truncation during training and evaluation matches inference-time behavior. In practice, aligning chunk length within about a factor of two of the production length is sufficient. Exact boundary matching adds little benefit.
Hard-Negative Mining#
How should hard-negative mining thresholds be tuned to improve embedding discrimination?
Hard-negative mining uses a margin-based filter to exclude documents that are too similar to the positive. The key parameter is hard_neg_margin (default: 0.95 with perc margin type), which acts as an exclusion ceiling: any document scoring above min_positive_score * margin is eliminated, and the top-k highest-scoring survivors become the hard negatives. To tune:
Raise the margin (for example, 0.98–1.0) to narrow the exclusion zone, allowing negatives that score closer to the positive. This produces harder negatives that improve discrimination but risks including false negatives (relevant documents mislabeled as negative), especially in corpora with near-duplicate passages.
Lower the margin (for example, 0.85–0.90) to widen the exclusion zone, forcing negatives to be further from the positive score. This produces easier, safer negatives with less risk of false negatives, but provides weaker training signal.
Increase
hard_negatives_to_mine(default: 5) to give the model more contrastive examples per query. The training stage usestrain_n_passages(default: 5, meaning 1 positive + 4 negatives), so mine at least as many as you plan to train with.
Start with defaults and only raise the margin if Stage 3 metrics plateau — aggressive hard negatives on noisy data can hurt more than help.
What is the recommended number of hard negatives for best accuracy, such as 5, 10, or more?
The default of 4 hard negatives per query (train_n_passages: 5 = 1 positive + 4 negatives) is a solid baseline. Increasing to 10 negatives can improve discrimination, especially for large corpora with many similar-looking passages, but the gains taper off quickly beyond that. Adjust two parameters together: hard_negatives_to_mine in Stage 1 (how many candidates are mined) and train_n_passages in Stage 2 (how many are used during training). For example, mine 10 and train with 10.
Training Hyperparameters#
Which hyperparameters most strongly affect embedding accuracy (learning rate, epochs, batch size), and in what priority order should they be tuned?
In order of typical impact:
Learning rate (default: 1e-5) — the single most sensitive parameter. Try 5e-6 and 2e-5 as first alternatives. Too high causes instability or NaN loss; too low undertrains.
Epochs (default: 3) — controls how many passes the model makes over the data. The default of 3 is calibrated for the small example dataset in this recipe; for most real-world datasets, 1–2 epochs is recommended to avoid overfitting. See the epoch table below.
Learning rate warmup (default: 5 steps) — set to 5–10% of total training steps for better early stability.
Batch size (default: 128) — determines the number of gradient update steps per epoch. Use smaller values for small datasets to get more updates. Refer to the batch size FAQ.
What learning-rate sweep strategy is recommended to maximize accuracy, such as halving or doubling defaults?
Use a simple three-point sweep around the default. Start with the default 1e-5, then try 5e-6 (half) and 2e-5 (double). Compare Stage 3 eval metrics (nDCG@10) across the three runs. The best result is usually clear. If the best result is at an endpoint, for example, 2e-5 beats both others, extend one more step in that direction and try 4e-5 to confirm that you have not undershot. Keep epochs and all other hyperparameters fixed during the sweep so that the learning rate is the only variable.
How many epochs typically improve accuracy before overfitting becomes a risk? Is there a rule of thumb?#
The default num_epochs: 3 exists because the example dataset shipped with this recipe is very small and training for only 1–2 epochs may not produce a measurable signal. For your own data, start with 1–2 epochs and only increase if evaluation metrics are still improving.
Dataset Size |
Recommended Epochs |
Notes |
|---|---|---|
Small (fewer than 1,000 examples) |
2–3 |
Use 3 only if validation loss is still decreasing |
Medium (1,000–10,000 examples) |
1–2 |
2 epochs is usually the upper bound |
Large (10,000 or more examples) |
1 |
More than 1 epoch rarely helps and often hurts |
How does batch size affect training, and how should it be set?#
This pipeline uses only hard negatives in the contrastive loss (no in-batch negatives), so batch size does not change the number of negatives per query. Instead, batch size primarily affects the number of gradient update steps the model takes: steps_per_epoch = total_training_samples / global_batch_size. A smaller global_batch_size means more steps and more frequent weight updates; a larger one means fewer steps and faster wall-clock time per epoch.
As a rule of thumb, use a smaller global_batch_size for small datasets and a larger global_batch_size for larger datasets.
Loss Interpretation and Evaluation#
How should training loss and evaluation loss be interpreted to assess real accuracy gains?
Training loss (contrastive/InfoNCE loss) measures how well the model separates positives from negatives in each batch. A steadily decreasing training loss is expected; a very low floor (~0.0–0.01) suggests the model has learned the training set well.
Validation loss tracks the same metric on held-out data. The gap between training and validation loss is your primary overfitting indicator. If validation loss decreases alongside training loss, the model is generalizing. If validation loss plateaus or rises while training loss keeps falling, stop training or reduce epochs.
Neither loss directly equals retrieval accuracy. Always rely on Stage 3 eval metrics (nDCG@k, Recall@k) as the ground truth for actual embedding quality. Loss is a proxy — it is possible for loss to improve while retrieval metrics stagnate if the hard negatives are too easy.
Are there target loss behaviors or patterns that indicate optimal embedding learning?
Healthy training typically shows: (1) rapid loss decrease in the first 20–30% of training, (2) gradual flattening toward a stable floor, (3) validation loss tracking close to training loss throughout. Warning signs include loss spikes (often caused by bad data or LR too high), NaN loss (reduce LR or batch size), or loss that never decreases (LR too low, or data quality issues). There is no universal “target loss value” — the absolute number depends on batch size, number of negatives, and temperature. Focus on the trajectory and the train/val gap rather than the absolute value.
Should a fixed evaluation dataset always be used to measure true accuracy gains across runs?
Yes. The recipe creates a fixed held-out test split in Stage 1 (default: 10–20% of data, configurable via test_ratio) that is formatted into BEIR evaluation format (eval_beir/). This test set is never used during training and provides a consistent benchmark across experiments. When comparing runs with different hyperparameters, SDG models, or data volumes, always use the same evaluation set — otherwise metric differences may reflect data variance rather than model improvement. For the most rigorous comparison, freeze the evaluation set from your first run and reuse it across all subsequent experiments.
How large should the fixed evaluation set be to reliably reflect embedding accuracy improvements?
Aim for at least 100 queries in the evaluation set to get stable metric estimates; 200–500 queries is better for detecting small improvements. The pipeline warns if your evaluation set has fewer than 50 queries. With very small evaluation sets, metric variance can be high enough to mask real gains. If your total dataset is small, consider using a 80/0/20 train/val/test split (the default for small datasets) to maximize the evaluation set size at the cost of skipping validation-during-training.
What level of accuracy improvement (relative vs absolute) is typical or expected from embedding fine-tuning in similar enterprise domains?
Typical results on enterprise domains show +5 to +20 absolute points of nDCG@10 over the base model, depending on how specialized the domain is. Domains with highly specialized vocabulary (legal, biomedical, internal engineering docs) tend to see larger gains because the base model has less prior exposure. Domains closer to general web text see smaller but still meaningful improvements. If you see less than 5 absolute points of nDCG@10 improvement, investigate data quality, SDG coverage, or hyperparameter settings before concluding that fine-tuning doesn’t help your domain.
Further Reading#
NeMo Data Designer - Synthetic data generation framework
Automodel - Model training framework
BEIR Benchmark - Information retrieval evaluation
NVIDIA NIM Documentation - Production inference microservices
Retrieval-Synthetic-NVDocs-v1 Dataset - Pre-generated synthetic retrieval dataset on NVIDIA content
Support#
For issues, questions, or contributions:
Issues: GitHub Issues
Discussions: GitHub Discussions
Documentation: Nemotron Documentation