From 6cd7e9e5aa6cd9888bf8a1a8a0de4d6aadc03f9e Mon Sep 17 00:00:00 2001 From: Zhichenzzz Date: Wed, 15 Jul 2026 10:42:06 -0700 Subject: [PATCH] docs: add Inkling model recipe page --- docs/docs.json | 629 ++++++++++++------------ docs/models/index.md | 1 + docs/models/thinkingmachines/inkling.md | 202 ++++++++ 3 files changed, 518 insertions(+), 314 deletions(-) create mode 100644 docs/models/thinkingmachines/inkling.md diff --git a/docs/docs.json b/docs/docs.json index ea0a01473a..a1ac49e6a6 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -1,322 +1,323 @@ { - "$schema": "https://mintlify.com/schema.json", - "name": "Miles", - "theme": "mint", - "logo": { - "light": "/assets/images/miles_logo_light.png", - "dark": "/assets/images/miles_logo_dark.png", - "href": "/", - "width": 130 - }, - "favicon": "/assets/images/miles_square.png", - "seo": { - "metatags": { - "canonical": "https://miles.radixark.com/docs", - "og:site_name": "Miles Documentation" - } - }, - "colors": { - "primary": "#d55816", - "light": "#e8722a", - "dark": "#b84a12" - }, - "navbar": { - "links": [ - { - "type": "github", - "href": "https://github.com/radixark/miles" - } - ], - "primary": { - "type": "button", - "label": "Contact", - "href": "mailto:miles@radixark.ai" - } - }, - "navigation": { - "tabs": [ - { - "tab": "Welcome", - "groups": [ - { - "group": "Welcome", - "root": "index", - "pages": [ - "getting-started/index", - "getting-started/installation", - "getting-started/quick-start" - ] - } - ] - }, - { - "tab": "Models", - "groups": [ - { - "group": "Models", - "root": "models/index", - "pages": [ - { - "group": "DeepSeek", - "root": "models/deepseek/index", - "pages": [ - { - "group": "DeepSeek-V4", - "pages": [ - "models/deepseek/deepseek-v4-flash", - "models/deepseek/deepseek-v4-pro" - ], - "expanded": false - }, - "models/deepseek/deepseek" - ], - "expanded": false - }, - { - "group": "Qwen", - "root": "models/qwen/index", - "pages": [ - { - "group": "Qwen3.6", - "pages": [ - "models/qwen/qwen3-6", - "models/qwen/qwen3-6-moe" - ], - "expanded": false - }, - { - "group": "Qwen3.5", - "pages": [ - "models/qwen/qwen3-5", - "models/qwen/qwen3-5-moe" - ], - "expanded": false - }, - "models/qwen/qwen3-next", - { - "group": "Qwen3", - "pages": [ - "models/qwen/qwen3", - "models/qwen/qwen3-moe" - ], - "expanded": false - } - ], - "expanded": false - }, - { - "group": "GLM", - "root": "models/glm/index", - "pages": [ - "models/glm/glm5", - "models/glm/glm4-7-flash", - "models/glm/glm4-5", - "models/glm/glm4" - ], - "expanded": false - }, - { - "group": "Kimi", - "root": "models/kimi/index", - "pages": [ - "models/kimi/kimi-k2.5", - "models/kimi/kimi-k2", - "models/kimi/moonlight" - ], - "expanded": false - }, - { - "group": "Nemotron", - "root": "models/nemotron/index", - "pages": [ - { - "group": "Nemotron-3-Nano", - "pages": [ - "models/nemotron/nemotron-3-nano", - "models/nemotron/nemotron-3-nano-moe" - ], - "expanded": false - }, - "models/nemotron/nemotron-3-super" - ], - "expanded": false - }, - "models/mimo/mimo", - "models/gpt-oss/gpt-oss" - ] - } - ] - }, - { - "tab": "User Guide", - "groups": [ - { - "group": "User Guide", - "root": "user-guide/index", - "pages": [ - "user-guide/concepts", - "user-guide/argument-groups", - "user-guide/usage", - "user-guide/training-script-walkthrough", - "user-guide/monitoring", - "user-guide/customization", - "user-guide/rollout-endpoints", - "user-guide/fully-async", - "user-guide/agentic-chat-template", - "user-guide/cli-reference" - ] - } - ] - }, - { - "tab": "Advanced Features", - "groups": [ - { - "group": "Advanced Features", - "root": "advanced/index", - "pages": [ - { - "group": "Performance", - "pages": [ - "advanced/fp8-low-precision", - "advanced/int4-qat", - "advanced/speculative-decoding", - "advanced/lora" - ], - "expanded": false - }, - { - "group": "Scale & Reliability", - "pages": [ - "advanced/fault-tolerance", - "advanced/pd-disaggregation", - "advanced/p2p-weight-transfer" - ], - "expanded": false - }, - { - "group": "MoE & Routing", - "pages": [ - "advanced/miles-router" - ], - "expanded": false - }, - { - "group": "Backends", - "pages": [ - "advanced/architecture-support" - ], - "expanded": false - } - ] - } - ] - }, - { - "tab": "Examples", - "groups": [ - { - "group": "Examples", - "root": "examples/index", - "pages": [ - "examples/fully-async", - "examples/search-r1", - "examples/retool", - "examples/multi-agent", - "examples/reproducibility", - "examples/openhermes-sft" - ] - } - ] - }, - { - "tab": "Developer Guide", - "groups": [ - { - "group": "Developer Guide", - "root": "developer/index", - "pages": [ - "developer/contributor-guide", - "developer/debug", - "developer/migration", - "developer/architecture", - "developer/experimental-features" - ] - } - ] - }, - { - "tab": "Platforms", - "groups": [ - { - "group": "Platforms", - "root": "platforms/index", - "pages": [ - "platforms/nvidia", - "platforms/amd" - ] - } - ] - }, - { - "tab": "Resources", - "groups": [ - { - "group": "Resources", - "pages": [ - "faq", - "blog/index" - ] - } - ] - } + "$schema": "https://mintlify.com/schema.json", + "name": "Miles", + "theme": "mint", + "logo": { + "light": "/assets/images/miles_logo_light.png", + "dark": "/assets/images/miles_logo_dark.png", + "href": "/", + "width": 130 + }, + "favicon": "/assets/images/miles_square.png", + "seo": { + "metatags": { + "canonical": "https://miles.radixark.com/docs", + "og:site_name": "Miles Documentation" + } + }, + "colors": { + "primary": "#d55816", + "light": "#e8722a", + "dark": "#b84a12" + }, + "navbar": { + "links": [ + { + "type": "github", + "href": "https://github.com/radixark/miles" + } + ], + "primary": { + "type": "button", + "label": "Contact", + "href": "mailto:miles@radixark.ai" + } + }, + "navigation": { + "tabs": [ + { + "tab": "Welcome", + "groups": [ + { + "group": "Welcome", + "root": "index", + "pages": [ + "getting-started/index", + "getting-started/installation", + "getting-started/quick-start" + ] + } ] - }, - "background": { - "dark": "#0c0b0a", - "light": "#faf7f4" - }, - "url": "https://www.radixark.com", - "contextual": { - "options": [ - { - "title": "Raise a docs issue", - "description": "Flag a wording, formatting, or accuracy issue on this page.", - "icon": "github", - "href": "https://github.com/radixark/miles/issues/new" - } + }, + { + "tab": "Models", + "groups": [ + { + "group": "Models", + "root": "models/index", + "pages": [ + "models/thinkingmachines/inkling", + { + "group": "DeepSeek", + "root": "models/deepseek/index", + "pages": [ + { + "group": "DeepSeek-V4", + "pages": [ + "models/deepseek/deepseek-v4-flash", + "models/deepseek/deepseek-v4-pro" + ], + "expanded": false + }, + "models/deepseek/deepseek" + ], + "expanded": false + }, + { + "group": "Qwen", + "root": "models/qwen/index", + "pages": [ + { + "group": "Qwen3.6", + "pages": [ + "models/qwen/qwen3-6", + "models/qwen/qwen3-6-moe" + ], + "expanded": false + }, + { + "group": "Qwen3.5", + "pages": [ + "models/qwen/qwen3-5", + "models/qwen/qwen3-5-moe" + ], + "expanded": false + }, + "models/qwen/qwen3-next", + { + "group": "Qwen3", + "pages": [ + "models/qwen/qwen3", + "models/qwen/qwen3-moe" + ], + "expanded": false + } + ], + "expanded": false + }, + { + "group": "GLM", + "root": "models/glm/index", + "pages": [ + "models/glm/glm5", + "models/glm/glm4-7-flash", + "models/glm/glm4-5", + "models/glm/glm4" + ], + "expanded": false + }, + { + "group": "Kimi", + "root": "models/kimi/index", + "pages": [ + "models/kimi/kimi-k2.5", + "models/kimi/kimi-k2", + "models/kimi/moonlight" + ], + "expanded": false + }, + { + "group": "Nemotron", + "root": "models/nemotron/index", + "pages": [ + { + "group": "Nemotron-3-Nano", + "pages": [ + "models/nemotron/nemotron-3-nano", + "models/nemotron/nemotron-3-nano-moe" + ], + "expanded": false + }, + "models/nemotron/nemotron-3-super" + ], + "expanded": false + }, + "models/mimo/mimo", + "models/gpt-oss/gpt-oss" + ] + } + ] + }, + { + "tab": "User Guide", + "groups": [ + { + "group": "User Guide", + "root": "user-guide/index", + "pages": [ + "user-guide/concepts", + "user-guide/argument-groups", + "user-guide/usage", + "user-guide/training-script-walkthrough", + "user-guide/monitoring", + "user-guide/customization", + "user-guide/rollout-endpoints", + "user-guide/fully-async", + "user-guide/agentic-chat-template", + "user-guide/cli-reference" + ] + } + ] + }, + { + "tab": "Advanced Features", + "groups": [ + { + "group": "Advanced Features", + "root": "advanced/index", + "pages": [ + { + "group": "Performance", + "pages": [ + "advanced/fp8-low-precision", + "advanced/int4-qat", + "advanced/speculative-decoding", + "advanced/lora" + ], + "expanded": false + }, + { + "group": "Scale & Reliability", + "pages": [ + "advanced/fault-tolerance", + "advanced/pd-disaggregation", + "advanced/p2p-weight-transfer" + ], + "expanded": false + }, + { + "group": "MoE & Routing", + "pages": [ + "advanced/miles-router" + ], + "expanded": false + }, + { + "group": "Backends", + "pages": [ + "advanced/architecture-support" + ], + "expanded": false + } + ] + } + ] + }, + { + "tab": "Examples", + "groups": [ + { + "group": "Examples", + "root": "examples/index", + "pages": [ + "examples/fully-async", + "examples/search-r1", + "examples/retool", + "examples/multi-agent", + "examples/reproducibility", + "examples/openhermes-sft" + ] + } + ] + }, + { + "tab": "Developer Guide", + "groups": [ + { + "group": "Developer Guide", + "root": "developer/index", + "pages": [ + "developer/contributor-guide", + "developer/debug", + "developer/migration", + "developer/architecture", + "developer/experimental-features" + ] + } + ] + }, + { + "tab": "Platforms", + "groups": [ + { + "group": "Platforms", + "root": "platforms/index", + "pages": [ + "platforms/nvidia", + "platforms/amd" + ] + } + ] + }, + { + "tab": "Resources", + "groups": [ + { + "group": "Resources", + "pages": [ + "faq", + "blog/index" + ] + } ] + } + ] + }, + "background": { + "dark": "#0c0b0a", + "light": "#faf7f4" + }, + "url": "https://www.radixark.com", + "contextual": { + "options": [ + { + "title": "Raise a docs issue", + "description": "Flag a wording, formatting, or accuracy issue on this page.", + "icon": "github", + "href": "https://github.com/radixark/miles/issues/new" + } + ] + }, + "footer": { + "socials": { + "github": "https://github.com/radixark/miles" }, - "footer": { - "socials": { - "github": "https://github.com/radixark/miles" - }, - "links": [ - { - "header": "Contribute", - "items": [ - { - "label": "Raise a docs issue", - "href": "https://github.com/radixark/miles/issues/new" - }, - { - "label": "Source on GitHub", - "href": "https://github.com/radixark/miles" - } - ] - } + "links": [ + { + "header": "Contribute", + "items": [ + { + "label": "Raise a docs issue", + "href": "https://github.com/radixark/miles/issues/new" + }, + { + "label": "Source on GitHub", + "href": "https://github.com/radixark/miles" + } ] + } + ] + }, + "font": { + "headings": { + "family": "Hanken Grotesk", + "weight": 600, + "url": "https://fonts.googleapis.com/css2?family=Hanken+Grotesk:wght@100..900&display=swap" }, - "font": { - "headings": { - "family": "Hanken Grotesk", - "weight": 600, - "url": "https://fonts.googleapis.com/css2?family=Hanken+Grotesk:wght@100..900&display=swap" - }, - "body": { - "family": "Inter", - "weight": 400, - "url": "https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500&display=swap" - } + "body": { + "family": "Inter", + "weight": 400, + "url": "https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500&display=swap" } + } } diff --git a/docs/models/index.md b/docs/models/index.md index a81b880c1a..da58791bb0 100644 --- a/docs/models/index.md +++ b/docs/models/index.md @@ -12,6 +12,7 @@ Each model name links to its recipe page. | Family | Models | |---|---| +| **Thinking Machines** | [Inkling](/models/thinkingmachines/inkling) | | **DeepSeek** | [DeepSeek-V4 Pro](/models/deepseek/deepseek-v4-pro)
[DeepSeek-V4 Flash](/models/deepseek/deepseek-v4-flash)
[DeepSeek-R1](/models/deepseek/deepseek)
[DeepSeek-V3](/models/deepseek/deepseek) | | **Qwen** | [Qwen3.6 MoE](/models/qwen/qwen3-6-moe)
[Qwen3.6](/models/qwen/qwen3-6)
[Qwen3.5-35B-A3B](/models/qwen/qwen3-5-moe)
[Qwen3.5-4B / 9B / 27B](/models/qwen/qwen3-5)
[Qwen3-Next-80B-A3B-Thinking](/models/qwen/qwen3-next)
[Qwen3-30B-A3B / 235B-A22B](/models/qwen/qwen3-moe)
[Qwen3-0.6B / 1.7B / 4B / 8B / 14B / 32B](/models/qwen/qwen3) | | **GLM** | [GLM-5.1](/models/glm/glm5)
[GLM-5](/models/glm/glm5)
[GLM-4.7-Flash](/models/glm/glm4-7-flash)
[GLM-4.5](/models/glm/glm4-5)
[GLM-Z1-9B-0414](/models/glm/glm4) | diff --git a/docs/models/thinkingmachines/inkling.md b/docs/models/thinkingmachines/inkling.md new file mode 100644 index 0000000000..3b4d49381b --- /dev/null +++ b/docs/models/thinkingmachines/inkling.md @@ -0,0 +1,202 @@ +--- +title: Inkling +description: Launch recipe for Inkling (975 B), Thinking Machines' multimodal MoE with short convolution, relative attention, and a shared-expert sink. +--- + +The complete Inkling RL implementation is open at the Miles pull request: [`radixark/miles#1683`](https://github.com/radixark/miles/pull/1683). + +## 1. Model Introduction + +[Inkling](https://huggingface.co/thinkingmachines/Inkling) is a mixture-of-experts transformer released by Thinking Machines Lab, with 975 B total parameters and 41 B active, a context window of up to 1 M tokens, and pretraining on 45 trillion tokens of text, images, audio and video. Its architecture introduces short convolution, attention with relative positional embedding, and a novel MoE design with a shared-expert sink. Miles implements Inkling as a native Megatron model: local and global relative attention, the residual ShortConv, the shared-sink router and experts, and the image and audio encoders, and the same backend drives both full-parameter and LoRA RL. + +**Key highlights**: + +- **ShortConv**: a short causal convolution with a residual connection, applied on the K and V streams and on the attention and MLP/MoE outputs. Miles implements it with fused, packing-aware Triton kernels. +- **Relative attention**: a learned relative-position bias replaces positional embeddings; the stack mixes sliding-window and full-attention layers, with context length up to 1 M tokens. +- **Shared-expert sink MoE**: sigmoid top-k routing where the router also scores the shared experts and renormalizes their weights together with the selected routed experts'. +- **Train–inference consistency by construction**: customized relative-attention score-mod, ShortConv, and FP32 SwiGLU/combine kernels, while Rollout Routing Replay (R3) replays the rollout's routed expert IDs, including over media-expanded multimodal sequences. + +## 2. Supported Variants + +| Model | Active / Total | Layers | HF ID | +|---|---|---|---| +| Inkling | 41 B / 975 B | 66 | [thinkingmachines/Inkling](https://huggingface.co/thinkingmachines/Inkling) | + +## 3. Quick start + +### 3.1 One-line launch + +```bash +# Pull the image +docker pull radixark/miles:inkling + +# Full-parameter GRPO on 16 nodes x 4 GB300, inside the container +cd /root/miles +python scripts/run_inkling_975b.py train \ + --model-name Inkling --train-mode full --task dapo_math \ + --num-nodes 16 --num-gpus-per-node 4 + +# LoRA GRPO (rank 32, all-linear), same cluster +python scripts/run_inkling_975b.py train \ + --model-name Inkling --train-mode lora --task dapo_math \ + --num-nodes 16 --num-gpus-per-node 4 +``` + + +### 3.2 Launcher path defaults + +| Flag | Default | Use | +|---|---|---| +| `--model-dir` | `/root/models` | parent directory holding the HF checkpoint and Megatron `_torch_dist` artifacts | +| `--hf-checkpoint` | `{model-dir}/{model-name}` | released HF weights | +| `--torch-dist` | `{model-dir}/{model-name}_torch_dist` | converted Megatron torch-dist checkpoint | +| `--data-dir` | `/root/datasets` | HF datasets (dapo-math-17k, geo3k, …) | +| `--save-dir` | unset | training checkpoints | + +Every option can also be preconfigured via `MILES_SCRIPT_` env vars (precedence: CLI flag > env var > built-in default). Pass any extra Miles / Megatron / SGLang flags through `--extra-args`. + +## 4. Script breakdown + +This section explains what the launcher does under the hood, and how to drive each stage manually. + +### 4.1 Download model + datasets + +```bash +# inside the container +hf download thinkingmachines/Inkling --local-dir /root/models/Inkling +hf download --repo-type dataset zhuzilin/dapo-math-17k --local-dir /root/datasets/dapo-math-17k +hf download --repo-type dataset hiyouga/geometry3k --local-dir /root/datasets/geo3k +``` + +Pass `--hf-checkpoint ` to the launcher when the weights are already on a shared filesystem. + +### 4.2 HF → Megatron `torch_dist` conversion + +Inkling ships in BF16, so conversion is a single distributed `torch_dist` shard (no precision cast). The model definition comes from `scripts/models/inkling-975b.sh`: + +```bash +cd /root/miles +source scripts/models/inkling-975b.sh +PYTHONPATH=/root/Megatron-LM torchrun \ + --nproc-per-node 4 --nnodes 4 \ + --master-addr ${MASTER_ADDR} --master-port 12345 \ + --node-rank ${NODE_RANK} \ + tools/convert_hf_to_torch_dist.py \ + ${MODEL_ARGS[@]} \ + --tensor-model-parallel-size 4 \ + --pipeline-model-parallel-size 1 \ + --expert-model-parallel-size 4 \ + --hf-checkpoint /root/models/Inkling \ + --save /root/models/Inkling_torch_dist/ +``` + +The saved `torch_dist` checkpoint is parallelism-agnostic: training can load it under any validated TP / PP / EP layout. Point the launcher at the result with `--torch-dist`. + +### 4.3 Multi-node fan-out + +Start each pod with the image and a shared filesystem mounted at the same path on every node, then bring up Ray: + +```bash +# head node +ray start --head --num-gpus 4 --disable-usage-stats +# each worker +ray start --address=${HEAD_IP}:6379 --num-gpus 4 --disable-usage-stats +``` + +Set `MILES_SCRIPT_EXTERNAL_RAY=1` to point the launcher at this existing Ray cluster. When it is unset, the launcher boots a local Ray head itself. + +## 5. Example Recipe Configuration + +### 5.1 Megatron Parallelism + +These are the validated layouts shipped with the launcher. Other TP / EP / PP / CP combinations that fit your compute can be supplied via `--extra-args` (the launcher raises on untested GPU counts to keep you honest). + +| Hardware | GPUs | TP | SP | PP | EP | expert-TP | Notes | +|---|---|---|---|---|---|---|---| +| GB300 | 64 | 4 | on | 4 | 16 | 1 | `--decoder-last-pipeline-num-layers 15` | + + +### 5.2 Algorithm + +GRPO with truncated importance sampling. The launcher defaults: global batch size 32, group size 8, maximum response length 4096 with truncation, Adam with `lr 1e-6`, constant decay. Rollout Routing Replay is on by default (`--use-rollout-routing-replay`). It replays only the routed expert IDs; the continuous routed *and* shared weights are recomputed from the current router under one common normalization, so gradients still flow through both. + +### 5.3 Training attention backends + +`--inkling-attn-backend` selects the training-side attention implementation: + +| Backend | Role | 8K packed, rel-extent 1024, GB300 | +|---|---|---| +| `flex` (default) | block-sparse FlexAttention, differentiable fwd+bwd | ~34 ms fwd+bwd, 10.9 GB peak | +| `te` | Transformer Engine DPA reference | ~189 ms, 46 GB peak | +| `fa4` | serving-bit-identical FA4 forward + TE-recompute backward | ~195 ms, 46 GB peak | + + +### 5.4 Rollout & SGLang + +```bash +SGLANG_ARGS=( + --rollout-num-gpus-per-engine 16 + --sglang-attention-backend fa4 + --sglang-moe-runner-backend triton + --sglang-mamba-scheduler-strategy extra_buffer + --sglang-enable-multimodal + --sglang-context-length 8192 + + # full-parameter + --sglang-mem-fraction-static 0.6 + --sglang-max-running-requests 64 + --sglang-max-total-tokens 327680 + + # LoRA (replaces the three flags above) + --sglang-ep-size 16 + --no-offload-rollout --no-offload-train + --sglang-mem-fraction-static 0.65 + --sglang-max-running-requests 32 + --sglang-lora-backend triton + --sglang-lora-use-virtual-experts + --sglang-max-loras-per-batch 1 +) +``` + +Weight updates stream Megatron shards into SGLang's tensor layout in bounded buckets over CUDA IPC (colocated). In LoRA mode only the adapter is synchronized. + +### 5.5 Optimizer + +```bash +--optimizer adam +--lr 1e-6 --lr-decay-style constant +--accumulate-allreduce-grads-in-fp32 +--attention-softmax-in-fp32 + +# full-parameter only, set by the launcher +--optimizer-state-nvme-dir /tmp/opt_offload +--optimizer-state-nvme-chunk-mb 256 +--offload-train-target disk +--offload-train-disk-dir /tmp/train_offload +--micro-batch-size 1 +``` + +Within a single GB300 rack the 975 B policy, gradients, and FP32 optimizer state exceed GPU memory, so Miles streams Megatron `DistributedOptimizer` state between a bounded GPU working set and node-local NVMe. The offload changes storage placement, not the update math. The paused training actor's weights are additionally disk-backed through `torch_memory_saver`. LoRA training skips both offloads and uses dynamic batching (`--use-dynamic-batch-size --max-tokens-per-gpu 4096`) instead of the fixed micro-batch. + + + +1. **Fixed micro-batches for full-parameter runs.** Dynamic token packing exposes a PP-p2p × EP-all-to-all NCCL launch-order race on varlen shapes; the launcher pins `--micro-batch-size 1` for full-parameter training. Keep it pinned until the pad-to-fixed fix lands. +2. **One LoRA adapter per engine.** RL serving uses `--sglang-max-loras-per-batch 1` with the triton LoRA backend and virtual experts: the engine holds exactly the current policy's adapter (see [LoRA RL](#6-lora-rl)). + + + +## 6. LoRA RL + +`--train-mode lora` switches the same backend and parallel stack to adapter-only training. The base model stays frozen in both runtimes, and GRPO updates only the low-rank factors: + +$$ +y = Wx + \frac{\alpha}{r}\,B(Ax). +$$ + +The adapter follows Inkling's released LoRA schema, covering the attention, dense MLP, MoE, and LM-head projections (defaults: rank 32, `alpha = 32`, all-linear). The routed experts use a shared-outer factorization: one factor is shared across experts while the expert-specific factors follow EP sharding. + +After each optimizer step, Miles exports a serving-ready adapter directly from the distributed training state and hands it to the colocated SGLang worker over CUDA IPC; the frozen base is never re-transferred. This cuts the weight update from 49.4 s to 2.5 s (20×) and brings training-step time to ~85 % of full-parameter training, with no optimizer offload needed. Released Inkling adapters in safetensors format support warm starts via `--lora-adapter-path`, and per-rank adapter checkpoints allow exact training resume. + +## 7. Multimodal RL + +`--task geo3k` switches to the vision-language recipe: structured multimodal rollouts, Megatron-side vision and audio towers, and routing replay preserved across the media-expanded sequence. Each image or audio sentinel in the rendered prompt expands into its patch/frame positions before packing, and the R3 trace is indexed over the expanded sequence, so replay stays aligned even though SGLang made its routing decisions after expansion. Production recipes keep the vision and audio towers frozen and train the language model (or its adapter) around their embeddings; training the towers is available as an experimental option. The same path supports audio inputs and both full-parameter and LoRA training.