ADR-0012 Sole Tensor Manager And Scoped Backends¶
语言: 简体中文
Status: Proposed
Date: 2026-10-02
Owners: Env / Manager / Training / Backend maintainers
Supersedes: ADR-0011
Superseded by: ADR-0018(仅 2026-10-17 的 #2382 改名增补;其余决策仍有效)
Roadmap: Issue #1811
Context¶
ADR-0011 removed the legacy NpEnv class and established TorchEnv as the sole lifecycle base,
but the runtime is not yet the sole tensor-native Manager. At the current
develop/tensor-runtime baseline:
generic Manager execution still has NumPy/host boundaries in event transactions, reset composition, row handling, and selected-row reset (#1703);
env.tensor_runtimeremains a per-owner switch and a runner-side placement input;FlashSAC
g1_motion_trackingregisters a second task-owned direct environment,TorchG1MotionTrackingFlashSACEnv, rather than entering through the generic Manager factory;task/runtime code still contains backend-private
_sensor_mapprobing and backend-name readiness branches (#1790);active backend breadth exceeds the scope that can be validated during this closing migration.
Recent low-clock multi-GPU measurements show that host-boundary count, not MJWarp physics, dominates collector cost. Reusing stable device views improved G1 walk throughput by roughly 22–25%, while replacing a compact reset composer with many small Torch operations regressed selected reset. The final contract therefore needs fewer and larger public operations, not merely “more Torch”.
This ADR records the structural decisions approved in #1811. It is a review baseline, not a delivery checklist; implementation remains staged in that roadmap.
Decision¶
Sole Manager-Based training entry point¶
make_manager_based_rl_env() is the sole production factory for training environments. A task
owner may register fused observation/reward/reset components for performance, but those components
are Manager-owned: they are declared by Manager config, execute inside the Manager lifecycle,
consume only public SimBackend APIs, and remain protected by an owner semantic fingerprint. They
are not a second environment class, not a direct runner mode, and not a backend-specific branch.
When this ADR is implemented, task-owned direct environment classes are not registered as training entry points.
Tensor-only Manager carrier¶
The Manager public lifecycle and its internal execution are tensor-native. Public row selectors, state, observations, rewards, terminations, commands, events, metrics, and recorder carriers are Torch tensors. Generic NumPy execution and dual-carrier term branches are deleted.
NumPy remains allowed only inside a backend adapter that declares a HOST_BRIDGE data plane and
owns its explicit packed conversion boundary. MuJoCo remains a production backend and is the
canonical in-process host-bridge implementation; it is not a test-only fallback.
env.tensor_runtime and env.tensor_runtime_device are removed without compatibility reads.
Tensor execution is an invariant
of the Manager runtime. Placement is derived from the declared backend data plane and, for a
HOST_BRIDGE, the process’s explicit carrier request. No NumPy/dual-runtime compatibility alias
or hidden fallback is retained.
For a HOST_BRIDGE backend, CPU-authoritative physics keeps the default Manager/TorchEnv
carriers on CPU. MuJoCo training may explicitly request the unindexed accelerator family with
training.sim_carrier_device=cuda; routing maps that request to the
env.sim_carrier_device owner field, and the collector process resolves it to its current
rank-local Torch CUDA ordinal. UniLab validates the request against the backend’s declared
Torch devices. Learner CUDA selection, GPU visibility, and backend device acceptance alone
are not placement requests. DEVICE_RESIDENT adapters keep their own CUDA-only placement and
platform requirements; accepting HIP Torch buffers on a host bridge does not make those
physics engines ROCm-compatible.
Addendum (2026-10-15, issue #2365): The sentence “Learner CUDA selection, GPU visibility, and backend device acceptance alone are not placement requests” is superseded for the scoped MuJoCo HOST_BRIDGE training path:
training.collector_tensor_devicenow defaults toauto, which turns the learner’s CUDA device into the carrier placement request, routed to the rank-local indexed learner device. CPU and torch.mps learners keep the CPU carrier, and explicitcpu/cudavalues are unchanged and win overauto. Decision record: https://github.com/Motphys/UniLab/issues/2365#issuecomment-6189905767.Addendum (2026-10-17, issue #2382):
training.collector_tensor_deviceandmanager_torch_deviceare renamed totraining.sim_carrier_deviceandenv.sim_carrier_devicewithout dual-read compatibility. Removed keys fail closed with a migration hint.run_config.jsonrecords the configured-to-resolved device map, andcudanever silently maps tomps; only the abstractgpualias may select an available accelerator family.Superseded (2026-10-21, issue #2481, ADR-0018): the rename above is reversed. The carrier knob and the off-policy inference transport merged into the single one-dimensional
training.collector_tensor_device(auto/cpu/cuda); the “name exceeds semantics” objection behind the #2382 rename no longer applies once carrier and ring placement are derived from the same knob.training.sim_carrier_device,training.inference_transport, andenv.sim_carrier_deviceare removed and fail closed with migration hints.Addendum (2026-10-19, issue #2401): Carrier routing now follows the public SDK-free
TensorPlatformProfileinventory rather than a MuJoCo-only backend-name scope. Any in-process packedHOST_BRIDGEprofile may route the training carrier, subject to its declaredtorch_devices; Motrix, Drake, and SuperDex therefore follow the sameauto/cpu/cudacontract as MuJoCo. Missing or unsupported capability declarations fail closed, while final construction remains guarded by the actualSimBackend.get_tensor_capabilities()declaration.
Manager-owned RNG¶
The Manager runtime owns one ManagerRng-backed Torch generator seeded from the resolved owner seed. Observation noise, commands, events, and tensor selected reset consume that generator or generators explicitly derived from it. Seed/reset state and selected-row reproducibility are contract-tested.
Legacy NumPy stream parity is not a compatibility requirement. Changing the stream is acceptable; nondeterministic owner seed behavior is not.
Strong selected-reset publication postcondition¶
For a backend declaring selected reset, once set_state_tensor returns, subsequent public state
and sensor views are authoritative for the committed rows. A backend may implement this by
immediate refresh or by lazy refresh at the first public view. Callers must not issue an extra
physics/control step to obtain readiness.
MuJoCo’s host-bridge contract remains the paired selected reset/read boundary. Runtime diagnostics may describe implementation details, but capability semantics—not diagnostic values—control dispatch.
Public backend metadata replaces probing¶
Task/runtime code must not inspect backend-private attributes, dispatch capability by backend
name, or require undeclared nq/nv attributes. Backend behavior is consumed through public
contract methods and capabilities, including:
selected-reset publication semantics;
a complete public sensor namespace/inventory; and
public qpos/qvel state widths.
A repository architecture gate rejects backend-private attribute access and backend-name capability dispatch in UniLab task/runtime code.
Temporary backend scope gate¶
This migration’s active runtime scope is mujoco, mjwarp, genesis, and newton. Other adapters remain
present in UniSim but are gated out of this runtime with actionable errors. Re-enabling a backend
requires its own capability, parity, and support-matrix evidence. Permanent adapter deletion is a
separate maintainer decision; this ADR does not delete those adapters.
Addendum (2026-10-18, issue #2406): The four-backend sentence above and the “Backend support claims narrow during migration” consequence below are historical decision context, not the current support scope. They describe the temporary gate at the original 2026-10-02 baseline and were superseded through staged, evidence-backed backend reintroductions; no later ADR replaces this record. The current tensor Manager scope is the nine explicit owner selections
mujoco,mjwarp,genesis,newton,motrix,superdex,drake,isaacsim, andisaacgym, matchingsrc/unilab/base/registry.py::_SUPPORTED_SIM_BACKENDSandsrc/unilab/cli.py::SUPPORTED_SIMS. Drake and the external-worker Isaac backends remain explicit selections and are excluded from implicit fallback ordering. Backend-specific capability support remains defined by the generated support matrix rather than by a global shelve list.
Single-GPU default device behavior¶
A single-GPU MJWarp run does not require CUDA_VISIBLE_DEVICES. It uses the current default CUDA
device. Explicit device selection remains required for ambiguous multi-GPU training and remains
useful for launcher/debug/MPS isolation.
Stable Contracts¶
Contract |
Owner / planned evidence |
|---|---|
Sole training factory and no direct registration |
|
Tensor-only Manager execution |
|
Removal of |
|
Manager-owned RNG |
Manager RNG owner, seed/reset and selected-row reproducibility tests |
Selected-reset publication postcondition |
UniSim tensor capability + MuJoCo/MJWarp/Genesis/Newton contract tests |
Public sensor namespace |
UniSim |
Public state widths |
UniSim state-width API and reset-plan tests |
No backend private/name probing |
architecture gate in UniLab tests |
Temporary backend gate |
backend factory/registry/docs/support matrix tests |
Single-GPU default device |
process-device/train smoke tests |
Alternatives Considered¶
Keep the direct FlashSAC environment as a performance exception. Rejected: it preserves a second training entry point and makes backend contract governance conditional on workload performance.
Make every Manager term execute through the generic per-term loop. Rejected as a forced implementation choice: it reintroduces known Python-dispatch overhead. Fused Manager-owned terms preserve the sole API without mandating one execution strategy.
Keep
tensor_runtimeas an owner switch. Rejected: the switch preserves dual contracts and lets unsupported workloads silently select a host fallback.Negotiate readiness through runtime diagnostics. Rejected: diagnostics describe state; capability semantics must own control flow.
Permanently delete all non-scoped adapters now. Rejected: this mixes an irreversible support decision with a runtime migration. The temporary gate keeps the review boundary explicit.
Set a strict “no regression” migration gate. Rejected: absorbing the fused direct owner can transiently regress a narrow workload. The roadmap uses a bounded migration allowance plus a mandatory optimization follow-up.
Consequences¶
Manager-Based semantics remain, but the Manager is the only training entry point and its carrier is tensor-only.
Fused owner kernels are valid only as Manager-owned implementation strategies, not as direct modes.
MuJoCo continues to carry the production host-bridge contract.
MJWarp, Genesis, and Newton must make public views authoritative after selected reset without an extra control step.
Backend support claims narrow during migration and are restored only with new evidence.
Owner configurations lose
env.tensor_runtime; migration documentation must state the breaking boundary without offering a compatibility alias.RNG streams may change, but reproducibility from an owner seed becomes explicit.
Performance convergence is staged: architectural closure is separated from a mandatory optimization follow-up.
Evidence In Repo¶
Manager runtime:
src/unilab/envs/manager_based_rl_env.pyTensor state store/readiness consumer:
src/unilab/tasks/motion_tracking/common/tensor_state_store.pyPublic backend contract:
unisim.backend.base.SimBackendCurrent tensor Manager backend scope:
src/unilab/base/registry.py(_SUPPORTED_SIM_BACKENDS,_DEFAULT_SIM_BACKEND_ORDER) andsrc/unilab/cli.py(SUPPORTED_SIMS)Current adapters:
unisim.backend.mujoco,unisim.backend.mjwarp,unisim.backend.genesis,unisim.backend.newton,unisim.backend.motrix,unisim.backend.superdex,unisim.backend.drake,unisim.backend.isaacsim,unisim.backend.isaacgymBackend-name readiness issue: #1790
Current Manager tensor migration: #1703
Delivery roadmap and performance budget: #1811
Superseded runtime decision: ADR-0011