Repository navigation
CI follow-up: cache source-built wheels and extensions, bump CI containers, trim slow GPU tests #2836
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
CI follow-up: cache source-built wheels and extensions, bump CI containers, trim slow GPU tests #2836
Changes from all commits
b7b7657
e5d149e
4aedd5f
95b4913
7e8cfd1
8c5fadc
613e40e
ae6f163
e0dafde
27235c7
db68967
4ffb17e
a04bd58
878ffc5
6253454
50615b3
635c761
f181890
9d3d714
9d9ab38
7fc0595
528c39e
1203fcd
0ef079a
f222d46
f086740
996f48e
f1311ea
39f45bd
8f58d40
f25ff98
165cdd6
378b5b6
49ab19f
3ae2c85
d704983
6bc0119
cb1cac9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| name: Save extensions | ||
| description: Save the JIT-compiled extensions restored by ./.github/actions/cache-extensions. Run it with `always()` so a failing or timed-out job still | ||
| populates the cache (actions/cache itself only saves when the job succeeds). | ||
|
|
||
| inputs: | ||
| cache-key: | ||
| description: The `cache-key` output of ./.github/actions/cache-extensions. | ||
| required: true | ||
|
|
||
| runs: | ||
| using: composite | ||
| steps: | ||
| # A job cancelled before building anything must not claim the key with an empty cache: | ||
| # later runs would restore it as an exact hit and never save again. | ||
| - id: built | ||
| shell: bash | ||
| run: find /root/.cache/torch_extensions -name '*.so' 2>/dev/null | grep -q . && echo "any=true" >> "$GITHUB_OUTPUT" || true | ||
| - if: steps.built.outputs.any == 'true' | ||
| uses: actions/cache/save@v6 | ||
| with: | ||
| path: /root/.cache/torch_extensions | ||
| key: ${{ inputs.cache-key }} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -46,6 +46,24 @@ def _cast_per_block_scale_to_fp8( | |
| return per_block_scale.clamp(min=2**-9, max=E4M3_MAX).to(torch.float8_e4m3fn) | ||
|
|
||
|
|
||
| def cutlass_fp4_scale_to_modelopt_fp4_scale( | ||
| cutlass_scale: torch.Tensor, weight_shape: tuple[int, int] | ||
| ) -> torch.Tensor: | ||
| """Undo the cuBLAS/cutlass tiled swizzle of NVFP4 block scales (TensorRT-LLM ``fp4_quantize``). | ||
|
|
||
| The swizzled scale holds 128x4 tiles, each stored as ``[row % 32, row // 32, col]``; this is the | ||
| inverse of the rearrangement in ``swizzle_nvfp4_scales``. Returns the ``[m, n // 16]`` E4M3 | ||
| scales of an ``[m, n]`` weight with block size 16. | ||
| """ | ||
| m, n = weight_shape | ||
| n //= 16 | ||
| row_blocks, col_blocks = -(-m // 128), -(-n // 4) | ||
| tiles = cutlass_scale.reshape(row_blocks, col_blocks, 32, 4, 4) | ||
| padded = tiles.permute(0, 3, 2, 1, 4).reshape(row_blocks * 128, col_blocks * 4) | ||
| # contiguous(): the slice is a strided view, and fp4_dequantize indexes the scale flatly. | ||
| return padded[:m, :n].contiguous().view(torch.float8_e4m3fn) | ||
|
|
||
|
|
||
| class NVFP4QTensor(BaseQuantizedTensor): | ||
| """Implements the NVFP4 quantization on tensors for more efficient storage or computation. | ||
|
|
||
|
|
@@ -294,11 +312,6 @@ def quantize( | |
| try: | ||
| import tensorrt_llm # noqa: F401 | ||
|
|
||
| # Make sure this utils is available for dequantize | ||
| from tensorrt_llm._torch.auto_deploy.utils.quantization_utils import ( | ||
| cutlass_fp4_scale_to_modelopt_fp4_scale, # noqa: F401 | ||
| ) | ||
|
Comment on lines
295
to
-300
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we check if there is some util function/torch ops from trtllm? since we already import it anyway. Their kernel implementation will be much faster to do the conversion.
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Checked: |
||
|
|
||
| packed_weight, weights_scaling_factor = torch.ops.trtllm.fp4_quantize( | ||
| input, 1.0 / weights_scaling_factor_2, block_size, False | ||
| ) | ||
|
|
@@ -364,18 +377,9 @@ def _unpack_tensor(input: torch.Tensor): | |
| # Get scales from kwargs | ||
| if kwarg["scale"].dtype == torch.uint8 and kwarg["scale"].ndim == 1: | ||
| # If quantization is done by trtllm, convert cutlass fp4 scale to modelopt fp4 scale | ||
| try: | ||
| from tensorrt_llm._torch.auto_deploy.utils.quantization_utils import ( | ||
| cutlass_fp4_scale_to_modelopt_fp4_scale, | ||
| ) | ||
|
|
||
| kwarg["scale"] = cutlass_fp4_scale_to_modelopt_fp4_scale( | ||
| kwarg["scale"], self.metadata["shape"][-2:] | ||
| ) | ||
| except ImportError as e: | ||
| raise ImportError( | ||
| "This tensor is quantized by trtllm, but tensorrt_llm cannot be imported." | ||
| ) from e | ||
| kwarg["scale"] = cutlass_fp4_scale_to_modelopt_fp4_scale( | ||
| kwarg["scale"], self.metadata["shape"][-2:] | ||
| ) | ||
|
|
||
| if fast: | ||
| from modelopt.torch.kernels.quantization.gemm.fp4_kernel import fp4_dequantize | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -828,20 +828,37 @@ def _init_mp_dtypes(self) -> None: | |
|
|
||
| @contextmanager | ||
| def _disable_fsdp_unshard_reshard(layer): | ||
| """Disable FSDP2 unshard/reshard if *layer* is FSDP-wrapped.""" | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @sugunav14 could you help review this part? |
||
| if isinstance(layer, FSDPModule): | ||
| _pg_cls = torch.distributed.fsdp._fully_shard._fsdp_param_group.FSDPParamGroup | ||
| orig_unshard = _pg_cls.unshard | ||
| orig_reshard = _pg_cls.reshard | ||
| _pg_cls.unshard = lambda self, async_op=False: None | ||
| _pg_cls.reshard = lambda self: None | ||
| try: | ||
| yield | ||
| finally: | ||
| _pg_cls.unshard = orig_unshard | ||
| _pg_cls.reshard = orig_reshard | ||
| else: | ||
| """Make the FSDP2 param groups inside *layer* skip unshard/reshard (already gathered). | ||
|
|
||
| Patched per group instance, not on ``FSDPParamGroup``: the rest of the model still runs forward | ||
| (e.g. while collecting the next layer's inputs) and must unshard as usual. | ||
| """ | ||
| if not isinstance(layer, FSDPModule): # nothing was gathered for its FSDP submodules | ||
| yield | ||
| return | ||
| groups = { | ||
| id(group): group # ``fully_shard([a, b])`` gives several modules one group | ||
| for module in layer.modules() | ||
| if isinstance(module, FSDPModule) | ||
| and (group := fully_shard.state(module)._fsdp_param_group) is not None | ||
| }.values() | ||
| # Contexts nest (``persistent_materialization(writeback=False)`` enters this twice), so restore | ||
| # whatever instance attributes were there before instead of deleting them. | ||
| saved = [ | ||
| (group, {k: group.__dict__.get(k) for k in ("unshard", "reshard")}) for group in groups | ||
| ] | ||
| for group in groups: | ||
| group.unshard = lambda async_op=False: None | ||
| group.reshard = lambda: None | ||
|
kevalmorabia97 marked this conversation as resolved.
Resolved
|
||
| try: | ||
| yield | ||
| finally: | ||
| for group, prior in saved: | ||
| for name, value in prior.items(): | ||
| if value is None: | ||
| del group.__dict__[name] | ||
| else: | ||
| setattr(group, name, value) | ||
|
|
||
|
|
||
| def build_param_index(model): | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.