fix: materialize weights before VRAM-management wrapping (#1596)#2041
Open
MushiSenpai wants to merge 1 commit into
Open
fix: materialize weights before VRAM-management wrapping (#1596)#2041MushiSenpai wants to merge 1 commit into
MushiSenpai wants to merge 1 commit into
Conversation
WanVideoVRAMManagement crashes model loading with "Cannot copy out of meta tensor; no data!" (also kijai#843 / kijai#1188). Root cause: the transformer is built with init_empty_weights() (meta device). On the no-lora / no-scaled-quant path, load_weights() is never called before the vram block, so every parameter is still a meta tensor when enable_vram_management runs. AutoWrappedModule.__init__ does `self.module = module.to(offload_device)`, and moving a meta tensor with .to() raises NotImplementedError. The crash is in the wrapper construction, not in any sd[name] lookup. Fix: - nodes_model_loading.py: materialize weights from sd via load_weights() *before* wrapping, so enable_vram_management wraps real (non-meta) modules. - module_config: onload_device=offload_device (was =device). With CPU-resident weights this makes onload_device != computation_device, routing forward through the cast path instead of assuming weights are already on the compute device. - after wrapping, move params NOT inside an AutoWrapped* module (e.g. block modulation, patch_embedding) to the compute device, and clear sd so a later load_weights over the now-renamed (.module.) param names can't KeyError. - layers.py: AutoWrappedModule.__getattr__ proxy so model code reaching e.g. norm_layer.weight.dtype through the wrapper still works; forward() moves the inner module to the compute device for the call and back to offload after (no deepcopy), correct regardless of where the weights were loaded. Validated end-to-end on a Wan2.1-VACE workflow (wan2.1_vace_14B_fp16, fp16, quantization disabled, no lora) with WanVideoVRAMManagement: before = crash at enable_vram_management; after = weights load and the VACE edit completes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #1596 — and the same root cause behind #843 / #1188 (related: #409, #506).
The bug
Enabling the WanVideoVRAMManagement node crashes model loading with
Cannot copy out of meta tensor; no data!.Root cause
The transformer is built with
init_empty_weights(), so every parameter starts onthe meta device. On the no-lora / no-scaled-quant path (e.g. a plain
Wan2.1-VACE workflow),
load_weights()is not called before the vram block —neither the
lora is not None and merge_lorasbranch nor the"scaled" in quantization or lora is not Nonebranch runs — so the parameters arestill meta tensors when
enable_vram_managementexecutes.enable_vram_managementwraps eachnorm/Conv3d/LayerNorminAutoWrappedModule, whose__init__does:Calling
.to()to move a meta tensor raisesNotImplementedError: Cannot copy out of meta tensor; no data!. The crash is in thewrapper construction, before any weight lookup — not in an
sd[name]miss.Observed traceback (live, on this stack):
The fix
nodes_model_loading.pyload_weights(...)tofill the meta tensors from
sdbeforeenable_vram_management, so it wrapsreal (non-meta) modules. This is what removes the crash.
onload_device=offload_device(was=device) inmodule_config. WithCPU-resident weights, keeping
onload_device == computation_devicemakes thewrappers assume weights are already on the compute device; setting it to the
offload (CPU) device makes
onload_device != computation_device, which routesforwardthrough the cast path that moves weights to CUDA on demand.enable_vram_managementdoes notwrap (raw
nn.Parameterlike blockmodulation, and excluded modules such aspatch_embedding/rope_embedder) stay on CPU and would mismatch CUDA tensors inthe forward pass; move them to the compute device. Then clear
sdso a laterload_weightsover the now-renamed.module.param names can'tKeyError.diffsynth/vram_management/layers.py4.
AutoWrappedModule.__getattr__proxy so model code that reaches the wrappedmodule's attributes (e.g.
norm_layer.weight.dtype) through the wrapper stillworks.
5.
AutoWrappedModule.forwardmoves the inner module to the compute device for thecall and back to the offload device afterwards (no
deepcopy), which is correctregardless of where the weights were loaded.
Validation
End-to-end on a Wan2.1-VACE workflow (
wan2.1_vace_14B_fp16, base precisionfp16,quantization
disabled, no lora) with WanVideoVRAMManagement (offload 0.9):main): crash atenable_vram_management→Cannot copy out of meta tensor; no data!(full traceback above; captured liveby forcing the loader to run in isolation).
Transformer weights loaded, the VACE edit completes(~490–520 s/clip on an RTX 5090, well under 32 GB).
A CPU-only mechanism check (
verify_1596.py) reproduces the meta-tensor crash on awrapped meta module and confirms that materializing first lets
enable_vram_managementsucceed, plus the
__getattr__proxy and the device-routedforward.Scope / alternatives
The
.module.-nameKeyErrorsome reports mention is a secondary symptom (it onlyoccurs when
load_weightsruns after wrapping, over renamed params); this PRsidesteps it by materializing before wrapping and clearing
sd. Stripping the.module.infix inload_weightsis a viable complementary hardening but is notrequired once weights are materialized up front.
Disclosure: drafted and validated with AI assistance (Claude); reviewed and
submitted by me. The commit carries a
Co-Authored-Bytrailer.