Skip to content

Commit ac96651

Browse files
WanZzzzzzksivaman
andauthored
Fix memory overheads with FP4 native weights (NVIDIA#2834)
* fix memory overheads Signed-off-by: qiyuw <qiyuw@nvidia.com> * comments Signed-off-by: qiyuw <qiyuw@nvidia.com> * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Signed-off-by: qiyuw <qiyuw@nvidia.com> Co-authored-by: Kirthi Shankar Sivamani <ksivamani@nvidia.com>
1 parent 5abadf4 commit ac96651

1 file changed

Lines changed: 24 additions & 69 deletions

File tree

  • transformer_engine/pytorch/tensor

transformer_engine/pytorch/tensor/utils.py

Lines changed: 24 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -118,46 +118,6 @@ def quantize_master_weights(
118118
else:
119119
use_fsdp_shard_model_weights = True
120120

121-
# Batch convert master_weights to model dtype for NVFP4 (single kernel instead of N kernels)
122-
# Check if there are any NVFP4 weights
123-
has_nvfp4 = any(
124-
isinstance(w._get_quantizer(), NVFP4Quantizer)
125-
for w in model_weights
126-
if hasattr(w, "_get_quantizer")
127-
)
128-
if has_nvfp4 and len(model_weights) > 0:
129-
# Find target dtype from first NVFP4 weight
130-
target_dtype = None
131-
for w in model_weights:
132-
if hasattr(w, "_get_quantizer") and isinstance(w._get_quantizer(), NVFP4Quantizer):
133-
target_dtype = w.dtype
134-
break
135-
136-
if target_dtype is not None:
137-
# Collect non-None master_weights and their indices
138-
non_none_indices = []
139-
non_none_weights = []
140-
sizes = []
141-
for i, mw in enumerate(master_weights):
142-
if mw is not None:
143-
non_none_indices.append(i)
144-
non_none_weights.append(mw.view(-1))
145-
sizes.append(mw.numel())
146-
147-
if len(non_none_weights) > 0 and non_none_weights[0].dtype != target_dtype:
148-
# Concatenate, convert once, then split
149-
concatenated = torch.cat(non_none_weights)
150-
converted = concatenated.to(target_dtype)
151-
split_weights = torch.split(converted, sizes)
152-
153-
# Rebuild master_weights list with converted tensors
154-
converted_master_weights = list(master_weights)
155-
for idx, split_w, orig_mw in zip(
156-
non_none_indices, split_weights, [master_weights[i] for i in non_none_indices]
157-
):
158-
converted_master_weights[idx] = split_w.view(orig_mw.shape)
159-
master_weights = converted_master_weights
160-
161121
for model_weight, master_weight, start_offset, fsdp_shard_model_weight in zip(
162122
model_weights, master_weights, start_offsets, fsdp_shard_model_weights
163123
):
@@ -176,42 +136,37 @@ def quantize_master_weights(
176136
if hasattr(model_weight, "clear_high_precision_init_val"):
177137
model_weight.clear_high_precision_init_val()
178138

139+
if master_weight is not None:
140+
# When not using fp8/fp4_primary_weights, the master_weight (fp32) is first cast to
141+
# bf16/fp16, and then cast to fp8 during forward. Although it's not necessary when
142+
# fp8/fp4_primary_weights is enabled, we still keep this logic to keep numerical
143+
# consistency. So here we cast the master_weight to model_weight.dtype.
144+
master_weight = master_weight.to(model_weight.dtype)
145+
179146
quantizer = model_weight._get_quantizer()
180147

181148
if isinstance(quantizer, NVFP4Quantizer):
182-
# NVFP4: master_weight dtype conversion already done above
183149
nvfp4_params.append(
184150
(model_weight, master_weight, start_offset, fsdp_shard_model_weight)
185151
)
152+
elif isinstance(quantizer, Float8Quantizer):
153+
delayed_scaling_params.append(
154+
(model_weight, master_weight, start_offset, fsdp_shard_model_weight)
155+
)
156+
elif isinstance(quantizer, Float8CurrentScalingQuantizer):
157+
current_scaling_params.append(
158+
(model_weight, master_weight, start_offset, fsdp_shard_model_weight)
159+
)
160+
elif isinstance(quantizer, Float8BlockQuantizer):
161+
blockwise_scaling_params.append(
162+
(model_weight, master_weight, start_offset, fsdp_shard_model_weight)
163+
)
164+
elif isinstance(quantizer, MXFP8Quantizer):
165+
mxfp8_scaling_params.append(
166+
(model_weight, master_weight, start_offset, fsdp_shard_model_weight)
167+
)
186168
else:
187-
# FP8: convert master_weight to model dtype
188-
if master_weight is not None:
189-
# When not using fp8_primary_weights, the master_weight (fp32) is first cast to
190-
# bf16/fp16, and then cast to fp8 during forward. Although it's not necessary when
191-
# fp8_primary_weights is enabled, we still keep this logic to keep numerical
192-
# consistency. So here we cast the master_weight to model_weight.dtype.
193-
master_weight = master_weight.to(model_weight.dtype)
194-
195-
if isinstance(quantizer, Float8Quantizer):
196-
delayed_scaling_params.append(
197-
(model_weight, master_weight, start_offset, fsdp_shard_model_weight)
198-
)
199-
elif isinstance(quantizer, Float8CurrentScalingQuantizer):
200-
current_scaling_params.append(
201-
(model_weight, master_weight, start_offset, fsdp_shard_model_weight)
202-
)
203-
elif isinstance(quantizer, Float8BlockQuantizer):
204-
blockwise_scaling_params.append(
205-
(model_weight, master_weight, start_offset, fsdp_shard_model_weight)
206-
)
207-
elif isinstance(quantizer, MXFP8Quantizer):
208-
mxfp8_scaling_params.append(
209-
(model_weight, master_weight, start_offset, fsdp_shard_model_weight)
210-
)
211-
else:
212-
raise ValueError(
213-
f"quantize_master_weights for {type(quantizer)} is not supported yet"
214-
)
169+
raise ValueError(f"quantize_master_weights for {type(quantizer)} is not supported yet")
215170

216171
extra_args = [group, use_fsdp_shard_model_weights, manual_post_all_gather_processing]
217172
if len(delayed_scaling_params) > 0:

0 commit comments

Comments
 (0)