mstar.model.submodule_base#
Classes
|
Unlike in regular ModelInputs, for LLMInputs we expect either input_ids or input_embeds to be set (but typically not both), and we require input_seq_len to be set (for cache planning). |
|
The batch's ``PerRequestState``s, resolved on first read. |
|
|
|
|
Base class for a model's compute units: defines the prepare_inputs → preprocess → forward(_batched) contract the engines drive. |
|
|
Engine-owned per-request state a submodule persists across forwards. |
|
- class mstar.model.submodule_base.ARNodeInputs(tensor_inputs=<factory>, kwargs=<factory>, resource_step_info=None, input_seq_len=0, input_ids=None, input_embeds=None, custom_pos_ids=None)[source]#
Bases:
NodeInputsUnlike in regular ModelInputs, for LLMInputs we expect either input_ids or input_embeds to be set (but typically not both), and we require input_seq_len to be set (for cache planning).
The tensor_inputs and kwargs dicts are still available for additional inputs as needed; but the main LLM inputs should be provided in the given dedicated fields.
- Parameters:
- classmethod collate(inputs_list, stacking_method=StackingMethod.NONE)[source]#
- Parameters:
inputs_list (list[ARNodeInputs])
- class mstar.model.submodule_base.ARNodeSubmodule[source]#
Bases:
NodeSubmodule- abstractmethod prepare_inputs(graph_walk, fwd_info, inputs, **kwargs)[source]#
- Parameters:
- Return type:
- abstractmethod preprocess(graph_walk, engine_inputs, inputs)[source]#
- Parameters:
graph_walk (str)
engine_inputs (ModelInputsFromEngine)
inputs (list[ARNodeInputs])
- Return type:
- class mstar.model.submodule_base.LazyRequestStates(submodule, rids)[source]#
Bases:
MappingThe batch’s ``PerRequestState``s, resolved on first read.
Only a couple of submodules read these, but the engine builds the view for every step of every node; materialising the dict there is bs dict inserts (and, for a padded step, bs
PerRequestStateallocations) per step that nothing usually looks at.- Parameters:
submodule (NodeSubmodule)
rids (Sequence[str])
- class mstar.model.submodule_base.ModelInputsFromEngine(request_ids: 'list[str]', per_request_info: 'dict[str, CurrentForwardPassInfo]', resources: 'dict[str, Resource]'=<factory>, piecewise_runners: "dict[str, 'PiecewiseCudaGraphRunner']"=<factory>, per_request_states: "'Mapping[str, PerRequestState] | None'"=None, step: 'SubmoduleStep | None' = None, captured: 'bool' = False)[source]#
Bases:
object- Parameters:
per_request_info (dict[str, CurrentForwardPassInfo])
per_request_states (Mapping[str, PerRequestState] | None)
step (SubmoduleStep | None)
captured (bool)
- property first_request_info#
unlike single_request_info, does not assert that there is only one request
- per_request_info: dict[str, CurrentForwardPassInfo]#
- per_request_states: Mapping[str, PerRequestState] | None = None#
- property single_request_info#
asserts that there is only one request
- Type:
IMPORTANT
- step: SubmoduleStep | None = None#
- class mstar.model.submodule_base.NodeInputs(tensor_inputs: 'dict[str, torch.Tensor]'=<factory>, kwargs: 'dict' = <factory>, resource_step_info: 'Any | None' = None, input_seq_len: 'int' = 0)[source]#
Bases:
object- Parameters:
- class mstar.model.submodule_base.NodeSubmodule[source]#
-
Base class for a model’s compute units: defines the prepare_inputs → preprocess → forward(_batched) contract the engines drive.
- bind_node_resources(resources)[source]#
Receive the engine-built resources for this submodule’s node, and pass them down to every layer that calls one.
A layer body (attention, cross-attention) calls the resources directly —
attn.run,kv.write_kv,pos.apply_qk— so it needs its own references. It resolves them here, once at load, by the labels the model declared inget_node_resources; a layer that names a label this node doesn’t have fails at bind rather than in the middle of a forward.
- can_batch(batch, model_inputs)[source]#
- Parameters:
batch (ExecutingBatch)
model_inputs (list[NodeInputs])
- can_use_cuda_graphs(batch, model_inputs)[source]#
Return True if this submodule supports CUDA graphs for
batch.Default: derives from
get_cuda_graph_configs— if any declared config can replay for this batch’s graph_walk, CUDA graphs are supported. We checkcfg.replay_graph_walks(not justcfg.capture_graph_walk) so aliased walks — e.g. Qwen3-Omni’sprefill_audioreusing theprefill_textcapture, orprefill_visionreusing its own — are correctly admitted at the eligibility gate. The runner’s_config_foralready looks up byreplay_graph_walks; this keeps the gate consistent so aliased walks don’t silently fall through to the eager path.replay_graph_walksis always a superset of{capture_graph_walk}(seeCudaGraphConfig.__init__), so this never narrows what the previous code accepted — only widens it for configs that explicitly declared aliases.Subclasses can override to reject on batch shape / metadata (e.g. codec submodules that need homogeneous frame counts).
- Parameters:
batch (ExecutingBatch)
model_inputs (list[NodeInputs])
- Return type:
- cg_key_info(graph_walk, per_request_info)[source]#
Which of this walk’s capture buckets a batch belongs to.
A walk can be captured more than once when the batch’s shape is not the whole story — bagel captures decode twice, guidance on and off, because the two declare different segments over the same token count. The engine leases a slot before the step is declared, so it cannot read the answer off the step; it asks here instead.
Must equal the
additional_key_infoon the config that captured the bucket, and thecg_key_infothis batch’sdeclare_stepputs on its step. Disagreeing is not an error anywhere — it just misses the capture and runs eager — so derive both from one place.None (the default) means the walk has a single capture.
- Parameters:
graph_walk (str)
per_request_info (dict[str, CurrentForwardPassInfo])
- Return type:
- check_stop(request_id, request_info, outputs)[source]#
Return the set of dynamic-loop names that should stop after this step.
Runs on the worker’s slow-postprocess path after
execute_batchreturns — never insideexecute_batch. Allowed to read tensor values (.item()/.cpu()) because by this point the GPU thread is no longer blocked by it.Stops returned here are deferred by one step: they apply to the worker’s next iter’s fast postprocess. The current in-flight step (already submitted under the assumption that the rid continues) will run for that rid and its output discarded — the standard 1-wasted-step cost for any stop signal.
Default: no stops.
- cleanup_request(request_id)[source]#
Remove per-request state when a request completes. The engines call this on request removal; overrides with extra internal state should call super().
- Parameters:
request_id (str)
- declare_step(graph_walk, request_ids, inputs, slot_lease=None, piecewise_leases=None, **kwargs)[source]#
Declare this batch’s step for the runner to drive: which cache streams it touches, what spans they grow by, which plans back it, which streams fork, and what commits when it lands. The runner drives the declaration before
preprocessand commits it after the forward, so a declaring submodule keeps no plan or advance calls of its own. None means the submodule still plans and advances through the facade itself.request_idspairs positionally withinputs. Under a captured graph the batch is padded to the bucket’s shape, so it carries the padding rows’ ids too — declare their segments like any other row.slot_leaseis the slot this step will replay on, or None for an eager step. A submodule whose declaration differs between the two (cosmos3 packs both guidance branches into one plan for the captured shape) must key off this, not off its own capture key: the key says the batch could be captured, the lease says it was.piecewise_leasesnames the regions of this node that hold a slot for this step. Such a region declares, plans and commits its own work, so a resource it owns must be left out of this declaration.- Parameters:
- Return type:
SubmoduleStep | None
- filter_batched_output(request_info, outputs)[source]#
Drop keys a real request shouldn’t receive. A captured forward emits a fixed key set for graph compat, so the filtering happens here.
- abstractmethod forward(graph_walk, engine_inputs, **kwargs)[source]#
Pure tensor → NameToTensorList computation. Compilable + CUDA-graphable.
- forward_batched(graph_walk, engine_inputs, **kwargs)[source]#
Batched form of
forward: maps a multi-request batch to per-request outputs. Override whencan_batchreturns True.
- get_autocast_dtype()[source]#
Per-submodule autocast dtype override for the engine’s forward wrap. The engine consults this on each
execute_batchand uses the returned dtype instead of its own when non-None.Default:
None(inherit the engine’s autocast dtype). To turn autocast off for one specific submodule whose engine otherwise has it enabled, wrap the submodule’s forward withtorch.amp.autocast(enabled=False)— that path is engine-agnostic and doesn’t need this surface.- Return type:
dtype | None
- get_cuda_graph_configs(device, tp_world_size=1)[source]#
- Parameters:
device (torch.device)
tp_world_size (int)
- Return type:
- get_piecewise_cuda_graph_configs(device, autocast_dtype, tp_world_size=1)[source]#
Return the piecewise CUDA graph configs this submodule opts into.
autocast_dtypeis the engine’s autocast dtype — passed so a config’smake_static_inputscan allocate the hidden-state buffer in the dtype the captured region runs under (avoids a copy-time upcast at replay).A piecewise CUDA graph captures ONE inner callable of this submodule’s forward (e.g. a transformer block loop) as a CUDA graph while the surrounding compute stays eager. The engine builds one
PiecewiseCudaGraphRunnerper returned label and threads the runners intoModelInputsFromEngine.piecewise_runnersso the submodule’s forward can look them up by label:runner = engine_inputs.piecewise_runners.get(“block_loop”) if runner is not None and runner.can_run(bs):
out = runner.run(static_inputs={…}, request_ids=…, seq_lens=…)
A config’s
capture_fntakes onePiecewiseCallInputs, whoseengine_inputs.resourcescarries the node’s resources — so a resource call (sampling included) can live INSIDE the capture, reading params straight from buffers whose addresses are stable across replays instead of being hoisted out as static inputs. A region that touches a resource declares its work in the config’s owndeclare_step; the runner admits, plans and commits it per replay.Default: no piecewise graphs. Override to return
{label: PiecewiseCudaGraphConfig}; multiple labels capture multiple independent graphs (i.e., one per outer function to be graphed).- Parameters:
device (torch.device)
autocast_dtype (torch.dtype)
tp_world_size (int)
- Return type:
- postprocess(request_id, request_info, outputs, inputs=None, **kwargs)[source]#
Per-request postprocessing on the submodule outputs.
Runs on the GPU thread inside
execute_batch, after the forward (eager, batched, or CUDA-graph replay).inputsis the request’sprepare_inputsresult for this step, so a submodule can finish a step the captured graph could not hold (e.g. combine guidance branches and run a Python multistep scheduler against the step’s input latents).Keep it metadata-only where possible. Avoid reading tensor values —
.item()/.cpu()sync here block the GPU thread and forfeit the worker’s async-scheduling overlap; stop-condition decisions that need token values (e.g. EOS) belong incheck_stop. A captured-path tail that must read scheduler state is the sanctioned exception — it costs the same sync wherever it runs.- Typical uses:
rebind output names for graph routing (
outputs["text_inputs"] = outputs["new_token"]);drop keys on a per-request basis for static-capture submodules (e.g. Qwen3-Omni Thinker dropping
thinker_statesfor requests that don’t need audio);finish a captured step from
inputs(Cosmos3 denoise tail).
Modifies
outputsin-place; returns nothing.- Parameters:
request_id (str)
request_info (CurrentForwardPassInfo)
inputs (NodeInputs | None)
- abstractmethod prepare_inputs(graph_walk, fwd_info, inputs, **kwargs)[source]#
- Parameters:
- Return type:
- preprocess(graph_walk, engine_inputs, inputs)[source]#
- Parameters:
graph_walk (str)
engine_inputs (ModelInputsFromEngine)
inputs (list[NodeInputs])
- Return type:
- request_state(request_id)[source]#
The request’s state, created on first access.
- Parameters:
request_id (str)
- Return type:
- request_states: dict[str, PerRequestState]#
- unpack_packed_outputs(static_output, request_ids, real_seq_lens, inputs, per_request_info)[source]#
Per-rid slicing for packed sentinels emitted by the captured graph.
Decode-style submodules emit per-rid entries inside the captured forward (one slice per request, fixed shape), so they don’t need this. Prefill-style submodules pack a (total_tokens, …) tensor whose per-request slice ends depend on real seq_lens — slicing has to happen post-replay, outside the captured region. Default no-ops; override and key off
static_outputsentinel names.
- class mstar.model.submodule_base.PerRequestState(tensors=<factory>, kwargs=<factory>, disag_shared_keys=<factory>)[source]#
Bases:
objectEngine-owned per-request state a submodule persists across forwards.
Submodules stash whatever a request’s later steps need (schedulers, conditioning latents, packing metadata) instead of keeping private
dict[request_id, ...]attributes. The engine owns the lifecycle: it injects the batch’s states viaModelInputsFromEngine.per_request_statesand drops a request’s state when the request is removed — no submodule cleanup code required.tensorsvskwargssplit by value kind: device tensors go intensors, everything else (numbers, dicts, scheduler objects) inkwargs.disag_shared_keysis reserved for PD disaggregation — marked keys would travel with the request (tensors via the tensor manager, kwargs with the forward-pass info); no engine implements the transfer yet.