Skip to content

Commit f6f1133

Browse files
committed
[test_all] Better docs
1 parent b5d4b5b commit f6f1133

File tree

5 files changed

+120
-10
lines changed

5 files changed

+120
-10
lines changed
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
<!--Copyright 2025 The HuggingFace Team. All rights reserved.
2+
3+
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
4+
the License. You may obtain a copy of the License at
5+
6+
http://www.apache.org/licenses/LICENSE-2.0
7+
8+
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
9+
an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
10+
specific language governing permissions and limitations under the License.
11+
12+
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
13+
rendered properly in your Markdown viewer.
14+
15+
-->
16+
17+
# Import Utilities
18+
19+
This page goes through the transformers utilities to enable lazy and fast object import.
20+
While we strive for minimal dependencies, some models have specific dependencies requirements that cannot be
21+
worked around. We don't want for all users of `transformers` to have to install those dependencies to use other models,
22+
we therefore mark those as soft dependencies rather than hard dependencies.
23+
24+
The transformers toolkit is not made to error-out on import of a model that has a specific dependency; instead, an
25+
object for which you are lacking a dependency will error-out when calling any method on it. As an example, if
26+
`torchvision` isn't installed, the fast image processors will not be available.
27+
28+
This object is still importable:
29+
30+
```python
31+
>>> from transformers import DetrImageProcessorFast
32+
>>> print(DetrImageProcessorFast)
33+
<class 'DetrImageProcessorFast'>
34+
```
35+
36+
However, no method can be called on that object:
37+
38+
```python
39+
>>> DetrImageProcessorFast.from_pretrained()
40+
ImportError:
41+
DetrImageProcessorFast requires the Torchvision library but it was not found in your environment. Checkout the instructions on the
42+
installation page: https://pytorch.org/get-started/locally/ and follow the ones that match your environment.
43+
Please note that you may need to restart your runtime after installation.
44+
```
45+
46+
Let's see how to specify specific object dependencies.
47+
48+
## Specifying Object Dependencies
49+
50+
### Filename-based
51+
52+
All objects under a given filename have an automatic dependency to the tool linked to the filename
53+
54+
**TensorFlow**: All files starting with `modeling_tf_` have an automatic TensorFlow dependency.
55+
56+
**Flax**: All files starting with `modeling_flax_` have an automatic Flax dependency
57+
58+
**PyTorch**: All files starting with `modeling_` and not valid with the above (TensorFlow and Flax) have an automatic
59+
PyTorch dependency
60+
61+
**Tokenizers**: All files starting with `tokenization_` and ending with `_fast` have an automatic `tokenizers` dependency
62+
63+
**Vision**: All files starting with `image_processing_` have an automatic dependency to the `vision` dependency group;
64+
at the time of writing, this only contains the `pillow` dependency.
65+
66+
**Vision + Torch + Torchvision**: All files starting with `image_processing_` and ending with `_fast` have an automatic
67+
dependency to `vision`, `torch`, and `torchvision`.
68+
69+
All of these automatic dependencies are added on top of the explicit dependencies that are detailed below.
70+
71+
### Explicit Object Dependencies
72+
73+
We add a method called `requires` that is used to explicitly specify the dependencies of a given object. As an
74+
example, the `Trainer` class has two hard dependencies: `torch` and `accelerate`. Here is how we specify these
75+
required dependencies:
76+
77+
```python
78+
from .utils.import_utils import requires
79+
80+
@requires(backends=("torch", "accelerate"))
81+
class Trainer:
82+
...
83+
```
84+
85+
Backends that can be added here are all the backends that are available in the `import_utils.py` module.
86+
87+
## Methods
88+
89+
[[autodoc]] import_utils.define_import_structure
90+
91+
[[autodoc]] import_utils.requires

src/transformers/commands/chat.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -491,6 +491,7 @@ def run(self):
491491
user = args.user
492492

493493
model, tokenizer = load_model_and_tokenizer(args)
494+
print(model.device)
494495
generation_streamer = TextIteratorStreamer(tokenizer, skip_special_tokens=True, skip_prompt=True)
495496

496497
pad_token_id, eos_token_ids = parse_eos_tokens(tokenizer, args.eos_tokens, args.eos_token_ids)

src/transformers/trainer.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,12 @@ def safe_globals():
314314
FSDP_MODEL_NAME = "pytorch_model_fsdp"
315315

316316

317-
@requires(backends=("accelerate",))
317+
@requires(
318+
backends=(
319+
"torch",
320+
"accelerate",
321+
)
322+
)
318323
class Trainer:
319324
"""
320325
Trainer is a simple but feature-complete training and eval loop for PyTorch, optimized for 🤗 Transformers.

src/transformers/utils/import_utils.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1884,6 +1884,22 @@ def __init__(
18841884

18851885
for backends, module in import_structure.items():
18861886
missing_backends = []
1887+
1888+
# This ensures that if a module is importable, then all other keys of the module are importable.
1889+
# As an example, in module.keys() we might have the following:
1890+
#
1891+
# dict_keys(['models.nllb_moe.configuration_nllb_moe', 'models.sew_d.configuration_sew_d'])
1892+
#
1893+
# with this, we don't only want to be able to import these explicitely, we want to be able to import
1894+
# every intermediate module as well. Therefore, this is what is returned:
1895+
#
1896+
# {
1897+
# 'models.nllb_moe.configuration_nllb_moe',
1898+
# 'models.sew_d.configuration_sew_d',
1899+
# 'models',
1900+
# 'models.sew_d', 'models.nllb_moe'
1901+
# }
1902+
18871903
module_keys = set(
18881904
chain(*[[k.rsplit(".", i)[0] for i in range(k.count(".") + 1)] for k in list(module.keys())])
18891905
)

utils/tests_fetcher.py

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -741,10 +741,13 @@ def get_module_dependencies(module_fname: str, cache: Dict[str, List[str]] = Non
741741
# Add imports via `define_import_structure` after the #35167 as we remove explicit import in `__init__.py`
742742
from transformers.utils.import_utils import define_import_structure
743743

744-
new_imported_modules_2 = define_import_structure(PATH_TO_REPO / module)
744+
new_imported_modules_from_import_structure = define_import_structure(PATH_TO_REPO / module)
745745

746-
for mapping in new_imported_modules_2.values():
746+
for mapping in new_imported_modules_from_import_structure.values():
747747
for _module, _imports in mapping.items():
748+
# Import Structure returns _module keys as import paths rather than local paths
749+
# We replace with os.path.sep so that it's Windows-compatible
750+
_module = _module.replace(".", os.path.sep)
748751
_module = module.replace("__init__.py", f"{_module}.py")
749752
new_imported_modules.append((_module, list(_imports)))
750753

@@ -921,11 +924,7 @@ def create_reverse_dependency_map() -> Dict[str, List[str]]:
921924
if d.endswith("__init__.py"):
922925
continue
923926
if d not in direct_deps:
924-
module_prefix = d.rsplit(".", 1)[0].replace(".", "/")
925-
d = module_prefix + ".py"
926-
927-
if d not in direct_deps:
928-
raise ValueError(f"KeyError:{d}. From {m}")
927+
raise ValueError(f"KeyError:{d}. From {m}")
929928
new_deps = set(direct_deps[d]) - set(direct_deps[m])
930929
if len(new_deps) > 0:
931930
direct_deps[m].extend(list(new_deps))
@@ -1054,8 +1053,6 @@ def infer_tests_to_run(
10541053
print("\n### test_all is TRUE, FETCHING ALL FILES###\n")
10551054
print(f"\n### MODIFIED FILES ###\n{_print_list(modified_files)}")
10561055

1057-
# Create the map that will give us all impacted modules.
1058-
10591056
# Remove duplicates
10601057
impacted_files = sorted(set(impacted_files))
10611058
print(f"\n### IMPACTED FILES ###\n{_print_list(impacted_files)}")

0 commit comments

Comments
 (0)