-
Notifications
You must be signed in to change notification settings - Fork 536
Fix 2-GPU test_model_load_utils hang; test import and fixture cleanup #2079
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
Merged
Merged
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
3531f55
Fix test_model_load_utils.py hang on 2-gpu
kevalmorabia97 890e0f7
Reorganize test imports to top
kevalmorabia97 7a7a412
Optimize transformers fixture usage
kevalmorabia97 2ed5db0
Address review: guard shared test helper, assert shared fixtures unmo…
kevalmorabia97 c7e696e
Skip flaky test_nested_model_save_restore on Windows
kevalmorabia97 3022924
Fail when a shared fixture directory is deleted outright
kevalmorabia97 687f66c
Address re-review: drop unused helpers, clarify the Windows skip
kevalmorabia97 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,57 @@ | ||
| # SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
| # | ||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||
| # you may not use this file except in compliance with the License. | ||
| # You may obtain a copy of the License at | ||
| # | ||
| # http://www.apache.org/licenses/LICENSE-2.0 | ||
| # | ||
| # Unless required by applicable law or agreed to in writing, software | ||
| # distributed under the License is distributed on an "AS IS" BASIS, | ||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| # See the License for the specific language governing permissions and | ||
| # limitations under the License. | ||
|
|
||
| """Filesystem helpers for tests.""" | ||
|
|
||
| from collections.abc import Iterator | ||
| from contextlib import contextmanager | ||
| from pathlib import Path | ||
|
|
||
|
|
||
| def _manifest(root: Path) -> dict[str, tuple[int, int]]: | ||
| """``relative path -> (size, mtime_ns)`` for every file below ``root``.""" | ||
| return { | ||
| str(p.relative_to(root)): (p.stat().st_size, p.stat().st_mtime_ns) | ||
| for p in root.rglob("*") | ||
| if p.is_file() and not p.is_symlink() | ||
| } | ||
|
|
||
|
|
||
| @contextmanager | ||
| def assert_unmodified_tree(path: Path | str) -> Iterator[Path]: | ||
| """Fail if anything under ``path`` is added, removed, or rewritten inside the ``with``. | ||
|
|
||
| For session/module-scoped model-directory fixtures: a test that writes into a shared | ||
| directory silently changes what every later test sees. Comparing a file manifest on | ||
| teardown catches that. ``chmod``-ing the tree read-only would report at the write rather | ||
| than at teardown, but it only works for an unprivileged user -- root has | ||
| ``CAP_DAC_OVERRIDE`` and writes straight through the permission bits, and the CI | ||
| containers run as root. | ||
| """ | ||
| path = Path(path) | ||
| before = _manifest(path) | ||
| yield path | ||
| if not path.exists(): | ||
| raise AssertionError(f"shared fixture directory {path} was deleted by a test") | ||
| after = _manifest(path) | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
| added = sorted(after.keys() - before.keys()) | ||
| removed = sorted(before.keys() - after.keys()) | ||
| changed = sorted(k for k in before.keys() & after.keys() if before[k] != after[k]) | ||
| if added or removed or changed: | ||
| raise AssertionError( | ||
| f"shared fixture directory {path} was modified by a test " | ||
| f"(added={added}, removed={removed}, changed={changed}); " | ||
| "copy it into the test's own tmp_path instead of writing into the shared tree" | ||
| ) | ||
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
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| # SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
| # | ||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||
| # you may not use this file except in compliance with the License. | ||
| # You may obtain a copy of the License at | ||
| # | ||
| # http://www.apache.org/licenses/LICENSE-2.0 | ||
| # | ||
| # Unless required by applicable law or agreed to in writing, software | ||
| # distributed under the License is distributed on an "AS IS" BASIS, | ||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| # See the License for the specific language governing permissions and | ||
| # limitations under the License. | ||
|
|
||
| """Shared attention-quantization fixtures for the unit and gpu attention tests.""" | ||
|
|
||
| import pytest | ||
|
|
||
| pytest.importorskip("transformers") | ||
|
|
||
| from transformers import LlamaConfig | ||
|
kevalmorabia97 marked this conversation as resolved.
|
||
| from transformers.models.llama.modeling_llama import LlamaAttention | ||
|
|
||
| from modelopt.torch.quantization.plugins.huggingface import _QuantAttention | ||
|
|
||
|
|
||
| def make_quant_attention(hidden_size=128, num_q_heads=4, num_kv_heads=2): | ||
| """A single ``_QuantAttention``-converted Llama attention layer, pinned to the sdpa impl.""" | ||
| config = LlamaConfig( | ||
| hidden_size=hidden_size, | ||
| num_attention_heads=num_q_heads, | ||
| num_key_value_heads=num_kv_heads, | ||
| ) | ||
| quant_attention = _QuantAttention.convert(LlamaAttention(config, layer_idx=0)) | ||
| quant_attention.config._attn_implementation = "sdpa" | ||
| return quant_attention | ||
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,73 @@ | ||
| # SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
| # | ||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||
| # you may not use this file except in compliance with the License. | ||
| # You may obtain a copy of the License at | ||
| # | ||
| # http://www.apache.org/licenses/LICENSE-2.0 | ||
| # | ||
| # Unless required by applicable law or agreed to in writing, software | ||
| # distributed under the License is distributed on an "AS IS" BASIS, | ||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| # See the License for the specific language governing permissions and | ||
| # limitations under the License. | ||
|
|
||
| """Shared helpers for accelerate-offloaded and layerwise-calibration quantization tests.""" | ||
|
|
||
| import copy | ||
|
|
||
| import torch | ||
| from _test_utils.torch.transformers_models import create_tiny_llama_dir | ||
| from accelerate import init_empty_weights, load_checkpoint_and_dispatch | ||
| from transformers import AutoConfig, AutoModelForCausalLM | ||
|
|
||
|
|
||
| def make_tiny_llama_and_inputs(tmp_path, num_hidden_layers=3): | ||
| """Tiny LLaMA checkpoint dir + its config + a GPU token batch sized for its vocab.""" | ||
| tiny_llama_dir = create_tiny_llama_dir(tmp_path, num_hidden_layers=num_hidden_layers) | ||
| config = AutoConfig.from_pretrained(tiny_llama_dir) | ||
| inputs = torch.randint(0, config.vocab_size, (1, 4)).cuda() | ||
| return tiny_llama_dir, config, inputs | ||
|
|
||
|
|
||
| def make_cpu_offloaded_model(tmp_path, num_hidden_layers=3): | ||
| """Tiny LLaMA with layer 0 offloaded to CPU via accelerate. | ||
|
|
||
| Returns ``(model, config, tiny_llama_dir, inputs)``; ``inputs`` is a GPU token batch | ||
| sized for the model's vocab. | ||
| """ | ||
| tiny_llama_dir = create_tiny_llama_dir(tmp_path, num_hidden_layers=num_hidden_layers) | ||
| config = AutoConfig.from_pretrained(tiny_llama_dir) | ||
|
|
||
| with init_empty_weights(): | ||
| model = AutoModelForCausalLM.from_config(config) | ||
|
|
||
| device_map = { | ||
| n: 0 | ||
| for n, m in model.named_modules() | ||
| if "layers" not in n or n.split("layers.")[-1].isdigit() | ||
| } | ||
| device_map["model.layers.0"] = "cpu" | ||
|
|
||
| model = load_checkpoint_and_dispatch(model, tiny_llama_dir, device_map=device_map) | ||
| inputs = torch.randint(0, config.vocab_size, (1, 4)).cuda() | ||
| return model, config, tiny_llama_dir, inputs | ||
|
|
||
|
|
||
| def make_layerwise_cfg(base_cfg): | ||
| """Copy of ``base_cfg`` with ``layerwise=True`` set on its algorithm field.""" | ||
| cfg = copy.deepcopy(base_cfg) | ||
| algo = cfg.get("algorithm", "max") | ||
| if isinstance(algo, str): | ||
| cfg["algorithm"] = {"method": algo, "layerwise": True} | ||
| else: | ||
| algo["layerwise"] = True | ||
| return cfg | ||
|
|
||
|
|
||
| def make_layerwise_checkpoint_cfg(base_cfg, checkpoint_dir): | ||
| """``make_layerwise_cfg`` plus a ``layerwise_checkpoint_dir``.""" | ||
| cfg = make_layerwise_cfg(base_cfg) | ||
| cfg["algorithm"]["layerwise_checkpoint_dir"] = checkpoint_dir | ||
| return cfg |
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
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
| # SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
| # | ||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||
| # you may not use this file except in compliance with the License. | ||
| # You may obtain a copy of the License at | ||
| # | ||
| # http://www.apache.org/licenses/LICENSE-2.0 | ||
| # | ||
| # Unless required by applicable law or agreed to in writing, software | ||
| # distributed under the License is distributed on an "AS IS" BASIS, | ||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| # See the License for the specific language governing permissions and | ||
| # limitations under the License. | ||
|
|
||
| """Shared DFlash test config, used by the unit and gpu speculative-decoding tests.""" | ||
|
|
||
| from copy import deepcopy | ||
|
|
||
| from modelopt.torch.speculative.config import DFLASH_DEFAULT_CFG | ||
|
|
||
| DFLASH_BLOCK_SIZE = 4 | ||
| DFLASH_NUM_DRAFT_LAYERS = 2 | ||
|
|
||
|
|
||
| def get_dflash_config( | ||
| block_size: int = DFLASH_BLOCK_SIZE, | ||
| num_layers: int = DFLASH_NUM_DRAFT_LAYERS, | ||
| offline: bool | None = None, | ||
| ): | ||
| """DFlash config sized for a tiny model: no torch.compile, token 0 as the mask token. | ||
|
|
||
| ``offline`` is only written when set, so callers that don't care keep the default. | ||
| """ | ||
| config = deepcopy(DFLASH_DEFAULT_CFG["config"]) | ||
| config["dflash_block_size"] = block_size | ||
| config["dflash_use_torch_compile"] = False | ||
| config["dflash_mask_token_id"] = 0 # use token 0 as mask for tiny model | ||
| config["dflash_architecture_config"] = {"num_hidden_layers": num_layers} | ||
| if offline is not None: | ||
| config["dflash_offline"] = offline | ||
| return config |
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
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
Oops, something went wrong.
Oops, something went wrong.
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.
Uh oh!
There was an error while loading. Please reload this page.