[PyTorch] Optionally release columnwise copy of frozen FP8 block-scaled weights after dgrad#3233
Open
1tex wants to merge 2 commits into
Open
[PyTorch] Optionally release columnwise copy of frozen FP8 block-scaled weights after dgrad#32331tex wants to merge 2 commits into
1tex wants to merge 2 commits into
Conversation
1tex
force-pushed
the
release-frozen-weight-columnwise
branch
from
July 22, 2026 01:43
d48b05f to
16f4f73
Compare
…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 26, 2026 07:13
16f4f73 to
ce88e3c
Compare
1tex
marked this pull request as ready for review
July 26, 2026 07:14
Contributor
Greptile SummaryAdds an opt-in mechanism to release and lazily rebuild columnwise copies of frozen 2D block-scaled FP8 weights.
Confidence Score: 5/5The PR appears safe to merge. No blocking failure remains. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[Backward requires dgrad] --> B[Run dgrad GEMM]
B --> C{Weight gradient required?}
C -- Yes --> D[Keep columnwise representation]
C -- No --> E{Release option enabled?}
E -- No --> D
E -- Yes --> F{2D block-scaled weight with complete rowwise data?}
F -- No --> D
F -- Yes --> G{CUDA graph capture active?}
G -- Yes --> D
G -- No --> H[Release columnwise representation]
H --> I[Rebuild on demand through update_usage]
Reviews (2): Last reviewed commit: "[PyTorch] Add frozen FP8 weight release ..." | Re-trigger Greptile |
Signed-off-by: Tianyu Zhao <tyzhao10@gmail.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.
Description
PEFT/LoRA-style fine-tuning keeps a large frozen base model in memory. With primary FP8
parameters (
quantized_model_init) and theFloat8BlockScalingrecipe, each weight holdstwo FP8 copies: rowwise (used by fprop) and columnwise (used only as the dgrad GEMM
operand). For frozen (
requires_grad=False) weights the columnwise copy is needed onlytransiently, yet it stays resident after the first backward pass — up to 1 byte per
locally resident frozen parameter. This is the compute-for-memory trade-off suggested by
@timmoon10 in #1880; #1847 addressed initialization, this PR addresses the steady state
during training.
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 via the existing
update_usagepath — one quantization-aware transpose per frozen layer per step in exchange for the
resident memory.
Known limitation (documented in
envvars.rst): if the weight's quantizer requestscolumnwise usage (e.g. parameters initialized outside
torch.no_grad()), the copy isrebuilt in the next forward, so the 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(env-var gated; only2D-block-scaled
Float8BlockwiseQTensorStoragewith a full rowwise representation;no-op during CUDA graph capture), called after the dgrad GEMM in
Linear,GroupedLinear,LayerNormLinear, andLayerNormMLP(FC1/FC2), gated on the caller'swgrad-requirement flags.
docs/envvars.rst.non-2D layouts,
backward_override, workspace caching, activation recompute, CUDAgraphs) plus FSDP2/TP+SP multi-GPU validation scripts with a pytest driver.
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, and additionally coversLayerNormMLP.I asked about coordination in #2168 on Jul 18. This PR provides a concrete frozen-only
implementation based on current main; happy to fold this work into #2168 if preferred.
Validation
Everything coverable on H800 (8 GPUs) passes: the 23-test suite (on both the default and
the fused grouped-GEMM paths), the distributed driver
(FSDP2 with both
reshard_after_forwardmodes, TP+SP), and module regressions, all withzero failures. No Blackwell hardware was available locally; a spy-based test provides an
architecture-independent guarantee that non-blockwise layouts are never touched.
On a 16-layer frozen stack (features=4096, tokens=4096, 0.268B params), steady-state and
peak memory drop by 0.25 GiB — matching the theoretical columnwise size — at +3.9% step
time under
torch.no_grad()initialization; with grad-enabled initialization onlybetween-step residency drops (the documented limitation).
Checklist: