Skip to content

[Fix] Load Laya without the throwaway random weight init - #22

Merged
Yunaik merged 1 commit into
ThinkFlowLab:mainfrom
cacheline999:fix/laya-skip-random-init
Sep 27, 2026
Merged

Yunaik merged 1 commit into
ThinkFlowLab:mainfrom
cacheline999:fix/laya-skip-random-init

Conversation

@cacheline999

Copy link
Copy Markdown
Contributor

Why

--model laya spends about 35 s loading a 0.4B model, and every CLI call pays it again because the model loads in process. Most of that time is spent initializing weights that get overwritten right away.

How

laya.load builds the ModernBERT encoder with AutoModel.from_config, so transformers draws every weight at random, and then laya loads the checkpoint over all of them with strict=True. Profiling the load on CPU puts ~33 s of it in _init_weights / trunc_normal_.

LayaModel.from_env now runs laya.load under transformers' no_init_weights(). The helper moved from transformers.modeling_utils (4.x) to transformers.initialization (5.x); without_weight_init() in s1a/decision_models/laya.py tries both and falls back to a plain load if neither is there. Because laya loads with strict=True, a checkpoint that misses a weight still fails loudly instead of leaving it uninitialized.

The from_env tests stub the helper. Without the stub the real one imports torch inside patch.dict(sys.modules), which drops torch again on exit, and the next torch import in the same process segfaults. This only happens with the laya extra installed, not in CI.

What

--model laya (agents, decide, probe, MCP decide) loads in about 3 s. No flags, outputs or records change.

Verification

Default checkpoint, laya 0.3.5, M1 Pro 16 GB. Each load in a fresh process:

transformers device load before load after state dict + buffers answers
5.17.0 (lock) cpu 35.3 s 2.5 s identical identical
5.17.0 (lock) mps 35.0 s 3.7 s identical identical
4.57.1 cpu 31.4 s 1.0 s identical identical
4.48.0 (laya's minimum) cpu 33.2 s 1.5 s identical identical

s1a decide --model laya end to end: 37.6 s → 9.9 s on CPU, 39.7 s → 8.5 s on MPS, same output.

Warm latency is unchanged. On CPU the first request after load is ~0.2–0.3 s slower, since the random init no longer warms up torch's CPU path during load.

  • uv run ruff format --check . && uv run ruff check . && uv run ty check
  • uv run pytest -q and scripts/smoke.sh: all pass on the core install (no torch, as in CI). With the laya extra installed, test_an_agent_without_system_one_is_a_config_error_naming_the_method fails on main too, because it expects laya's version to be unknown.
  • CHANGELOG.md

laya.load builds the ModernBERT encoder from its config, so transformers
draws every weight at random before the checkpoint is loaded over all of
them with strict=True. That draw is ~33 of the ~35 s load. Run the load
under transformers' no_init_weights (transformers.initialization in 5.x,
transformers.modeling_utils in 4.x, plain load if neither exists).

The from_env tests stub the helper: importing torch inside
patch.dict(sys.modules) and importing it again later segfaults.

@Yunaik Yunaik 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.

great find! thanks!

@Yunaik

Yunaik commented Sep 27, 2026

Copy link
Copy Markdown
Collaborator

Follow-ups:

@Yunaik

Yunaik commented Sep 27, 2026

Copy link
Copy Markdown
Collaborator

this issue seems to be fixed with laya 0.3.9 btw

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants