Skip to content

[tml] Inkling model support - #1683

Merged
Zhichenzzz merged 52 commits into
mainfrom
zhichen/feat
Aug 3, 2026
Merged

[tml] Inkling model support#1683
Zhichenzzz merged 52 commits into
mainfrom
zhichen/feat

Conversation

@Zhichenzzz

@Zhichenzzz Zhichenzzz commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Inkling model + full-parameter RL support. The native LoRA layer is stacked on top in #2122.

https://www.lmsys.org/blog/2026-07-15-inkling-day0-support

sgl-project/sglang#31681

radixark/Megatron-LM#68

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Note

Gemini is unable to generate a review for this pull request due to the file types involved not being currently supported.

@Zhichenzzz Zhichenzzz closed this Jul 15, 2026
@Zhichenzzz
Zhichenzzz deleted the zhichen/feat branch July 15, 2026 18:18
@Zhichenzzz Zhichenzzz changed the title [WIP] feat [tml] Inkling model support Jul 15, 2026
@Zhichenzzz
Zhichenzzz restored the zhichen/feat branch July 15, 2026 18:21
@Zhichenzzz Zhichenzzz reopened this Jul 15, 2026
@Zhichenzzz Zhichenzzz closed this Jul 15, 2026
@Zhichenzzz
Zhichenzzz deleted the zhichen/feat branch July 15, 2026 18:22
@Zhichenzzz
Zhichenzzz restored the zhichen/feat branch July 15, 2026 18:24
@Zhichenzzz Zhichenzzz reopened this Jul 15, 2026
@Zhichenzzz Zhichenzzz closed this Jul 15, 2026
@Zhichenzzz
Zhichenzzz deleted the zhichen/feat branch July 15, 2026 18:24
@Zhichenzzz
Zhichenzzz restored the zhichen/feat branch July 15, 2026 18:26
@Zhichenzzz Zhichenzzz reopened this Jul 15, 2026
@Zhichenzzz
Zhichenzzz marked this pull request as ready for review July 15, 2026 18:27
13 conflicting files. Where main had refactored or generalized the same code,
main wins; where the two sides added independent features, both are kept.

Take main:
- megatron_utils/arguments.py, sglang_utils/arguments.py: main is a strict
  superset (multi-LoRA plain-DDP branch; the --sglang-* aliases 1683 guarded
  with hasattr are gone, and --sglang-ep-size is now the real flag).
- ray/actor_group.py: main moved the body into allocate_gpus_for_actor().
  Verified that helper carries everything 1683 added inline -- the TMS preload
  path via get_binary_path_from_package, NVSHMEM_DISABLE_NCCL, and the disk
  backup env vars.
- megatron_utils/actor.py reclaim: TMS_DISK_BACKUP_DIR is per-rank
  (actor_factory: cell{i}_rank{r}), so main's wholesale rmtree of it is both
  correct and simpler than globbing tms_*.bin, and hunk 4 must read that env
  var rather than the shared root.
- utils/arguments.py: uid-scoped offload dir, the chunk-mb positivity assert,
  sglang_cuda_graph_backend_prefill replacing the piecewise-cuda-graph flags
  (nothing else on this branch referenced them), and the
  async_max_concurrent_samples assert.

Keep both:
- sglang_engine.py: 1683's full-adapter serialized_tensors transport with its
  exactly-one check AND main's in-place upsert; the Inkling "all" target-module
  sentinel survives.
- update_weight_from_tensor.py: skip_base_sync now covers all three base
  retention paths (distributed, cpu_backup, and 1683's colocate_base_persistent)
  AND main's opt-out when --check-weight-update-equal is on. Main's
  placeholder-rank guard is kept, but NOT its load_format="flattened_bucket":
  this branch serializes a LoRA adapter as a plain named dict, so declaring a
  flattened bucket would misread the payload. Main's to-do-1 described its own
  bucket path and no longer applies; its CI-coverage to-do is kept.
- model.py: main's multi-LoRA hide_adapters load context composed with 1683's
  missing-checkpoint tolerance and post-load native adapter load.
- lora_utils.py save: 1683 saves one shard per global rank because ranks
  sharing (tp,pp) hold different EP experts, and the already-merged load side
  reads that name with a legacy tp/pp fallback. Main's parallel_state
  accessors are adopted so the HF PEFT write gate can use its pp_rank fix.
- The rollout-side files take main's module layout (LORA_ADAPTER_NAME and
  friends now live in miles/utils/lora, not the megatron backend) while their
  single-adapter branches gate on lora_rollout_enabled so --lora-train-only
  still keeps the rollout side adapter-free.

Two breakages git could not see, both in non-conflicting regions:
- main renamed is_megatron_main_rank -> is_first_replica_megatron_main_rank;
  model.py had two surviving calls to the old name.
- both sides registered --check-lora-weight-equal, which makes argparse raise
  on startup. Main's is kept (identical behaviour, more precise help).

lora_rollout_enabled now lives in miles/utils/lora.py next to is_lora_enabled
so rollout code need not import the megatron backend, and is re-exported from
lora_utils.py for the training-side callers.
run_inkling_975b.py: the optimizer_args concatenation no longer needs to be
split across lines after the NVMe args were dropped, and the comment above it
still described them.

run_inkling_975b_fully_async.py: a stray blank line after the docstring-only
callback; pre-existing on this branch and failing the pinned black 24.3.0.
Three places where 1683's code and main's tests disagreed after the merge.
git could not see any of them: none are in a conflicting region.

1. sglang_lora_target_all_sentinel read args.hf_checkpoint directly, so main's
   TestBuildLoraSyncConfig cases (a minimal Namespace) raised AttributeError.
   is_inkling_checkpoint already treats an empty path as 'not Inkling'.

2. setup_model_and_optimizer raised NotImplementedError for LoRA in raw mode
   unless the provider was the Inkling plugin, which broke main's
   test_lora_raw_mode_skips_bridge and changed behaviour for models this PR is
   not about. Apply the Inkling adapter wrapping when the Inkling provider is in
   use and otherwise leave main's path alone, so the PR stays additive.

3. get_named_update_units: 1683 replaced main's 'group references no params'
   assert with an unconditional continue -- a dead loop -- because a PP rank can
   legitimately hold no layer for an MoE-only group. Express that per group
   instead: AtomicUpdateGroup gains optional=False, Inkling's three MoE groups
   set it, and every other group keeps main's guard against a mistyped suffix.
…-train

The bridge LoRA path patches _ParamAndGradBuffer so adapter param/grad
buffers land in the "param_buffer" torch_memory_saver region, which
pause(tag="default") leaves mapped. The native Inkling path skipped that
patch, so under --offload-train the adapter buffers sat in the pausable
region: sleep() unmapped them, and the by-design asleep update_weights hit
an illegal memory access when the expert-parallel all_gather read the
adapter weights. Production never saw this because engines with >=16 GPUs
auto-disable offload; the 4-GPU CI topology was the first to combine LoRA
with offload-train. Mirror the bridge gating in apply_inkling_lora.
_w1_delta/_a_cat are sglang-side buffers recomputed from the adapter at
load time; the checker's pre-sync snapshot holds their uninitialized
storage and can never match. Skip them like the frozen towers.
Same logic, new shape: module-level imports and adapter class, per-module
appliers (attention / dense MLP / routed experts / shared experts / lm head),
per-kind loader and exporter tables, and descriptive names throughout. The
flat one-all_gather-per-group export batching is kept. Drops the unused
megatron<->HF lora name mappers and the _APPLIED_MODELS registry.
yushengsu-thu

This comment was marked as duplicate.

@yushengsu-thu yushengsu-thu left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

6 issues might need to be resolved.

Comment thread miles/backends/megatron_utils/model.py Outdated
Comment thread scripts/run_inkling_fully_async.py Outdated
Comment thread miles/backends/megatron_utils/update_weight/update_weight_from_tensor.py Outdated
Comment thread miles_plugins/models/inkling/mm_towers.py
Comment thread miles/utils/chat_template_utils/template.py
Comment thread docs/models/thinkingmachines/inkling.md
Comment thread scripts/run_inkling.py
load_inkling_lora_adapter writes the adapter params after load_checkpoint
has already populated the distributed optimizer's fp32 masters, so the
first step() would restore the pre-load init values over the adapter.
Refresh the masters from the just-loaded model params.
…izer refactors

The launcher predates two main-side moves: #1716 replaced the
examples/fully_async module with miles.rollout.fully_async_rollout
(selected by --fully-async + MILES_EXPERIMENTAL_ROLLOUT_REFACTOR=1), and
the NVMe optimizer streaming merged as --stream-optimizer-state-to-disk /
--offload-train-disk-dir rather than --optimizer-state-nvme-dir. Point the
script at the current interfaces and drop the stale knob from run_inkling.
The gate still read args.inkling_mm_towers, but that CLI knob was removed
when the plugin knobs folded into the model config: the towers are now
chosen by the provider (inkling_mm_model_provider). The dead gate meant
tower tensors were never appended to base syncs, leaving the engine with
scrambled towers after its first offload cycle on multimodal runs.
wire_mm_towers runs with train=False, so the no_grad context covered not
just the frozen tower forwards but also _scatter, whose clone of the
embedding output detached it from the graph: embeddings received zero
gradient on every multimodal batch. Scope the context to the towers.
The hand-rolled python renderer covered plain user/system text but not
the rest of the chat spec: no thinking-effort line, no assistant
tool_calls, no end-sampling token, and image/audio parts were rejected.
inkling_fixed.jinja already implements all of it (and is what the TITO
path serves), so route apply_chat_template through the bundled template
and retire the python renderer.
The converter auto-bumps PP toward the rank count when launched with
PP1 across many ranks, which is incompatible with the documented TP4
16-rank command and fails the world-size divisibility check.
else:
# Start async all_gather
if ".experts." in info.name:
if ".experts." in info.name and ".shared_experts." not in info.name:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

".experts." seems to have more callings across many places... better to change all by adding not ".shared_experts."

Comment thread miles/backends/megatron_utils/update_weight/update_weight_from_tensor.py Outdated
Comment thread miles/backends/megatron_utils/update_weight/update_weight_from_tensor.py Outdated
Comment thread scripts/run_inkling_fully_async.py Outdated
@yueming-yuan

Copy link
Copy Markdown
Collaborator

have some thoughts on lora checkpoint; will discuss offline

Inkling's shared experts nest an inner ModuleList
(mlp.shared_experts.experts.N), so a bare ".experts." substring test
misclassifies their regular-TP params as expert-parallel. Three call
sites already carried the ".shared_experts." exclusion inline; extract
it as is_routed_expert_param() and use it at every megatron-name site
(gather group choice, EP broadcast, full-size accounting, expert/dense
iteration split). A no-op for models whose shared experts do not nest.
One launcher, one flag: --fully-async (with --rollout-num-nodes) selects
the disaggregated topology - train_async.py driver, --fully-async rollout,
bf16 grad reduce, NVMe-streamed optimizer state, and the validated
TP4 PP2 EP16 profile for 8x4 training GPUs. Colocate arg assembly is
unchanged. Also drop the two thin run-inkling-small*.sh wrappers; their
validated recipes (full 5e-5 / lora 2e-4 at 64x128) now live in the doc
launch commands.
…tions

inkling.sh and inkling-small.sh already take MODEL_ARGS_NUM_LAYERS; the
4-layer files were two-line wrappers setting it, so let the launcher set
it for *-4layer model names and point the registry at the base files.
inkling-lora.sh defined a LORA_ARGS array nothing consumes (the launcher
assembles its own LoRA flags) - delete it.
This PR now carries the Inkling model + full-parameter RL only: the model
plugin, launcher, multimodal path, chat template, weight-sync infra, docs,
and the full-parameter 4-layer CI test. The LoRA adapter plugin, its
launcher mode, engine serving wiring, and the LoRA CI test move to the
follow-up PR stacked on this branch.
Comment thread miles/backends/sglang_utils/sglang_engine.py Outdated
The shim papered over dev-lineage sglang builds that lack
begin/end_weight_update; the paired sglang here serves both, and
swallowing 404s would mask a genuinely broken endpoint.
@Zhichenzzz
Zhichenzzz merged commit 5c51759 into main Aug 3, 2026
41 checks passed
@Zhichenzzz
Zhichenzzz deleted the zhichen/feat branch August 3, 2026 20:59
Zhichenzzz added a commit that referenced this pull request Aug 11, 2026
…nkling

Kimi-K3 now has a page. It documents the day-0 LoRA RL recipe from #1825: the
MXFP4 to BF16 upcast, the 32-rank torch_dist conversion, and the validated
16-node launch, with the LoRA target modules and what a healthy run looks like
on the GB300 validation cluster. A line at the top says the branch it comes
from, since none of it is on main yet.

The page leans on two things worth calling out. LoRA is not a nicety here, it
is what makes the recipe fit: the base stays frozen and only the adapters carry
gradients, with one shared A factor and per-expert B factors across the 896
experts. And the memory figure in "what a healthy run looks like" is the one to
watch, because an adapter export that leaks shows up as allocated memory not
returning to baseline after a weight sync, long before the run dies.

Inkling still said its implementation "is open at" #1683. That merged on
2026-08-03 and the code is on main, so the line is gone; the page is the
documentation now.

Both tables link Kimi-K3 at the page instead of the pull request. MiMo and
GPT-OSS move below JoyAI so the families the home page lists appear in the same
order in both, with the two it does not carry after them.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants