Automatically omit unused columnwise primary weights for backward overrides - #3468
Automatically omit unused columnwise primary weights for backward overrides#3468xiuhu17 wants to merge 4 commits into
Conversation
Backward overrides run dgrad with high-precision or dequantized weights, so primary quantized parameters do not need a columnwise representation. Initialize only rowwise storage for these modes while preserving bidirectional storage for quantized backward. Add coverage for MXFP8 and 1D NVFP4 before and after backward. Signed-off-by: xiuhu17 <zhihao.wang@perplexity.ai>
Signed-off-by: xiuhu17 <zhihao.wang@perplexity.ai>
Greptile SummaryThis PR changes quantized primary-weight allocation and adds guards and tests for rowwise-only weights.
Confidence Score: 4/5The PR is not safe to merge because it makes rowwise-only storage mandatory for override recipes, breaking supported runtime switching and storage-dependent writeback without an opt-out. Override recipes now always omit columnwise primary-weight storage. Models that previously retained both directions by default can consequently fail either when switching to quantized backward or when a master-weight writeback path accesses the missing columnwise buffers. Files Needing Attention: transformer_engine/pytorch/module/base.py, transformer_engine/pytorch/ops/basic/basic_linear.py, transformer_engine/pytorch/ops/basic/grouped_linear.py, transformer_engine/pytorch/quantization.py Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[quantized_model_init with backward override] --> B[Initialize primary weight]
B --> C[Allocate rowwise storage only]
C --> D{Later consumer}
D -->|Override backward| E[Forward and backward proceed]
D -->|Quantized backward| F[Runtime guard raises]
D -->|Master-weight writeback| G[Columnwise storage accessed]
G --> H[Missing-storage failure]
Reviews (2): Last reviewed commit: "Infer primary weight storage from backwa..." | Re-trigger Greptile |
timmoon10
left a comment
There was a problem hiding this comment.
This is a nice memory optimization. I don't trust users to configure this correctly, so I'd prefer if we enabled it automatically.
| quantizer.set_usage( | ||
| rowwise=True, | ||
| columnwise=( | ||
| torch.is_grad_enabled() and not self.omit_columnwise_primary_weight_storage | ||
| ), | ||
| ) |
There was a problem hiding this comment.
Couldn't we deduce this case automatically?
| quantizer.set_usage( | |
| rowwise=True, | |
| columnwise=( | |
| torch.is_grad_enabled() and not self.omit_columnwise_primary_weight_storage | |
| ), | |
| ) | |
| columnwise_usage = torch.is_grad_enabled() | |
| if columnwise_usage: | |
| recipe = FP8GlobalStateManager.get_fp8_recipe() | |
| if recipe.backward_override in ("high_precision", "dequantized"): | |
| columnwise_usage = False | |
| quantizer.set_usage(rowwise=True, columnwise=columnwise_usage) |
| enabled: bool = True, | ||
| recipe: Optional[Recipe] = None, | ||
| preserve_high_precision_init_val: bool = False, | ||
| omit_columnwise_primary_weight_storage: bool = False, |
There was a problem hiding this comment.
This option is esoteric and low-level, enough that I don't think it's reasonable to expect users to set it correctly. Besides, we can deduce this automatically when constructing the primary weights.
| omit_columnwise_primary_weight_storage: bool = False, |
There was a problem hiding this comment.
Similar changes should be made in the op fuser API:
TransformerEngine/transformer_engine/pytorch/ops/basic/basic_linear.py
Lines 331 to 334 in d1e9c33
| self._primary_weights_rowwise_only = ( | ||
| FP8GlobalStateManager.get_fp8_recipe().backward_override | ||
| in ("high_precision", "dequantized") | ||
| ) | ||
| quantizer.set_usage( | ||
| rowwise=True, | ||
| columnwise=torch.is_grad_enabled() and not self._primary_weights_rowwise_only, |
There was a problem hiding this comment.
Override Removes Required Storage
Initializing a quantized model with either backward override now always disables columnwise primary-weight storage. Previously, omitting this storage was an explicit opt-in, so callers could initialize under an override while retaining both directions. Existing callers that later switch to quantized backward now hit the runtime error at base.py:2072-2077. Distributed master-weight writeback can also access _columnwise_scale_inv and _columnwise_data unconditionally. Since the public storage option was removed, these callers cannot preserve the previous bidirectional layout. Please retain an explicit opt-in instead of deriving the storage layout solely from the recipe. The same automatic policy is applied in basic_linear.py:331-337 and grouped_linear.py:466-473.
Description
Quantized primary weights normally allocate rowwise and columnwise representations when autograd is enabled. With
backward_override="high_precision"or"dequantized", the backward computation does not consume the columnwise primary weight. Keeping that representation wastes persistent memory, especially for a large frozen LoRA base.Primary-weight initialization now derives its storage usage from the recipe automatically:
No storage-policy argument is required. With an override recipe, primary weights are initialized rowwise-only. Without an override, autograd-enabled initialization retains both directions. The same allocation policy applies to the module API and the op fuser's
BasicLinearandGroupedLinear.The implementation records the inferred policy locally to reject an incompatible switch to default quantized backward before it requests missing columnwise storage. Weights initialized with both directions can still enter and leave override mode. There is no new global storage-policy state or public opt-in.
For block-scaled formats, omitting one persistent direction saves approximately 1.03 bytes/parameter for MXFP8 and 0.56 bytes/parameter for 1D NVFP4 before padding. The NVFP4 tests use one-dimensional scaling.
Compatibility
This changes storage automatically for override recipes, including trainable primary weights. External optimizers or distributed writeback paths that require both directions must initialize with a non-override recipe or add row-only support. In particular, current Megatron distributed MXFP8 master-weight writeback still assumes columnwise data and scales exist; this PR does not change that integration. Frozen LoRA bases excluded from optimizer parameter groups do not enter that writeback path.
The op fuser GroupedLinear change covers allocation and incompatible-recipe checking; it does not add grouped-op backward-override compute support.
Tests and validation
git diff --checkpassed.