Nemotron-3.5 Lightning Text2SQL LoRA — runbook for a coding agent
This skill helps you run the cookbook in this directory (mbridge_lora_cookbook.ipynb) on the
user's behalf. Your job is to gather a few environment details, pick a GPU configuration that fits
their hardware, run the four steps in order, and confirm each one produced what it should.
What the tutorial does
Four steps, in order. Only step 3 needs a GPU — this is the single most useful thing to know
when planning the run.
- Data prep (CPU, ~2 min) — builds a BIRD Text2SQL
training.jsonl from the no-reasoning and
reasoning splits, formatted with Nemotron-3.5's chat template.
- Convert (CPU, ~4 min) — imports the Hugging Face checkpoint into Megatron-Bridge format.
- LoRA fine-tune (GPU) — packed-sequence LoRA training; saves an adapter.
- Merge & export (CPU) — merges the adapter into the base weights, writing a standard Hugging
Face checkpoint.
Information to gather from the user
Ask for these up front, in one batch:
- Path to the Nemotron-3.5 Lightning checkpoint (already downloaded), or confirmation that you should
download it and where to put it. It is ~62 GB.
- How many GPUs they want to use, and what kind. Drives the whole training config.
- Where to write outputs — needs ~130 GB free.
- A Hugging Face token (
$HF_TOKEN) so BIRD can be downloaded during data prep. Reference it by
environment variable; never print it.
- The container image to use, if it differs from the one in the notebook.
Choosing the GPU configuration
The model's 128 experts are split across GPUs with expert parallelism, so n_devices is the only
knob that really matters — set EP = n_devices. Measured peak memory per GPU on 80GB H100s at
seq_length=2048:
| GPUs |
Peak/GPU |
One epoch |
Recommendation |
| 1 |
78.8 GB |
~62 min |
Works only with REDUCE_MTP_HEADS=1. ~0.4 GB margin — fine if that is all they have. |
| 2 |
51.0 GB |
~34 min |
Default to this when available. Stock recipe, ~28 GB margin. |
| 4 |
34.8 GB |
~18 min |
Good if available. |
| 8 |
26.8 GB |
~8 min |
Fastest. |
All measured over a full epoch (189 iterations, GBS 32, seq_length=2048) on the complete
12,544-example dataset. Final loss lands within ~2% across all four, so choose on hardware
availability and how long the user is willing to wait — not on expected quality.
If the user has GPUs smaller than 80 GB, scale by the same logic: peak memory is roughly
(model weights ÷ EP) + ~12 GB of overhead. Spare memory is best spent raising seq_length, which
increases how much of the dataset survives the length filter — not just headroom.
How to run it
- Launch the container with the notebook directory and the checkpoint path mounted, and
$HF_TOKEN
exposed. Use the docker run invocation in the notebook's first cell as the template.
- Fill in the notebook's Configuration cell (paths,
n_devices) — it is the only cell that
should need editing.
- Run the steps in order. After each, run its sanity-check cell before moving on.
- Training is the long step. Run it in the background and poll; do not hold a blocking session
open, and do not stream the full log.
You can also run the steps directly rather than through the notebook — each is a plain script driven
by environment variables (MODEL_ID, MAX_SEQ_LEN, DATAPREP_OUTPUT_DIR for data prep;
HF_MODEL, MEGATRON_MODEL_PATH for convert; and N_DEVICES, EP, DATASET_DIR,
TRAINING_OUTPUT_DIR, EXPERIMENT_NAME for training).
Verifying success per step
- Data prep:
$DATAPREP_OUTPUT_DIR/training.jsonl exists with ~12,500 rows at seq_length=2048.
Spot-check one record: input should end with <think>\n (reasoning) or <think></think>
(non-reasoning), and output should continue directly from there.
- Convert:
$MEGATRON_MODEL_PATH/latest_checkpointed_iteration.txt plus an iter_* directory
exist (~62 GB).
- Train: an
iter_* adapter checkpoint under $TRAINING_OUTPUT_DIR/$EXPERIMENT_NAME, and the
log shows lm loss trending down.
- Merge: the output directory contains
model-*.safetensors shards, config.json, and the
tokenizer files, and the log ends with Success: All tensors from the original checkpoint were written.
Report per-step status, wall-clock time, and the final training loss.
Things already handled — do not change them
- The recipe supplies everything model-specific.
train.py calls
the shipped PEFT recipe and overrides only local paths, parallelism, dataset, and
schedule. Don't hand-write LoRA target modules — the recipe's already cover the Mamba
projections, attention, and both routed and shared experts.
- The MoE dispatcher is set to
alltoall rather than the recipe's default flex/DeepEP, for
portability. Only change this if DeepEP is known good on the user's system.
- Synchronous checkpoint saving (
async_save=False) is deliberate.
- Steps are idempotent: data prep skips if
training.jsonl exists; convert skips if the
checkpoint exists.
Expected friction (so you don't misread it)
- The first training iteration takes 1–2 minutes with no output while CUDA graphs are captured
and the MoE warms up. Subsequent iterations are seconds. Do not cancel the job.
- Startup log noise is not failure.
Failed to import Triton kernels, MimoModelConfig is experimental, Unable to import torchao, and torch_dtype is deprecated all appear on healthy
runs. Judge by the sanity checks.
- Do not enable
RECOMPUTE_ACTIVATIONS. It lowers memory but fails at iteration 2 with an
assertion in Megatron's gradient buffer. If the user is out of memory, add a GPU or lower
seq_length instead.
REDUCE_MTP_HEADS reduces to one head, it cannot disable MTP. The hybrid model asserts
mtp_num_layers > 0.
- If you point the recipe at local data, you must also clear its Hugging Face dataset fields —
a dataset config accepts exactly one source.
train.py already does this; preserve it if you
refactor.
- Serve with vLLM, not Transformers. vLLM supports this architecture natively and works.
transformers.generate() currently fails inside the model's bundled remote code — on the base
checkpoint too, so don't diagnose it as a fine-tuning problem.
- Any vLLM script needs an
if __name__ == "__main__": guard. vLLM spawns workers; without it
the failure surfaces as Engine core initialization failed wrapping a multiprocessing
bootstrap error that never mentions vLLM.
What success looks like at the end
Serving the merged checkpoint and prompting it the way data prep formatted training examples should
yield bare SQL, e.g. SELECT T2.dept_name FROM employees AS T1 INNER JOIN .... The base model
instead answers conversationally with fenced SQL and a prose explanation. If the fine-tuned model
still explains itself, something upstream went wrong — suspect the chat-template format first.
1---2name: nemotron-3-5-lightning-text2sql-lora3description: Run the Nemotron-3.5 Lightning Text2SQL LoRA fine-tuning tutorial (NeMo Megatron-Bridge) end-to-end for the user on a single node: data prep, checkpoint conversion, LoRA fine-tuning of the 30B-A3B hybrid Mamba-Transformer MoE, and merging the adapter back to a Hugging Face checkpoint. Use when the user wants to run this cookbook, fine-tune Nemotron-3.5 Lightning with LoRA, or adapt the notebook to their own machine.4---56# Nemotron-3.5 Lightning Text2SQL LoRA — runbook for a coding agent78This skill helps you run the cookbook in this directory (`mbridge_lora_cookbook.ipynb`) on the9user's behalf. Your job is to gather a few environment details, pick a GPU configuration that fits10their hardware, run the four steps in order, and confirm each one produced what it should.1112## What the tutorial does1314Four steps, in order. **Only step 3 needs a GPU** — this is the single most useful thing to know15when planning the run.16171. **Data prep** (CPU, ~2 min) — builds a BIRD Text2SQL `training.jsonl` from the no-reasoning and18 reasoning splits, formatted with Nemotron-3.5's chat template.192. **Convert** (CPU, ~4 min) — imports the Hugging Face checkpoint into Megatron-Bridge format.203. **LoRA fine-tune** (GPU) — packed-sequence LoRA training; saves an adapter.214. **Merge & export** (CPU) — merges the adapter into the base weights, writing a standard Hugging22 Face checkpoint.2324## Information to gather from the user2526Ask for these up front, in one batch:2728- **Path to the Nemotron-3.5 Lightning checkpoint** (already downloaded), or confirmation that you should29 download it and where to put it. It is ~62 GB.30- **How many GPUs** they want to use, and what kind. Drives the whole training config.31- **Where to write outputs** — needs ~130 GB free.32- **A Hugging Face token** (`$HF_TOKEN`) so BIRD can be downloaded during data prep. Reference it by33 environment variable; never print it.34- **The container image** to use, if it differs from the one in the notebook.3536## Choosing the GPU configuration3738The model's 128 experts are split across GPUs with expert parallelism, so `n_devices` is the only39knob that really matters — set `EP = n_devices`. Measured peak memory per GPU on 80GB H100s at40`seq_length=2048`:4142| GPUs | Peak/GPU | One epoch | Recommendation |43| --- | --- | --- | --- |44| 1 | 78.8 GB | ~62 min | Works only with `REDUCE_MTP_HEADS=1`. ~0.4 GB margin — fine if that is all they have. |45| 2 | 51.0 GB | ~34 min | **Default to this when available.** Stock recipe, ~28 GB margin. |46| 4 | 34.8 GB | ~18 min | Good if available. |47| 8 | 26.8 GB | ~8 min | Fastest. |4849All measured over a full epoch (189 iterations, GBS 32, `seq_length=2048`) on the complete5012,544-example dataset. Final loss lands within ~2% across all four, so choose on hardware51availability and how long the user is willing to wait — not on expected quality.5253If the user has GPUs smaller than 80 GB, scale by the same logic: peak memory is roughly54(model weights ÷ EP) + ~12 GB of overhead. Spare memory is best spent raising `seq_length`, which55increases how much of the dataset survives the length filter — not just headroom.5657## How to run it58591. Launch the container with the notebook directory and the checkpoint path mounted, and `$HF_TOKEN`60 exposed. Use the `docker run` invocation in the notebook's first cell as the template.612. Fill in the notebook's **Configuration** cell (paths, `n_devices`) — it is the only cell that62 should need editing.633. Run the steps in order. After each, run its sanity-check cell before moving on.644. Training is the long step. Run it in the background and poll; do not hold a blocking session65 open, and do not stream the full log.6667You can also run the steps directly rather than through the notebook — each is a plain script driven68by environment variables (`MODEL_ID`, `MAX_SEQ_LEN`, `DATAPREP_OUTPUT_DIR` for data prep;69`HF_MODEL`, `MEGATRON_MODEL_PATH` for convert; and `N_DEVICES`, `EP`, `DATASET_DIR`,70`TRAINING_OUTPUT_DIR`, `EXPERIMENT_NAME` for training).7172## Verifying success per step7374- **Data prep:** `$DATAPREP_OUTPUT_DIR/training.jsonl` exists with ~12,500 rows at `seq_length=2048`.75 Spot-check one record: `input` should end with `<think>\n` (reasoning) or `<think></think>`76 (non-reasoning), and `output` should continue directly from there.77- **Convert:** `$MEGATRON_MODEL_PATH/latest_checkpointed_iteration.txt` plus an `iter_*` directory78 exist (~62 GB).79- **Train:** an `iter_*` adapter checkpoint under `$TRAINING_OUTPUT_DIR/$EXPERIMENT_NAME`, and the80 log shows `lm loss` trending down.81- **Merge:** the output directory contains `model-*.safetensors` shards, `config.json`, and the82 tokenizer files, and the log ends with `Success: All tensors from the original checkpoint were83 written.`8485Report per-step status, wall-clock time, and the final training loss.8687## Things already handled — do not change them8889- **The recipe supplies everything model-specific.** `train.py` calls90 the shipped PEFT recipe and overrides only local paths, parallelism, dataset, and91 schedule. Don't hand-write LoRA target modules — the recipe's already cover the Mamba92 projections, attention, and both routed and shared experts.93- **The MoE dispatcher is set to `alltoall`** rather than the recipe's default `flex`/DeepEP, for94 portability. Only change this if DeepEP is known good on the user's system.95- **Synchronous checkpoint saving** (`async_save=False`) is deliberate.96- **Steps are idempotent:** data prep skips if `training.jsonl` exists; convert skips if the97 checkpoint exists.9899## Expected friction (so you don't misread it)100101- **The first training iteration takes 1–2 minutes** with no output while CUDA graphs are captured102 and the MoE warms up. Subsequent iterations are seconds. Do not cancel the job.103- **Startup log noise is not failure.** `Failed to import Triton kernels`, `MimoModelConfig is104 experimental`, `Unable to import torchao`, and `torch_dtype is deprecated` all appear on healthy105 runs. Judge by the sanity checks.106- **Do not enable `RECOMPUTE_ACTIVATIONS`.** It lowers memory but fails at iteration 2 with an107 assertion in Megatron's gradient buffer. If the user is out of memory, add a GPU or lower108 `seq_length` instead.109- **`REDUCE_MTP_HEADS` reduces to one head, it cannot disable MTP.** The hybrid model asserts110 `mtp_num_layers > 0`.111- **If you point the recipe at local data**, you must also clear its Hugging Face dataset fields —112 a dataset config accepts exactly one source. `train.py` already does this; preserve it if you113 refactor.114- **Serve with vLLM, not Transformers.** vLLM supports this architecture natively and works.115 `transformers.generate()` currently fails inside the model's bundled remote code — on the *base*116 checkpoint too, so don't diagnose it as a fine-tuning problem.117- **Any vLLM script needs an `if __name__ == "__main__":` guard.** vLLM spawns workers; without it118 the failure surfaces as `Engine core initialization failed` wrapping a `multiprocessing`119 bootstrap error that never mentions vLLM.120121## What success looks like at the end122123Serving the merged checkpoint and prompting it the way data prep formatted training examples should124yield bare SQL, e.g. `SELECT T2.dept_name FROM employees AS T1 INNER JOIN ...`. The base model125instead answers conversationally with fenced SQL and a prose explanation. If the fine-tuned model126still explains itself, something upstream went wrong — suspect the chat-template format first.