[PyTorch] Optionally release columnwise copy of frozen FP8 block-scaled weights after dgrad#3233
Draft
1tex wants to merge 1 commit into
Draft
[PyTorch] Optionally release columnwise copy of frozen FP8 block-scaled weights after dgrad#32331tex wants to merge 1 commit into
1tex wants to merge 1 commit into
Conversation
…ed weights after dgrad Add an opt-in path for frozen 2D-block-scaled FP8 weights to release their columnwise representation after dgrad and rebuild it on demand. The behavior is disabled by default and covers Linear, GroupedLinear, LayerNormLinear, and LayerNormMLP. Preserve trainable-weight, CUDA graph, and FSDP2 behavior, and add unit and distributed coverage for rebuild numerics, workspace caching, activation recompute, CUDA graphs, FSDP2, and TP/SP. Signed-off-by: Tianyu Zhao <tyzhao10@gmail.com>
1tex
force-pushed
the
release-frozen-weight-columnwise
branch
from
July 22, 2026 01:43
d48b05f to
16f4f73
Compare
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.
Description
PEFT/LoRA-style fine-tuning keeps a large frozen base model in memory. When the base
model is stored as primary FP8 parameters (
quantized_model_init) with theFloat8BlockScalingrecipe, each weight holds two FP8 copies: rowwise (used by fprop)and columnwise (used only as the dgrad GEMM operand). For frozen weights
(
requires_grad=False) the columnwise copy is needed only transiently, yet today itstays resident after the first backward pass — up to 1 byte/param of the frozen model
per rank, for the whole run.
This PR adds an opt-in environment variable
NVTE_RELEASE_FROZEN_WEIGHT_COLUMNWISE(default off). When enabled, the columnwise copy of frozen 2D-block-scaled weights is
released right after the dgrad GEMM and rebuilt on demand by the existing
update_usage(columnwise_usage=True)path in the next backward — trading onequantization-aware transpose each time the columnwise copy is rebuilt (typically once
per frozen layer per training step) for the resident memory.
This is the trade-off suggested by @timmoon10 in #1880 ("reduce training memory usage
to 1 byte/param in exchange for some extra compute"). #1847 addressed initialization
(no columnwise usage when initializing under
torch.no_grad()); this PR addresses thesteady state after the first backward. #2168 explores a more general on-demand
columnwise mechanism for all weights; see the "Relationship with #2168" section below.
Known limitation (documented in
envvars.rst): for weights whose quantizer requestscolumnwise usage (e.g. initialized outside
torch.no_grad()), the copy is rebuilt inthe next forward, so this option mainly reduces between-step residency; the peak-memory
benefit requires initializing frozen parameters without columnwise usage.
Type of change
Changes
Core library change is ~80 lines; the rest is tests and validation scripts.
release_frozen_weight_columnwisehelper inmodule/base.py, gated on the envvar; only applies to
Float8BlockwiseQTensorStoragewith_is_2D_scaled=Trueand afull rowwise representation (data + scale-inv); no-op during CUDA graph capture.
Linear,GroupedLinear(both grouped-tensor andlegacy paths, including
backward_override),LayerNormLinear, andLayerNormMLP(FC1 and FC2), gated on the caller's wgrad-requirement flags.
docs/envvars.rst.tests/pytorch/test_frozen_weight_columnwise_release.py(23 tests): release/rebuildstability, bitwise-exact numerics vs. flag-off, flag-off regression, trainable weights
unaffected, non-2D layouts not released,
backward_override, columnwise-only guard,architecture-independent
update_usagespy, workspace/microbatch-cache paths,activation recompute, CUDA graphs (
make_graphed_callables+ directtorch.cuda.graph).tests/pytorch/distributed/run_fsdp2_frozen_release.py(both
reshard_after_forwardmodes) andrun_tpsp_frozen_release.py(TP+SP), with apytest driver
tests/pytorch/distributed/test_frozen_weight_columnwise_release.py(three parametrized cases, skipped with a clear reason on <2 GPUs).
Relationship with #2168
#2168 proposes a more general on-demand columnwise mechanism for blockwise FP8
weights. This PR is intentionally narrower: it applies only to frozen weights,
reuses the existing
update_usagepath, releases immediately after dgrad, andadditionally covers
LayerNormMLP.I asked about coordination in #2168 on Jul 18. I am opening this as a draft so
the concrete diff is available; happy to fold this work into #2168 if preferred.
Validation
All targeted validation coverable on H800 (8 GPUs) completed: 23/23 unit tests, FSDP2
both reshard modes (workspace/cache-free path; the columnwise-only guard is covered at
unit level since upstream FSDP2 + primary FP8 params is currently broken), TP+SP smoke,
and module regressions (
test_grouped_linear,test_backward_override,test_cuda_graphs,test_sanity) with zero failures.Measured on a 16-layer frozen stack (features=4096, tokens=4096, 0.268B params):
steady-state and peak memory drop
by 0.25 GiB under
torch.no_grad()initialization, matching the theoretical columnwisesize, at +3.9% step time (CUDA-event timing of fwd+bwd, 50 iterations); with
grad-enabled initialization only between-step residency drops (documented limitation).
No Blackwell hardware was available locally, so Blackwell validation is left for upstream;
a spy-based test provides an architecture-independent guarantee for non-blockwise layouts.
Checklist: