chore: import upstream snapshot with attribution
Secret Leaks / trufflehog (push) Failing after 1s
Build documentation / build (push) Failing after 1s
Build documentation / build_other_lang (push) Failing after 0s
CodeQL Security Analysis / CodeQL Analysis (push) Failing after 0s
PR CI / pr-ci (push) Failing after 1s
Slow tests on important models (on Push - A10) / Get all modified files (push) Failing after 1s
Slow tests on important models (on Push - A10) / Model CI (push) Has been skipped
Self-hosted runner (benchmark) / Benchmark (aws-g5-4xlarge-cache) (push) Has been cancelled
New model PR merged notification / Notify new model (push) Has been cancelled
Update Transformers metadata / build_and_package (push) Has been cancelled
Secret Leaks / trufflehog (push) Failing after 1s
Build documentation / build (push) Failing after 1s
Build documentation / build_other_lang (push) Failing after 0s
CodeQL Security Analysis / CodeQL Analysis (push) Failing after 0s
PR CI / pr-ci (push) Failing after 1s
Slow tests on important models (on Push - A10) / Get all modified files (push) Failing after 1s
Slow tests on important models (on Push - A10) / Model CI (push) Has been skipped
Self-hosted runner (benchmark) / Benchmark (aws-g5-4xlarge-cache) (push) Has been cancelled
New model PR merged notification / Notify new model (push) Has been cancelled
Update Transformers metadata / build_and_package (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,14 @@
|
||||
# docstyle-ignore
|
||||
INSTALL_CONTENT = """
|
||||
# Transformers installation
|
||||
! pip install transformers datasets evaluate accelerate
|
||||
# To install from source instead of the last release, comment the command above and uncomment the following one.
|
||||
# ! pip install git+https://github.com/huggingface/transformers.git
|
||||
"""
|
||||
|
||||
notebook_first_cells = [{"type": "code", "content": INSTALL_CONTENT}]
|
||||
black_avoid_patterns = {
|
||||
"{processor_class}": "FakeProcessorClass",
|
||||
"{model_class}": "FakeModelClass",
|
||||
"{object_class}": "FakeObjectClass",
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
# Optimizing inference
|
||||
|
||||
perf_infer_gpu_many: perf_infer_gpu_one
|
||||
perf_train_cpu_many: perf_train_cpu
|
||||
transformers_agents: agents
|
||||
quantization: quantization/overview
|
||||
serving: serve-cli/serving
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,123 @@
|
||||
<!--Copyright 2024 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Accelerate
|
||||
|
||||
[Accelerate](https://hf.co/docs/accelerate/index) provides a unified interface for distributed training backends like [FSDP](https://docs.pytorch.org/tutorials/intermediate/FSDP_tutorial.html) or [DeepSpeed](https://www.deepspeed.ai/). It detects your environment (number of GPUs, distributed backend, mixed precision, etc.) and automatically configures training, whether you're on 1 GPU with DDP or 8 GPUs with FSDP.
|
||||
|
||||
Accelerate wraps the model in the appropriate distributed wrapper, moves it to the correct device, and creates a compatible optimizer. During training, Accelerate uses its own [`~accelerate.Accelerator.backward`] method to handle gradient scaling for mixed precision. [`Trainer`] calls the appropriate Accelerate APIs and delegates all distributed mechanics to Accelerate.
|
||||
|
||||
Configure Accelerate for [`Trainer`] with either an Accelerate config file or [`TrainingArguments`].
|
||||
|
||||
## Accelerate config file
|
||||
|
||||
Run the [accelerate config](https://huggingface.co/docs/accelerate/en/package_reference/cli#accelerate-config) command and answer questions about your hardware and training setup. This creates a `default_config.yaml` file in your cache. The example below is for FSDP.
|
||||
|
||||
```yaml
|
||||
compute_environment: LOCAL_MACHINE
|
||||
distributed_type: FSDP
|
||||
fsdp_config:
|
||||
fsdp_version: 2
|
||||
fsdp_reshard_after_forward: true
|
||||
fsdp_cpu_offload: false
|
||||
fsdp_auto_wrap_policy: TRANSFORMER_BASED_WRAP
|
||||
fsdp_cpu_ram_efficient_loading: true
|
||||
fsdp_activation_checkpointing: false
|
||||
fsdp_state_dict_type: SHARDED_STATE_DICT
|
||||
fsdp_transformer_layer_cls_to_wrap: LlamaDecoderLayer
|
||||
mixed_precision: bf16
|
||||
num_machines: 1
|
||||
num_processes: 4
|
||||
```
|
||||
|
||||
Run [accelerate launch](https://huggingface.co/docs/accelerate/en/package_reference/cli#accelerate-launch) with a [`Trainer`]-based script, and Accelerate reads the config file to set up training. The [`~TrainingArguments#fsdp_config`] and [`~TrainingArguments#deepspeed`] args are unnecessary because the Accelerate config file covers the same settings.
|
||||
|
||||
```cli
|
||||
accelerate launch train.py
|
||||
```
|
||||
|
||||
The [`~TrainingArguments#accelerator_config`] accepts settings that don't have dedicated top-level arguments. For example, set `non_blocking=True` together with [`~TrainingArguments.dataloader_pin_memory`] to overlap data transfer with compute for higher GPU throughput.
|
||||
|
||||
```py
|
||||
from transformers import TrainingArguments
|
||||
|
||||
TrainingArguments(
|
||||
...,
|
||||
dataloader_pin_memory=True,
|
||||
accelerator_config={
|
||||
"non_blocking": True,
|
||||
},
|
||||
)
|
||||
```
|
||||
|
||||
## TrainingArguments
|
||||
|
||||
Pass a backend-specific config to [`TrainingArguments`]. The [`~Trainer.create_accelerator_and_postprocess`] method reads the settings and configures training.
|
||||
|
||||
<hfoptions id="backend">
|
||||
<hfoption id="FSDP">
|
||||
|
||||
Pass a JSON config file or dict to [`~TrainingArguments.fsdp_config`]. See [FSDP](./fsdp) for a full guide and config reference.
|
||||
|
||||
```py
|
||||
from transformers import TrainingArguments
|
||||
|
||||
TrainingArguments(
|
||||
...,
|
||||
fsdp=True,
|
||||
fsdp_config="path/to/fsdp.json",
|
||||
)
|
||||
```
|
||||
|
||||
</hfoption>
|
||||
<hfoption id="DeepSpeed">
|
||||
|
||||
Pass a JSON config file or dict to [`~TrainingArguments.deepspeed`]. See [DeepSpeed](./deepspeed) for a full guide and config reference.
|
||||
|
||||
```py
|
||||
from transformers import TrainingArguments
|
||||
|
||||
TrainingArguments(
|
||||
...,
|
||||
deepspeed="path/to/ds_config.json",
|
||||
)
|
||||
```
|
||||
|
||||
</hfoption>
|
||||
<hfoption id="DDP">
|
||||
|
||||
DDP is configured directly through [`TrainingArguments`] fields. See [DDP](./ddp) for details.
|
||||
|
||||
```py
|
||||
from transformers import TrainingArguments
|
||||
|
||||
TrainingArguments(
|
||||
...,
|
||||
ddp_backend="nccl",
|
||||
ddp_find_unused_parameters=False,
|
||||
ddp_bucket_cap_mb=25,
|
||||
ddp_timeout=1800,
|
||||
)
|
||||
```
|
||||
|
||||
</hfoption>
|
||||
</hfoptions>
|
||||
|
||||
## Next steps
|
||||
|
||||
- See [DDP](./ddp) for data-parallel training when your model fits on one GPU.
|
||||
- See [FSDP](./fsdp) for sharding parameters, gradients, and optimizer states across GPUs.
|
||||
- See [DeepSpeed](./deepspeed) for ZeRO optimization and offloading.
|
||||
@@ -0,0 +1,85 @@
|
||||
<!--Copyright 2025 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contains specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Accelerator selection
|
||||
|
||||
You can control which accelerators (CUDA, XPU, MPS, HPU, etc.) PyTorch sees and in what order during distributed training. Prioritize faster devices or limit training to a subset of available hardware. It works with both [DistributedDataParallel](https://pytorch.org/docs/stable/generated/torch.nn.parallel.DistributedDataParallel.html) and [DataParallel](https://pytorch.org/docs/stable/generated/torch.nn.DataParallel.html), and doesn't require Accelerate or the [DeepSpeed integration](./main_classes/deepspeed).
|
||||
|
||||
## Order of accelerators
|
||||
|
||||
Use the hardware-specific environment variable to select accelerators and set their order. Set it on the command line per run, or add it to `~/.bashrc` or another startup config file.
|
||||
|
||||
> [!WARNING]
|
||||
> Avoid exporting environment variables because if you forget how an environment variable was set up, you may silently train on the wrong accelerators. Set the environment variable on the same command line as the training run.
|
||||
|
||||
For example, to select accelerators 0 and 2 out of four:
|
||||
|
||||
<hfoptions id="accelerator-type">
|
||||
<hfoption id="CUDA">
|
||||
|
||||
```cli
|
||||
CUDA_VISIBLE_DEVICES=0,2 torchrun trainer-program.py ...
|
||||
```
|
||||
|
||||
PyTorch sees only GPUs 0 and 2, which are mapped to `cuda:0` and `cuda:1`. To reverse the order (use GPU 2 as `cuda:0` and GPU 0 as `cuda:1`):
|
||||
|
||||
```cli
|
||||
CUDA_VISIBLE_DEVICES=2,0 torchrun trainer-program.py ...
|
||||
```
|
||||
|
||||
To run without any GPUs:
|
||||
|
||||
```cli
|
||||
CUDA_VISIBLE_DEVICES= python trainer-program.py ...
|
||||
```
|
||||
|
||||
Control the order of CUDA devices with `CUDA_DEVICE_ORDER`.
|
||||
|
||||
- Order by PCIe bus ID (matches `nvidia-smi`):
|
||||
|
||||
```cli
|
||||
export CUDA_DEVICE_ORDER=PCI_BUS_ID
|
||||
```
|
||||
|
||||
- Order by compute capability (fastest first):
|
||||
|
||||
```cli
|
||||
export CUDA_DEVICE_ORDER=FASTEST_FIRST
|
||||
```
|
||||
|
||||
</hfoption>
|
||||
<hfoption id="Intel XPU">
|
||||
|
||||
```cli
|
||||
ZE_AFFINITY_MASK=0,2 torchrun trainer-program.py ...
|
||||
```
|
||||
|
||||
PyTorch sees only XPUs 0 and 2, which are mapped to `xpu:0` and `xpu:1`. To reverse the order (use XPU 2 as `xpu:0` and XPU 0 as `xpu:1`):
|
||||
|
||||
```cli
|
||||
ZE_AFFINITY_MASK=2,0 torchrun trainer-program.py ...
|
||||
```
|
||||
|
||||
Control the order of Intel XPUs with:
|
||||
|
||||
```cli
|
||||
export ZE_ENABLE_PCI_ID_DEVICE_ORDER=1
|
||||
```
|
||||
|
||||
For more on device enumeration and sorting on Intel XPU, see the [Level Zero](https://github.com/oneapi-src/level-zero/blob/master/README.md?plain=1#L87) documentation.
|
||||
|
||||
</hfoption>
|
||||
</hfoptions>
|
||||
@@ -0,0 +1,103 @@
|
||||
<!--Copyright 2026 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Add audio processing components
|
||||
|
||||
Audio models require a feature extractor which is accessible behind the [`AutoFeatureExtractor`] entry point.
|
||||
|
||||
> [!NOTE]
|
||||
> For the model and configuration steps, follow the [modular](./modular_transformers) guide first.
|
||||
|
||||
## Feature extractor
|
||||
|
||||
Add a feature extractor when the model consumes raw audio or audio-derived features.
|
||||
|
||||
Create `feature_extraction_<model_name>.py` in the model directory. Inherit from [`SequenceFeatureExtractor`] so the new class gets shared padding, truncation, saving, and loading behavior.
|
||||
|
||||
```py
|
||||
from ...feature_extraction_sequence_utils import SequenceFeatureExtractor
|
||||
|
||||
|
||||
class MyModelFeatureExtractor(SequenceFeatureExtractor):
|
||||
model_input_names = ["input_features", "attention_mask"]
|
||||
|
||||
def __init__(self, feature_size=80, sampling_rate=16000, padding_value=0.0, **kwargs):
|
||||
super().__init__(feature_size=feature_size, sampling_rate=sampling_rate, padding_value=padding_value, **kwargs)
|
||||
|
||||
def __call__(self, raw_speech, sampling_rate=None, **kwargs):
|
||||
if sampling_rate is not None and sampling_rate != self.sampling_rate:
|
||||
raise ValueError(f"`sampling_rate` must be {self.sampling_rate}, but got {sampling_rate}.")
|
||||
|
||||
# Convert raw_speech to model features here.
|
||||
...
|
||||
```
|
||||
|
||||
Keep the constructor small and serializable. Store every value needed to reproduce preprocessing as an instance attribute, and avoid storing runtime-only values such as open files, devices, or decoded audio arrays.
|
||||
|
||||
The `__call__` method must validate the input sampling rate when users pass `sampling_rate`. If the input rate differs from the model's expected rate, raise an error instead of silently resampling.
|
||||
|
||||
Save the feature extractor with the checkpoint by instantiating it in the conversion script and calling [`~FeatureExtractionMixin.save_pretrained`]. Do not manually create or edit preprocessing config files.
|
||||
|
||||
> [!TIP]
|
||||
> See [`Gemma4AudioFeatureExtractor`] for reference.
|
||||
|
||||
## Register the classes
|
||||
|
||||
Expose the new classes from the model package `__init__.py`. Follow the lazy import pattern used by nearby models and guard imports with the same optional dependencies required by the class.
|
||||
|
||||
Map the new class to the model config so [`AutoFeatureExtractor`] can load it. Add an entry to `FEATURE_EXTRACTOR_MAPPING_NAMES` in `src/transformers/models/auto/feature_extraction_auto.py`, following the pattern of nearby entries. Then verify the model type appears there under `FEATURE_EXTRACTOR_MAPPING_NAMES` for [`AutoFeatureExtractor`].
|
||||
|
||||
- `FEATURE_EXTRACTOR_MAPPING_NAMES` for [`AutoFeatureExtractor`]
|
||||
|
||||
## Testing
|
||||
|
||||
Add tests for each audio processing component in the model test directory. Feature extractor tests usually live in `tests/models/<model_name>/test_feature_extraction_<model_name>.py`.
|
||||
|
||||
For feature extractors that inherit from [`SequenceFeatureExtractor`], inherit from [`SequenceFeatureExtractionTestMixin`]. The mixin covers save and load behavior, padding, truncation, tensor conversion, and common feature extractor properties. Provide a tester object with `prepare_feat_extract_dict()` and `prepare_inputs_for_common()` so the mixin can instantiate the feature extractor and build short dummy audio inputs.
|
||||
|
||||
```py
|
||||
from ...test_sequence_feature_extraction_common import SequenceFeatureExtractionTestMixin
|
||||
|
||||
class MyModelFeatureExtractionTest(SequenceFeatureExtractionTestMixin, unittest.TestCase):
|
||||
feature_extraction_class = MyModelFeatureExtractor
|
||||
|
||||
def setUp(self):
|
||||
self.feat_extract_tester = MyModelFeatureExtractionTester(self)
|
||||
```
|
||||
|
||||
Add focused tests for model-specific behavior that the mixin doesn't know about. For audio feature extractors, that usually means checking the feature shape returned by `__call__`, validating that an incorrect `sampling_rate` raises an error, and checking any custom normalization or feature computation.
|
||||
|
||||
If the model also has a [`ProcessorMixin`] that wraps the feature extractor, add `tests/models/<model_name>/test_processing_<model_name>.py` and inherit from [`ProcessorTesterMixin`]. Set `processor_class` and override `_setup_<component>()` class methods for components that can't be constructed without arguments. Use `_setup_test_attributes()` to expose placeholder tokens used by the common processor tests.
|
||||
|
||||
```py
|
||||
from ...test_processing_common import ProcessorTesterMixin
|
||||
|
||||
class MyModelProcessorTest(ProcessorTesterMixin, unittest.TestCase):
|
||||
processor_class = MyModelProcessor
|
||||
|
||||
@classmethod
|
||||
def _setup_feature_extractor(cls):
|
||||
return cls._get_component_class_from_processor("feature_extractor")(sampling_rate=16000)
|
||||
|
||||
@classmethod
|
||||
def _setup_test_attributes(cls, processor):
|
||||
cls.audio_token = getattr(processor, "audio_token", "")
|
||||
```
|
||||
|
||||
## Next steps
|
||||
|
||||
- Read the [Auto-generating docstrings](./auto_docstring) guide to auto-generate consistent docstrings with `@auto_docstring`.
|
||||
- Read the [Feature extractors](./feature_extractors) guide for user-facing preprocessing behavior.
|
||||
@@ -0,0 +1,642 @@
|
||||
<!--Copyright 2024 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Legacy model contribution
|
||||
|
||||
> [!TIP]
|
||||
> Try adding new models with a more [modular](./modular_transformers) approach first. This makes it significantly easier to contribute a model to Transformers!
|
||||
|
||||
Many of the models in Transformers are contributed by developers and researchers. As an open-source first project, we're invested in empowering the community to actively and independently add more models.
|
||||
|
||||
When you add a model to Transformers, you'll learn:
|
||||
|
||||
- more about open-source best practices
|
||||
- about a models architecture
|
||||
- about Transformers' design principles
|
||||
- how to efficiently test large models
|
||||
- how to use Python utilities like [Black](https://black.readthedocs.io/en/stable/) and [Ruff](https://docs.astral.sh/ruff/) to create clean and readable code
|
||||
|
||||
It is a challenging but rewarding process.
|
||||
|
||||
This guide will walk you through adding an example BrandNewLlama PyTorch model to Transformers. Before you begin, it is a good idea to familiarize yourself with the library.
|
||||
|
||||
## Transformers overview
|
||||
|
||||
Transformers is an opinionated library with its own unique philosophy and design choices. These choices help us sustainably scale and maintain Transformers.
|
||||
|
||||
> [!TIP]
|
||||
> Learn more about our design principles on the [Philosophy](./philosophy) doc.
|
||||
|
||||
Some of these design choices are:
|
||||
|
||||
- composition > over-abstraction
|
||||
- duplicate code isn't always bad if it greatly improves readability and accessibility
|
||||
- model files are self-contained and all the necessary model code is found in the `modeling_mymodel.py` file
|
||||
|
||||
These design choices are important *for everyone* interacting with the model. It is easier to read, understand, and modify.
|
||||
|
||||
This section describes how the model and configuration classes interact and the Transformers code style.
|
||||
|
||||
### Model and configuration
|
||||
|
||||
All Transformers' models inherit from a base [`PreTrainedModel`] and [`PreTrainedConfig`] class. The configuration is the models blueprint.
|
||||
|
||||
There is never more than two levels of abstraction for any model to keep the code readable. The example model here, BrandNewLlama, inherits from `BrandNewLlamaPreTrainedModel` and [`PreTrainedModel`]. It is important that a new model only depends on [`PreTrainedModel`] so that it can use the [`~PreTrainedModel.from_pretrained`] and [`~PreTrainedModel.save_pretrained`] methods.
|
||||
|
||||
Other important functions like the forward method are defined in the `modeling.py` file.
|
||||
|
||||
Specific model heads (for example, sequence classification or language modeling) should call the base model in the forward pass rather than inheriting from it to keep abstraction low.
|
||||
|
||||
New models require a configuration, for example `BrandNewLlamaConfig`, that is stored as an attribute of [`PreTrainedModel`].
|
||||
|
||||
```py
|
||||
model = BrandNewLlamaModel.from_pretrained("username/brand_new_llama")
|
||||
model.config
|
||||
```
|
||||
|
||||
[`PreTrainedConfig`] provides the [`~PreTrainedConfig.from_pretrained`] and [`~PreTrainedConfig.save_pretrained`] methods.
|
||||
|
||||
When you use [`PreTrainedModel.save_pretrained`], it automatically calls [`PreTrainedConfig.save_pretrained`] so that both the model and configuration are saved together.
|
||||
|
||||
A model is saved to a `model.safetensors` file and a configuration is saved to a `config.json` file.
|
||||
|
||||
### Code style
|
||||
|
||||
Transformers prefers a clean and readable code over a more abstracted code style. Some of the code style choices include:
|
||||
|
||||
- The code should be accessible to non-English users. Pick descriptive variable names and avoid abbreviations. For example, "activation" is preferred over "act". One letter variables names are highly discouraged unless it's an index in a for loop.
|
||||
|
||||
- Explicit code is preferred - even if it's longer - over shorter code.
|
||||
|
||||
- Avoid subclassing [nn.Sequential](https://pytorch.org/docs/stable/generated/torch.nn.Sequential.html). Subclass [nn.Module](https://pytorch.org/docs/stable/generated/torch.nn.Module.html#torch.nn.Module) instead so the code can be quickly debugged with print statements or breakpoints.
|
||||
|
||||
- Function signatures should be type-annotated. Otherwise, use good variable names so they're more understandable.
|
||||
|
||||
## New model addition issue
|
||||
|
||||
Open a [New model addition](https://github.com/huggingface/transformers/issues/new?assignees=&labels=New+model&template=new-model-addition.yml) issue to add a specific model.
|
||||
|
||||
> [!TIP]
|
||||
> Filter by the [New model](https://github.com/huggingface/transformers/labels/New%20model) label on GitHub to view and add any existing model requests.
|
||||
|
||||
Now is a good time to get familiar with BrandNewLlama. It is helpful to read a models research paper to understand its technical design and implementation. You don't necessarily have to worry too much about the theoretical details. Instead, focus on the practical ones. Use the questions below to guide your reading.
|
||||
|
||||
- What type of model is BrandNewLlama? Is it a encoder, decoder, or encoder-decoder model?
|
||||
- What tasks can BrandNewLlama be used for?
|
||||
- What makes BrandNewLlama different from other models?
|
||||
- What models in Transformers are most similar to BrandNewLlama?
|
||||
- What tokenizer does BrandNewLlama use?
|
||||
|
||||
In addition to learning more about your model, use the tips below to help you add a model faster.
|
||||
|
||||
> [!TIP]
|
||||
> Each contributor has a unique style and workflow for adding models to Transformers. For an example, take a look at how [Gemma](https://github.com/huggingface/transformers/pull/29167) was added.
|
||||
|
||||
- Don't reinvent the wheel! Take your time to explore existing models and tokenizers to see what you can copy and reuse. [Grep](https://www.gnu.org/software/grep/) and [ripgrep](https://github.com/BurntSushi/ripgrep) are great tools for this.
|
||||
- This is more of an engineering than a science challenge. Focus on the more practical (setting up an efficient debugging environment for example) instead of the theorertical aspects of the model.
|
||||
- Don't be shy to ask for help! We are here to support you. 🤗
|
||||
|
||||
## Dev environment
|
||||
|
||||
Click on the **Fork** button on the [Transformers](https://github.com/huggingface/transformers) repository to create your own copy to work on. Clone the repository to your local disk and add the base repository as the remote.
|
||||
|
||||
```bash
|
||||
git clone https://github.com/[your Github handle]/transformers.git
|
||||
cd transformers
|
||||
git remote add upstream https://github.com/huggingface/transformers.git
|
||||
```
|
||||
|
||||
Create a virtual environment and perform an [editable install](./installation#editable-install) of the library with the "dev" or development dependencies.
|
||||
|
||||
```bash
|
||||
python -m venv .env
|
||||
source .env/bin/activate
|
||||
pip install -e ".[dev]"
|
||||
```
|
||||
|
||||
Due to the number of optional dependencies as Transformers grows, this command may fail. In this case, install the "quality" dependencies. Also make sure you have a deep learning framework installed.
|
||||
|
||||
```bash
|
||||
pip install -e ".[quality]"
|
||||
```
|
||||
|
||||
Return to the parent directory and clone and install the original BrandNewLlama repository.
|
||||
|
||||
```bash
|
||||
git clone https://github.com/org_that_created_brand_new_llama_org/brand_new_llama.git
|
||||
cd brand_new_bert
|
||||
pip install -e .
|
||||
```
|
||||
|
||||
Return to your clone of Transformers to begin porting BrandNewLlama.
|
||||
|
||||
```bash
|
||||
cd transformers
|
||||
```
|
||||
|
||||
There are two possible debugging environments for running the original model, a notebook ([Google Colab](https://colab.research.google.com/notebooks/intro.ipynb) or [Jupyter](https://jupyter.org/)) or a local Python script.
|
||||
|
||||
> [!WARNING]
|
||||
> We don't recommend setting up a GPU environment to run the original model because it can be expensive. Instead, work in a CPU environment first to verify the model works in Transformers. Once it does, then you can verify it on a GPU.
|
||||
|
||||
Notebooks are great for executing code cell-by-cell which can help split logical components from one another. It can also accelerate debugging cycles because intermediate results can be stored. You can also share notebooks when working with other contributors.
|
||||
|
||||
The downside is that if you aren't used to them, it may take some time to get used to.
|
||||
|
||||
> [!TIP]
|
||||
> If the model architecture is identical to an existing model, skip ahead to add a [conversion script](#conversion-script), because you can reuse the architecture of the existing model.
|
||||
|
||||
Run the command below to start and complete the questionnaire with some basic information about the new model. This command jumpstarts the process by automatically generating some model code that you'll need to adapt.
|
||||
|
||||
```bash
|
||||
transformers add-new-model-like
|
||||
```
|
||||
|
||||
## Create a pull request
|
||||
|
||||
Before you start adapting the code, create a pull request to track your progress and get feedback from the Transformers team. Title your pull request **[WIP] Add BrandNewLlama** so it's clear that this is a work in progress.
|
||||
|
||||
Create a branch with a descriptive name from your main branch.
|
||||
|
||||
```bash
|
||||
git checkout -b add_brand_new_bert
|
||||
```
|
||||
|
||||
Commit the code, and then fetch and rebase on the main branch.
|
||||
|
||||
```bash
|
||||
git add .
|
||||
git commit
|
||||
git fetch upstream
|
||||
git rebase upstream/main
|
||||
```
|
||||
|
||||
Push any changes to your branch and click on **Compare & pull request** to open a pull request on GitHub. Open the pull request as a *draft* to indicate it's a work in progress.
|
||||
|
||||
```bash
|
||||
git push -u origin a-descriptive-name-for-my-changes
|
||||
```
|
||||
|
||||
Include relevant Hugging Face team members by adding their GitHub handles in the pull request for questions, feedback, comments, and reviews. Direct team members to specific parts of the code you want by clicking on the **Files changed** tab, and then clicking on **+** to the left of the line number to add a comment. When a question or problem is solved, click on **Resolve** to indicate the issue is resolved. This keeps the conversation organized and clean.
|
||||
|
||||
Remember to periodically commit and push your work, and update your work with the current main branch.
|
||||
|
||||
```bash
|
||||
git fetch upstream
|
||||
git merge upstream/main
|
||||
```
|
||||
|
||||
## Original checkpoint
|
||||
|
||||
Take some time to work on the original model implementation first to understand how it works.
|
||||
|
||||
This can be difficult if the original model repository is lacking documentation or if the codebase is complex. But you should use this as your motivation to implement the model in Transformers. Your contribution makes it more accessible and user-friendly to everyone!
|
||||
|
||||
Orient yourself with the original repository by doing the following.
|
||||
|
||||
- Locate the pretrained weights.
|
||||
- Figure out how to the load pretrained weights into the model.
|
||||
- Figure out how to run the tokenizer independently of the model.
|
||||
- Trace one forward pass to understand which classes and functions are required. These are probably the only classes and functions you'll have to implement.
|
||||
- Locate all the important components (model class, model subclasses, self-attention layer, etc.) of the model.
|
||||
- Figure out how to debug the model in the original repository. Add print statements, use interactive debuggers like [ipdb](https://github.com/gotcha/ipdb), or a efficient integrated development environment (IDE) like [PyCharm](https://www.jetbrains.com/pycharm/).
|
||||
|
||||
The last point is especially important because you'll need a thorough understanding of what's happening inside the original model before you can reimplement it in Transformers. Feel free to open issues and pull requests in the original repository if you encounter any issues.
|
||||
|
||||
A good first step is to load a *small* pretrained checkpoint and try to reproduce a single forward pass with an example integer vector of inputs. For example, in pseudocode, this could look like the following.
|
||||
|
||||
```py
|
||||
model = BrandNewLlamaModel.load_pretrained_checkpoint("/path/to/checkpoint/")
|
||||
input_ids = [0, 4, 5, 2, 3, 7, 9] # vector of input ids
|
||||
original_output = model.generate(input_ids)
|
||||
```
|
||||
|
||||
### Debugging
|
||||
|
||||
If you run into issues, you'll need to choose one of the following debugging strategies depending on the original models codebase.
|
||||
|
||||
<hfoptions id="debug-strategy">
|
||||
<hfoption id="sub-components">
|
||||
|
||||
This strategy relies on breaking the original model into smaller sub-components, such as when the code can be easily run in eager mode. While more difficult, there are some advantages to this approach.
|
||||
|
||||
1. It is easier later to compare the original model to your implementation. You can automatically verify that each individual component matches its corresponding component in the Transformers' implementation. This is better than relying on a visual comparison based on print statements.
|
||||
2. It is easier to port individual components instead of the entire model.
|
||||
3. It is easier for understanding how a model works by breaking it up into smaller parts.
|
||||
4. It is easier to prevent regressions at a later stage when you change your code thanks to component-by-component tests.
|
||||
|
||||
> [!TIP]
|
||||
> Refer to the ELECTRA [integration checks](https://gist.github.com/LysandreJik/db4c948f6b4483960de5cbac598ad4ed) for a good example of how to decompose a model into smaller components.
|
||||
|
||||
</hfoption>
|
||||
<hfoption id="model and tokenizer">
|
||||
|
||||
This strategy is viable when the original codebase is too complex, only allows intermediate components to be run in compiled mode, or if it's too time-consuming (maybe even impossible) to separate the model into smaller sub-components.
|
||||
|
||||
For example, the MeshTensorFlow implementation of [T5](https://github.com/tensorflow/mesh/tree/master/mesh_tensorflow) is too complex and doesn't offer a simple way to decompose the model into its sub-components. In this situation, you'll have to rely on verifying print statements.
|
||||
|
||||
</hfoption>
|
||||
</hfoptions>
|
||||
|
||||
Whichever strategy you choose, it is recommended to debug the initial layers first and the final layers last. Retrieve the output, either with print statements or sub-component functions, of the following layers in this order.
|
||||
|
||||
1. input ids passed to the model
|
||||
2. word embeddings
|
||||
3. input of the first Transformer layer
|
||||
4. output of the first Transformer layer
|
||||
5. output of the following n-1 Transformer layers
|
||||
6. output of the whole model
|
||||
|
||||
The input ids should just be an array of integers like `input_ids = [0, 4, 4, 3, 2, 4, 1, 7, 19]`.
|
||||
|
||||
Layer outputs often consist of multi-dimensional float arrays.
|
||||
|
||||
```py
|
||||
[[
|
||||
[-0.1465, -0.6501, 0.1993, ..., 0.1451, 0.3430, 0.6024],
|
||||
[-0.4417, -0.5920, 0.3450, ..., -0.3062, 0.6182, 0.7132],
|
||||
[-0.5009, -0.7122, 0.4548, ..., -0.3662, 0.6091, 0.7648],
|
||||
...,
|
||||
[-0.5613, -0.6332, 0.4324, ..., -0.3792, 0.7372, 0.9288],
|
||||
[-0.5416, -0.6345, 0.4180, ..., -0.3564, 0.6992, 0.9191],
|
||||
[-0.5334, -0.6403, 0.4271, ..., -0.3339, 0.6533, 0.8694]]],
|
||||
```
|
||||
|
||||
Every Transformers model output should have a precision or error tolerance of *1e-3*. This accounts for any output differences that arise from using a different library framework. Compare the intermediate outputs of the original model with the Transformers implementation to ensure they're nearly identical. Having an *efficient* debugging environment is crucial for this step.
|
||||
|
||||
Here are some tips for an efficient debugging environment.
|
||||
|
||||
- To debug intermediate results, it depends on the machine learning framework the original model repository is using. For PyTorch, you should write a script to decompose the original model into smaller sub-components to retrieve the intermediate values.
|
||||
|
||||
- It is faster to debug with a smaller pretrained checkpoint versus a larger checkpoint where the forward pass takes more than 10 seconds. If only large checkpoints are available, create a dummy model with randomly initialized weights and save those weights to compare against the Transformers implementation.
|
||||
|
||||
- Find the easiest way to call the model's forward pass. Ideally, this function (may be called `predict`, `evaluate`, `forward`, or `__call__`) should only call the forward pass *once*. It is more difficult to debug a function that calls the forward pass multiple times.
|
||||
|
||||
- Separate tokenization from the forward pass. Locate where a string input is changed to input ids in the forward pass and start here. You may need to create a small script or modify the original code to directly input the input ids instead of an input string.
|
||||
|
||||
- Ensure the model is *not* in training mode. This can produce random outputs due to multiple dropout layers in a model. The forward pass in your debugging environment should be *deterministic* so that the dropout layers aren't used.
|
||||
|
||||
Once you're able to run the original checkpoint, you're ready to start adapting the model code for Transformers.
|
||||
|
||||
## Adapt the model code
|
||||
|
||||
The `transformers add-new-model-like` command should have generated a model and configuration file.
|
||||
|
||||
- `src/transformers/models/brand_new_llama/modeling_brand_new_llama.py`
|
||||
- `src/transformers/models/brand_new_llama/configuration_brand_new_llama.py`
|
||||
|
||||
The automatically generated code in the `modeling.py` file has the same architecture as Llama if you answered it's a decoder-only model or it will have the same architecture as BART if you answered it's an encoder-decoder model. The generated code is just a starting point. Based on your research on the new model, you'll need to implement those specific changes by adapting the generated code. This may involve changes to the self-attention layer, the order of the normalization layer, and so on.
|
||||
|
||||
### Model initialization
|
||||
|
||||
At this point, your code doesn't have to be clean or even fully correct, It is more efficient to quickly create a first draft and then iteratively improve on it. The most important thing is that your model can be instantiated from Transformers. The command below creates a model from the configuration with random weights, verifying that the `__init__` method works.
|
||||
|
||||
```py
|
||||
from transformers import BrandNewLlama, BrandNewLlamaConfig
|
||||
model = BrandNewLlama(BrandNewLlamaConfig())
|
||||
```
|
||||
|
||||
Random initialization occurs in the `_init_weights` method of `BrandNewLlamaPreTrainedModel`. All leaf modules are initialized depending on the configuration's variables. Use the helpers from the `transformers.initialization` module to set the values, rather than calling in-place operations directly on a weight or its `.data`.
|
||||
|
||||
```py
|
||||
from transformers import initialization as init
|
||||
|
||||
def _init_weights(self, module):
|
||||
"""Initialize the weights"""
|
||||
if isinstance(module, nn.Linear):
|
||||
init.normal_(module.weight, mean=0.0, std=self.config.initializer_range)
|
||||
if module.bias is not None:
|
||||
init.zeros_(module.bias)
|
||||
elif isinstance(module, nn.Embedding):
|
||||
init.normal_(module.weight, mean=0.0, std=self.config.initializer_range)
|
||||
if module.padding_idx is not None:
|
||||
init.zeros_(module.weight[module.padding_idx])
|
||||
elif isinstance(module, nn.LayerNorm):
|
||||
init.zeros_(module.bias)
|
||||
init.ones_(module.weight)
|
||||
```
|
||||
|
||||
Always initialize weights through the `transformers.initialization` helpers. In-place operations such as `module.bias.zero_()` or anything that touches `module.weight.data` bypass `_is_hf_initialized` that flags which parameters are already loaded. [`~PreTrainedModel.from_pretrained`] runs `_init_weights` after loading the checkpoint, so in-place operations silently overwrite the loaded weights with random values. This is enforced for Transformers models by the [TRF012](./modeling_rules#trf012) rule.
|
||||
|
||||
The initialization scheme can look different if you need to adapt it to your model. A submodule with its own `reset_parameters` method can call it directly. For example, [`Wav2Vec2ForPreTraining`] initializes [nn.Linear](https://pytorch.org/docs/stable/generated/torch.nn.Linear.html) in its last two linear layers. The call is safe because [`~PreTrainedModel.from_pretrained`] patches the underlying `torch.nn.init` functions to respect the `_is_hf_initialized` flag while it runs `_init_weights`, so loaded weights aren't overwritten.
|
||||
|
||||
```py
|
||||
def _init_weights(self, module):
|
||||
"""Initialize the weights"""
|
||||
if isinstance(module, Wav2Vec2ForPreTraining):
|
||||
module.project_hid.reset_parameters()
|
||||
module.project_q.reset_parameters()
|
||||
```
|
||||
|
||||
### Convert checkpoints to Transformers
|
||||
|
||||
The original checkpoint must be converted to a Transformers compatible checkpoint.
|
||||
|
||||
> [!TIP]
|
||||
> Try looking for an existing conversion script to copy, adapt, and reuse for your model!
|
||||
>
|
||||
> - If you're porting a model from TensorFlow to PyTorch, a good starting point may be the BERT [conversion script](https://github.com/huggingface/transformers/blob/7acfa95afb8194f8f9c1f4d2c6028224dbed35a2/src/transformers/models/bert/modeling_bert.py#L91).
|
||||
> - If you're porting a model from PyTorch to PyTorch, a good starting point may be the BART [conversion script](https://github.com/huggingface/transformers/blob/main/src/transformers/models/bart/convert_bart_original_pytorch_checkpoint_to_pytorch.py).
|
||||
|
||||
Make sure **all** required weights are initialized and print out all the checkpoint weights that weren't used for initialization to make sure the model has been converted correctly.
|
||||
|
||||
You may encounter wrong shape statements or name assignments during the conversion. This is most likely because of incorrect parameters in `BrandNewLlamaConfig`, the wrong architecture, a bug in the `init` method of your implementation, or you need to transpose one of the checkpoint weights.
|
||||
|
||||
Keep iterating on the [Adapt the model code](#adapt-the-model-code) section until all the checkpoint weights are correctly loaded. Once you can load a checkpoint in your model, save it to a folder. This should contain a `model.safetensors` file and a `config.json` file.
|
||||
|
||||
```py
|
||||
model.save_pretrained("/path/to/converted/checkpoint/folder")
|
||||
```
|
||||
|
||||
To help with conversion, the next section briefly describes how PyTorch models stores and defines layer weights and names.
|
||||
|
||||
#### PyTorch layer weights and names
|
||||
|
||||
It is helpful to create a basic PyTorch model to understand how layer names are defined and weights are initialized.
|
||||
|
||||
```py
|
||||
from torch import nn
|
||||
|
||||
class SimpleModel(nn.Module):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.dense = nn.Linear(10, 10)
|
||||
self.intermediate = nn.Linear(10, 10)
|
||||
self.layer_norm = nn.LayerNorm(10)
|
||||
```
|
||||
|
||||
PyTorch layer names are defined by the class attribute name of the layer (`dense`, `intermediate`, `layer_norm`). Create a instance of `SimpleModel` to fill all the layers with random weights.
|
||||
|
||||
```py
|
||||
model = SimpleModel()
|
||||
print(model)
|
||||
SimpleModel(
|
||||
(dense): Linear(in_features=10, out_features=10, bias=True)
|
||||
(intermediate): Linear(in_features=10, out_features=10, bias=True)
|
||||
(layer_norm): LayerNorm((10,), eps=1e-05, elementwise_affine=True)
|
||||
)
|
||||
```
|
||||
|
||||
The weight values of a specific layer are randomly initialized.
|
||||
|
||||
```py
|
||||
print(model.dense.weight.data)
|
||||
tensor([[-0.0818, 0.2207, -0.0749, -0.0030, 0.0045, -0.1569, -0.1598, 0.0212,
|
||||
-0.2077, 0.2157],
|
||||
[ 0.1044, 0.0201, 0.0990, 0.2482, 0.3116, 0.2509, 0.2866, -0.2190,
|
||||
0.2166, -0.0212],
|
||||
[-0.2000, 0.1107, -0.1999, -0.3119, 0.1559, 0.0993, 0.1776, -0.1950,
|
||||
-0.1023, -0.0447],
|
||||
[-0.0888, -0.1092, 0.2281, 0.0336, 0.1817, -0.0115, 0.2096, 0.1415,
|
||||
-0.1876, -0.2467],
|
||||
[ 0.2208, -0.2352, -0.1426, -0.2636, -0.2889, -0.2061, -0.2849, -0.0465,
|
||||
0.2577, 0.0402],
|
||||
[ 0.1502, 0.2465, 0.2566, 0.0693, 0.2352, -0.0530, 0.1859, -0.0604,
|
||||
0.2132, 0.1680],
|
||||
[ 0.1733, -0.2407, -0.1721, 0.1484, 0.0358, -0.0633, -0.0721, -0.0090,
|
||||
0.2707, -0.2509],
|
||||
[-0.1173, 0.1561, 0.2945, 0.0595, -0.1996, 0.2988, -0.0802, 0.0407,
|
||||
0.1829, -0.1568],
|
||||
[-0.1164, -0.2228, -0.0403, 0.0428, 0.1339, 0.0047, 0.1967, 0.2923,
|
||||
0.0333, -0.0536],
|
||||
[-0.1492, -0.1616, 0.1057, 0.1950, -0.2807, -0.2710, -0.1586, 0.0739,
|
||||
0.2220, 0.2358]]).
|
||||
```
|
||||
|
||||
In the conversion script, the random weights should be replaced with the exact weights from the corresponding layer in the original checkpoint.
|
||||
|
||||
```py
|
||||
# retrieve matching layer weights with recursive algorithm
|
||||
layer_name = "dense"
|
||||
pretrained_weight = array_of_dense_layer
|
||||
|
||||
model_pointer = getattr(model, "dense")
|
||||
model_pointer.weight.data = torch.from_numpy(pretrained_weight)
|
||||
```
|
||||
|
||||
Verify the randomly initialized weights and their corresponding pretrained checkpoint weights have the identical **shape** and **name**. Add assert statements for the shape and print out the checkpoint weight names.
|
||||
|
||||
```py
|
||||
assert (
|
||||
model_pointer.weight.shape == pretrained_weight.shape
|
||||
), f"Pointer shape of random weight {model_pointer.shape} and array shape of checkpoint weight {pretrained_weight.shape} mismatched"
|
||||
|
||||
logger.info(f"Initialize PyTorch weight {layer_name} from {pretrained_weight.name}")
|
||||
```
|
||||
|
||||
When the shape or name don't match, you may have assigned the incorrect checkpoint weight to a randomly initialized layer. An incorrect shape may be because the `BrandNewLlama` parameters don't exactly match the original models parameters. But it could also be that the PyTorch layer implementation requires the weights to be transposed first.
|
||||
|
||||
### Implement the forward pass
|
||||
|
||||
The forward pass should be implemented next if the model loads correctly. It takes some inputs and returns the model output.
|
||||
|
||||
```py
|
||||
model = BrandNewLlamaModel.from_pretrained("/path/to/converted/checkpoint/folder")
|
||||
input_ids = [0, 4, 4, 3, 2, 4, 1, 7, 19]
|
||||
output = model.generate(input_ids).last_hidden_states
|
||||
```
|
||||
|
||||
Don't be discouraged if your forward pass isn't identical with the output from the original model or if it returns an error. Check that the forward pass doesn't throw any errors. This is often because the dimensions are wrong or because the wrong data type is used ([torch.long](https://pytorch.org/docs/stable/generated/torch.Tensor.long.html) instead of [torch.float32](https://pytorch.org/docs/stable/tensors.html)).
|
||||
|
||||
Your output should have a precision of *1e-3*. Ensure the output shapes and output values are identical. Common reasons for why the outputs aren't identical include:
|
||||
|
||||
- Some layers were not added (activation layer or a residual connection).
|
||||
- The word embedding matrix is not tied.
|
||||
- The wrong positional embeddings are used because the original implementation includes an offset.
|
||||
- Dropout is applied during the forward pass. Fix this error by making sure `model.training` is `False` and passing `self.training` to [torch.nn.functional.dropout](https://pytorch.org/docs/stable/nn.functional.html?highlight=dropout#torch.nn.functional.dropout).
|
||||
|
||||
Compare the forward pass of the original model and your implementation to check if there are any differences. Ideally, debug and print out the intermediate outputs of both implementations of the forward pass to pinpoint where the original implementation differs from yours.
|
||||
|
||||
1. Make sure the hardcoded `input_ids` in both implementations are identical.
|
||||
2. Verify the outputs of the first transformation of `input_ids` (usually the word embeddings) are identical, and work your way through to the last layer.
|
||||
|
||||
Any difference between the two implementations should point to the bug in your implementation.
|
||||
|
||||
One of the best strategies is to add many print statements to the same positions in both implementations, and then successively remove them when they output identical values for the intermediate outputs.
|
||||
|
||||
When both implementations produce the same output, verify the outputs are within a precision of *1e-3*.
|
||||
|
||||
```py
|
||||
torch.allclose(original_output, output, atol=1e-3)
|
||||
```
|
||||
|
||||
This is typically the most difficult part of the process. Congratulations if you've made it this far!
|
||||
|
||||
And if you're stuck or struggling with this step, don't hesitate to ask for help on your pull request.
|
||||
|
||||
### Add model tests
|
||||
|
||||
While the model works, you still need to add tests to ensure it is compatible with Transformers. Tests are important because they help users understand your work by looking at specific tests, and because they prevent your model from breaking in the future if any changes are made.
|
||||
|
||||
[Cookiecutter](https://cookiecutter.readthedocs.io/en/stable/) should have added a test file for your model. Run the test file below to make sure all common tests pass.
|
||||
|
||||
```bash
|
||||
pytest tests/models/brand_new_llama/test_modeling_brand_new_llama.py
|
||||
```
|
||||
|
||||
The integration tests should be added first because they serve the same purpose as the debugging scripts you used earlier to implement the new model in Transformers. A template of those model tests, `BrandNewLlamaModelIntegrationTests`, was added by Cookiecutter and should be filled out. To ensure it passes, run the following command.
|
||||
|
||||
<hfoptions id="integration-test">
|
||||
<hfoption id="macOS">
|
||||
|
||||
```bash
|
||||
RUN_SLOW=1 pytest -sv tests/models/brand_new_llama/test_modeling_brand_new_llama.py::BrandNewLlamaModelIntegrationTests
|
||||
```
|
||||
|
||||
</hfoption>
|
||||
<hfoption id="Windows">
|
||||
|
||||
```bash
|
||||
SET RUN_SLOW=1 pytest -sv tests/models/brand_new_llama/test_modeling_brand_new_llama.py::BrandNewLlamaModelIntegrationTests
|
||||
```
|
||||
|
||||
</hfoption>
|
||||
</hfoptions>
|
||||
|
||||
All features unique to BrandNewLlama should be tested in a separate test under `BrandNewLlamaModelTester/BrandNewLlamaModelTest`. This test is often overlooked, but it is extremely important because:
|
||||
|
||||
- it helps transfer knowledge you acquired during the process to the community by showing how the models novel features work
|
||||
- future contributors can quickly test changes to the model by running these special tests
|
||||
|
||||
## Implement tokenizer
|
||||
|
||||
> [!TIP]
|
||||
> We recommend adding a fast tokenizer ([`PreTrainedTokenizerFast`]) to give users the best performance. Feel free to tag [@ArthurZucker](https://github.com/ArthurZucker) or [@itazap](https://github.com/itazap) in your PR for help on how to add [`PreTrainedTokenizerFast`].
|
||||
|
||||
With the model out of the way, time to focus on the tokenizer. The tokenizer should be identical or very similar to an existing tokenizer in Transformers.
|
||||
|
||||
Find and load the original tokenizer file into your implementation. Create a script in the original repository that inputs a string and returns the `input_ids`. The pseudocode should look similar to the code below.
|
||||
|
||||
```py
|
||||
input_str = "This is a long example input string containing special characters .$?-, numbers 2872 234 12 and words."
|
||||
model = BrandNewLlamaModel.load_pretrained_checkpoint("/path/to/checkpoint/")
|
||||
input_ids = model.tokenize(input_str)
|
||||
```
|
||||
|
||||
You may need to search the original repository to find the correct tokenizer function or modify the existing tokenizer in your clone of the original repository to only return the `input_ids`. The script for your tokenizer should look similar to the following.
|
||||
|
||||
```py
|
||||
from transformers import BrandNewLlamaTokenizer
|
||||
|
||||
input_str = "This is a long example input string containing special characters .$?-, numbers 2872 234 12 and words."
|
||||
tokenizer = BrandNewLlamaTokenizer.from_pretrained("/path/to/tokenizer/folder/")
|
||||
input_ids = tokenizer(input_str).input_ids
|
||||
```
|
||||
|
||||
When both implementations have the same `input_ids`, add a tokenizer test file. This file is analogous to the modeling test files. The tokenizer test files should contain a couple of hardcoded integration tests.
|
||||
|
||||
## Implement image processor
|
||||
|
||||
> [!TIP]
|
||||
> Image processors now use a backend-based architecture. The default backend is [`TorchvisionBackend`], which uses the [torchvision](https://pytorch.org/vision/stable/index.html) library and can perform image processing on the GPU. A PIL/NumPy alternative backend ([`PilBackend`]) is also provided. Both backends are imported from `image_processing_backends`. Feel free to tag [@yonigozlan](https://github.com/yonigozlan) for help.
|
||||
|
||||
While this example doesn't include an image processor, you may need to implement one if your model requires image inputs. The image processor is responsible for converting images into a format suitable for your model. Before implementing a new one, check whether an existing image processor in the Transformers library can be reused, as many models share similar image processing techniques. Note that you can also use [modular](./modular_transformers) for image processors to reuse existing components.
|
||||
|
||||
If you do need to implement a new image processor, each model has two processor files:
|
||||
|
||||
- `image_processing_<model>.py`: the **default** torchvision-backed processor (`<Model>ImageProcessor`), inheriting from [`TorchvisionBackend`]. This replaces the old "fast" processor.
|
||||
- `image_processing_pil_<model>.py`: the PIL/NumPy alternative processor (`<Model>ImageProcessorPil`), inheriting from [`PilBackend`]. This replaces the old "slow" processor.
|
||||
|
||||
The torchvision backend file also defines any custom kwargs class that the PIL file imports. Both files use the `@auto_docstring` decorator — do not add manual class docstrings. Refer to the [IMAGE_PROCESSOR_REFACTORING_GUIDE.md](https://github.com/huggingface/transformers/blob/main/IMAGE_PROCESSOR_REFACTORING_GUIDE.md) for a step-by-step walkthrough and complete examples.
|
||||
|
||||
Add tests for the image processor in `tests/models/your_model_name/test_image_processing_your_model_name.py`. These tests should be similar to those for other image processors and should verify that the image processor correctly handles image inputs. If your image processor includes unique features or processing methods, ensure you add specific tests for those as well.
|
||||
|
||||
## Implement processor
|
||||
|
||||
If your model accepts multiple modalities, like text and images, you need to add a processor. The processor centralizes the preprocessing of different modalities before passing them to the model.
|
||||
|
||||
The processor should call the appropriate modality-specific processors within its `__call__` function to handle each type of input correctly. Be sure to check existing processors in the library to understand their expected structure. Transformers uses the following convention in the `__call__` function signature.
|
||||
|
||||
```python
|
||||
def __call__(
|
||||
self,
|
||||
images: ImageInput = None,
|
||||
text: Union[TextInput, PreTokenizedInput, list[TextInput], list[PreTokenizedInput]] = None,
|
||||
audio=None,
|
||||
videos=None,
|
||||
**kwargs: Unpack[YourModelProcessorKwargs],
|
||||
) -> BatchFeature:
|
||||
...
|
||||
```
|
||||
|
||||
`YourModelProcessorKwargs` is a `TypedDict` that includes all the typical processing arguments and any extra arguments a specific processor may require.
|
||||
|
||||
Add tests for the processor in `tests/models/your_model_name/test_processor_your_model_name.py`. These tests should be similar to those for other processors and should verify that the processor correctly handles the different modalities.
|
||||
|
||||
## Integration tests
|
||||
|
||||
Now that you have a model and tokenizer, add end-to-end integration tests for the model and tokenizer to `tests/models/brand_new_llama/test_modeling_brand_new_llama.py`.
|
||||
|
||||
The test should provide a meaningful text-to-text example to show the model works as expected. For example, you can include a source-to-target translation pair, an article-to-summary pair, or a question-to-answer pair.
|
||||
|
||||
If the checkpoint hasn't been fine-tuned on a downstream task, then the model tests are sufficient.
|
||||
|
||||
Finally, try to make sure your tests can run on a GPU by adding `.to(self.device)` statements to the models internal tensors. If you don't have access to a GPU, we can take care of that for you.
|
||||
|
||||
## Add documentation
|
||||
|
||||
Your model is only useful if users know how to use it. This is why it's important to add documentation and docstrings. Cookiecutter added a template file, `docs/source/model_doc/brand_new_llama.md`, that you can fill out with information about your model.
|
||||
|
||||
This is generally a user's first interaction with a model, so the documentation should be clear and concise. It is often very useful to add examples of how the model should be used.
|
||||
|
||||
Make sure docstrings are added to `src/transformers/models/brand_new_llama/modeling_brand_new_llama.py` and includes all necessary inputs and outputs. Review our [guide](https://github.com/huggingface/transformers/tree/main/docs#writing-documentation---specification) for writing documentation and docstrings.
|
||||
|
||||
## Refactor
|
||||
|
||||
Time to tidy things up and make sure the code style is consistent with the rest of the library. Run the following command to automatically fix incorrect styles.
|
||||
|
||||
```bash
|
||||
make style
|
||||
```
|
||||
|
||||
To verify the code style passes quality checks, run the command below.
|
||||
|
||||
```bash
|
||||
make check-repo
|
||||
```
|
||||
|
||||
There may be other failing tests or checks (missing docstring or incorrect naming) on your pull request due to Transformers strict design tests. We can help you with these issues if you're stuck.
|
||||
|
||||
After ensuring the code runs correctly, you may want to refactor it to make it more readable or cleaner.
|
||||
|
||||
## Upload to the Hub
|
||||
|
||||
Convert and upload all checkpoints to the [Hub](https://hf.co/models). Add a model card to provide more transparency and context about the model. The model card should highlight specific characteristics of a checkpoint, how the model was trained, and code examples of how to use it.
|
||||
|
||||
> [!TIP]
|
||||
> In many cases, adding an interactive notebook users can run is a great way to showcase how to use the model for inference or fine-tune it on a downstream task. While not required, including a notebook can drive greater adoption of your model.
|
||||
|
||||
You should also consult with the Transformers team to decide on an appropriate name for the model, and getting the required access rights to upload the model.
|
||||
|
||||
Use the [`~PreTrainedModel.push_to_hub`] method to upload the model.
|
||||
|
||||
```py
|
||||
brand_new_bert.push_to_hub("brand_new_llama")
|
||||
```
|
||||
|
||||
Refer to the [Sharing](./model_sharing) guide for more information about uploading models to the Hub.
|
||||
|
||||
## Merge your model
|
||||
|
||||
You're finally ready to merge your pull request and officially add the model to Transformers! Make sure all the tests are passing and all comments and feedback have been addressed.
|
||||
|
||||
Congratulations on adding a new model to Transformers! 🥳
|
||||
|
||||
This is a very significant contribution. Your work makes Transformers more accessible to developers and researchers around the world. You should be proud of your contribution and share your accomplishment with the community!
|
||||
|
||||
## See also
|
||||
|
||||
- [Model structure rules](./modeling_rules) — static rules enforced on all `modeling_*.py` and `configuration_*.py` files. Run `make typing` to check them before opening a PR.
|
||||
- [Pull request checks](./pr_checks) — full reference for what CI checks run on your PR and how to pass them.
|
||||
@@ -0,0 +1,224 @@
|
||||
<!--Copyright 2024 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Adding a new pipeline
|
||||
|
||||
Make [`Pipeline`] your own by subclassing it and implementing a few methods. Share the code with the community on the [Hub](https://hf.co) and register the pipeline with Transformers so that everyone can quickly and easily use it.
|
||||
|
||||
This guide will walk you through the process of adding a new pipeline to Transformers.
|
||||
|
||||
## Design choices
|
||||
|
||||
At a minimum, you only need to provide [`Pipeline`] with an appropriate input for a task. This is also where you should begin when designing your pipeline.
|
||||
|
||||
Decide what input types [`Pipeline`] can accept. It can be strings, raw bytes, dictionaries, and so on. Try to keep the inputs in pure Python where possible because it's more compatible. Next, decide on the output [`Pipeline`] should return. Again, keeping the output in Python is the simplest and best option because it's easier to work with.
|
||||
|
||||
Keeping the inputs and outputs simple, and ideally JSON-serializable, makes it easier for users to run your [`Pipeline`] without needing to learn new object types. It's also common to support many different input types for even greater ease of use. For example, making an audio file acceptable from a filename, URL, or raw bytes gives the user more flexibility in how they provide the audio data.
|
||||
|
||||
## Create a pipeline
|
||||
|
||||
With an input and output decided, you can start implementing [`Pipeline`]. Your pipeline should inherit from the base [`Pipeline`] class and include 4 methods.
|
||||
|
||||
```py
|
||||
from transformers import Pipeline
|
||||
|
||||
class MyPipeline(Pipeline):
|
||||
def _sanitize_parameters(self, **kwargs):
|
||||
|
||||
def preprocess(self, inputs, args=2):
|
||||
|
||||
def _forward(self, model_inputs):
|
||||
|
||||
def postprocess(self, model_outputs):
|
||||
```
|
||||
|
||||
1. `preprocess` takes the inputs and transforms them into the appropriate input format for the model.
|
||||
|
||||
```py
|
||||
def preprocess(self, inputs, maybe_arg=2):
|
||||
model_input = Tensor(inputs["input_ids"])
|
||||
return {"model_input": model_input}
|
||||
```
|
||||
|
||||
2. `_forward` shouldn't be called directly. `forward` is the preferred method because it includes safeguards to make sure everything works correctly on the expected device. Anything linked to the model belongs in `_forward` and everything else belongs in either `preprocess` or `postprocess`.
|
||||
|
||||
```py
|
||||
def _forward(self, model_inputs):
|
||||
outputs = self.model(**model_inputs)
|
||||
return outputs
|
||||
```
|
||||
|
||||
3. `postprocess` generates the final output from the models output in `_forward`.
|
||||
|
||||
```py
|
||||
def postprocess(self, model_outputs, top_k=5):
|
||||
best_class = model_outputs["logits"].softmax(-1)
|
||||
return best_class
|
||||
```
|
||||
|
||||
4. `_sanitize_parameters` lets users pass additional parameters to [`Pipeline`]. This could be during initialization or when [`Pipeline`] is called. `_sanitize_parameters` returns 3 dicts of additional keyword arguments that are passed directly to `preprocess`, `_forward`, and `postprocess`. Don't add anything if a user didn't call the pipeline with extra parameters. This keeps the default arguments in the function definition which is always more natural.
|
||||
|
||||
For example, add a `top_k` parameter in `postprocess` to return the top 5 most likely classes. Then in `_sanitize_parameters`, check if the user passed in `top_k` and add it to `postprocess_kwargs`.
|
||||
|
||||
```py
|
||||
def _sanitize_parameters(self, **kwargs):
|
||||
preprocess_kwargs = {}
|
||||
if "maybe_arg" in kwargs:
|
||||
preprocess_kwargs["maybe_arg"] = kwargs["maybe_arg"]
|
||||
|
||||
postprocess_kwargs = {}
|
||||
if "top_k" in kwargs:
|
||||
postprocess_kwargs["top_k"] = kwargs["top_k"]
|
||||
return preprocess_kwargs, {}, postprocess_kwargs
|
||||
```
|
||||
|
||||
Now the pipeline can return the top most likely labels if a user chooses to.
|
||||
|
||||
```py
|
||||
from transformers import pipeline
|
||||
|
||||
pipeline = pipeline("my-task")
|
||||
# returns 3 most likely labels
|
||||
pipeline("This is the best meal I've ever had", top_k=3)
|
||||
# returns 5 most likely labels by default
|
||||
pipeline("This is the best meal I've ever had")
|
||||
```
|
||||
|
||||
## Register a pipeline
|
||||
|
||||
Register the new task your pipeline supports in the `PIPELINE_REGISTRY`. The registry defines:
|
||||
|
||||
- The supported Pytorch model class with `pt_model`
|
||||
- a default model which should come from a specific revision (branch, or commit hash) where the model works as expected with `default`
|
||||
- the expected input with `type`
|
||||
|
||||
```py
|
||||
from transformers.pipelines import PIPELINE_REGISTRY
|
||||
from transformers import AutoModelForSequenceClassification
|
||||
|
||||
PIPELINE_REGISTRY.register_pipeline(
|
||||
"new-task",
|
||||
pipeline_class=MyPipeline,
|
||||
pt_model=AutoModelForSequenceClassification,
|
||||
default={"pt": ("user/awesome-model", "branch-name")},
|
||||
type="text",
|
||||
)
|
||||
```
|
||||
|
||||
## Share your pipeline
|
||||
|
||||
Share your pipeline with the community on the [Hub](https://hf.co) or you can add it directly to Transformers.
|
||||
|
||||
It's faster to upload your pipeline code to the Hub because it doesn't require a review from the Transformers team. Adding the pipeline to Transformers may be slower because it requires a review and you need to add tests to ensure your [`Pipeline`] works.
|
||||
|
||||
### Upload to the Hub
|
||||
|
||||
Add your pipeline code to the Hub in a Python file.
|
||||
|
||||
For example, a custom pipeline for sentence pair classification might look like the following code below.
|
||||
|
||||
```py
|
||||
import numpy as np
|
||||
from transformers import Pipeline
|
||||
|
||||
def softmax(outputs):
|
||||
maxes = np.max(outputs, axis=-1, keepdims=True)
|
||||
shifted_exp = np.exp(outputs - maxes)
|
||||
return shifted_exp / shifted_exp.sum(axis=-1, keepdims=True)
|
||||
|
||||
class PairClassificationPipeline(Pipeline):
|
||||
def _sanitize_parameters(self, **kwargs):
|
||||
preprocess_kwargs = {}
|
||||
if "second_text" in kwargs:
|
||||
preprocess_kwargs["second_text"] = kwargs["second_text"]
|
||||
return preprocess_kwargs, {}, {}
|
||||
|
||||
def preprocess(self, text, second_text=None):
|
||||
return self.tokenizer(text, text_pair=second_text, return_tensors=self.framework)
|
||||
|
||||
def _forward(self, model_inputs):
|
||||
return self.model(**model_inputs)
|
||||
|
||||
def postprocess(self, model_outputs):
|
||||
logits = model_outputs.logits[0].numpy()
|
||||
probabilities = softmax(logits)
|
||||
|
||||
best_class = np.argmax(probabilities)
|
||||
label = self.model.config.id2label[best_class]
|
||||
score = probabilities[best_class].item()
|
||||
logits = logits.tolist()
|
||||
return {"label": label, "score": score, "logits": logits}
|
||||
```
|
||||
|
||||
Save the code in a file named `pair_classification.py`, and import and register it as shown below.
|
||||
|
||||
```py
|
||||
from pair_classification import PairClassificationPipeline
|
||||
from transformers.pipelines import PIPELINE_REGISTRY
|
||||
from transformers import AutoModelForSequenceClassification
|
||||
|
||||
PIPELINE_REGISTRY.register_pipeline(
|
||||
"pair-classification",
|
||||
pipeline_class=PairClassificationPipeline,
|
||||
pt_model=AutoModelForSequenceClassification,
|
||||
)
|
||||
```
|
||||
|
||||
The [register_pipeline](https://github.com/huggingface/transformers/blob/9feae5fb0164e89d4998e5776897c16f7330d3df/src/transformers/pipelines/base.py#L1387) function registers the pipeline details (task type, pipeline class, supported backends) to a models `config.json` file.
|
||||
|
||||
```json
|
||||
"custom_pipelines": {
|
||||
"pair-classification": {
|
||||
"impl": "pair_classification.PairClassificationPipeline",
|
||||
"pt": [
|
||||
"AutoModelForSequenceClassification"
|
||||
],
|
||||
}
|
||||
},
|
||||
```
|
||||
|
||||
Call [`~Pipeline.push_to_hub`] to push the pipeline to the Hub. The Python file containing the code is copied to the Hub, and the pipelines model and tokenizer are also saved and pushed to the Hub. Your pipeline should now be available on the Hub under your namespace.
|
||||
|
||||
```py
|
||||
from transformers import pipeline
|
||||
|
||||
pipeline = pipeline(task="pair-classification", model="sgugger/finetuned-bert-mrpc")
|
||||
pipeline.push_to_hub("pair-classification-pipeline")
|
||||
```
|
||||
|
||||
To use the pipeline, add `trust_remote_code=True` when loading the pipeline.
|
||||
|
||||
```py
|
||||
from transformers import pipeline
|
||||
|
||||
pipeline = pipeline(task="pair-classification", trust_remote_code=True)
|
||||
```
|
||||
|
||||
### Add to Transformers
|
||||
|
||||
Adding a custom pipeline to Transformers requires adding tests to make sure everything works as expected, and requesting a review from the Transformers team.
|
||||
|
||||
Add your pipeline code as a new module to the [pipelines](https://github.com/huggingface/transformers/tree/main/src/transformers/pipelines) submodule, and add it to the list of tasks defined in [pipelines/__init__.py](https://github.com/huggingface/transformers/blob/main/src/transformers/pipelines/__init__.py).
|
||||
|
||||
Next, add a new test for the pipeline in [transformers/tests/pipelines](https://github.com/huggingface/transformers/tree/main/tests/pipelines). You can look at the other tests for examples of how to test your pipeline.
|
||||
|
||||
The [run_pipeline_test](https://github.com/huggingface/transformers/blob/db70426854fe7850f2c5834d633aff637f14772e/tests/pipelines/test_pipelines_text_classification.py#L186) function should be very generic and run on the models defined in [model_mapping](https://github.com/huggingface/transformers/blob/db70426854fe7850f2c5834d633aff637f14772e/tests/pipelines/test_pipelines_text_classification.py#L48). This is important for testing future compatibility with new models.
|
||||
|
||||
You'll also notice `ANY` is used throughout the [run_pipeline_test](https://github.com/huggingface/transformers/blob/db70426854fe7850f2c5834d633aff637f14772e/tests/pipelines/test_pipelines_text_classification.py#L186) function. The models are random, so you can't check the actual values. Using `ANY` allows the test to match the output of the pipeline type instead.
|
||||
|
||||
Finally, you should also implement the following 4 tests.
|
||||
|
||||
1. [test_small_model_pt](https://github.com/huggingface/transformers/blob/db70426854fe7850f2c5834d633aff637f14772e/tests/pipelines/test_pipelines_text_classification.py#L59), use a small model for these pipelines to make sure they return the correct outputs. The results don't have to make sense. Each pipeline should return the same result.
|
||||
1. [test_large_model_pt](https://github.com/huggingface/transformers/blob/db70426854fe7850f2c5834d633aff637f14772e/tests/pipelines/test_pipelines_zero_shot_image_classification.py#L187), use a realistic model for these pipelines to make sure they return meaningful results. These tests are slow and should be marked as slow.
|
||||
@@ -0,0 +1,261 @@
|
||||
<!--Copyright 2026 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Add vision processing components
|
||||
|
||||
Adding a vision model requires image or video processing components on top of the standard [modular](./modular_transformers) approach. Image-only models need image processors and video models need a video processor, both of which are accessible behind the [`AutoImageProcessor`] and [`AutoVideoProcessor`] entry points.
|
||||
|
||||
> [!NOTE]
|
||||
> For the modeling and config steps, follow the [modular](./modular_transformers) guide first.
|
||||
|
||||
## Image processors
|
||||
|
||||
Create image processors when the model consumes images. The [torchvision](https://docs.pytorch.org/vision/stable/index.html) backend is the default and supports GPU acceleration. [PIL](https://pillow.readthedocs.io/en/stable/index.html) is the fallback when torchvision isn't available.
|
||||
|
||||
Both image processor classes share the same preprocessing logic but have different backends. Their constructor signatures and default values must be identical. [`AutoImageProcessor.from_pretrained`] selects the backend at load time and falls back to PIL when torchvision isn't available. Mismatched signatures cause the same saved config to behave differently across environments.
|
||||
|
||||
### torchvision
|
||||
|
||||
Create `image_processing_<model_name>.py` with a class that inherits from [`TorchvisionBackend`]. If your processor needs custom parameters beyond the standard [ImagesKwargs], define a kwargs class.
|
||||
|
||||
```py
|
||||
from ...image_processing_backends import TorchvisionBackend
|
||||
from ...image_utils import OPENAI_CLIP_MEAN, OPENAI_CLIP_STD, PILImageResampling
|
||||
from ...processing_utils import ImagesKwargs, Unpack
|
||||
from ...utils import auto_docstring
|
||||
|
||||
class MyModelImageProcessorKwargs(ImagesKwargs, total=False):
|
||||
tile_size: int # any model-specific kwargs
|
||||
|
||||
@auto_docstring
|
||||
class MyModelImageProcessor(TorchvisionBackend):
|
||||
resample = PILImageResampling.BICUBIC
|
||||
image_mean = OPENAI_CLIP_MEAN
|
||||
image_std = OPENAI_CLIP_STD
|
||||
size = {"shortest_edge": 224}
|
||||
do_resize = True
|
||||
do_rescale = True
|
||||
do_normalize = True
|
||||
do_convert_rgb = True
|
||||
|
||||
def __init__(self, **kwargs: Unpack[MyModelImageProcessorKwargs]):
|
||||
super().__init__(**kwargs)
|
||||
```
|
||||
|
||||
> [!TIP]
|
||||
> See [`LlavaOnevisionImageProcessor`] for reference.
|
||||
|
||||
### PIL
|
||||
|
||||
Create `image_processing_pil_<model_name>.py` with a class that inherits from [`PilBackend`]. Duplicate the kwargs class here instead of importing it from the torchvision file because it can fail when torchvision isn't installed. Add an `# Adapted from` comment so the two stay in sync. For processors with no custom parameters, use [`ImagesKwargs`] directly.
|
||||
|
||||
```py
|
||||
from ...image_processing_backends import PilBackend
|
||||
from ...image_utils import OPENAI_CLIP_MEAN, OPENAI_CLIP_STD, PILImageResampling
|
||||
from ...processing_utils import ImagesKwargs, Unpack
|
||||
from ...utils import auto_docstring
|
||||
|
||||
# Adapted from transformers.models.my_model.image_processing_my_model.MyModelImageProcessorKwargs
|
||||
class MyModelImageProcessorKwargs(ImagesKwargs, total=False):
|
||||
tile_size: int # any model-specific kwargs
|
||||
|
||||
@auto_docstring
|
||||
class MyModelImageProcessorPil(PilBackend):
|
||||
resample = PILImageResampling.BICUBIC
|
||||
image_mean = OPENAI_CLIP_MEAN
|
||||
image_std = OPENAI_CLIP_STD
|
||||
size = {"shortest_edge": 224}
|
||||
do_resize = True
|
||||
do_rescale = True
|
||||
do_normalize = True
|
||||
do_convert_rgb = True
|
||||
|
||||
def __init__(self, **kwargs: Unpack[MyModelImageProcessorKwargs]):
|
||||
super().__init__(**kwargs)
|
||||
```
|
||||
|
||||
> [!TIP]
|
||||
> See [`LlavaOnevisionImageProcessorPil`] for reference.
|
||||
|
||||
### Add post-processing methods
|
||||
|
||||
Add post-processing methods directly to the processor class. Post-processing methods are called with the model outputs (`outputs`) and any additional arguments required for the specific post-processing method.
|
||||
|
||||
```py
|
||||
class MyModelImageProcessor(TorchvisionBackend):
|
||||
...
|
||||
|
||||
def post_process_my_task(self, outputs, ...):
|
||||
...
|
||||
```
|
||||
|
||||
Post-processors return either a list of simple objects (`list[str]` or `list[torch.Tensor]`) or a list of complex objects (`list[MyTaskPostProcessorOutput]` or `list[dict]`). Post-processor outputs are defined in `src/transformers/image_processing_outputs.py` and inherit from [`BatchFeature`].
|
||||
|
||||
```py
|
||||
class MyTaskPostProcessorOutput(BatchFeature):
|
||||
predictions: torch.Tensor
|
||||
scores: torch.Tensor
|
||||
```
|
||||
|
||||
## Video processor
|
||||
|
||||
Add a video processor when the model consumes videos or sampled video frames.
|
||||
|
||||
Create `video_processing_<model_name>.py` in the model directory. [`BaseVideoProcessor`] inherits from the [`TorchvisionBackend`] and provides shared decoding, frame sampling, resizing, rescaling, normalization, saving, and loading behavior.
|
||||
|
||||
The class attributes are the default preprocessing values. Users can override them at initialization or call time. Use the same names as [`VideosKwargs`] when possible, such as `size`, `crop_size`, `do_resize`, `do_sample_frames`, `num_frames`, and `fps`.
|
||||
|
||||
Define a kwargs class if your video processor needs custom parameters beyond the standard [`VideosKwargs`]. Set it as `valid_kwargs` and use it to annotate `__init__` for both runtime validation and the auto-generated docstring.
|
||||
|
||||
```py
|
||||
from ...processing_utils import Unpack, VideosKwargs
|
||||
from ...utils import auto_docstring
|
||||
from ...video_processing_utils import BaseVideoProcessor
|
||||
|
||||
class MyModelVideoProcessorKwargs(VideosKwargs, total=False):
|
||||
min_frames: int
|
||||
max_frames: int
|
||||
|
||||
@auto_docstring
|
||||
class MyModelVideoProcessor(BaseVideoProcessor):
|
||||
size = {"shortest_edge": 224}
|
||||
crop_size = {"height": 224, "width": 224}
|
||||
do_resize = True
|
||||
do_center_crop = True
|
||||
do_normalize = True
|
||||
do_sample_frames = True
|
||||
num_frames = 16
|
||||
model_input_names = ["pixel_values_videos"]
|
||||
valid_kwargs = MyModelVideoProcessorKwargs
|
||||
|
||||
def __init__(self, **kwargs: Unpack[MyModelVideoProcessorKwargs]):
|
||||
super().__init__(**kwargs)
|
||||
```
|
||||
|
||||
Override [`~BaseVideoProcessor.sample_frames`] only when the model requires a sampling rule that the base uniform sampler can't express. For example, some models enforce a minimum or maximum number of frames, or sample based on model-specific constraints.
|
||||
|
||||
If the model's forward method expects a legacy input name, override `preprocess` and rename the key after calling the base implementation.
|
||||
|
||||
```py
|
||||
class MyModelVideoProcessor(BaseVideoProcessor):
|
||||
model_input_names = ["pixel_values"]
|
||||
|
||||
def preprocess(self, videos, **kwargs):
|
||||
batch = super().preprocess(videos, **kwargs)
|
||||
batch["pixel_values"] = batch.pop("pixel_values_videos")
|
||||
return batch
|
||||
```
|
||||
|
||||
Save the video processor with the checkpoint by instantiating it in the conversion script and calling [`~BaseVideoProcessor.save_pretrained`]. If a [`ProcessorMixin`] wraps the video processor, call [`~ProcessorMixin.save_pretrained`] instead. Do not manually create or edit preprocessing config files.
|
||||
|
||||
> [!TIP]
|
||||
> See [`Qwen3VLVideoProcessor`] for reference.
|
||||
|
||||
## Register the classes
|
||||
|
||||
Expose the processing classes from the model package `__init__.py`. Follow the lazy import pattern used by nearby models and guard imports with the same optional dependencies required by each backend.
|
||||
|
||||
Map the new classes to the model config so the `Auto` classes can load them. The generated auto mapping file has a warning at the top. Do not edit it by hand. Add or update the model config, then run:
|
||||
|
||||
```bash
|
||||
python utils/check_auto.py --fix_and_overwrite
|
||||
```
|
||||
|
||||
After the mapping is generated, verify the model type appears in the relevant mappings in `src/transformers/models/auto/auto_mappings.py`.
|
||||
|
||||
- `IMAGE_PROCESSOR_MAPPING_NAMES` for [`AutoImageProcessor`]
|
||||
- `VIDEO_PROCESSOR_MAPPING_NAMES` for [`AutoVideoProcessor`]
|
||||
|
||||
## Testing
|
||||
|
||||
Add tests for each vision processing component in the model test directory. Image and video processor tests follow the same pattern. Inherit from the shared mixin, indicate the fast and slow processing classes when automatic discovery isn't enough, provide model-specific init kwargs, and override the input name when the model uses a non-default output key.
|
||||
|
||||
### Image processor tests
|
||||
|
||||
Image processor tests usually live in `tests/models/<model_name>/test_image_processing_<model_name>.py` and inherit from [`ImageProcessingTestMixin`].
|
||||
|
||||
The image processing mixin finds the image processor classes from `IMAGE_PROCESSOR_MAPPING_NAMES`. Expose model-specific defaults through `image_processor_dict`. Add a tester object only when you need reusable dummy inputs or helper methods for focused tests.
|
||||
|
||||
```py
|
||||
from transformers.testing_utils import require_torch, require_vision
|
||||
from ...test_image_processing_common import ImageProcessingTestMixin
|
||||
|
||||
@require_torch
|
||||
@require_vision
|
||||
class MyModelImageProcessingTest(ImageProcessingTestMixin, unittest.TestCase):
|
||||
@property
|
||||
def image_processor_dict(self):
|
||||
return {"size": {"shortest_edge": 224}, "do_resize": True}
|
||||
```
|
||||
|
||||
Add focused tests for behavior the mixin can't infer, such as custom resizing rules or model-specific kwargs.
|
||||
|
||||
Post-processing test mixins are available in `tests/test_image_processing_common.py` and are added on top of [`ImageProcessingTestMixin`].
|
||||
|
||||
```py
|
||||
class MyModelImageProcessingTest(ImageProcessingTestMixin, MyTaskPostProcessTestMixin, unittest.TestCase):
|
||||
```
|
||||
|
||||
The tests automatically verify that the correct mixins are used for your model. Mixins for new tasks must be added to `tests/test_image_processing_common.py`.
|
||||
|
||||
### Video processor tests
|
||||
|
||||
Video processor tests usually live in `tests/models/<model_name>/test_video_processing_<model_name>.py` and inherit from [`VideoProcessingTestMixin`]. Set `fast_video_processing_class`, define `video_processor_dict`, and override `input_name` if the model uses a key other than `pixel_values_videos`.
|
||||
|
||||
```py
|
||||
from transformers.testing_utils import require_torch, require_vision
|
||||
from transformers.utils import is_torchvision_available
|
||||
from ...test_video_processing_common import VideoProcessingTestMixin
|
||||
|
||||
@require_torch
|
||||
@require_vision
|
||||
class MyModelVideoProcessingTest(VideoProcessingTestMixin, unittest.TestCase):
|
||||
fast_video_processing_class = MyModelVideoProcessor if is_torchvision_available() else None
|
||||
input_name = "pixel_values_videos"
|
||||
|
||||
@property
|
||||
def video_processor_dict(self):
|
||||
return {"size": {"shortest_edge": 224}, "num_frames": 16}
|
||||
```
|
||||
|
||||
Add focused video tests for frame sampling, metadata handling, decoded video inputs, list-of-frame inputs, and output shapes. If your processor renames `pixel_values_videos`, assert the renamed key is returned.
|
||||
|
||||
If the model also has a [`ProcessorMixin`] that wraps the image or video processor, add `tests/models/<model_name>/test_processing_<model_name>.py` and inherit from [`ProcessorTesterMixin`]. Set `processor_class` and override `_setup_<component>()` class methods for components that can't be constructed without arguments. Use `_setup_test_attributes()` to expose placeholder tokens used by the common processor tests.
|
||||
|
||||
```py
|
||||
from ...test_processing_common import ProcessorTesterMixin
|
||||
|
||||
class MyModelProcessorTest(ProcessorTesterMixin, unittest.TestCase):
|
||||
processor_class = MyModelProcessor
|
||||
|
||||
@classmethod
|
||||
def _setup_image_processor(cls):
|
||||
return cls._get_component_class_from_processor("image_processor")(size={"shortest_edge": 224})
|
||||
|
||||
@classmethod
|
||||
def _setup_video_processor(cls):
|
||||
return cls._get_component_class_from_processor("video_processor")(num_frames=2)
|
||||
|
||||
@classmethod
|
||||
def _setup_test_attributes(cls, processor):
|
||||
cls.image_token = getattr(processor, "image_token", "")
|
||||
cls.video_token = getattr(processor, "video_token", "")
|
||||
```
|
||||
|
||||
## Next steps
|
||||
|
||||
- Read the [Auto-generating docstrings](./auto_docstring) guide to auto-generate consistent docstrings with `@auto_docstring`.
|
||||
- Read the [Image processors](./image_processors) and [Video processors](./video_processors) guides for user-facing preprocessing behavior.
|
||||
@@ -0,0 +1,186 @@
|
||||
<!--Copyright 2025 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Assisted decoding
|
||||
|
||||
Assisted decoding speeds up text generation by allowing a helper propose candidate tokens before the main model commits to them. The main model verifies the candidate tokens in one forward pass. The helper is fast and cheap and can replace dozens of more expensive forward passes by the main model.
|
||||
|
||||
This guide covers assisted decoding methods in Transformers.
|
||||
|
||||
## Speculative decoding
|
||||
|
||||
[Speculative decoding](https://hf.co/papers/2211.17192) uses a smaller assistant model to draft candidate tokens. The main model checks these tokens in one pass. Validated tokens enter the final output and rejected tokens trigger standard sampling. Generation is faster because the main model runs fewer expensive forward passes.
|
||||
|
||||
The method works best when the assistant model is significantly smaller than the main model and uses the same tokenizer. Speculative decoding supports greedy search and sampling but not batched inputs.
|
||||
|
||||
Pass `assistant_model` to [`~GenerationMixin.generate`]. Set `do_sample=True` to resample if token validation fails.
|
||||
|
||||
<hfoptions id="spec-decoding">
|
||||
<hfoption id="greedy search">
|
||||
|
||||
```py
|
||||
import torch
|
||||
from transformers import AutoModelForCausalLM, AutoTokenizer
|
||||
|
||||
tokenizer = AutoTokenizer.from_pretrained("HuggingFaceTB/SmolLM-1.7B")
|
||||
model = AutoModelForCausalLM.from_pretrained("HuggingFaceTB/SmolLM-1.7B", dtype="auto")
|
||||
assistant_model = AutoModelForCausalLM.from_pretrained("HuggingFaceTB/SmolLM-135M", dtype="auto")
|
||||
inputs = tokenizer("Hugging Face is an open-source company", return_tensors="pt")
|
||||
|
||||
outputs = model.generate(**inputs, assistant_model=assistant_model)
|
||||
tokenizer.batch_decode(outputs, skip_special_tokens=True)
|
||||
'Hugging Face is an open-source company that provides a platform for developers to build and deploy machine'
|
||||
```
|
||||
|
||||
The `assistant_model` argument is also available in the [`Pipeline`] API.
|
||||
|
||||
```python
|
||||
import torch
|
||||
from transformers import pipeline
|
||||
|
||||
pipeline = pipeline(
|
||||
"text-generation",
|
||||
model="meta-llama/Llama-3.1-8B",
|
||||
assistant_model="meta-llama/Llama-3.2-1B",
|
||||
dtype="auto"
|
||||
)
|
||||
pipeline("Hugging Face is an open-source company, ", max_new_tokens=50, do_sample=False)
|
||||
```
|
||||
|
||||
</hfoption>
|
||||
<hfoption id="sampling">
|
||||
|
||||
Set `temperature` to control randomness. Lower temperatures often improve latency.
|
||||
|
||||
```py
|
||||
from transformers import AutoModelForCausalLM, AutoTokenizer
|
||||
|
||||
tokenizer = AutoTokenizer.from_pretrained("HuggingFaceTB/SmolLM-1.7B")
|
||||
model = AutoModelForCausalLM.from_pretrained("HuggingFaceTB/SmolLM-1.7B", dtype="auto")
|
||||
assistant_model = AutoModelForCausalLM.from_pretrained("HuggingFaceTB/SmolLM-135M", dtype="auto")
|
||||
inputs = tokenizer("Hugging Face is an open-source company", return_tensors="pt")
|
||||
|
||||
outputs = model.generate(**inputs, assistant_model=assistant_model, do_sample=True, temperature=0.5)
|
||||
tokenizer.batch_decode(outputs, skip_special_tokens=True)
|
||||
'Hugging Face is an open-source company that is dedicated to creating a better world through technology.'
|
||||
```
|
||||
|
||||
</hfoption>
|
||||
</hfoptions>
|
||||
|
||||
## Prompt lookup decoding
|
||||
|
||||
Prompt lookup decoding doesn't need an assistant model. It finds overlapping n-grams in the prompt to propose candidate tokens. If no match exists, it falls back to normal autoregressive decoding. This suits input-grounded tasks like summarization and translation because candidate tokens often mirror local patterns in the source text.
|
||||
|
||||
Pass `prompt_lookup_num_tokens` to [`~GenerationMixin.generate`]. This sets how many tokens the algorithm tries to copy from earlier in the prompt when it detects a repeated pattern.
|
||||
|
||||
<hfoptions id="prompt-lookup-decoding">
|
||||
<hfoption id="greedy decoding">
|
||||
|
||||
```py
|
||||
import torch
|
||||
from transformers import AutoModelForCausalLM, AutoTokenizer
|
||||
|
||||
tokenizer = AutoTokenizer.from_pretrained("HuggingFaceTB/SmolLM-1.7B")
|
||||
model = AutoModelForCausalLM.from_pretrained("HuggingFaceTB/SmolLM-1.7B", dtype="auto")
|
||||
inputs = tokenizer("Hugging Face is an open-source company", return_tensors="pt")
|
||||
|
||||
outputs = model.generate(**inputs, prompt_lookup_num_tokens=5)
|
||||
tokenizer.batch_decode(outputs, skip_special_tokens=True)
|
||||
'Hugging Face is an open-source company that provides a platform for developers to build and deploy machine learning models. It offers a variety of tools'
|
||||
```
|
||||
|
||||
</hfoption>
|
||||
<hfoption id="sampling">
|
||||
|
||||
```py
|
||||
import torch
|
||||
from transformers import AutoModelForCausalLM, AutoTokenizer
|
||||
|
||||
tokenizer = AutoTokenizer.from_pretrained("HuggingFaceTB/SmolLM-1.7B")
|
||||
model = AutoModelForCausalLM.from_pretrained("HuggingFaceTB/SmolLM-1.7B", dtype="auto")
|
||||
inputs = tokenizer("Hugging Face is an open-source company", return_tensors="pt")
|
||||
|
||||
outputs = model.generate(**inputs, prompt_lookup_num_tokens=5, do_sample=True, temperature=0.5)
|
||||
tokenizer.batch_decode(outputs, skip_special_tokens=True)
|
||||
'Hugging Face is an open-source company that provides a platform for developers to build and deploy machine learning models. It offers a variety of tools'
|
||||
```
|
||||
|
||||
</hfoption>
|
||||
</hfoptions>
|
||||
|
||||
## Self-speculative decoding
|
||||
|
||||
Self-speculative decoding uses a model's intermediate layers as the assistant to propose candidate tokens. If the proposal matches, the model exits early and the remaining layers verify or correct the tokens.
|
||||
|
||||
Because it's all one model, weights and caches are shared, which boosts speed without extra memory overhead. This technique only works for models trained to support early-exit logits from intermediate layers.
|
||||
|
||||
Pass `assistant_early_exit` to [`~GenerationMixin.generate`] to set the exit layer.
|
||||
|
||||
```py
|
||||
import torch
|
||||
from transformers import AutoModelForCausalLM, AutoTokenizer
|
||||
|
||||
tokenizer = AutoTokenizer.from_pretrained("facebook/layerskip-llama3.2-1B")
|
||||
model = AutoModelForCausalLM.from_pretrained("facebook/layerskip-llama3.2-1B", dtype="auto")
|
||||
inputs = tokenizer("Hugging Face is an open-source company", return_tensors="pt")
|
||||
|
||||
outputs = model.generate(**inputs, assistant_early_exit=4, do_sample=False, max_new_tokens=20)
|
||||
tokenizer.batch_decode(outputs, skip_special_tokens=True)
|
||||
```
|
||||
|
||||
## Universal assisted decoding
|
||||
|
||||
Universal assisted decoding (UAD) makes speculative decoding possible even when the main and assistant models have different tokenizers. It lets you pair any small assistant model with the main model. Candidate tokens are re-encoded and the algorithm computes the longest common subsequence so the continuation stays aligned.
|
||||
|
||||
Pass `tokenizer`, `assistant_tokenizer`, and `assistant_model` to [`~GenerationMixin.generate`] to enable UAD.
|
||||
|
||||
```py
|
||||
import torch
|
||||
from transformers import AutoModelForCausalLM, AutoTokenizer
|
||||
|
||||
assistant_tokenizer = AutoTokenizer.from_pretrained("double7/vicuna-68m")
|
||||
tokenizer = AutoTokenizer.from_pretrained("google/gemma-2-9b")
|
||||
model = AutoModelForCausalLM.from_pretrained("google/gemma-2-9b", dtype="auto")
|
||||
assistant_model = AutoModelForCausalLM.from_pretrained("double7/vicuna-68m", dtype="auto")
|
||||
inputs = tokenizer("Hugging Face is an open-source company", return_tensors="pt")
|
||||
|
||||
outputs = model.generate(**inputs, assistant_model=assistant_model, tokenizer=tokenizer, assistant_tokenizer=assistant_tokenizer)
|
||||
tokenizer.batch_decode(outputs, skip_special_tokens=True)
|
||||
'Hugging Face is an open-source company that is dedicated to creating a better world through technology.'
|
||||
```
|
||||
|
||||
### Static ensemble verification
|
||||
|
||||
Standard speculative decoding is *lossless* — it guarantees the output distribution matches the target model exactly. [Static ensemble verification](https://arxiv.org/abs/2604.07622) relaxes this by verifying against a mixture of the target and draft distributions, increasing the acceptance rate (faster inference) at the cost of making the output distribution a mixture rather than the exact target distribution. A recommended starting value is `0.7`.
|
||||
|
||||
```python
|
||||
import torch
|
||||
from transformers import AutoModelForCausalLM, AutoTokenizer
|
||||
|
||||
tokenizer = AutoTokenizer.from_pretrained("HuggingFaceTB/SmolLM-1.7B")
|
||||
model = AutoModelForCausalLM.from_pretrained("HuggingFaceTB/SmolLM-1.7B", dtype="auto")
|
||||
assistant_model = AutoModelForCausalLM.from_pretrained("HuggingFaceTB/SmolLM-135M", dtype="auto")
|
||||
inputs = tokenizer("Hugging Face is an open-source company", return_tensors="pt")
|
||||
|
||||
outputs = model.generate(**inputs, assistant_model=assistant_model, assistant_ensemble_weight=0.7, do_sample=True)
|
||||
tokenizer.batch_decode(outputs, skip_special_tokens=True)
|
||||
```
|
||||
|
||||
This requires candidate logits from the assistant model and is not supported with prompt lookup decoding.
|
||||
|
||||
## Resources
|
||||
|
||||
- Read the [Assisted Generation: a new direction toward low-latency text generation](https://huggingface.co/blog/assisted-generation) blog post for more context about text generation latency and assisted generation.
|
||||
@@ -0,0 +1,398 @@
|
||||
<!--Copyright 2025 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Attention backends
|
||||
|
||||
All attention implementations perform the same computation. Every token is compared to every other token. The difference is *how* the computation is performed. Basic attention scales poorly because it materializes the full attention matrix in memory, creating bottlenecks that slow down inference. Optimized implementations rearrange the math to reduce memory traffic for faster, more affordable inference.
|
||||
|
||||
The [`AttentionInterface`] provides optimized attention implementations. It decouples the attention implementation from the model implementation to simplify experimentation with different functions. Add new backends easily with this consistent interface.
|
||||
|
||||
<table>
|
||||
<tr><th>Attention backend</th><th>Description</th></tr>
|
||||
<tr><td><code>"flash_attention_3"</code></td><td>improves FlashAttention-2 by also overlapping operations and fusing forward and backward passes more tightly</td></tr>
|
||||
<tr><td><code>"flash_attention_2"</code></td><td>tiles computations into smaller blocks and uses fast on-chip memory</td></tr>
|
||||
<tr><td><code>"flex_attention"</code></td><td>framework for specifying custom attention patterns (sparse, block-local, sliding window) without writing low-level kernels by hand</td></tr>
|
||||
<tr><td><code>"sdpa"</code></td><td>built-in PyTorch implementation of <a href="https://docs.pytorch.org/docs/stable/generated/torch.nn.functional.scaled_dot_product_attention.html">scaled dot product attention</a></td></tr>
|
||||
<tr><td><code>"paged|flash_attention_3"</code></td><td>Paged version of FlashAttention-3</td></tr>
|
||||
<tr><td><code>"paged|flash_attention_2"</code></td><td>Paged version of FlashAttention-2</td></tr>
|
||||
<tr><td><code>"paged|sdpa"</code></td><td>Paged version of SDPA</td></tr>
|
||||
<tr><td><code>"paged|eager"</code></td><td>Paged version of eager</td></tr>
|
||||
</table>
|
||||
|
||||
## Set an attention backend
|
||||
|
||||
Use the `attn_implementation` argument in [`~PreTrainedModel.from_pretrained`] to instantiate a model with a specific attention function.
|
||||
|
||||
```py
|
||||
import torch
|
||||
from transformers import AutoModelForCausalLM
|
||||
|
||||
model = AutoModelForCausalLM.from_pretrained(
|
||||
"meta-llama/Llama-3.2-1B", attn_implementation="flash_attention_2"
|
||||
)
|
||||
```
|
||||
|
||||
Switch between attention backends at runtime without reloading the model using [`~PreTrainedModel.set_attn_implementation`].
|
||||
|
||||
```py
|
||||
model.set_attn_implementation("sdpa")
|
||||
```
|
||||
|
||||
### Kernels
|
||||
|
||||
Download and load compiled compute kernels directly from the [Hub](https://huggingface.co/models?other=kernels) at runtime with the [Kernels](https://huggingface.co/docs/kernels/index) library. This avoids packaging issues from mismatched PyTorch or CUDA versions.
|
||||
|
||||
Kernels automatically register to [`AttentionInterface`] upon detection. You don't need to install the FlashAttention package explicitly.
|
||||
|
||||
```py
|
||||
import torch
|
||||
from transformers import AutoModelForCausalLM
|
||||
|
||||
model = AutoModelForCausalLM.from_pretrained(
|
||||
"meta-llama/Llama-3.2-1B", attn_implementation="kernels-community/flash-attn2"
|
||||
)
|
||||
```
|
||||
|
||||
### SDPA context manager
|
||||
|
||||
PyTorch's scaled dot product attention (SDPA) selects the fastest attention function for CUDA backends automatically. It defaults to the PyTorch C++ implementation for other backends.
|
||||
|
||||
Force SDPA to use a specific implementation with the [torch.nn.attention.sdpa_kernel](https://pytorch.org/docs/stable/generated/torch.nn.attention.sdpa_kernel.html) context manager.
|
||||
|
||||
```py
|
||||
import torch
|
||||
from torch.nn.attention import SDPBackend, sdpa_kernel
|
||||
from transformers import AutoModelForCausalLM
|
||||
|
||||
model = AutoModelForCausalLM.from_pretrained(
|
||||
"meta-llama/Llama-3.2-1B", attn_implementation="sdpa"
|
||||
)
|
||||
|
||||
with sdpa_kernel(SDPBackend.FLASH_ATTENTION):
|
||||
outputs = model.generate(**inputs)
|
||||
```
|
||||
|
||||
## Backbone-specific attention
|
||||
|
||||
Multimodal models use different backbones for each modality. Optimize performance by assigning specific attention functions to each backbone. Some vision backbones perform better in fp32, for example, which FlashAttention does not support.
|
||||
|
||||
Map vision backbones to different attention functions with a dict while the text backbone continues to use FlashAttention. Keys in the attention implementation must match sub-config names.
|
||||
|
||||
```py
|
||||
from transformers import AutoModelForImageTextToText
|
||||
|
||||
attention_implementation_per_backbone = {"vision_config": "sdpa", "text_config": "flash_attention_2"}
|
||||
|
||||
for key in attention_implementation_per_backbone:
|
||||
assert key in model.config.sub_configs, f"Invalid key in `attention_implementation`"
|
||||
|
||||
model = AutoModelForImageTextToText.from_pretrained(
|
||||
"facebook/chameleon-7b", attn_implementation=attention_implementation_per_backbone
|
||||
)
|
||||
```
|
||||
|
||||
Omit certain backbones from the dict to use the default attention function (SDPA).
|
||||
|
||||
```py
|
||||
model = AutoModelForImageTextToText.from_pretrained(
|
||||
"facebook/chameleon-7b", attn_implementation={"text_config": "flash_attention_2"}
|
||||
)
|
||||
```
|
||||
|
||||
Set the same attention function for all backbones with a single string.
|
||||
|
||||
```py
|
||||
model = AutoModelForImageTextToText.from_pretrained(
|
||||
"facebook/chameleon-7b", attn_implementation="eager"
|
||||
)
|
||||
```
|
||||
|
||||
Set the attention function globally with an empty key.
|
||||
|
||||
```py
|
||||
model = AutoModelForImageTextToText.from_pretrained(
|
||||
"facebook/chameleon-7b", attn_implementation={"": "eager"}
|
||||
)
|
||||
```
|
||||
|
||||
## Create a new attention function
|
||||
|
||||
Customize or create new attention functions by adding them to the attention registry with [`AttentionInterface.register`]. Models use these functions through the `attn_implementation` argument.
|
||||
|
||||
> [!WARNING]
|
||||
> Register a matching attention mask function when you register a custom attention function. If the custom `attn_implementation` name is not registered in [`AttentionMaskInterface`], Transformers skips mask creation and passes `attention_mask=None` to the attention layers. Your attention function must handle causal, padding, packing, or sliding-window constraints itself, or those constraints can be silently dropped.
|
||||
|
||||
This example customizes the attention function to print a statement for each layer. It keeps the mask in the original implementation by registering `masking_utils.sdpa_mask` as the attention mask function.
|
||||
|
||||
```python
|
||||
import torch
|
||||
from transformers import AutoModelForCausalLM, AttentionInterface, AttentionMaskInterface
|
||||
from transformers.integrations.sdpa_attention import sdpa_attention_forward
|
||||
from transformers.masking_utils import sdpa_mask
|
||||
|
||||
def my_new_sdpa(*args, **kwargs):
|
||||
print("I just entered the attention computation")
|
||||
return sdpa_attention_forward(*args, **kwargs)
|
||||
|
||||
AttentionInterface.register("my_new_sdpa", my_new_sdpa)
|
||||
AttentionMaskInterface.register("my_new_sdpa", sdpa_mask) # must have the same name as the registered attention function
|
||||
|
||||
model = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-3.2-1B", attn_implementation="my_new_sdpa")
|
||||
model(torch.ones(1, 5, dtype=int))
|
||||
```
|
||||
|
||||
You can also add new arguments to the attention function. Models supporting [`AttentionInterface`] propagate kwargs to attention layers and the attention function. Pass arguments as kwargs in the model's forward function. Custom attention functions must follow this signature and return format.
|
||||
|
||||
```python
|
||||
import torch
|
||||
from transformers import AutoModelForCausalLM, AttentionInterface, AttentionMaskInterface
|
||||
from transformers.integrations.sdpa_attention import sdpa_attention_forward
|
||||
from transformers.masking_utils import sdpa_mask
|
||||
|
||||
def custom_attention(
|
||||
module: torch.nn.Module, # required arg
|
||||
query: torch.Tensor, # required arg
|
||||
key: torch.Tensor, # required arg
|
||||
value: torch.Tensor, # required arg
|
||||
attention_mask: Optional[torch.Tensor], # required arg
|
||||
a_new_kwargs = None, # You can now add as many kwargs as you need
|
||||
another_new_kwargs = None, # You can now add as many kwargs as you need
|
||||
**kwargs, # You need to accept **kwargs as models will pass other args
|
||||
) -> tuple[torch.Tensor, Optional[torch.Tensor]]
|
||||
... # do your magic!
|
||||
return attn_output, attn_weights # attn_weights are optional here
|
||||
|
||||
AttentionInterface.register("custom", custom_attention)
|
||||
AttentionMaskInterface.register("custom", sdpa_mask) # to leave the existing mask untouched
|
||||
|
||||
model = AutoModelForCausalLM.from_pretrained(model_id, attn_implementation="custom")
|
||||
model(torch.ones(1, 5, dtype=int), a_new_kwargs=..., another_new_kwargs=...)
|
||||
```
|
||||
|
||||
Check a model's [modeling code](https://github.com/huggingface/transformers/tree/main/src/transformers/models) to confirm what arguments and kwargs it sends to the attention function.
|
||||
|
||||
## AttentionMaskInterface
|
||||
|
||||
[`AttentionMaskInterface`] is the registry the [`create_*_mask`](#build-an-attention-mask) functions consult to convert a mask into the format the active attention backend expects. FlexAttention needs a [BlockMask](https://docs.pytorch.org/docs/stable/nn.attention.flex_attention.html#torch.nn.attention.flex_attention.BlockMask), SDPA needs a 4D tensor, and FlashAttention needs the base 2D padding mask. Register a custom backend, or override the formatter for an existing one, with [`AttentionMaskInterface.register`].
|
||||
|
||||
```python
|
||||
import torch
|
||||
from transformers import AttentionMaskInterface
|
||||
from transformers.masking_utils import sdpa_mask
|
||||
|
||||
def my_new_sdpa_mask(*args, **kwargs):
|
||||
print("I just entered the attention mask computation")
|
||||
return sdpa_mask(*args, **kwargs)
|
||||
|
||||
AttentionMaskInterface.register("my_new_sdpa_mask", my_new_sdpa_mask)
|
||||
```
|
||||
|
||||
Without a registered formatter for the active `attn_implementation`, mask creation is skipped and `attention_mask=None` passes to the attention layers.
|
||||
|
||||
Registered functions must match this signature.
|
||||
|
||||
```python
|
||||
def custom_attention_mask(
|
||||
batch_size: int, # required arg
|
||||
q_length: int, # required arg
|
||||
kv_length: int, # required arg
|
||||
q_offset: int = 0, # required arg
|
||||
kv_offset: int = 0, # required arg
|
||||
mask_function: Callable = causal_mask_function, # required arg
|
||||
attention_mask: Optional[torch.Tensor] = None, # required arg
|
||||
**kwargs, # a few additional args may be passed as kwargs, especially the model's config is always passed
|
||||
) -> Optional[torch.Tensor]:
|
||||
```
|
||||
|
||||
The `mask_function` argument is a `Callable` that mimics PyTorch's [mask_mod](https://pytorch.org/blog/flexattention/) functions. It takes 4 indices `(batch_idx, head_idx, q_idx, kv_idx)` and returns a boolean indicating whether that position contributes to the attention computation. This is the same primitive shape used by `or_mask_function` and `and_mask_function` in [Build an attention mask](#build-an-attention-mask).
|
||||
|
||||
> [!TIP]
|
||||
> Use this [workaround](https://github.com/huggingface/transformers/blob/main/src/transformers/integrations/executorch.py) for torch.export if `mask_function` fails to create a mask.
|
||||
|
||||
## Build an attention mask
|
||||
|
||||
Build attention masks with the `create_*_mask` functions in [transformers.masking_utils](https://github.com/huggingface/transformers/blob/main/src/transformers/masking_utils.py#L894). Each function reads the active attention backend from the model config, looks up the backend's mask formatter in [`AttentionMaskInterface`], and returns the format that backend expects. You don't need to invert, expand, or cast the mask yourself.
|
||||
|
||||
Pick the function that matches the attention pattern.
|
||||
|
||||
| function | use case |
|
||||
|---|---|
|
||||
| [`create_causal_mask`] | decoder-only models where each token attends to itself and earlier tokens |
|
||||
| [`create_bidirectional_mask`] | encoder models, or cross-attention from a decoder to encoder states |
|
||||
| [`create_sliding_window_causal_mask`] | decoder models with a sliding-window attention pattern |
|
||||
| [`create_chunked_causal_mask`] | decoder models that chunk the sequence into fixed-size blocks |
|
||||
| [`create_bidirectional_sliding_window_mask`] | encoder models with a sliding-window attention pattern |
|
||||
|
||||
> [!WARNING]
|
||||
> The legacy callable mask helpers - `get_extended_attention_mask`, `create_extended_attention_mask_for_decoder`, `invert_attention_mask` - emit a deprecation warning and will be removed in a future release. Use the `create_*_mask` functions instead.
|
||||
|
||||
<hfoptions id="build-mask">
|
||||
<hfoption id="causal attention">
|
||||
|
||||
Call [`create_causal_mask`] inside a decoder forward pass. Pass the config, the input embeddings, the user-provided 2D `attention_mask`, and the cache. The function uses the embeddings to read the batch size, query length, dtype, and device, and uses the cache to compute the key length.
|
||||
|
||||
```py
|
||||
from transformers.masking_utils import create_causal_mask
|
||||
|
||||
attention_mask = create_causal_mask(
|
||||
config=self.config,
|
||||
inputs_embeds=inputs_embeds,
|
||||
attention_mask=attention_mask,
|
||||
past_key_values=past_key_values,
|
||||
)
|
||||
```
|
||||
|
||||
</hfoption>
|
||||
<hfoption id="encoder self-attention">
|
||||
|
||||
Call [`create_bidirectional_mask`] for encoder self-attention. Drop `past_key_values` because encoders don't cache.
|
||||
|
||||
```py
|
||||
from transformers.masking_utils import create_bidirectional_mask
|
||||
|
||||
attention_mask = create_bidirectional_mask(
|
||||
config=self.config,
|
||||
inputs_embeds=embedding_output,
|
||||
attention_mask=attention_mask,
|
||||
)
|
||||
```
|
||||
|
||||
</hfoption>
|
||||
<hfoption id="cross-attention">
|
||||
|
||||
For cross-attention, pass the encoder states as `encoder_hidden_states` so the mask uses the encoder's key and value length instead of the decoder's query length.
|
||||
|
||||
```py
|
||||
encoder_attention_mask = create_bidirectional_mask(
|
||||
config=self.config,
|
||||
inputs_embeds=embedding_output,
|
||||
attention_mask=encoder_attention_mask,
|
||||
encoder_hidden_states=encoder_hidden_states,
|
||||
)
|
||||
```
|
||||
|
||||
</hfoption>
|
||||
</hfoptions>
|
||||
|
||||
Add extra constraints on top of the base mask with the `or_mask_function` and `and_mask_function` arguments. Use `or_mask_function` to let additional positions attend, and `and_mask_function` to restrict the base pattern further. Both follow the 4-index `mask_function` signature described in [AttentionMaskInterface](#attentionmaskinterface). They take `(batch_idx, head_idx, q_idx, kv_idx)` and return a boolean.
|
||||
|
||||
> [!WARNING]
|
||||
> `or_mask_function` and `and_mask_function` can express any attention pattern, but they're slower than the built-in patterns and are not compatible with ExecuTorch. The overhead is most noticeable on smaller models (~200M parameters), where mask creation takes a larger share of forward-pass time. Reach for them only when the standard `create_*_mask` functions can't express what you need.
|
||||
|
||||
For example, overlay a function that returns `True` everywhere on a causal mask to turn it into a fully bidirectional one. The union with the causal pattern lets every token attend to every other token.
|
||||
|
||||
```py
|
||||
mask_kwargs = {
|
||||
"config": self.config,
|
||||
"inputs_embeds": inputs_embeds,
|
||||
"attention_mask": attention_mask,
|
||||
"past_key_values": past_key_values,
|
||||
"position_ids": position_ids,
|
||||
"or_mask_function": lambda *args: torch.tensor(True, dtype=torch.bool),
|
||||
}
|
||||
|
||||
attention_mask = create_causal_mask(**mask_kwargs)
|
||||
```
|
||||
|
||||
During generation, [`~GenerationMixin.generate`] builds masks through [`create_masks_for_generate`], which dispatches to the right `create_*_mask` based on the model config. Override it on a model class to plug in a custom masking strategy for generation.
|
||||
|
||||
## Pass a custom 4D attention mask
|
||||
|
||||
Pass your own 4D mask when you need an attention pattern the `create_*_mask` functions can't express. A 4D mask has the shape `(batch_size, 1, query_length, kv_length)`, where `1` broadcasts the same mask across every attention head. Transformers detects and uses the mask as-is, skipping `create_*_mask`.
|
||||
|
||||
A 4D mask uses one of two value conventions.
|
||||
|
||||
| dtype | attend | mask out |
|
||||
|---|---|---|
|
||||
| boolean | `True` | `False` |
|
||||
| float | `0.0` | `-inf` |
|
||||
|
||||
The float convention adds the mask to the attention scores before the softmax. A score plus `0.0` stays unchanged, so the position contributes. A score plus `-inf` drops to zero after the softmax, so the position is excluded.
|
||||
|
||||
> [!IMPORTANT]
|
||||
> The accepted convention depends on the attention backend. `sdpa` takes a boolean or a float mask. `eager` adds the mask to the scores, so it takes a float mask only. `flash_attention_2` and `flex_attention` consume their own formats (a 2D padding mask and a [BlockMask](https://docs.pytorch.org/docs/stable/nn.attention.flex_attention.html#torch.nn.attention.flex_attention.BlockMask)) and don't accept a raw 4D mask.
|
||||
|
||||
A common mistake is to reuse the `1`/`0` convention of a 2D padding mask in a float 4D mask. Because the mask is added to the scores, `0.0` keeps a position and `1.0` only adds a small bias.
|
||||
|
||||
The example below contrasts a wrong mask with a correct one. Both start from the same `1`/`0` causal pattern.
|
||||
|
||||
```py
|
||||
import torch
|
||||
from transformers import AutoModelForCausalLM, AutoTokenizer
|
||||
|
||||
model = AutoModelForCausalLM.from_pretrained("TinyLlama/TinyLlama-1.1B-Chat-v1.0", attn_implementation="sdpa")
|
||||
tokenizer = AutoTokenizer.from_pretrained("TinyLlama/TinyLlama-1.1B-Chat-v1.0")
|
||||
|
||||
input_ids = tokenizer("my favorite condiment on a", return_tensors="pt").input_ids
|
||||
seq_len = input_ids.shape[1]
|
||||
|
||||
# 1 attends, 0 masks
|
||||
causal = torch.tril(torch.ones(seq_len, seq_len))
|
||||
|
||||
# wrong: 1.0/0.0 floats are added to the scores, so 0.0 keeps a token and 1.0 barely changes it
|
||||
wrong_mask = causal[None, None]
|
||||
|
||||
# correct: 0.0 attends, -inf masks
|
||||
correct_mask = torch.where(causal.bool(), 0.0, float("-inf"))[None, None]
|
||||
```
|
||||
|
||||
The wrong mask keeps every position because `0.0` is the value that masks, so it never excludes anything.
|
||||
|
||||
```text
|
||||
wrong_mask correct_mask
|
||||
(1 attends, 0 masks) (0 attends, -inf masks)
|
||||
|
||||
k0 k1 k2 k3 k4 k0 k1 k2 k3 k4
|
||||
q0 1 0 0 0 0 q0 0 -inf -inf -inf -inf
|
||||
q1 1 1 0 0 0 q1 0 0 -inf -inf -inf
|
||||
q2 1 1 1 0 0 q2 0 0 0 -inf -inf
|
||||
q3 1 1 1 1 0 q3 0 0 0 0 -inf
|
||||
q4 1 1 1 1 1 q4 0 0 0 0 0
|
||||
```
|
||||
|
||||
## Bidirectional attention
|
||||
|
||||
Decoder-only models use causal (unidirectional) attention by default, where each token only attends to itself and previous tokens. Set `is_causal=False` to switch to bidirectional attention, where every token attends to every other token. This lets you use decoder-only models as text encoders, for example, to generate embeddings.
|
||||
|
||||
> [!NOTE]
|
||||
> This only works for causal (decoder) models. It does not turn encoder models into decoder models.
|
||||
|
||||
Set `is_causal=False` in the model config to make bidirectional attention the default for every forward pass.
|
||||
|
||||
```py
|
||||
from transformers import AutoModel, AutoConfig
|
||||
|
||||
config = AutoConfig.from_pretrained("meta-llama/Llama-3.2-1B")
|
||||
config.is_causal = False
|
||||
|
||||
model = AutoModel.from_pretrained("meta-llama/Llama-3.2-1B", config=config)
|
||||
|
||||
# all forward passes now use bidirectional attention
|
||||
outputs = model(**inputs)
|
||||
```
|
||||
|
||||
Pass `is_causal` in the forward call instead of the model config to switch between causal and bidirectional attention without loading the model twice. The kwarg temporarily overrides the config and is restored after the call.
|
||||
|
||||
```py
|
||||
from transformers import AutoModel
|
||||
|
||||
model = AutoModel.from_pretrained("meta-llama/Llama-3.2-1B")
|
||||
|
||||
# run with bidirectional attention
|
||||
outputs = model(**inputs, is_causal=False)
|
||||
|
||||
# run with default causal attention
|
||||
outputs = model(**inputs)
|
||||
```
|
||||
@@ -0,0 +1,383 @@
|
||||
<!--Copyright 2025 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Auto-generating docstrings
|
||||
|
||||
The `@auto_docstring` decorator generates consistent docstrings for model classes and methods. It pulls in standard argument descriptions automatically, so you only write documentation for new or custom arguments. When [adding a new model](./modular_transformers), skip the boilerplate and focus on what's new.
|
||||
|
||||
## @auto_docstring
|
||||
|
||||
Import the decorator in your `modular_model.py` file (or `modeling_model.py` for older models).
|
||||
|
||||
```python
|
||||
from ...utils import auto_docstring
|
||||
```
|
||||
|
||||
If your model inherits from another library model in a modular file, `@auto_docstring` is already applied in the parent. `make fix-repo` copies it into the generated `modeling_model.py` file for you. Only apply the decorator explicitly to customize its behavior (standalone models, custom intros, or overridden arguments).
|
||||
|
||||
> [!WARNING]
|
||||
> When overriding any decorator in a modular file, include **all** decorators from the parent function or class. If you only override some, the rest won't appear in the generated modeling file.
|
||||
|
||||
The decorator accepts the following optional arguments:
|
||||
|
||||
| argument | description |
|
||||
|---|---|
|
||||
| `custom_intro` | A description of the class or method, inserted before the Args section. Required for classes that don't end with a [recognized suffix](#how-it-works) like `ForCausalLM` or `ForTokenClassification`. |
|
||||
| `custom_args` | Docstring text for specific parameters. Useful when the same custom arguments appear in several places in the modeling file. |
|
||||
| `checkpoint` | A model checkpoint identifier (`"org/my-model"`) used to generate usage examples. Overrides the checkpoint auto-inferred from the config class. Typically set on config classes. |
|
||||
|
||||
## Usage
|
||||
|
||||
How `@auto_docstring` works depends on what you're decorating. Model classes pull parameter docs from `__init__`, config classes pull from class-level annotations, processor classes auto-generate intros from their components, and methods like `forward` get return types and usage examples.
|
||||
|
||||
### Model classes
|
||||
|
||||
Place `@auto_docstring` directly above the class definition. The decorator derives parameter descriptions from the `__init__` method's signature and docstring.
|
||||
|
||||
```python
|
||||
from transformers.modeling_utils import PreTrainedModel
|
||||
from ...utils import auto_docstring
|
||||
|
||||
@auto_docstring
|
||||
class MyAwesomeModel(PreTrainedModel):
|
||||
def __init__(self, config, custom_parameter: int = 10, another_custom_arg: str = "default"):
|
||||
r"""
|
||||
custom_parameter (`int`, *optional*, defaults to 10):
|
||||
Description of the custom_parameter for MyAwesomeModel.
|
||||
another_custom_arg (`str`, *optional*, defaults to "default"):
|
||||
Documentation for another unique argument.
|
||||
"""
|
||||
super().__init__(config)
|
||||
self.custom_parameter = custom_parameter
|
||||
self.another_custom_arg = another_custom_arg
|
||||
# ... rest of your init
|
||||
|
||||
# ... other methods
|
||||
```
|
||||
|
||||
Pass `custom_intro` and `custom_args` for more control. Custom arguments can go in `custom_args` or in the `__init__` docstring. Use `custom_args` when the same arguments repeat across several methods.
|
||||
|
||||
```python
|
||||
@auto_docstring(
|
||||
custom_intro="""This model performs specific synergistic operations.
|
||||
It builds upon the standard Transformer architecture with unique modifications.""",
|
||||
custom_args="""
|
||||
custom_parameter (`type`, *optional*, defaults to `default_value`):
|
||||
A concise description for custom_parameter if not defined or overriding the description in `auto_docstring.py`.
|
||||
internal_helper_arg (`type`, *optional*, defaults to `default_value`):
|
||||
A concise description for internal_helper_arg if not defined or overriding the description in `auto_docstring.py`.
|
||||
"""
|
||||
)
|
||||
class MySpecialModel(PreTrainedModel):
|
||||
def __init__(self, config: ConfigType, custom_parameter: "type" = "default_value", internal_helper_arg=None):
|
||||
# ...
|
||||
```
|
||||
|
||||
Also apply `@auto_docstring` to classes that inherit from [`~utils.ModelOutput`].
|
||||
|
||||
```python
|
||||
@auto_docstring(
|
||||
custom_intro="""
|
||||
Custom model outputs with additional fields.
|
||||
"""
|
||||
)
|
||||
@dataclass
|
||||
class MyModelOutput(ImageClassifierOutput):
|
||||
r"""
|
||||
loss (`torch.FloatTensor`, *optional*):
|
||||
The loss of the model.
|
||||
custom_field (`torch.FloatTensor` of shape `(batch_size, hidden_size)`, *optional*):
|
||||
A custom output field specific to this model.
|
||||
"""
|
||||
|
||||
# Standard fields (hidden_states, logits, attentions, etc.) are documented automatically when
|
||||
# the description matches the standard text. Loss typically varies per model, so document it above.
|
||||
loss: Optional[torch.FloatTensor] = None
|
||||
logits: Optional[torch.FloatTensor] = None
|
||||
hidden_states: Optional[tuple[torch.FloatTensor, ...]] = None
|
||||
attentions: Optional[tuple[torch.FloatTensor, ...]] = None
|
||||
# Custom fields need to be documented in the docstring above
|
||||
custom_field: Optional[torch.FloatTensor] = None
|
||||
```
|
||||
|
||||
### Config classes
|
||||
|
||||
Place `@auto_docstring` directly above a [`PreTrainedConfig`] subclass, alongside the `@strict` decorator. `@strict` adds runtime type validation and turns the class into a validated dataclass. Config parameters are *class-level annotations* (not `__init__` arguments), and `@auto_docstring` reads them from the class body to generate docs.
|
||||
|
||||
[`ConfigArgs`] provides standard parameters like `vocab_size`, `hidden_size`, and `num_hidden_layers`, so they don't need a description unless the behavior differs. [`PreTrainedConfig`] base parameters are excluded automatically. The `checkpoint` argument generates the usage example.
|
||||
|
||||
```python
|
||||
from huggingface_hub.dataclasses import strict
|
||||
from ...configuration_utils import PreTrainedConfig
|
||||
from ...utils import auto_docstring
|
||||
|
||||
@strict
|
||||
@auto_docstring(checkpoint="org/my-model-checkpoint")
|
||||
class MyModelConfig(PreTrainedConfig):
|
||||
r"""
|
||||
custom_param (`int`, *optional*, defaults to 64):
|
||||
Description of a parameter specific to this model.
|
||||
another_param (`str`, *optional*, defaults to `"gelu"`):
|
||||
Description of another model-specific parameter.
|
||||
|
||||
```python
|
||||
>>> from transformers import MyModelConfig, MyModel
|
||||
|
||||
>>> configuration = MyModelConfig()
|
||||
>>> model = MyModel(configuration)
|
||||
>>> configuration = model.config
|
||||
```
|
||||
"""
|
||||
|
||||
model_type = "my_model"
|
||||
|
||||
# Standard params (vocab_size, hidden_size, etc.) are auto-documented from ConfigArgs.
|
||||
vocab_size: int = 32000
|
||||
hidden_size: int = 768
|
||||
num_hidden_layers: int = 12
|
||||
# Model-specific params must be documented in the class docstring above.
|
||||
custom_param: int = 64
|
||||
another_param: str = "gelu"
|
||||
```
|
||||
|
||||
### Processor classes
|
||||
|
||||
Multimodal processors ([`ProcessorMixin`] subclasses, `processing_*.py`) always use the bare `@auto_docstring`. The class intro is auto-generated. Document only `__init__` parameters not already covered by [`ProcessorArgs`] (`image_processor`, `tokenizer`, `chat_template`, and others).
|
||||
|
||||
If every parameter is standard, omit the docstring. Decorate `__call__` with `@auto_docstring` too. Its body docstring holds only a `Returns:` section plus any extra model-specific call arguments. `return_tensors` is appended automatically.
|
||||
|
||||
```python
|
||||
from ...processing_utils import ProcessorMixin, ProcessingKwargs, Unpack
|
||||
from ...utils import auto_docstring
|
||||
|
||||
class MyModelProcessorKwargs(ProcessingKwargs, total=False):
|
||||
_defaults = {"text_kwargs": {"padding": False}}
|
||||
|
||||
@auto_docstring
|
||||
class MyModelProcessor(ProcessorMixin):
|
||||
def __init__(self, image_processor=None, tokenizer=None, custom_param: int = 4, **kwargs):
|
||||
r"""
|
||||
custom_param (`int`, *optional*, defaults to 4):
|
||||
A parameter specific to this processor not covered by the standard ProcessorArgs.
|
||||
"""
|
||||
super().__init__(image_processor, tokenizer)
|
||||
self.custom_param = custom_param
|
||||
|
||||
@auto_docstring
|
||||
def __call__(self, images=None, text=None, **kwargs: Unpack[MyModelProcessorKwargs]):
|
||||
r"""
|
||||
Returns:
|
||||
[`BatchFeature`]: A [`BatchFeature`] with the following fields:
|
||||
|
||||
- **input_ids** -- Token ids to be fed to the model.
|
||||
- **pixel_values** -- Pixel values to be fed to the model.
|
||||
"""
|
||||
# ...
|
||||
```
|
||||
|
||||
#### Image and video processors
|
||||
|
||||
Image and video processors (`BaseImageProcessor` subclasses, `image_processing_*.py`) follow one of two patterns.
|
||||
|
||||
If the processor has model-specific parameters, define a `XxxImageProcessorKwargs(ImagesKwargs, total=False)` TypedDict with a docstring for those parameters, set `valid_kwargs` on the class, and use the bare `@auto_docstring`. The `__init__` has no docstring.
|
||||
|
||||
```python
|
||||
class MyModelImageProcessorKwargs(ImagesKwargs, total=False):
|
||||
r"""
|
||||
custom_threshold (`float`, *optional*, defaults to `self.custom_threshold`):
|
||||
A parameter specific to this image processor.
|
||||
"""
|
||||
custom_threshold: float | None
|
||||
|
||||
@auto_docstring
|
||||
class MyModelImageProcessor(TorchvisionBackend):
|
||||
valid_kwargs = MyModelImageProcessorKwargs
|
||||
custom_threshold: float = 0.5
|
||||
|
||||
def __init__(self, **kwargs: Unpack[MyModelImageProcessorKwargs]):
|
||||
super().__init__(**kwargs)
|
||||
```
|
||||
|
||||
If the class only sets standard class-level attributes (`size`, `resample`, `image_mean`, etc.) with no custom kwargs, use `@auto_docstring(custom_intro="Constructs a MyModel image processor.")` instead.
|
||||
|
||||
```python
|
||||
@auto_docstring(custom_intro="Constructs a MyModel image processor.")
|
||||
class MyModelImageProcessor(TorchvisionBackend):
|
||||
resample = PILImageResampling.BICUBIC
|
||||
image_mean = IMAGENET_STANDARD_MEAN
|
||||
image_std = IMAGENET_STANDARD_STD
|
||||
size = {"height": 224, "width": 224}
|
||||
```
|
||||
|
||||
When overriding `preprocess`, decorate it with `@auto_docstring` and document only arguments not in [`ImageProcessorArgs`]. Standard arguments and `return_tensors` are included automatically.
|
||||
|
||||
### Functions
|
||||
|
||||
Place `@auto_docstring` directly above the function definition. The decorator derives parameter descriptions from the function signature.
|
||||
|
||||
The decorator generates return-value text from the [`ModelOutput`] class docstring.
|
||||
|
||||
```python
|
||||
class MyModel(PreTrainedModel):
|
||||
# ...
|
||||
@auto_docstring
|
||||
def forward(
|
||||
self,
|
||||
input_ids: Optional[torch.Tensor] = None,
|
||||
attention_mask: Optional[torch.Tensor] = None,
|
||||
new_custom_argument: Optional[torch.Tensor] = None,
|
||||
# ... other arguments
|
||||
) -> Union[Tuple, ModelOutput]:
|
||||
r"""
|
||||
new_custom_argument (`torch.Tensor`, *optional*):
|
||||
Description of this new custom argument and its expected shape or type.
|
||||
"""
|
||||
# ...
|
||||
```
|
||||
|
||||
Pass `custom_intro` and `custom_args` for more control. Use `custom_args` to define shared argument docs once when the same parameters appear in several methods.
|
||||
|
||||
```python
|
||||
MODEL_COMMON_CUSTOM_ARGS = r"""
|
||||
common_arg_1 (`torch.Tensor`, *optional*, defaults to `default_value`):
|
||||
Description of common_arg_1
|
||||
common_arg_2 (`torch.Tensor`, *optional*, defaults to `default_value`):
|
||||
Description of common_arg_2
|
||||
"""
|
||||
|
||||
class MyModel(PreTrainedModel):
|
||||
# ...
|
||||
@auto_docstring(
|
||||
custom_intro="""This is a custom introduction for the function.""",
|
||||
custom_args=MODEL_COMMON_CUSTOM_ARGS
|
||||
)
|
||||
def forward(self, input_ids=None, common_arg_1=None, common_arg_2=None) -> ModelOutput:
|
||||
r"""method-specific args go here"""
|
||||
# ...
|
||||
```
|
||||
|
||||
Write `Returns` and `Examples` sections manually in the docstring to override the auto-generated versions.
|
||||
|
||||
```python
|
||||
def forward(self, input_ids=None) -> torch.Tensor:
|
||||
r"""
|
||||
Returns:
|
||||
`torch.Tensor`: A custom Returns section for non-ModelOutput return types.
|
||||
|
||||
Example:
|
||||
|
||||
```python
|
||||
>>> model = MyModel.from_pretrained("org/my-model")
|
||||
>>> output = model(input_ids)
|
||||
```
|
||||
"""
|
||||
# ...
|
||||
```
|
||||
|
||||
### Documenting arguments
|
||||
|
||||
Follow these rules when documenting different argument types.
|
||||
|
||||
- `auto_docstring.py` defines standard arguments (`input_ids`, `attention_mask`, `pixel_values`, etc.) and includes them automatically. Don't redefine them locally unless the argument behaves differently in your model.
|
||||
|
||||
If a standard argument behaves differently in your model, override it locally in a `r""" """` block. The local definition takes priority. The `labels` argument, for instance, is commonly customized per model and often needs an override.
|
||||
|
||||
- Standard config arguments (`vocab_size`, `hidden_size`, `num_hidden_layers`, etc.) follow the same principle but come from [`ConfigArgs`]. Standard processor arguments (`image_processor`, `tokenizer`, `do_resize`, `return_tensors`, etc.) come from [`ProcessorArgs`] and [`ImageProcessorArgs`]. Only document a parameter if it is model-specific or behaves differently from the standard description.
|
||||
|
||||
- Document new or custom arguments in an `r""" """` block. Place them after the signature for functions, in the `__init__` docstring for model or processor classes, in the class body docstring for config classes, or in the `XxxImageProcessorKwargs` TypedDict body for image processors.
|
||||
|
||||
```py
|
||||
argument_name (`type`, *optional*, defaults to `X`):
|
||||
Description of the argument.
|
||||
Explain its purpose, expected shape/type if complex, and default behavior.
|
||||
This can span multiple lines.
|
||||
```
|
||||
|
||||
* Include `type` in backticks.
|
||||
* Add *optional* if the argument is not required or has a default value.
|
||||
* Add "defaults to X" if it has a default value. You don't need to add "defaults to `None`" if the default value is `None`.
|
||||
* Pass the same block into `custom_args` when the same arguments repeat across several methods (see the [Functions example above](#functions)).
|
||||
|
||||
- The decorator extracts types from function signatures automatically. If a parameter has a type annotation, you don't need to repeat the type in the docstring format string. When both are present, the signature type takes precedence. The docstring type acts as a fallback for unannotated parameters.
|
||||
|
||||
## Checking the docstrings
|
||||
|
||||
A utility script validates docstrings when you open a pull request. CI runs the script and checks the following.
|
||||
|
||||
> [!TIP]
|
||||
> If you see an `[ERROR]` in the output, add the parameter's description to the docstring or the appropriate Args class in `auto_docstring.py`.
|
||||
|
||||
* Checks that `@auto_docstring` is applied to relevant model classes and public methods.
|
||||
* Validates argument completeness and consistency: documented arguments must exist in the signature, and types and default values must match. Unknown arguments without a local description are flagged.
|
||||
* Flags incomplete placeholders like `<fill_type>` and `<fill_docstring>`.
|
||||
* Verifies docstrings follow the expected formatting style.
|
||||
|
||||
Run the check locally before committing.
|
||||
|
||||
```bash
|
||||
make fix-repo
|
||||
```
|
||||
|
||||
`make fix-repo` runs several other checks too. To run only the docstring and auto-docstring checks, use the command below.
|
||||
|
||||
```bash
|
||||
# to only check files included in the diff without fixing them
|
||||
python utils/check_docstrings.py
|
||||
# to fix and overwrite the files in the diff
|
||||
# python utils/check_docstrings.py --fix_and_overwrite
|
||||
# to fix and overwrite all files
|
||||
# python utils/check_docstrings.py --fix_and_overwrite --check_all
|
||||
```
|
||||
|
||||
## Quick-reference checklist
|
||||
|
||||
| Do | Don't |
|
||||
|---|---|
|
||||
| Apply `@auto_docstring` to model, config, and processor classes and their primary methods (`forward`, `__call__`, `preprocess`). | Add `@auto_docstring` to inherited models in modular files because it carries over automatically. |
|
||||
| Document only new or model-specific arguments. | Redefine standard arguments (`input_ids`, `attention_mask`, `vocab_size`, etc.) that behave the same as their default descriptions. |
|
||||
| Put config parameters in the class body docstring as class-level annotations. | Put config parameters in `__init__`. |
|
||||
| Put image processor parameters in a `XxxImageProcessorKwargs` TypedDict. | Put image processor parameters in `__init__`. |
|
||||
| Run `python utils/check_docstrings.py --fix_and_overwrite` before committing. | Ignore `[ERROR]` output because it means a parameter is undocumented. |
|
||||
|
||||
## How it works
|
||||
|
||||
The `@auto_docstring` decorator generates docstrings through the following steps.
|
||||
|
||||
1. The decorator inspects the signature to read arguments, types, and defaults from the decorated class's `__init__` or the decorated function. For config classes, it walks class-level annotations up the inheritance chain and stops before [`PreTrainedConfig`], excluding base class fields.
|
||||
|
||||
It automatically filters out parameters like `self`, `kwargs`, `args`, `deprecated_arguments`, and `_`-prefixed names. A few private parameters are renamed to their public equivalents (`_out_features` → `out_features` for backbone models).
|
||||
|
||||
2. Common argument descriptions come from `auto_docstring.py`: [`ModelArgs`] (model inputs), [`ModelOutputArgs`] (output fields like `hidden_states`), [`ImageProcessorArgs`] (image preprocessing), [`ProcessorArgs`] (multimodal processor components), and [`ConfigArgs`] (config hyperparameters).
|
||||
|
||||
3. Each parameter's description follows this priority chain:
|
||||
|
||||
- A manual docstring (`r""" """` block or `custom_args`) takes priority.
|
||||
- The predefined source dict ([`ModelArgs`], [`ConfigArgs`], [`ImageProcessorArgs`], [`ProcessorArgs`], [`ModelOutputArgs`]) is the fallback.
|
||||
- If neither source has a description, the parameter is flagged with `[ERROR]` in the build output.
|
||||
|
||||
4. For model classes with standard names like `ModelForCausalLM`, or classes that map to a pipeline, `@auto_docstring` generates the intro. For multimodal processors, the intro lists which components (tokenizer, image processor, and so on) the class wraps. See [ClassDocstring](https://github.com/huggingface/transformers/blob/main/src/transformers/utils/auto_docstring.py#L2437) for the full list.
|
||||
|
||||
If the class name isn't in `ClassDocstring`, set `custom_intro`.
|
||||
|
||||
5. Predefined docstrings can reference dynamic values from Transformers' [auto_modules](https://github.com/huggingface/transformers/tree/main/src/transformers/models/auto), such as `{processor_class}`, `{image_processor_class}`, and `{config_class}`. The placeholders resolve automatically.
|
||||
|
||||
6. The decorator picks usage examples based on the model's task or pipeline compatibility. It reads checkpoint metadata from the configuration class so examples use real model IDs. The `checkpoint` argument overrides the checkpoint inferred from the config class's docstring. Set `checkpoint` on config classes, or when checkpoint inference fails. If you see an error like `"Config not found for <model_name>"`, add an entry to `HARDCODED_CONFIG_FOR_MODELS` in `auto_docstring.py`.
|
||||
|
||||
7. For methods like `forward`, the decorator writes the `Returns` section from the method's return type. When the return type is a [`~transformers.utils.ModelOutput`] subclass, `@auto_docstring` pulls field descriptions from that class's docstring. A custom `Returns` block in the function's docstring takes precedence.
|
||||
|
||||
8. For methods in `UNROLL_KWARGS_METHODS` and classes in `UNROLL_KWARGS_CLASSES`, the decorator expands `**kwargs` typed with `Unpack[KwargsTypedDict]`. Each key from the `TypedDict` becomes a documented parameter.
|
||||
|
||||
The same expansion applies to `__call__` and `preprocess` methods on [`BaseImageProcessor`] and [`ProcessorMixin`] subclasses. Generic base types (`TextKwargs`, `ImagesKwargs`, `VideosKwargs`, `AudioKwargs`) are skipped. Only model-specific subclasses are unrolled.
|
||||
@@ -0,0 +1,155 @@
|
||||
<!--Copyright 2024 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Backbones
|
||||
|
||||
Higher-level computer visions tasks, such as object detection or image segmentation, use several models together to generate a prediction. A separate model is used for the *backbone*, neck, and head. The backbone extracts useful features from an input image into a feature map, the neck combines and processes the feature maps, and the head uses them to make a prediction.
|
||||
|
||||
<div class="flex justify-center">
|
||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/Backbone.png"/>
|
||||
</div>
|
||||
|
||||
Load a backbone with [`~PreTrainedConfig.from_pretrained`] and use the `out_indices` parameter to determine which layer, given by the index, to extract a feature map from.
|
||||
|
||||
```py
|
||||
from transformers import AutoBackbone
|
||||
|
||||
model = AutoBackbone.from_pretrained("microsoft/swin-tiny-patch4-window7-224", out_indices=(1,))
|
||||
```
|
||||
|
||||
This guide describes the backbone class, backbones from the [timm](https://hf.co/docs/timm/index) library, and how to extract features with them.
|
||||
|
||||
## Backbone classes
|
||||
|
||||
There are two backbone classes.
|
||||
|
||||
- [`~transformers.utils.BackboneMixin`] allows you to load a backbone and includes functions for extracting the feature maps and indices from config.
|
||||
- [`~transformers.utils.BackboneConfigMixin`] allows you to set, align and verify the feature map and indices of a backbone configuration.
|
||||
|
||||
Refer to the [Backbone](./main_classes/backbones) API documentation to check which models support a backbone.
|
||||
|
||||
There are two ways to load a Transformers backbone, [`AutoBackbone`] and a model-specific backbone class.
|
||||
|
||||
<hfoptions id="backbone-classes">
|
||||
<hfoption id="AutoBackbone">
|
||||
|
||||
The [AutoClass](./model_doc/auto) API automatically loads a pretrained vision model with [`~PreTrainedConfig.from_pretrained`] as a backbone if it's supported.
|
||||
|
||||
Set the `out_indices` parameter to the layer you'd like to get the feature map from. If you know the name of the layer, you could also use `out_features`. These parameters can be used interchangeably, but if you use both, make sure they refer to the same layer.
|
||||
|
||||
When `out_indices` or `out_features` isn't used, the backbone returns the feature map from the last layer. The example code below uses `out_indices=(1,)` to get the feature map from the first layer.
|
||||
|
||||
<div class="flex justify-center">
|
||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/Swin%20Stage%201.png"/>
|
||||
</div>
|
||||
|
||||
```py
|
||||
from transformers import AutoImageProcessor, AutoBackbone
|
||||
|
||||
model = AutoBackbone.from_pretrained("microsoft/swin-tiny-patch4-window7-224", out_indices=(1,))
|
||||
```
|
||||
|
||||
</hfoption>
|
||||
<hfoption id="model-specific backbone">
|
||||
|
||||
When you know a model supports a backbone, you can load the backbone and neck directly into the models configuration. Pass the configuration to the model to initialize it for a task.
|
||||
|
||||
The example below loads a [ResNet](./model_doc/resnet) backbone and neck for use in a [MaskFormer](./model_doc/maskformer) instance segmentation head.
|
||||
|
||||
Note that initializing from config will create the model with random weights. If you want to load a pretrained model, use `from_pretrained` API.
|
||||
|
||||
```py
|
||||
from transformers import MaskFormerConfig, MaskFormerForInstanceSegmentation
|
||||
|
||||
backbone_config = AutoConfig.from_pretrained("microsoft/resnet-50")
|
||||
config = MaskFormerConfig(backbone_config=backbone_config)
|
||||
model = MaskFormerForInstanceSegmentation(config)
|
||||
```
|
||||
|
||||
Another option is to separately load the backbone configuration and then pass it to `backbone_config` in the model configuration.
|
||||
|
||||
```py
|
||||
from transformers import MaskFormerConfig, MaskFormerForInstanceSegmentation, ResNetConfig
|
||||
|
||||
# instantiate backbone configuration
|
||||
backbone_config = ResNetConfig()
|
||||
# load backbone in model
|
||||
config = MaskFormerConfig(backbone_config=backbone_config)
|
||||
# attach backbone to model head
|
||||
model = MaskFormerForInstanceSegmentation(config)
|
||||
```
|
||||
|
||||
</hfoption>
|
||||
</hfoptions>
|
||||
|
||||
## timm backbones
|
||||
|
||||
[timm](https://hf.co/docs/timm/index) is a collection of vision models for training and inference. Transformers supports timm models as backbones with the [`TimmBackbone`] and [`TimmBackboneConfig`] classes. Set the necessary backbone checkpoint in `backbone` to create a model with Timm backbone with randomly initialized weights.
|
||||
|
||||
```py
|
||||
from transformers import MaskFormerConfig, MaskFormerForInstanceSegmentation
|
||||
|
||||
backbone_config = TimmBackboneConfig(backbone="resnet50", out_indices=[-1])
|
||||
config = MaskFormerConfig(backbone_config=backbone_config)
|
||||
model = MaskFormerForInstanceSegmentation(config)
|
||||
```
|
||||
|
||||
You could also explicitly call the [`TimmBackboneConfig`] class to load and create a pretrained timm backbone.
|
||||
|
||||
```py
|
||||
from transformers import TimmBackboneConfig
|
||||
|
||||
backbone_config = TimmBackboneConfig("resnet50")
|
||||
```
|
||||
|
||||
Pass the backbone configuration to the model configuration and instantiate the model head, [`MaskFormerForInstanceSegmentation`], with the backbone.
|
||||
|
||||
```py
|
||||
from transformers import MaskFormerConfig, MaskFormerForInstanceSegmentation
|
||||
|
||||
config = MaskFormerConfig(backbone_config=backbone_config)
|
||||
model = MaskFormerForInstanceSegmentation(config)
|
||||
```
|
||||
|
||||
## Feature extraction
|
||||
|
||||
The backbone is used to extract image features. Pass an image through the backbone to get the feature maps.
|
||||
|
||||
Load and preprocess an image and pass it to the backbone. The example below extracts the feature maps from the first layer.
|
||||
|
||||
```py
|
||||
from transformers import AutoImageProcessor, AutoBackbone
|
||||
import torch
|
||||
from PIL import Image
|
||||
import requests
|
||||
|
||||
model = AutoBackbone.from_pretrained("microsoft/swin-tiny-patch4-window7-224", out_indices=(1,))
|
||||
processor = AutoImageProcessor.from_pretrained("microsoft/swin-tiny-patch4-window7-224")
|
||||
|
||||
url = "http://images.cocodataset.org/val2017/000000039769.jpg"
|
||||
image = Image.open(requests.get(url, stream=True).raw)
|
||||
|
||||
inputs = processor(image, return_tensors="pt")
|
||||
outputs = model(**inputs)
|
||||
```
|
||||
|
||||
The features are stored and accessed from the outputs `feature_maps` attribute.
|
||||
|
||||
```py
|
||||
feature_maps = outputs.feature_maps
|
||||
list(feature_maps[0].shape)
|
||||
[1, 96, 56, 56]
|
||||
```
|
||||
@@ -0,0 +1,128 @@
|
||||
<!--Copyright 2024 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contains specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Caching
|
||||
|
||||
Imagine you're having a conversation with someone, and instead of remembering what they previously said, they have to start from scratch every time you respond. This would be slow and inefficient, right?
|
||||
|
||||
You can extend this analogy to transformer models. Autoregressive model generation can be slow because it makes a prediction one token at a time. Each new prediction is dependent on all the previous context.
|
||||
|
||||
To predict the 1000th token, the model requires information from the previous 999 tokens. The information is represented as matrix multiplications across the token representations.
|
||||
|
||||
To predict the 1001th token, you need the same information from the previous 999 tokens in addition to any information from the 1000th token. This is a lot of matrix multiplications a model has to compute over and over for each token!
|
||||
|
||||
A key-value (KV) cache eliminates this inefficiency by storing kv pairs derived from the attention layers of previously processed tokens. The stored kv pairs are retrieved from the cache and reused for subsequent tokens, avoiding the need to recompute.
|
||||
|
||||
> [!WARNING]
|
||||
> Caching should only be used for **inference**. It may cause unexpected errors if it's enabled during training.
|
||||
|
||||
To better understand how and why caching works, let's take a closer look at the structure of the attention matrices.
|
||||
|
||||
## Attention matrices
|
||||
|
||||
The **scaled dot-product attention** is calculated as shown below for a batch of size `b`, number of attention heads `h`, sequence length so far `T`, and dimension per attention head `d_head`.
|
||||
|
||||
$$
|
||||
\text{Attention}(Q, K, V) = \text{softmax}\left( \frac{Q K^\top}{\sqrt{d_{\text{head}}}} \times \text{mask} \right) V
|
||||
$$
|
||||
|
||||
The query (`Q`), key (`K`), and value (`V`) matrices are projections from the input embeddings of shape `(b, h, T, d_head)`.
|
||||
|
||||
For causal attention, the mask prevents the model from attending to future tokens. Once a token is processed, its representation never changes with respect to future tokens, which means $ K_{\text{past}} $ and $ V_{\text{past}} $ can be cached and reused to compute the last token's representation.
|
||||
|
||||
$$
|
||||
\text{Attention}(q_t, [\underbrace{k_1, k_2, \dots, k_{t-1}}_{\text{cached}}, k_{t}], [\underbrace{v_1, v_2, \dots, v_{t-1}}_{\text{cached}}, v_{t}])
|
||||
$$
|
||||
|
||||
At inference time, you only need the last token's query to compute the representation $ x_t $ that predicts the next token $ t+1 $. At each step, the new key and value vectors are **stored** in the cache and **appended** to the past keys and values.
|
||||
|
||||
$$
|
||||
K_{\text{cache}} \leftarrow \text{concat}(K_{\text{past}}, k_t), \quad V_{\text{cache}} \leftarrow \text{concat}(V_{\text{past}}, v_t)
|
||||
$$
|
||||
|
||||
Attention is calculated independently in each layer of the model, and caching is done on a per-layer basis.
|
||||
|
||||
Refer to the table below to compare how caching improves efficiency.
|
||||
|
||||
| without caching | with caching |
|
||||
|---|---|
|
||||
| for each step, recompute all previous `K` and `V` | for each step, only compute current `K` and `V` |
|
||||
| attention cost per step is **quadratic** with sequence length | attention cost per step is **linear** with sequence length (memory grows linearly, but compute/token remains low) |
|
||||
|
||||
## Cache class
|
||||
|
||||
A basic KV cache interface takes a key and value tensor for the current token and returns the updated `K` and `V` tensors. This is internally managed by a model's `forward` method.
|
||||
|
||||
```py
|
||||
new_K, new_V = cache.update(k_t, v_t, layer_idx)
|
||||
attn_output = attn_layer_idx_fn(q_t, new_K, new_V)
|
||||
```
|
||||
|
||||
When you use Transformers' [`Cache`] class, the self-attention module performs several critical steps to integrate past and present information.
|
||||
|
||||
1. The attention module concatenates current kv pairs with past kv pairs stored in the cache. This creates attentions weights with the shape `(new_tokens_length, past_kv_length + new_tokens_length)`. The current and past kv pairs are essentially combined to compute the attention scores, ensuring a model is aware of previous context and the current input.
|
||||
|
||||
2. When the `forward` method is called iteratively, it's crucial that the attention mask shape matches the combined length of the past and current kv pairs. The attention mask should have the shape `(batch_size, past_kv_length + new_tokens_length)`. This is typically handled internally in [`~GenerationMixin.generate`], but if you want to implement your own generation loop with [`Cache`], keep this in mind! The attention mask should hold the past and current token values.
|
||||
|
||||
## Cache storage implementation
|
||||
|
||||
Caches are structured as a list of layers, where each layer contains a key and value cache. The key and value caches are tensors with the shape `[batch_size, num_heads, seq_len, head_dim]`.
|
||||
|
||||
Layers can be of different types (e.g. `DynamicLayer`, `StaticLayer`, `StaticSlidingWindowLayer`), which mostly changes how sequence length is handled and how the cache is updated.
|
||||
|
||||
The simplest is a `DynamicLayer` that grows as more tokens are processed. The sequence length dimension (`seq_len`) increases with each new token:
|
||||
|
||||
```py
|
||||
cache.layers[idx].keys = torch.cat([cache.layers[idx].keys, key_states], dim=-2)
|
||||
cache.layers[idx].values = torch.cat([cache.layers[idx].values, value_states], dim=-2)
|
||||
```
|
||||
|
||||
Other layer types like `StaticLayer` and `StaticSlidingWindowLayer` have a fixed sequence length that is set when the cache is created. This makes them compatible with `torch.compile`. In the case of `StaticSlidingWindowLayer`, existing tokens are shifted out of the cache when a new token is added.
|
||||
|
||||
The example below demonstrates how to create a generation loop with [`DynamicCache`]. As discussed, the attention mask is a concatenation of past and current token values.
|
||||
|
||||
```py
|
||||
import torch
|
||||
from transformers import AutoTokenizer, AutoModelForCausalLM, DynamicCache
|
||||
from accelerate import Accelerator
|
||||
|
||||
device = Accelerator().device
|
||||
|
||||
model_id = "meta-llama/Llama-2-7b-chat-hf"
|
||||
model = AutoModelForCausalLM.from_pretrained(model_id, dtype=torch.bfloat16, device_map=device)
|
||||
tokenizer = AutoTokenizer.from_pretrained(model_id)
|
||||
|
||||
past_key_values = DynamicCache(config=model.config)
|
||||
messages = [{"role": "user", "content": "Hello, what's your name."}]
|
||||
inputs = tokenizer.apply_chat_template(messages, add_generation_prompt=True, return_tensors="pt", return_dict=True).to(model.device)
|
||||
|
||||
generated_ids = inputs.input_ids
|
||||
max_new_tokens = 10
|
||||
|
||||
for _ in range(max_new_tokens):
|
||||
outputs = model(**inputs, past_key_values=past_key_values, use_cache=True)
|
||||
# Greedily sample one next token
|
||||
next_token_ids = outputs.logits[:, -1:].argmax(-1)
|
||||
generated_ids = torch.cat([generated_ids, next_token_ids], dim=-1)
|
||||
# Prepare inputs for the next generation step by leaving unprocessed tokens, in our case we have only one new token
|
||||
# and expanding attn mask for the new token, as explained above
|
||||
attention_mask = inputs["attention_mask"]
|
||||
attention_mask = torch.cat([attention_mask, attention_mask.new_ones((attention_mask.shape[0], 1))], dim=-1)
|
||||
inputs = {"input_ids": next_token_ids, "attention_mask": attention_mask}
|
||||
|
||||
print(tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0])
|
||||
"[INST] Hello, what's your name. [/INST] Hello! My name is LLaMA,"
|
||||
```
|
||||
@@ -0,0 +1,198 @@
|
||||
<!--Copyright 2025 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Chat message patterns
|
||||
|
||||
Chat models expect conversations as a list of dictionaries. Each dictionary uses `role` and `content` keys. The `content` key holds the user message passed to the model. Large language models accept text and tools and multimodal models combine text with images, videos, and audio.
|
||||
|
||||
Transformers uses a unified format where each modality type is specified explicitly, making it straightforward to mix and match inputs in a single message.
|
||||
|
||||
This guide covers message formatting patterns for each modality, tools, batch inference, and multi-turn conversations.
|
||||
|
||||
## Text
|
||||
|
||||
Text is the most basic content type. It's the foundation for all other patterns. Pass your message to `"content"` as a string.
|
||||
|
||||
```py
|
||||
message = [
|
||||
{
|
||||
"role": "user",
|
||||
"content": "Explain the French Bread Law."
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
You could also use the explicit `"type": "text"` format to keep your code consistent when you add images, videos, or audio later.
|
||||
|
||||
```py
|
||||
message = [
|
||||
{
|
||||
"role": "user",
|
||||
"content": [{"type": "text", "text": "Explain the French Bread Law."}]
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
## Tools
|
||||
|
||||
[Tools](./chat_extras) are functions a chat model can call, like getting real-time weather data, instead of generating it on its own.
|
||||
|
||||
The `assistant` role handles the tool request. Set `"type": "function"` in the `"tool_calls"` key and provide your tool to the `"function"` key. Append the assistant's tool request to your message.
|
||||
|
||||
```py
|
||||
weather = {"name": "get_current_temperature", "arguments": {"location": "Paris, France", "unit": "celsius"}}
|
||||
message.append(
|
||||
{
|
||||
"role": "assistant",
|
||||
"tool_calls": [{"type": "function", "function": weather}]
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
The `tool` role handles the result. Append it in `"content"`. This value should always be a string.
|
||||
|
||||
```py
|
||||
message.append({"role": "tool", "content": "22"})
|
||||
```
|
||||
|
||||
## Multimodal
|
||||
|
||||
Multimodal models extend this format to handle images, videos, and audio. Each input specifies its `"type"` and provides the media with `"url"` or `"path"`.
|
||||
|
||||
### Image
|
||||
|
||||
Set `"type": "image"` and use `"url"` for links or `"path"` for local files.
|
||||
|
||||
```py
|
||||
message = [
|
||||
{
|
||||
"role": "user",
|
||||
"content": [
|
||||
{"type": "image", "url": "https://assets.bonappetit.com/photos/57ad4ebc53e63daf11a4ddc7/master/w_1280,c_limit/kouign-amann.jpg"},
|
||||
{"type": "text", "text": "What pastry is shown in the image?"}
|
||||
]
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
### Video
|
||||
|
||||
Set `"type": "video"` and use `"url"` for links or `"path"` for local files.
|
||||
|
||||
```py
|
||||
message = [
|
||||
{
|
||||
"role": "user",
|
||||
"content": [
|
||||
{"type": "video", "url": "https://static01.nyt.com/images/2019/10/01/dining/01Sourdough-GIF-1/01Sourdough-GIF-1-superJumbo.gif"},
|
||||
{"type": "text", "text": "What is shown in this video?"}
|
||||
]
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
### Audio
|
||||
|
||||
Set `"type": "audio"` and use `"url"` for links or `"path"` for local files.
|
||||
|
||||
```py
|
||||
message = [
|
||||
{
|
||||
"role": "user",
|
||||
"content": [
|
||||
{"type": "audio", "url": "https://huggingface.co/datasets/Narsil/asr_dummy/resolve/main/mlk.flac"},
|
||||
{"type": "text", "text": "Transcribe the speech."}
|
||||
]
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
### Mixed multiple
|
||||
|
||||
The `content` list accepts any combination of types. The model processes all inputs together, enabling comparisons or cross-modal reasoning.
|
||||
|
||||
```py
|
||||
message = [
|
||||
{
|
||||
"role": "user",
|
||||
"content": [
|
||||
{"type": "image", "url": "https://assets.bonappetit.com/photos/57ad4ebc53e63daf11a4ddc7/master/w_1280,c_limit/kouign-amann.jpg"},
|
||||
{"type": "video", "url": "https://static01.nyt.com/images/2019/10/01/dining/01Sourdough-GIF-1/01Sourdough-GIF-1-superJumbo.gif"},
|
||||
{"type": "text", "text": "What does the image and video share in common?"},
|
||||
],
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": [
|
||||
{"type": "image", "url": "https://assets.bonappetit.com/photos/57ad4ebc53e63daf11a4ddc7/master/w_1280,c_limit/kouign-amann.jpg"},
|
||||
{"type": "image", "url": "https://assets.bonappetit.com/photos/57e191f49f19b4610e6b7693/master/w_1600%2Cc_limit/undefined"},
|
||||
{"type": "text", "text": "What type of pastries are these?"},
|
||||
],
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
## Batched
|
||||
|
||||
Batched inference processes multiple conversations in a single forward pass to improve throughput and efficiency. Wrap each conversation in its own list, then pass them together as a list of lists.
|
||||
|
||||
```py
|
||||
messages = [
|
||||
[
|
||||
{"role": "user",
|
||||
"content": [
|
||||
{"type": "image", "url": "https://assets.bonappetit.com/photos/57ad4ebc53e63daf11a4ddc7/master/w_1280,c_limit/kouign-amann.jpg"},
|
||||
{"type": "text", "text": "What type of pastry is this?"}
|
||||
]
|
||||
},
|
||||
],
|
||||
[
|
||||
{"role": "user",
|
||||
"content": [
|
||||
{"type": "image", "url": "https://assets.bonappetit.com/photos/57e191f49f19b4610e6b7693/master/w_1600%2Cc_limit/undefined"},
|
||||
{"type": "text", "text": "What type of pastry is this?"}
|
||||
]
|
||||
},
|
||||
],
|
||||
]
|
||||
```
|
||||
|
||||
## Multi-turn
|
||||
|
||||
Conversations span multiple exchanges, alternating between `"user"` and `"assistant"` roles. Each turn adds a new message to the list, giving the model access to the full conversation history. This context helps the model generate more appropriate responses.
|
||||
|
||||
```py
|
||||
message = [
|
||||
{
|
||||
"role": "user",
|
||||
"content": [
|
||||
{"type": "image", "url": "https://assets.bonappetit.com/photos/57ad4ebc53e63daf11a4ddc7/master/w_1280,c_limit/kouign-amann.jpg"},
|
||||
{"type": "text", "text": "What pastry is shown in the image?"}
|
||||
]
|
||||
},
|
||||
{
|
||||
"role": "assistant",
|
||||
"content": [{"type": "text", "text": "This is kouign amann, a laminated dough pastry (i.e., dough folded with layers of butter) that also incorporates sugar between layers so that during baking the sugar caramelizes."}]
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": [
|
||||
{"type": "image", "url": "https://static01.nyt.com/images/2023/07/21/multimedia/21baguettesrex-hbkc/21baguettesrex-hbkc-videoSixteenByNineJumbo1600.jpg"},
|
||||
{"type": "text", "text": "Compare it to this image now."}
|
||||
]
|
||||
}
|
||||
]
|
||||
```
|
||||
@@ -0,0 +1,227 @@
|
||||
<!--Copyright 2024 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Tool use
|
||||
|
||||
Chat models are commonly trained with support for "function-calling" or "tool-use". Tools are functions supplied by the user, which the model can choose to call as part of its response. For example, models could have access to a calculator tool to perform arithmetic without having to perform the computation internally.
|
||||
|
||||
This guide will demonstrate how to define tools, how to pass them to a chat model, and how to handle the model's output when it calls a tool.
|
||||
|
||||
## Passing tools
|
||||
|
||||
When a model supports tool-use, pass functions to the `tools` argument of [`~PreTrainedTokenizerBase.apply_chat_template`].
|
||||
The tools are passed as either a [JSON schema](https://json-schema.org/learn) or Python functions. If you pass Python functions,
|
||||
the arguments, argument types, and function docstring are parsed in order to generate the JSON schema automatically.
|
||||
|
||||
Although passing Python functions is very convenient, the parser can only handle [Google-style](https://google.github.io/styleguide/pyguide.html#38-comments-and-docstrings)
|
||||
docstrings. Refer to the examples below for how to format a tool-ready function.
|
||||
|
||||
```py
|
||||
def get_current_temperature(location: str, unit: str):
|
||||
"""
|
||||
Get the current temperature at a location.
|
||||
|
||||
Args:
|
||||
location: The location to get the temperature for, in the format "City, Country"
|
||||
unit: The unit to return the temperature in. (choices: ["celsius", "fahrenheit"])
|
||||
"""
|
||||
return 22. # A real function should probably actually get the temperature!
|
||||
|
||||
def get_current_wind_speed(location: str):
|
||||
"""
|
||||
Get the current wind speed in km/h at a given location.
|
||||
|
||||
Args:
|
||||
location: The location to get the wind speed for, in the format "City, Country"
|
||||
"""
|
||||
return 6. # A real function should probably actually get the wind speed!
|
||||
|
||||
tools = [get_current_temperature, get_current_wind_speed]
|
||||
```
|
||||
|
||||
You can optionally add a `Returns:` block to the docstring and a return type to the function header, but most models won't use this information. The parser will also ignore the actual code inside the function!
|
||||
|
||||
What really matters is the function name, argument names, argument types, and docstring describing the function's purpose
|
||||
and the purpose of its arguments. These create the "signature" the model will use to decide whether to call the tool.
|
||||
|
||||
## Tool-calling Example
|
||||
|
||||
Load a model and tokenizer that supports tool-use like [NousResearch/Hermes-2-Pro-Llama-3-8B](https://hf.co/NousResearch/Hermes-2-Pro-Llama-3-8B), but you can also consider a larger model like [Command-R](./model_doc/cohere) and [Mixtral-8x22B](./model_doc/mixtral) if your hardware can support it.
|
||||
|
||||
```py
|
||||
import torch
|
||||
from transformers import AutoModelForCausalLM, AutoTokenizer
|
||||
|
||||
checkpoint = "NousResearch/Hermes-2-Pro-Llama-3-8B"
|
||||
tokenizer = AutoTokenizer.from_pretrained(checkpoint)
|
||||
model = AutoModelForCausalLM.from_pretrained(checkpoint, dtype="auto", device_map="auto")
|
||||
```
|
||||
|
||||
Create a chat history.
|
||||
|
||||
```py
|
||||
messages = [
|
||||
{"role": "system", "content": "You are a bot that responds to weather queries. You should reply with the unit used in the queried location."},
|
||||
{"role": "user", "content": "Hey, what's the temperature in Paris right now?"}
|
||||
]
|
||||
```
|
||||
|
||||
Next, pass `messages` and a list of tools to [`~PreTrainedTokenizerBase.apply_chat_template`]. Tokenize the chat and generate a response.
|
||||
|
||||
```py
|
||||
inputs = tokenizer.apply_chat_template(messages, tools=tools, add_generation_prompt=True, return_dict=True, return_tensors="pt")
|
||||
outputs = model.generate(**inputs.to(model.device), max_new_tokens=128)
|
||||
print(tokenizer.decode(outputs[0][len(inputs["input_ids"][0]):]))
|
||||
```
|
||||
|
||||
```txt
|
||||
<tool_call>
|
||||
{"arguments": {"location": "Paris, France", "unit": "celsius"}, "name": "get_current_temperature"}
|
||||
</tool_call><|im_end|>
|
||||
```
|
||||
|
||||
The chat model called the `get_current_temperature` tool with the correct parameters from the docstring. It inferred France as the location based on Paris, and that it should use Celsius for the units of temperature.
|
||||
|
||||
A model **cannot actually call the tool itself**. It requests a tool call, and it's your job to handle the call and append it and the result to the chat history. For
|
||||
models that support [response parsing](./chat_response_parsing), the response parsing will be handled automatically, and you can just use
|
||||
[`~PreTrainedTokenizer.parse_response`] to extract the tool call. For other models, you'll need to manually translate the output
|
||||
string into a tool call dict.
|
||||
|
||||
Regardless of the approach you use, the tool call should go in the `tool_calls` key of an `assistant` message. This is the recommended API, and should be supported by the chat template of most tool-using models.
|
||||
|
||||
> [!WARNING]
|
||||
> Although `tool_calls` is similar to the OpenAI API, the OpenAI API uses a JSON string as its `tool_calls` format. This may cause errors or strange model behavior if used in Transformers, which expects a dict.
|
||||
|
||||
```py
|
||||
tool_call = {"name": "get_current_temperature", "arguments": {"location": "Paris, France", "unit": "celsius"}}
|
||||
messages.append({"role": "assistant", "tool_calls": [{"type": "function", "function": tool_call}]})
|
||||
```
|
||||
|
||||
Append the tool response to the chat history with the `tool` role.
|
||||
|
||||
```py
|
||||
messages.append({"role": "tool", "content": "22"}) # Note that the returned content is always a string!
|
||||
```
|
||||
|
||||
Finally, allow the model to read the tool response and reply to the user.
|
||||
|
||||
```py
|
||||
inputs = tokenizer.apply_chat_template(messages, tools=tools, add_generation_prompt=True, return_dict=True, return_tensors="pt")
|
||||
out = model.generate(**inputs.to(model.device), max_new_tokens=128)
|
||||
print(tokenizer.decode(out[0][len(inputs["input_ids"][0]):]))
|
||||
```
|
||||
|
||||
```txt
|
||||
The temperature in Paris, France right now is 22°C.<|im_end|>
|
||||
```
|
||||
|
||||
> [!WARNING]
|
||||
> Although the key in the assistant message is called `tool_calls`, in most cases, models only emit a single tool call at a time. Some older models emit multiple tool calls at the same time, but this is a
|
||||
> significantly more complex process, as you need to handle multiple tool responses at once and disambiguate them, often using tool call IDs. Please refer to the model card to see exactly what format a model expects for tool calls.
|
||||
|
||||
## JSON schemas
|
||||
|
||||
Another way to define tools is by passing a [JSON schema](https://json-schema.org/learn/getting-started-step-by-step).
|
||||
|
||||
You can also manually call the low-level functions that convert Python functions to JSON schemas, and then check or edit the generated schemas. This is usually not necessary, but is useful for understanding the underlying mechanics. It's particularly important
|
||||
for chat template authors who need to access the JSON schema to render the tool definitions.
|
||||
|
||||
The [`~PreTrainedTokenizerBase.apply_chat_template`] method uses the [get_json_schema](https://github.com/huggingface/transformers/blob/14561209291255e51c55260306c7d00c159381a5/src/transformers/utils/chat_template_utils.py#L205) function to convert Python callables to a JSON schema. This includes methods: `self` and `cls` are treated as implicit receiver arguments and are ignored.
|
||||
|
||||
```py
|
||||
from transformers.utils import get_json_schema
|
||||
|
||||
def multiply(a: float, b: float):
|
||||
"""
|
||||
A function that multiplies two numbers
|
||||
|
||||
Args:
|
||||
a: The first number to multiply
|
||||
b: The second number to multiply
|
||||
"""
|
||||
return a * b
|
||||
|
||||
schema = get_json_schema(multiply)
|
||||
print(schema)
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "multiply",
|
||||
"description": "A function that multiplies two numbers",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"a": {
|
||||
"type": "number",
|
||||
"description": "The first number to multiply"
|
||||
},
|
||||
"b": {
|
||||
"type": "number",
|
||||
"description": "The second number to multiply"
|
||||
}
|
||||
},
|
||||
"required": ["a", "b"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
We won't go into the details of JSON schema itself here, since it's already [very well documented](https://json-schema.org/) elsewhere. We will, however, mention that you can pass JSON schema dicts to the `tools` argument of [`~PreTrainedTokenizerBase.apply_chat_template`] instead of Python functions:
|
||||
|
||||
```py
|
||||
# A simple function that takes no arguments
|
||||
current_time = {
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "current_time",
|
||||
"description": "Get the current local time as a string.",
|
||||
"parameters": {
|
||||
'type': 'object',
|
||||
'properties': {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# A more complete function that takes two numerical arguments
|
||||
multiply = {
|
||||
'type': 'function',
|
||||
'function': {
|
||||
'name': 'multiply',
|
||||
'description': 'A function that multiplies two numbers',
|
||||
'parameters': {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'a': {
|
||||
'type': 'number',
|
||||
'description': 'The first number to multiply'
|
||||
},
|
||||
'b': {
|
||||
'type': 'number', 'description': 'The second number to multiply'
|
||||
}
|
||||
},
|
||||
'required': ['a', 'b']
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
model_input = tokenizer.apply_chat_template(
|
||||
messages,
|
||||
tools = [current_time, multiply]
|
||||
)
|
||||
```
|
||||
@@ -0,0 +1,519 @@
|
||||
<!--Copyright 2026 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Response Parsing
|
||||
|
||||
It is increasingly common for chat models to generate structured outputs, rather than just a single reply string. For example,
|
||||
a [reasoning model](https://huggingface.co/reasoning-course) might emit a chain of thought containing its reasoning trace,
|
||||
while a [tool calling](./chat_extras) model might emit function names and arguments.
|
||||
|
||||
The problem with structured outputs, though, is that LLMs outputs are not inherently structured. LLM APIs usually
|
||||
accept and return message dicts, with keys like `role` and `content` and `thinking`, but internally, LLMs actually
|
||||
just continue a single sequence of tokens. We use a glue layer to connect the user-facing API to the actual token
|
||||
stream of the model. To turn inputs into a token stream, we use [`chat_templates`](./chat_templating), which are covered in other
|
||||
documents. This document is about the other half of that glue layer: **Response templates**, the system for turning the
|
||||
generated tokens output by the model back into a structured response dict.
|
||||
|
||||
In many ways, response templates perform the inverse operation to chat templates. With chat templates, you feed in
|
||||
a list of messages, and you get tokens ready to input to the model. With response templates, you feed in the raw
|
||||
model output tokens, and you get a structured message. Like chat templates, response
|
||||
templates allow users to ignore the messy details of what specific formats and control tokens a model expects,
|
||||
and use a universal API of message dicts that works with any model.
|
||||
|
||||
The best way to understand response templates is to see them in action. The main entry point is the
|
||||
[`~PreTrainedTokenizerBase.parse_response`] method, which accepts either a single sequence or a batch:
|
||||
|
||||
```python
|
||||
from transformers import AutoModelForCausalLM, AutoTokenizer
|
||||
|
||||
checkpoint = "HuggingFaceTB/SmolLM3-3B"
|
||||
tokenizer = AutoTokenizer.from_pretrained(checkpoint)
|
||||
model = AutoModelForCausalLM.from_pretrained(checkpoint, dtype="auto", device_map="auto")
|
||||
|
||||
messages = [{"role": "user", "content": "Summarize the end of the Cold War, very briefly."}]
|
||||
input_ids = tokenizer.apply_chat_template(messages, add_generation_prompt=True, return_tensors="pt")["input_ids"].to(model.device)
|
||||
outputs = model.generate(input_ids, max_new_tokens=1024)[0, input_ids.shape[1]:]
|
||||
out_text = tokenizer.decode(outputs)
|
||||
print(tokenizer.parse_response(out_text, prefix=input_ids[0]))
|
||||
# Outputs a structured dict: {"role": "assistant", "thinking": "...", "content": "..."}
|
||||
```
|
||||
|
||||
When a tokenizer has a `response_template`, the `parse_response` method will cleanly turn an output message into a
|
||||
structured dict, ready to append to the chat. Note that we need to pass the `prefix` (the prompt tokens) to this method as well. This is because many chat templates start
|
||||
messages or open thinking blocks before letting the model begin its response, and so our parser needs to see the
|
||||
prompt to understand the message. All of the prefix before the final turn is discarded; we only parse one message
|
||||
at a time. We just need the prefix to ensure we're seeing the entire final message, and not miss any prefilled
|
||||
fields!
|
||||
|
||||
Because a missing prefix can silently mis-parse a prefilled message, `prefix` is required when parsing with a
|
||||
new-style `response_template`: omitting it raises an error. In the rare case where you are sure the generation
|
||||
already contains the complete message and no prefix context is needed, pass `prefix=""` (or an empty list of
|
||||
token ids) to opt out explicitly.
|
||||
|
||||
If the tokenizer has no response template set, `parse_response` will raise an error. We're working on adding
|
||||
templates to more models as quickly as we can!
|
||||
|
||||
## Streaming response parsing
|
||||
|
||||
In the above example, we parse the model response all at once after generation has finished. Often, though, we may
|
||||
want to parse partial messages as they are generated, especially in user-facing apps where we don't just want to
|
||||
display a static page for a minute or two until the model is finished.
|
||||
|
||||
When you want streaming parsing, call `tokenizer.get_response_parser()`, which returns a [`~utils.chat_parsing.ResponseParser`].
|
||||
As with `parse_response`, pass the chat prompt as `prefix=` so the parser knows about any parts of the message that
|
||||
were prefilled by the chat template. The returned object is a
|
||||
stateful parser that you can feed text into as the model generates it:
|
||||
|
||||
```python
|
||||
parser = tokenizer.get_response_parser(prefix=input_ids[0])
|
||||
for event in parser.initial_events:
|
||||
render(event) # Display the partial message to the user however you want to
|
||||
for chunk in model_output:
|
||||
for event in parser.feed(chunk):
|
||||
render(event)
|
||||
message, final_events = parser.finalize()
|
||||
for event in final_events:
|
||||
render(event)
|
||||
```
|
||||
|
||||
The parser will emit **events** as text from the generation process is fed in. This indicates which region is currently being generated. When
|
||||
the region is complete, it will be emitted in a separate event with the fully parsed content. At the end of generation,
|
||||
the `finalize()` method flushes any remaining text and emits any final events, as well as the complete message dict.
|
||||
|
||||
Note that although `parse_response` can accept batches, streamed parsing is always single-sequence: each `ResponseParser` tracks the state of one generation.
|
||||
If you want to stream multiple generations at once, create one [`~utils.chat_parsing.ResponseParser`] per sequence.
|
||||
|
||||
## Streaming events
|
||||
|
||||
Each streamed parsing event is a dict with a `type` key. There are three kinds:
|
||||
|
||||
| Type | Description | Contents |
|
||||
|----------------|-------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `region_open` | Indicates that the model has started a new region, such as `content` or `thinking`. | `field` (str): the field name. |
|
||||
| `region_chunk` | A chunk of text for the current region. | `field` (str): the field name. `text` (str): the new chunk. `dirty` (bool): `True` if the chunk is raw text that needs parsing. |
|
||||
| `region_close` | Indicates that a region has finished, and that key is now finalized. | `field` (str): the field name. `value` (any): the fully parsed value for the region |
|
||||
|
||||
`region_chunk` events are emitted for every region as bytes arrive, so a streaming UI can render progress
|
||||
even for structured regions. For text-like regions (`text`, `int`, `float`, `bool`) chunks are flagged
|
||||
`dirty=False`: each chunk is already part of the final value (modulo trailing whitespace stripped at
|
||||
close). For structured regions, like JSON-format tool calls, chunks are flagged `dirty=True`. This means
|
||||
text is the raw, un-parsed body; it's safe to display incrementally, but the *parsed* value (a dict,
|
||||
list, etc.) only arrives in the matching `region_close` event. Either way, the finalized value of a
|
||||
region is always carried by `region_close`, so consumers that don't care about intermediate rendering
|
||||
can simply ignore `region_chunk` events.
|
||||
|
||||
If the chat `prefix` wrote anything into the message (e.g. the template opened a thinking block, or an
|
||||
assistant prefill started a response before handing off to the model), the parser exposes those events as
|
||||
`parser.initial_events`, a list you can replay into your renderer before feeding any model output. Regions
|
||||
that were opened *and* closed inside the prefix produce a full `region_open` / `region_chunk` / `region_close`
|
||||
sequence and their parsed value lands in the output dict, exactly as if the model itself had written them.
|
||||
|
||||
A typical event stream might look like this:
|
||||
|
||||
```python
|
||||
{"type": "region_open", "field": "thinking"}
|
||||
{"type": "region_chunk", "field": "thinking", "text": "I should ", "dirty": False}
|
||||
{"type": "region_chunk", "field": "thinking", "text": "greet the user", "dirty": False}
|
||||
{"type": "region_close", "field": "thinking", "value": "I should greet the user"}
|
||||
{"type": "region_open", "field": "tool_calls"}
|
||||
{"type": "region_chunk", "field": "tool_calls", "text": '{"name": "greet_user", ', "dirty": True}
|
||||
{"type": "region_chunk", "field": "tool_calls", "text": '"arguments": {"greeting": "Hi!"}}', "dirty": True}
|
||||
{"type": "region_close", "field": "tool_calls", "value": {"type": "function", "function": {"name": "greet_user", "arguments": {"greeting": "Hi!"}}}}
|
||||
```
|
||||
|
||||
Note how `thinking` is emitted with `dirty=False`, because fields like `thinking` and `content` are usually just raw
|
||||
text. This means you can treat the chunks as valid "partial output". However, `tool_calls` is flagged as `dirty` because
|
||||
the raw text needs significant cleanup - tool calls often need to be parsed as JSON or another format and then
|
||||
restructured to generate the final tool call dict. As a result, the final output for these regions often looks very,
|
||||
very different from the raw text. This final parsing will only happen when `region_close` is reached. It's
|
||||
up to you what you want to do with the `dirty` chunks until then - you can display them as-is to show the user the
|
||||
"raw" output, or you can simply wait until you have something clean to display.
|
||||
|
||||
This concludes most of what you need to know to use response templates. The rest of this document is focused on
|
||||
the internals of the parsing system and how to write response templates. This is mostly relevant for developers
|
||||
and model authors. Most people can safely stop here!
|
||||
|
||||
## Advanced: Writing a response template
|
||||
|
||||
The best way to understand how to write a response template is to pick a concrete example. Here's what a raw
|
||||
reply from `SmolLM` might look like:
|
||||
|
||||
```txt
|
||||
<think>
|
||||
I should greet the user
|
||||
</think>
|
||||
|
||||
<tool_call>{"name": "greet_user", "arguments": {"greeting": "Hi!"}}</tool_call>
|
||||
```
|
||||
|
||||
When we parse this output in the standard message dict format, it should look like this:
|
||||
|
||||
```json
|
||||
{
|
||||
"role": "assistant",
|
||||
"thinking": "I should greet the user",
|
||||
"tool_calls": [
|
||||
{"type": "function", "function": {"name": "greet_user", "arguments": {"greeting": "Hi!"}}}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
And here's the template that parses it. Don't be intimidated - a lot of it is fairly self-explanatory!
|
||||
|
||||
```python
|
||||
{
|
||||
"defaults": {"role": "assistant"},
|
||||
"start_anchor": "<|im_start|>assistant\n",
|
||||
"fields": {
|
||||
"thinking": {"open": "<think>", "close": "</think>", "content": "text"},
|
||||
"tool_calls": {
|
||||
"open": "<tool_call>",
|
||||
"close": "</tool_call>",
|
||||
"repeats": True,
|
||||
"content": "json",
|
||||
"transform": {"type": "function", "function": "{content}"},
|
||||
},
|
||||
"content": {
|
||||
"close": "<|im_end|>",
|
||||
"content": "text",
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
Essentially, the template defines **fields** and **delimiters**. Each field corresponds to a key in the
|
||||
output dict. Fields also include information for parsing the text inside their delimiters. There's one subtlety: The
|
||||
`content` field has no `open`, because in SmolLM (and several other models), it's not marked by a special token. Instead,
|
||||
`content` is stored in the space after the other regions, but before the end of the sequence. In our template, we
|
||||
represent this as an **implicit / leftover** field that picks up any text not claimed by another region.
|
||||
|
||||
In addition to `fields`, the template supports two top-level keys:
|
||||
|
||||
- `defaults` (optional) — A dict of values pre-populated in the output (e.g. `{"role": "assistant"}`). Keys here are
|
||||
always retained in the parsed output, even if no field wrote to them; other keys are dropped when their field
|
||||
captured nothing.
|
||||
- `start_anchor` (str) / `start_anchor_pattern` (str regex) — Marks where the current assistant message
|
||||
begins inside a chat prompt. When you pass `prefix=` to `parse_response` or `get_response_parser`, the parser
|
||||
right-truncates the prefix past the **last** occurrence of this anchor before processing it, so earlier turns in
|
||||
a multi-turn conversation don't pollute the current message's state. The anchor is applied only to the `prefix`,
|
||||
never to the response/generation you parse — some formats legitimately re-emit it mid-message (gpt-oss harmony
|
||||
output opens every channel with `<|start|>assistant`), so stripping the response past the anchor would drop the
|
||||
model's own reasoning and tool calls. This is why the generation alone is never enough to guard against history
|
||||
bleed: pass the prompt as `prefix=`. For ChatML-style models the anchor is typically `"<|im_start|>assistant\n"`.
|
||||
Exactly one of `start_anchor` or `start_anchor_pattern` must be set.
|
||||
|
||||
For example, given this multi-turn prefix (note the **two** assistant turns):
|
||||
|
||||
```txt
|
||||
<|im_start|>user
|
||||
Hi<|im_end|>
|
||||
<|im_start|>assistant
|
||||
Hello!<|im_end|>
|
||||
<|im_start|>user
|
||||
Again?<|im_end|>
|
||||
<|im_start|>assistant
|
||||
```
|
||||
|
||||
the parser truncates everything up to the **last** `<|im_start|>assistant\n`, discarding the earlier
|
||||
`"Hello!"` turn. The rule is that _everything but the final assistant turn is always dropped._
|
||||
|
||||
As with chat templates, response templates are stored as tokenizer attributes and saved with the tokenizer. Unlike
|
||||
chat templates, we save them inside `tokenizer_config.json` and not as a separate file, because their format fits
|
||||
naturally in JSON, unlike a chat template Jinja script.
|
||||
|
||||
```python
|
||||
tokenizer.response_template = template
|
||||
tokenizer.save_pretrained(...) # Written as a key in tokenizer_config.json
|
||||
```
|
||||
|
||||
## Advanced: Field API Reference
|
||||
|
||||
Each field supports several keys. We can divide these into two types. First, there are the keys that define how the field should be captured:
|
||||
|
||||
| Key | Type | Purpose |
|
||||
|-----------------|--------------------|-----------------------------------------------------------------------------------------------|
|
||||
| `open` | str or list[str] | Literal string that opens this region. A list of strings means "match any of these". |
|
||||
| `open_pattern` | str (regex) | Regex alternative to `open`. Named groups become capture variables available to `transform`. |
|
||||
| `close` | str or list[str] | Literal string (or list of strings) that closes this region. Omit to run to end-of-stream. |
|
||||
| `close_pattern` | str (regex) | Regex alternative to `close`. Named groups become capture variables available to `transform`. |
|
||||
| `repeats` | bool | If true, the field is a list and each match appends. Default `false`. |
|
||||
| `optional` | bool | If false and the region never matches, we raise an error. Default `true`. |
|
||||
|
||||
A field should have **either** `open` or `open_pattern`, but not both, and the same is true for `close` and `close_pattern`.
|
||||
|
||||
A field may omit `close`/`close_pattern` entirely, in which case the region stays open until the end of the
|
||||
generated text. This is useful for a final field that runs to the end of the message.
|
||||
|
||||
A field with **neither** `open` nor `open_pattern` is the **implicit** field: it's active whenever no explicit
|
||||
region is open, so it captures leftover text. At most one field can be implicit. This is most often used when `content`
|
||||
does not have special token tags, it's just written as plaintext after the other fields.
|
||||
|
||||
In addition to opening and closing delimiters, you can also specify `repeats`, which indicates that the field is a list
|
||||
and the delimiters can match multiple times. This is most common for parallel tool calling, when a model emits
|
||||
multiple tool calls simultaneously:
|
||||
|
||||
```python
|
||||
'<tool_call>{"name": "a", ...}</tool_call><tool_call>{"name": "b", ...}</tool_call>'
|
||||
# Returns `"tool_calls": [{... "a" ...}, {... "b" ...}]` in a template with repeats: true
|
||||
```
|
||||
|
||||
Finally, you can specify `optional: false` for fields that must be present. If such a field is missing,
|
||||
we raise an error instead of just returning a message dict without it.
|
||||
|
||||
The end of generation will close and finalize any open regions, even if their closing delimiter was not seen.
|
||||
|
||||
### Parsing the content of a field
|
||||
|
||||
Once we define how to capture a field, we also need to specify how to parse the raw text inside that capture. There are four
|
||||
keys that control this:
|
||||
|
||||
| Key | Type | Purpose |
|
||||
|------------------|--------------|------------------------------------------------------------------------------------------|
|
||||
| `content` | str | The content type inside this region. Defaults to `"text"`. Each type has its own parser. |
|
||||
| `content_args` | dict | Arguments to be passed to the content parser for this region. |
|
||||
| `transform` | dict/list | Optional post-parse template that reshapes the parsed body (see **Transform**). |
|
||||
| `transform_each` | bool | If true, the parsed content must be a list and `transform` is applied per-element. |
|
||||
|
||||
The first (and most important) key is `content`. This indicates the content type
|
||||
of the field, which determines the parser that will be used to convert the raw text captured in the field to the final output.
|
||||
`content_args` are used to configure the parser, and allow us to support various format quirks without needing custom code.
|
||||
We'll take a look at each type of parser and its arguments in turn.
|
||||
|
||||
#### Basic types
|
||||
`text`, `int`, `float` and `bool` are the basic types. These content types all just strip whitespace and then do a simple
|
||||
type conversion if required. They do not have any `content_args`, except for `text` which supports the arg `strip`,
|
||||
which strips whitespace from the start and end of the captured text, and defaults to `true`.
|
||||
|
||||
```python
|
||||
field = {"count": {"open": "<n>", "close": "</n>", "content": "int"}}
|
||||
input = "<n> 42 </n>"
|
||||
# Returns: {"count": 42}
|
||||
```
|
||||
|
||||
#### json
|
||||
|
||||
The `json` parser parses the captured text as JSON. It's the workhorse for tool-call arguments and
|
||||
anything else with nested structure. It accepts a handful of optional `content_args` to handle the
|
||||
various ways models mangle JSON in the wild:
|
||||
|
||||
- `unquoted_keys` (bool, default `false`): Enable when key names are raw rather than quoted
|
||||
(e.g. `{name: "foo"}`). Useful for models that emit Javascript-style
|
||||
object literals rather than strict JSON.
|
||||
- `string_delims` (list of `[open, close]` pairs, optional): for models that wrap string
|
||||
values in custom delimiters instead of `"..."`. Each pair gives an opening and closing marker.
|
||||
- `allow_non_json` (bool, default `false`): if parsing fails, return the stripped raw text instead
|
||||
of raising. Useful as a fallback for fields where the model *usually* emits JSON but occasionally
|
||||
drops to plain text.
|
||||
|
||||
`unquoted_keys` and `string_delims` both exist to handle models that emit non-standard,
|
||||
almost-but-not-quite-JSON output, so you should only need them for a handful of models.
|
||||
|
||||
```python
|
||||
field = {"args": {"open": "<args>", "close": "</args>", "content": "json", "content_args": {"unquoted_keys": True}}}
|
||||
input = '<args>{city: "London"}</args>'
|
||||
# Returns: {"args": {"city": "London"}}
|
||||
```
|
||||
|
||||
#### xml-inline
|
||||
|
||||
The `xml-inline` parser is for regions made up of a flat sequence of XML-ish tags, where each tag
|
||||
becomes one entry in a dict. It's most often used inside a `tool_calls` field for models that emit
|
||||
each argument as its own tag rather than as a JSON blob:
|
||||
|
||||
- `tag_pattern` (str, **required**): regex matching a single tag. Must contain named groups
|
||||
`key` (the resulting dict key) and `value` (the raw text that becomes the dict value).
|
||||
- `value_parser` (dict, optional): nested content parser applied to each captured `value`. A dict
|
||||
with `name` (the parser, e.g. `"json"`, `"int"`) and optional `args` (its `content_args`). If
|
||||
omitted, values stay as raw strings.
|
||||
- `merge_duplicates` (bool, default `false`): when the same key appears multiple times, collect the
|
||||
values into a list instead of letting later matches overwrite earlier ones.
|
||||
|
||||
For example, Qwen3 emits each tool-call argument as its own `<parameter>` tag, and we parse it
|
||||
like this:
|
||||
|
||||
```python
|
||||
"tool_calls": {
|
||||
"open_pattern": r"<tool_call>\s*<function=(?P<name>\w+)>",
|
||||
"close": "</tool_call>",
|
||||
"repeats": True,
|
||||
"content": "xml-inline",
|
||||
"content_args": {
|
||||
"tag_pattern": r"<parameter=(?P<key>\w+)>\s*(?P<value>.*?)\s*</parameter>",
|
||||
"value_parser": {"name": "json", "args": {"allow_non_json": True}},
|
||||
},
|
||||
"transform": {"type": "function", "function": {"name": "{name}", "arguments": "{content}"}},
|
||||
}
|
||||
```
|
||||
|
||||
Note the nested `value_parser`: each parameter value is itself run through the `json` parser (with
|
||||
`allow_non_json` so plain strings still pass through). Feeding the `tool_calls` field above this input:
|
||||
|
||||
```python
|
||||
input = "<tool_call><function=get_weather><parameter=city>London</parameter><parameter=units>celsius</parameter></function></tool_call>"
|
||||
# Returns: {"tool_calls": [{"type": "function", "function": {"name": "get_weather", "arguments": {"city": "London", "units": "celsius"}}}]}
|
||||
```
|
||||
|
||||
#### kv-lines
|
||||
|
||||
The `kv-lines` parser handles line-delimited `key: value` pairs (think YAML-ish metadata or `.env`
|
||||
files). Each line becomes one entry in the resulting dict. All arguments are optional:
|
||||
|
||||
- `line_sep` (str, default `"\n"`): separator between pairs.
|
||||
- `kv_sep` (str, default `":"`): separator between a key and its value inside a single line. Only
|
||||
the first occurrence is used as the split point, so values may themselves contain the separator.
|
||||
- `strip` (bool, default `true`): strip surrounding whitespace from each key and value.
|
||||
- `value_parser` (dict, optional): nested content parser applied to each value, in the same
|
||||
`{"name": ..., "args": ...}` format as for `xml-inline`. If omitted, values stay as raw strings.
|
||||
|
||||
Lines that are empty or do not contain `kv_sep` are silently skipped, so stray blank lines in the
|
||||
captured region are tolerated.
|
||||
|
||||
```python
|
||||
field = {"metadata": {"open": "<meta>", "close": "</meta>", "content": "kv-lines"}}
|
||||
input = "<meta>name: alice\nage: 30</meta>"
|
||||
# Returns: {"metadata": {"name": "alice", "age": "30"}}
|
||||
```
|
||||
|
||||
Note `age` keeps `"30"` as a string; add a `value_parser` of `{"name": "int"}` to parse it to `30`.
|
||||
|
||||
|
||||
### Transform
|
||||
|
||||
For most fields, the `transform` key is unnecessary. It's used when the parsed body needs to be reshaped into the final
|
||||
output, or when information from the delimiters has to be merged into the result. It most commonly appears in
|
||||
`tool_calls` fields, as these often have complex structure.
|
||||
|
||||
`transform` is a **template**: a dict (or list) that describes the output shape, where any string of the
|
||||
form `"{name}"` is replaced with the corresponding value. Values can be accessed from `content` (the parsed
|
||||
body of this region) and any named groups captured by `open_pattern` / `close_pattern`. A very common use-case is to wrap a tool
|
||||
call dict in an outer dict with a `function` key, as these are part of our standard tool call format:
|
||||
|
||||
```python
|
||||
"tool_calls": {
|
||||
"open": "<tool_call>",
|
||||
"close": "</tool_call>",
|
||||
"repeats": True,
|
||||
"content": "json",
|
||||
"transform": {"type": "function", "function": "{content}"},
|
||||
},
|
||||
```
|
||||
|
||||
So this raw output:
|
||||
|
||||
```txt
|
||||
<tool_call>{"name": "greet_user", "arguments": {"greeting": "Hi!"}}</tool_call>
|
||||
```
|
||||
|
||||
becomes (note `repeats: True` makes `tool_calls` a list):
|
||||
|
||||
```json
|
||||
[{"type": "function", "function": {"name": "greet_user", "arguments": {"greeting": "Hi!"}}}]
|
||||
```
|
||||
|
||||
A whole-string placeholder like `"{content}"` returns the looked-up value with its type preserved — so above, the
|
||||
parsed JSON dict slots in directly as the value of `function`. A placeholder must be the entire string: mixing
|
||||
text and placeholders (`"abc {name} def"`) is not permitted. They're not f-strings!
|
||||
|
||||
`transform` is quite versatile, which becomes necessary when the model output has a wildly different format
|
||||
to our standard API. GPT-OSS is a good example - it embeds the function name in the channel header rather than in
|
||||
the JSON body, so we have to capture it with a named group in `open_pattern` and merge it with `content` inside the
|
||||
transform. All named groups in `open_pattern` and `close_pattern` become available as variables alongside `content`:
|
||||
|
||||
```python
|
||||
"tool_calls": {
|
||||
"open_pattern": r"<\|channel\|>commentary to=functions\.(?P<name>\w+).*?<\|message\|>",
|
||||
"close": "<|call|>",
|
||||
"repeats": True,
|
||||
"content": "json",
|
||||
"transform": {"type": "function", "function": {"name": "{name}", "arguments": "{content}"}},
|
||||
},
|
||||
```
|
||||
|
||||
The function name lives in the channel header, not the JSON body, so this:
|
||||
|
||||
```txt
|
||||
<|channel|>commentary to=functions.get_current_weather <|constrain|>json<|message|>{"location": "San Francisco, CA"}<|call|>
|
||||
```
|
||||
|
||||
becomes:
|
||||
|
||||
```json
|
||||
[{"type": "function", "function": {"name": "get_current_weather", "arguments": {"location": "San Francisco, CA"}}}]
|
||||
```
|
||||
|
||||
Sometimes a field's parsed content is *itself* a list of records and you want to reshape each one. The Cohere
|
||||
template is a good example: It emits all tool calls inside a single JSON array, so we set `transform_each: True` to
|
||||
apply the transform per element. Each array element's keys are unpacked into the template scope, so
|
||||
`"{tool_name}"` looks up `tool_name` in the current element:
|
||||
|
||||
```python
|
||||
"tool_calls": {
|
||||
"open": "<|START_ACTION|>",
|
||||
"close": "<|END_ACTION|>",
|
||||
"content": "json",
|
||||
"transform_each": True,
|
||||
"transform": {"type": "function", "function": {"name": "{tool_name}", "arguments": "{parameters}"}},
|
||||
},
|
||||
```
|
||||
|
||||
This will convert an output like this:
|
||||
|
||||
```json
|
||||
[
|
||||
{"tool_name": "greet_user", "parameters": {"greeting": "Hi!"}},
|
||||
{"tool_name": "search", "parameters": {"query": "weather tomorrow"}}
|
||||
]
|
||||
```
|
||||
|
||||
Into an output like this, which fits our standard API:
|
||||
|
||||
```json
|
||||
[
|
||||
{"type": "function", "function": {"name": "greet_user", "arguments": {"greeting": "Hi!"}}},
|
||||
{"type": "function", "function": {"name": "search", "arguments": {"query": "weather tomorrow"}}}
|
||||
]
|
||||
```
|
||||
|
||||
The `transform_each` flag is only needed when `content` is already a list; for the more common case where each
|
||||
match contributes one element (and `repeats: True` accumulates them), then the transform will apply to each element
|
||||
by default.
|
||||
|
||||
## Framework developers: Regex portability
|
||||
|
||||
`open_pattern`, `close_pattern`, and `start_anchor_pattern` are regex strings. For most users, and even for most
|
||||
model authors, this shouldn't be a problem, but if you are a developer writing an implementation of response parsing
|
||||
in another language, you should be aware of our implementation details. This section is dedicated to everyone
|
||||
who had to implement an entire Jinja parser to get non-Python chat templating to work - we hope that if you
|
||||
follow the simple guidelines below, then response templates should be much less painful:
|
||||
|
||||
- We use Python's [`regex`](https://pypi.org/project/regex/) module for all regexes used in chat parsing.
|
||||
Since all Python3 strings are unicode, **all of our regex matches are unicode-aware**. This particularly affects
|
||||
common characters like `\w`. Make sure you set the relevant unicode flags in your engine.
|
||||
- We compile all regexes with `re.DOTALL` enabled and `re.MULTILINE` disabled, so `.` matches `\n` but `^` and `$`
|
||||
only match the start/end of the whole input, not line breaks.
|
||||
- We use `(?P<name>...)` syntax for named groups. Other regex implementations have very different named capture group
|
||||
syntax, so you may need to search for this pattern in regexes and rewrite it to match your local implementation.
|
||||
- We use partial regex matching to decide when we can emit data. This is necessary because the end of a region may consist of multiple tokens,
|
||||
and we don't want to emit that end-of-region delimiter, so we hold tokens back until we're sure that they're inside the region and not part of the boundary.
|
||||
This means that whenever a region end regex has a partial match, we hold back data until the regex either matches or fails. If your regex engine
|
||||
doesn't support partial matching, you can still implement response templates, but you may need to find another solution to this issue. One simple
|
||||
approach is just to hold back these regions / emit them as `dirty` until you definitively see the ending delimiter.
|
||||
- Your regex engine may (rarely) not support lookarounds like `(?!...)`. Although these aren't commonly used in response
|
||||
templates, they can appear and we do support them! You might need to either throw an error in those cases, or manually
|
||||
extract the lookarounds and enforce them in your code when the regex engine finds a possible match.
|
||||
- Other advanced features like backreferences, atomic groups, possessive quantifiers, recursion and so on are generally
|
||||
not used in response templates. We'll try to dissuade model authors from using them, so you can hopefully safely
|
||||
ignore them.
|
||||
@@ -0,0 +1,240 @@
|
||||
<!--Copyright 2024 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Chat templates
|
||||
|
||||
The [chat basics](./conversations) guide covers how to store chat histories and generate text from chat models using [`TextGenerationPipeline`].
|
||||
|
||||
This guide is intended for more advanced users, and covers the underlying classes and methods, as well as the key concepts for understanding what's actually going on when you chat with a model.
|
||||
|
||||
The critical insight needed to understand chat models is this: All causal LMs, whether chat-trained or not, continue a sequence of tokens. When causal LMs are trained, the training usually begins with "pre-training" on a huge corpus of text, which creates a "base" model.
|
||||
These base models are then often "fine-tuned" for chat, which means training them on data that is formatted as a sequence of messages. The chat is still just a sequence of tokens, though! The list of `role` and `content` dictionaries that you pass
|
||||
to a chat model get converted to a token sequence, often with control tokens like `<|user|>` or `<|assistant|>` or `<|end_of_message|>`, which allow the model to see the chat structure.
|
||||
There are many possible chat formats, and different models may use different formats or control tokens, even if they were fine-tuned from the same base model!
|
||||
|
||||
Don't panic, though - you don't need to memorize every possible chat format in order to use chat models. Chat models come with **chat templates**, which indicate how they expect chats to be formatted.
|
||||
You can access these with the [`apply_chat_template`] method. Let's see two examples. Both of these models are fine-tuned from the same `Mistral-7B` base model:
|
||||
|
||||
<hfoptions id="template">
|
||||
<hfoption id="Mistral">
|
||||
|
||||
```py
|
||||
from transformers import AutoTokenizer
|
||||
|
||||
tokenizer = AutoTokenizer.from_pretrained("mistralai/Mistral-7B-Instruct-v0.1")
|
||||
chat = [
|
||||
{"role": "user", "content": "Hello, how are you?"},
|
||||
{"role": "assistant", "content": "I'm doing great. How can I help you today?"},
|
||||
{"role": "user", "content": "I'd like to show off how chat templating works!"},
|
||||
]
|
||||
|
||||
tokenizer.apply_chat_template(chat, tokenize=False)
|
||||
```
|
||||
|
||||
```md
|
||||
<s>[INST] Hello, how are you? [/INST]I'm doing great. How can I help you today?</s> [INST] I'd like to show off how chat templating works! [/INST]
|
||||
```
|
||||
|
||||
</hfoption>
|
||||
<hfoption id="Zephyr">
|
||||
|
||||
```py
|
||||
from transformers import AutoTokenizer
|
||||
|
||||
tokenizer = AutoTokenizer.from_pretrained("HuggingFaceH4/zephyr-7b-beta")
|
||||
chat = [
|
||||
{"role": "user", "content": "Hello, how are you?"},
|
||||
{"role": "assistant", "content": "I'm doing great. How can I help you today?"},
|
||||
{"role": "user", "content": "I'd like to show off how chat templating works!"},
|
||||
]
|
||||
|
||||
tokenizer.apply_chat_template(chat, tokenize=False)
|
||||
```
|
||||
|
||||
```md
|
||||
<|user|>\nHello, how are you?</s>\n<|assistant|>\nI'm doing great. How can I help you today?</s>\n<|user|>\nI'd like to show off how chat templating works!</s>\n
|
||||
```
|
||||
|
||||
</hfoption>
|
||||
</hfoptions>
|
||||
|
||||
Mistral-7B-Instruct uses `[INST]` and `[/INST]` tokens to indicate the start and end of user messages, while Zephyr-7B uses `<|user|>` and `<|assistant|>` tokens to indicate speaker roles. This is why chat templates are important - with the wrong control tokens, these models would have drastically worse performance.
|
||||
|
||||
## Using `apply_chat_template`
|
||||
|
||||
The input to `apply_chat_template` should be structured as a list of dictionaries with `role` and `content` keys. The `role` key specifies the speaker, and the `content` key contains the message. The common roles are:
|
||||
|
||||
- `user` for messages from the user
|
||||
- `assistant` for messages from the model
|
||||
- `system` for directives on how the model should act (usually placed at the beginning of the chat)
|
||||
|
||||
[`apply_chat_template`] takes this list and returns a formatted sequence. Set `tokenize=True` if you want to tokenize the sequence.
|
||||
|
||||
```py
|
||||
import torch
|
||||
from transformers import AutoModelForCausalLM, AutoTokenizer
|
||||
|
||||
tokenizer = AutoTokenizer.from_pretrained("HuggingFaceH4/zephyr-7b-beta")
|
||||
model = AutoModelForCausalLM.from_pretrained("HuggingFaceH4/zephyr-7b-beta", device_map="auto", dtype=torch.bfloat16)
|
||||
|
||||
messages = [
|
||||
{"role": "system", "content": "You are a friendly chatbot who always responds in the style of a pirate",},
|
||||
{"role": "user", "content": "How many helicopters can a human eat in one sitting?"},
|
||||
]
|
||||
tokenized_chat = tokenizer.apply_chat_template(messages, tokenize=True, add_generation_prompt=True, return_tensors="pt")
|
||||
print(tokenizer.decode(tokenized_chat[0]))
|
||||
```
|
||||
|
||||
```md
|
||||
<|system|>
|
||||
You are a friendly chatbot who always responds in the style of a pirate</s>
|
||||
<|user|>
|
||||
How many helicopters can a human eat in one sitting?</s>
|
||||
<|assistant|>
|
||||
```
|
||||
|
||||
Pass the tokenized chat to [`~GenerationMixin.generate`] to generate a response.
|
||||
|
||||
```py
|
||||
outputs = model.generate(tokenized_chat, max_new_tokens=128)
|
||||
print(tokenizer.decode(outputs[0]))
|
||||
```
|
||||
|
||||
```md
|
||||
<|system|>
|
||||
You are a friendly chatbot who always responds in the style of a pirate</s>
|
||||
<|user|>
|
||||
How many helicopters can a human eat in one sitting?</s>
|
||||
<|assistant|>
|
||||
Matey, I'm afraid I must inform ye that humans cannot eat helicopters. Helicopters are not food, they are flying machines. Food is meant to be eaten, like a hearty plate o' grog, a savory bowl o' stew, or a delicious loaf o' bread. But helicopters, they be for transportin' and movin' around, not for eatin'. So, I'd say none, me hearties. None at all.
|
||||
```
|
||||
|
||||
> [!WARNING]
|
||||
> Some tokenizers add special `<bos>` and `<eos>` tokens. Chat templates should already include all the necessary special tokens, and adding additional special tokens is often incorrect or duplicated, hurting model performance. When you format text with `apply_chat_template(tokenize=False)`, make sure you set `add_special_tokens=False` if you tokenize later to avoid duplicating these tokens.
|
||||
> This isn't an issue if you use `apply_chat_template(tokenize=True)`, which means it's usually the safer option!
|
||||
|
||||
### add_generation_prompt
|
||||
|
||||
You may have noticed the [`~PreTrainedTokenizerBase.apply_chat_template#add_generation_prompt`] argument in the above examples.
|
||||
This argument adds tokens to the end of the chat that indicate the start of an `assistant` response. Remember: Beneath all the chat abstractions, chat models are still just language models that continue a sequence of tokens!
|
||||
If you include tokens that tell it that it's now in an `assistant` response, it will correctly write a response, but if you don't include these tokens, the model may get confused and do something strange, like **continuing** the user's message instead of replying to it!
|
||||
|
||||
Let's see an example to understand what `add_generation_prompt` is actually doing. First, let's format a chat without `add_generation_prompt`:
|
||||
|
||||
```py
|
||||
tokenized_chat = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=False)
|
||||
tokenized_chat
|
||||
```
|
||||
|
||||
```md
|
||||
<|im_start|>user
|
||||
Hi there!<|im_end|>
|
||||
<|im_start|>assistant
|
||||
Nice to meet you!<|im_end|>
|
||||
<|im_start|>user
|
||||
Can I ask a question?<|im_end|>
|
||||
```
|
||||
|
||||
Now, let's format the same chat with `add_generation_prompt=True`:
|
||||
|
||||
```py
|
||||
tokenized_chat = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
|
||||
tokenized_chat
|
||||
```
|
||||
|
||||
```md
|
||||
<|im_start|>user
|
||||
Hi there!<|im_end|>
|
||||
<|im_start|>assistant
|
||||
Nice to meet you!<|im_end|>
|
||||
<|im_start|>user
|
||||
Can I ask a question?<|im_end|>
|
||||
<|im_start|>assistant
|
||||
|
||||
```
|
||||
|
||||
When `add_generation_prompt=True`, `<|im_start|>assistant` is added at the end to indicate the start of an `assistant` message. This lets the model know an `assistant` response is next.
|
||||
|
||||
Not all models require generation prompts, and some models, like [Llama](./model_doc/llama), don't have any special tokens before the `assistant` response. In these cases, [`~PreTrainedTokenizerBase.apply_chat_template#add_generation_prompt`] has no effect.
|
||||
|
||||
### continue_final_message
|
||||
|
||||
The [`~PreTrainedTokenizerBase.apply_chat_template#continue_final_message`] parameter controls whether the final message in the chat should be continued or not instead of starting a new one. It removes end of sequence tokens so that the model continues generation from the final message.
|
||||
|
||||
This is useful for “prefilling” a model response. In the example below, the model generates text that continues the JSON string rather than starting a new message. It can be very useful for improving the accuracy of instruction following when you know how to start its replies.
|
||||
|
||||
```py
|
||||
chat = [
|
||||
{"role": "user", "content": "Can you format the answer in JSON?"},
|
||||
{"role": "assistant", "content": '{"name": "'},
|
||||
]
|
||||
|
||||
formatted_chat = tokenizer.apply_chat_template(chat, tokenize=True, return_dict=True, continue_final_message=True)
|
||||
model.generate(**formatted_chat)
|
||||
```
|
||||
|
||||
> [!WARNING]
|
||||
> You shouldn't use [`~PreTrainedTokenizerBase.apply_chat_template#add_generation_prompt`] and [`~PreTrainedTokenizerBase.apply_chat_template#continue_final_message`] together. The former adds tokens that start a new message, while the latter removes end of sequence tokens. Using them together returns an error.
|
||||
|
||||
Pass a field name as a string to prefill that field instead of `content`. Reasoning models often expose a separate field, like `reasoning_content` on Qwen or `thinking` on Gemma. Prefilling `content` closes the reasoning block before generation starts, so the model can't continue inside it. Prefilling the reasoning field directly leaves the block open.
|
||||
|
||||
```py
|
||||
chat = [
|
||||
{"role": "user", "content": "Explain 1+1"},
|
||||
{"role": "assistant", "reasoning_content": "The user wants a simple addition. ", "content": ""},
|
||||
]
|
||||
|
||||
formatted_chat = tokenizer.apply_chat_template(chat, tokenize=False, continue_final_message="reasoning_content")
|
||||
```
|
||||
|
||||
The named field must exist on the final message and must be referenced by the chat template. An error is raised when either check fails.
|
||||
|
||||
[`TextGenerationPipeline`] sets [`~PreTrainedTokenizerBase.apply_chat_template#add_generation_prompt`] to `True` by default to start a new message. However, if the final message in the chat has the `assistant` role, it assumes the message is a prefill and switches to `continue_final_message=True`. This is because most models don't support multiple consecutive assistant messages. To override this behavior, explicitly pass the [`~PreTrainedTokenizerBase.apply_chat_template#continue_final_message`] argument to the pipeline.
|
||||
|
||||
## Model training
|
||||
|
||||
Training a model with a chat template is a good way to ensure the template matches the tokens the model was trained on. Apply the chat template as a preprocessing step to your dataset. Set `add_generation_prompt=False` because the additional tokens to prompt an assistant response aren't helpful during training.
|
||||
|
||||
An example of preprocessing a dataset with a chat template is shown below.
|
||||
|
||||
```py
|
||||
from transformers import AutoTokenizer
|
||||
from datasets import Dataset
|
||||
|
||||
tokenizer = AutoTokenizer.from_pretrained("HuggingFaceH4/zephyr-7b-beta")
|
||||
|
||||
chat1 = [
|
||||
{"role": "user", "content": "Which is bigger, the moon or the sun?"},
|
||||
{"role": "assistant", "content": "The sun."}
|
||||
]
|
||||
chat2 = [
|
||||
{"role": "user", "content": "Which is bigger, a virus or a bacterium?"},
|
||||
{"role": "assistant", "content": "A bacterium."}
|
||||
]
|
||||
|
||||
dataset = Dataset.from_dict({"chat": [chat1, chat2]})
|
||||
dataset = dataset.map(lambda x: {"formatted_chat": tokenizer.apply_chat_template(x["chat"], tokenize=False, add_generation_prompt=False)})
|
||||
print(dataset['formatted_chat'][0])
|
||||
```
|
||||
|
||||
```md
|
||||
<|user|>
|
||||
Which is bigger, the moon or the sun?</s>
|
||||
<|assistant|>
|
||||
The sun.</s>
|
||||
```
|
||||
|
||||
After this step, you can continue following the [training recipe](./tasks/language_modeling) for causal language models using the `formatted_chat` column.
|
||||
@@ -0,0 +1,264 @@
|
||||
<!--Copyright 2025 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contains specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Multimodal chat templates
|
||||
|
||||
Multimodal chat models accept inputs like images, audio or video, in addition to text. The `content` key in a multimodal chat history is a list containing multiple items of different types. This is unlike text-only chat models whose `content` key is a single string.
|
||||
|
||||
In the same way the [Tokenizer](./fast_tokenizers) class handles chat templates and tokenization for text-only models,
|
||||
the [Processor](./processors) class handles preprocessing, tokenization and chat templates for multimodal models. Their [`~ProcessorMixin.apply_chat_template`] methods are almost identical.
|
||||
|
||||
This guide will show you how to chat with multimodal models with the high-level [`ImageTextToTextPipeline`] and at a lower level using the [`~ProcessorMixin.apply_chat_template`] and [`~GenerationMixin.generate`] methods.
|
||||
|
||||
## ImageTextToTextPipeline
|
||||
|
||||
[`ImageTextToTextPipeline`] is a high-level image and text generation class with a “chat mode”. Chat mode is enabled when a conversational model is detected and the chat prompt is [properly formatted](./llm_tutorial#wrong-prompt-format).
|
||||
|
||||
Add image and text blocks to the `content` key in the chat history.
|
||||
|
||||
```py
|
||||
messages = [
|
||||
{
|
||||
"role": "system",
|
||||
"content": [{"type": "text", "text": "You are a friendly chatbot who always responds in the style of a pirate"}],
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": [
|
||||
{"type": "image", "url": "http://images.cocodataset.org/val2017/000000039769.jpg"},
|
||||
{"type": "text", "text": "What are these?"},
|
||||
],
|
||||
},
|
||||
]
|
||||
```
|
||||
|
||||
Create an [`ImageTextToTextPipeline`] and pass the chat to it. For large models, setting [device_map="auto"](./models#big-model-inference) helps load the model quicker and automatically places it on the fastest device available. Setting the data type to [auto](./models#model-data-type) also helps save memory and improve speed.
|
||||
|
||||
```python
|
||||
import torch
|
||||
from transformers import pipeline
|
||||
|
||||
pipe = pipeline("image-text-to-text", model="Qwen/Qwen2.5-VL-3B-Instruct", device_map="auto", dtype="auto")
|
||||
out = pipe(text=messages, max_new_tokens=128)
|
||||
print(out[0]['generated_text'][-1]['content'])
|
||||
```
|
||||
|
||||
```text
|
||||
Ahoy, me hearty! These be two feline friends, likely some tabby cats, taking a siesta on a cozy pink blanket. They're resting near remote controls, perhaps after watching some TV or just enjoying some quiet time together. Cats sure know how to find comfort and relaxation, don't they?
|
||||
```
|
||||
|
||||
Aside from the gradual descent from pirate-speak into modern American English (it **is** only a 3B model, after all), this is correct!
|
||||
|
||||
## Using `apply_chat_template`
|
||||
|
||||
Like [text-only models](./chat_templating), use the [`~ProcessorMixin.apply_chat_template`] method to prepare the chat messages for multimodal models.
|
||||
This method handles the tokenization and formatting of the chat messages, including images and other media types. The resulting inputs are passed to the model for generation.
|
||||
|
||||
```python
|
||||
from transformers import AutoProcessor, AutoModelForImageTextToText
|
||||
|
||||
model = AutoModelForImageTextToText.from_pretrained("Qwen/Qwen2.5-VL-3B-Instruct", device_map="auto", torch_dtype="auto")
|
||||
processor = AutoProcessor.from_pretrained("Qwen/Qwen2.5-VL-3B-Instruct")
|
||||
|
||||
messages = [
|
||||
{
|
||||
"role": "system",
|
||||
"content": [{"type": "text", "text": "You are a friendly chatbot who always responds in the style of a pirate"}],
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": [
|
||||
{"type": "image", "url": "http://images.cocodataset.org/val2017/000000039769.jpg"},
|
||||
{"type": "text", "text": "What are these?"},
|
||||
],
|
||||
},
|
||||
]
|
||||
```
|
||||
|
||||
Pass `messages` to [`~ProcessorMixin.apply_chat_template`] to tokenize the input content. Unlike text models, the output of `apply_chat_template`
|
||||
contains a `pixel_values` key with the preprocessed image data, in addition to the tokenized text.
|
||||
|
||||
```py
|
||||
processed_chat = processor.apply_chat_template(messages, add_generation_prompt=True, tokenize=True, return_dict=True, return_tensors="pt")
|
||||
print(list(processed_chat.keys()))
|
||||
```
|
||||
|
||||
```text
|
||||
['input_ids', 'attention_mask', 'pixel_values', 'image_grid_thw']
|
||||
```
|
||||
|
||||
Pass these inputs to [`~GenerationMixin.generate`].
|
||||
|
||||
```python
|
||||
out = model.generate(**processed_chat.to(model.device), max_new_tokens=128)
|
||||
print(processor.decode(out[0]))
|
||||
```
|
||||
|
||||
The decoded output contains the full conversation so far, including the user message and the placeholder tokens that contain the image information. You may need to trim the previous conversation from the output before displaying it to the user.
|
||||
|
||||
## Video inputs
|
||||
|
||||
Some vision models also support video inputs. The message format is very similar to the format for [image inputs](#image-inputs).
|
||||
|
||||
- The content `"type"` should be `"video"` to indicate the content is a video.
|
||||
- For videos, it can be a link to the video (`"url"`) or it could be a file path (`"path"`). Videos loaded from a URL can only be decoded with [PyAV](https://pyav.basswood-io.com/docs/stable/) or [Decord](https://github.com/dmlc/decord).
|
||||
- In addition to loading videos from a URL or file path, you can also pass decoded video data directly. This is useful if you've already preprocessed or decoded video frames elsewhere in memory (e.g., using OpenCV, decord, or torchvision). You don't need to save to files or store it in an URL.
|
||||
|
||||
> [!WARNING]
|
||||
> Loading a video from `"url"` is only supported by the PyAV or Decord backends.
|
||||
|
||||
```python
|
||||
from transformers import AutoProcessor, LlavaOnevisionForConditionalGeneration
|
||||
|
||||
model_id = "llava-hf/llava-onevision-qwen2-0.5b-ov-hf"
|
||||
model = LlavaOnevisionForConditionalGeneration.from_pretrained(model_id)
|
||||
processor = AutoProcessor.from_pretrained(model_id)
|
||||
|
||||
messages = [
|
||||
{
|
||||
"role": "system",
|
||||
"content": [{"type": "text", "text": "You are a friendly chatbot who always responds in the style of a pirate"}],
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": [
|
||||
{"type": "video", "url": "https://test-videos.co.uk/vids/bigbuckbunny/mp4/h264/720/Big_Buck_Bunny_720_10s_10MB.mp4"},
|
||||
{"type": "text", "text": "What do you see in this video?"},
|
||||
],
|
||||
},
|
||||
]
|
||||
```
|
||||
|
||||
### Example: Passing decoded video objects
|
||||
|
||||
```python
|
||||
import numpy as np
|
||||
|
||||
video_object1 = np.random.randint(0, 255, size=(16, 224, 224, 3), dtype=np.uint8),
|
||||
|
||||
messages = [
|
||||
{
|
||||
"role": "system",
|
||||
"content": [{"type": "text", "text": "You are a friendly chatbot who always responds in the style of a pirate"}],
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": [
|
||||
{"type": "video", "video": video_object1},
|
||||
{"type": "text", "text": "What do you see in this video?"}
|
||||
],
|
||||
},
|
||||
]
|
||||
```
|
||||
|
||||
You can also use existing (`"load_video()"`) function to load a video, edit the video in memory and pass it in the messages.
|
||||
|
||||
```python
|
||||
|
||||
# Make sure a video backend library (pyav, decord, or torchvision) is available.
|
||||
from transformers.video_utils import load_video
|
||||
|
||||
# load a video file in memory for testing
|
||||
video_object2, _ = load_video(
|
||||
"https://test-videos.co.uk/vids/bigbuckbunny/mp4/h264/720/Big_Buck_Bunny_720_10s_10MB.mp4"
|
||||
)
|
||||
|
||||
messages = [
|
||||
{
|
||||
"role": "system",
|
||||
"content": [{"type": "text", "text": "You are a friendly chatbot who always responds in the style of a pirate"}],
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": [
|
||||
{"type": "video", "video": video_object2},
|
||||
{"type": "text", "text": "What do you see in this video?"}
|
||||
],
|
||||
},
|
||||
]
|
||||
```
|
||||
|
||||
Pass `messages` to [`~ProcessorMixin.apply_chat_template`] to tokenize the input content. There are a few extra parameters to include in [`~ProcessorMixin.apply_chat_template`] that controls the sampling process.
|
||||
|
||||
<hfoptions id="sampling">
|
||||
<hfoption id="fixed number of frames">
|
||||
|
||||
The `num_frames` parameter controls how many frames to uniformly sample from the video. Each checkpoint has a maximum frame count it was pretrained with and exceeding this count can significantly lower generation quality. It's important to choose a frame count that fits both the model capacity and your hardware resources. If `num_frames` isn't specified, the entire video is loaded without any frame sampling.
|
||||
|
||||
```python
|
||||
processed_chat = processor.apply_chat_template(
|
||||
messages,
|
||||
add_generation_prompt=True,
|
||||
tokenize=True,
|
||||
return_dict=True,
|
||||
return_tensors="pt",
|
||||
num_frames=32,
|
||||
)
|
||||
print(processed_chat.keys())
|
||||
```
|
||||
|
||||
These inputs are now ready to be used in [`~GenerationMixin.generate`].
|
||||
|
||||
</hfoption>
|
||||
<hfoption id="fps">
|
||||
|
||||
For longer videos, it may be better to sample more frames for better representation with the `fps` parameter. This determines how many frames per second to extract. As an example, if a video is 10 seconds long and `fps=2`, then the model samples 20 frames. In other words, 2 frames are uniformly sampled every 10 seconds.
|
||||
|
||||
```py
|
||||
processed_chat = processor.apply_chat_template(
|
||||
messages,
|
||||
add_generation_prompt=True,
|
||||
tokenize=True,
|
||||
return_dict=True,
|
||||
fps=16,
|
||||
)
|
||||
print(processed_chat.keys())
|
||||
```
|
||||
|
||||
</hfoption>
|
||||
<hfoption id="list of image frames">
|
||||
|
||||
Videos may also exist as a set of sampled frames stored as images rather than the full video file.
|
||||
|
||||
In this case, pass a list of image file paths and the processor automatically concatenates them into a video. Make sure all images are the same size since they are assumed to be from the same video.
|
||||
|
||||
```py
|
||||
frames_paths = ["/path/to/frame0.png", "/path/to/frame5.png", "/path/to/frame10.png"]
|
||||
messages = [
|
||||
{
|
||||
"role": "system",
|
||||
"content": [{"type": "text", "text": "You are a friendly chatbot who always responds in the style of a pirate"}],
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": [
|
||||
{"type": "video", "path": frames_paths},
|
||||
{"type": "text", "text": "What do you see in this video?"},
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
processed_chat = processor.apply_chat_template(
|
||||
messages,
|
||||
add_generation_prompt=True,
|
||||
tokenize=True,
|
||||
return_dict=True,
|
||||
)
|
||||
print(processed_chat.keys())
|
||||
```
|
||||
|
||||
</hfoption>
|
||||
</hfoptions>
|
||||
@@ -0,0 +1,267 @@
|
||||
<!--Copyright 2024 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Writing a chat template
|
||||
|
||||
A chat template is a [Jinja](https://jinja.palletsprojects.com/en/stable/templates/) template stored in the tokenizer's [`~PreTrainedTokenizer.chat_template`] attribute. Jinja is a templating language that allows you to write Python-like code and syntax.
|
||||
|
||||
```jinja
|
||||
{%- for message in messages %}
|
||||
{{- '<|' + message['role'] + |>\n' }}
|
||||
{{- message['content'] + eos_token }}
|
||||
{%- endfor %}
|
||||
{%- if add_generation_prompt %}
|
||||
{{- '<|assistant|>\n' }}
|
||||
{%- endif %}
|
||||
```
|
||||
|
||||
If you stare at this for a while, you should realize that this is actually very like Python, albeit with some strange
|
||||
`{%-` syntax. The template iterates over a list of messages, and for each message, it prints the role and content of
|
||||
the message, followed by an end-of-sequence token. If `add_generation_prompt=True`, it adds
|
||||
the starting header for an assistant message to the end of the conversation.
|
||||
|
||||
Load the written template as a string and assign it to the tokenizer's `chat_template` attribute. Once set, the template is used whenever you call [`~PreTrainedTokenizerBase.apply_chat_template`]. It is also saved
|
||||
with the tokenizer whenever [`~PreTrainedTokenizer.save_pretrained`] or [`~PreTrainedTokenizer.push_to_hub`] is called. The template is saved in the `chat_template.jinja` file in the tokenizer directory. You can
|
||||
edit this file directly to change the template, which is often easier than manipulating a template string.
|
||||
|
||||
## Template writing tips
|
||||
|
||||
The easiest way to start writing Jinja templates is to refer to existing templates. Use `print(tokenizer.chat_template)` on any chat model to see the template it's using. Try starting with simple models that don't call any tools or support RAG because tool-use models can have very complex templates. Finally, take a look at the [Jinja documentation](https://jinja.palletsprojects.com/en/stable/templates/#synopsis) for more details about formatting and syntax.
|
||||
|
||||
There are some specific tips and pitfalls you may encounter while writing chat templates specifically, though, and this section will cover some of them in more detail.
|
||||
|
||||
### Writing multimodal chat templates
|
||||
|
||||
For multimodal templates, the `chat_template` attribute is set on the **processor**, not the tokenizer. The `content` key of a message is often a list of content dicts,
|
||||
rather than just a single string. You may wish to check the type of each content item in the list, and handle it accordingly.
|
||||
|
||||
Generally, the template should not directly access image or video data. This is normally handled by the processor after template rendering has finished. Instead,
|
||||
your template should emit a single special token like `<|image|>` or `<|video|>` when it encounters image or video content. The processor will
|
||||
expand the single special token out into a sequence of image or video tokens later. The exact tokens to emit depends on the model you're working with. We strongly recommend loading an existing multimodal processor to see how it handles data.
|
||||
|
||||
The example template below handles mixed image and text content.
|
||||
|
||||
```jinja
|
||||
{%- for message in messages %}
|
||||
{%- if loop.index0 == 0 %}
|
||||
{{- bos_token }}
|
||||
{%- endif %}
|
||||
{{- '<|start_header_id|>' + message['role'] + '<|end_header_id|>\n\n' }}
|
||||
{%- if message['content'] is string %}
|
||||
{{- message['content'] }}
|
||||
{%- else %}
|
||||
{%- for content in message['content'] %}
|
||||
{%- if content['type'] == 'image' %}
|
||||
{{- '<|image|>' }}
|
||||
{%- elif content['type'] == 'text' %}
|
||||
{{- content['text'] }}
|
||||
{%- endif %}
|
||||
{%- endfor %}
|
||||
{%- endif %}
|
||||
{{- '<|eot_id|>' }}
|
||||
{%- endfor %}
|
||||
{%- if add_generation_prompt %}
|
||||
{{- '<|start_header_id|>assistant<|end_header_id|>\n\n' }}
|
||||
{%- endif %}
|
||||
```
|
||||
|
||||
This multimodal template is very similar to the more simple template above, but it checks for `content` lists,
|
||||
and iterates over them to render `<|image|>` tokens where necessary. This allows images to be inserted "into the flow"
|
||||
of user text.
|
||||
|
||||
Not all models work this way - some may move all images to the end of the user message,
|
||||
for example. The chat template should always match the format the model was trained with.
|
||||
|
||||
### Trimming whitespace
|
||||
|
||||
Jinja prints any whitespace before or after a block of text. This can be an issue for chat templates because adding extra whitespace that was not present during model training can harm performance. To remove the whitespace, add `-` to the Jinja line syntax. This allows you to write your template with Pythonic indentation and linebreaks, without accidentally printing an indentation in the rendered output.
|
||||
|
||||
The example template below doesn't use `-`, resulting in extra whitespace being printed in the output.
|
||||
|
||||
```jinja
|
||||
{% for message in messages %}
|
||||
{{ message['role'] + message['content'] }}
|
||||
{% endfor %}
|
||||
```
|
||||
|
||||
We strongly recommend using `-` to ensure only the intended content is printed.
|
||||
|
||||
```jinja
|
||||
{%- for message in messages %}
|
||||
{{- message['role'] + message['content'] }}
|
||||
{%- endfor %}
|
||||
```
|
||||
|
||||
### Special variables and callables
|
||||
|
||||
The only constants in a template are the `messages` variable and the `add_generation_prompt` boolean. However, you have
|
||||
access to **any other keyword arguments that are passed** to the [`~PreTrainedTokenizerBase.apply_chat_template`] method.
|
||||
|
||||
This provides flexibility and enables support for use-cases we may not have thought of while designing the spec. The most common additional variable is `tools`, which contains a list of tools in JSON schema format. Although you can use any variable name you like, we highly recommend sticking to convention and using `tools` for this purpose. This makes templates more compatible with the standard API.
|
||||
|
||||
You also have access to any tokens contained in `tokenizer.special_tokens_map`, which often includes special tokens like `bos_token` and `eos_token`. Access these directly by name, like `{{- bos_token }}`.
|
||||
|
||||
There are two callable functions available to you. To call them, use `{{- function_name(argument) }}`.
|
||||
|
||||
- `raise_exception(msg)` raises a `TemplateException`. This is useful for debugging or warning users about incorrect template usage.
|
||||
- `strftime_now(format_str)` retrieves the current date and time in a specific format, which is often required in system messages. It is equivalent to [datetime.now().strftime(format_str)](https://docs.python.org/3/library/datetime.html#datetime.datetime.now) in Python.
|
||||
|
||||
### Compatibility with non-Python Jinja
|
||||
|
||||
Jinja is implemented in multiple languages and they generally have the same syntax. Writing a template in Python allows you to use Python methods such as [lower](https://docs.python.org/3/library/stdtypes.html#str.lower) on strings or [items](https://docs.python.org/3/library/stdtypes.html#dict.items) on dicts. But this won't work if the template is used in a non-Python implementation, for example, when deploying with Javascript or Rust.
|
||||
|
||||
Make the changes below to ensure compatibility across all Jinja implementations.
|
||||
|
||||
- Replace Python methods with Jinja filters. For example, replace `string.lower()` with `string|lower` or `dict.items()` with `dict|dictitems`. Most of the changes follow the same pattern except `string.strip()`, which is replaced with `string|trim`. Refer to the list of [built-in filters](https://jinja.palletsprojects.com/en/3.1.x/templates/#builtin-filters) for a complete list of filters.
|
||||
- Replace `True`, `False`, and `None` (these are Python specific) with `true`, `false`, and `none` respectively.
|
||||
- Directly rendering a dict or list may return different results in other implementations. For example, string entries may change from single-quote to double-quote. To avoid this, add the [tojson](https://jinja.palletsprojects.com/en/3.1.x/templates/#jinja-filters.tojson) filter to maintain consistency.
|
||||
|
||||
### Big templates
|
||||
|
||||
Newer models or models with features like [tool-calling](./chat_extras) and RAG require larger templates that can be longer than 100 lines. It may be easier to write larger templates in a separate file. The line numbers in the separate file corresponds exactly to the line numbers in template parsing or execution errors, making it easier to debug any potential issues.
|
||||
|
||||
Write the template in a separate file and extract it to the chat template.
|
||||
|
||||
```py
|
||||
open("template.jinja", "w").write(tokenizer.chat_template)
|
||||
```
|
||||
|
||||
You could also load an edited template back into the tokenizer.
|
||||
|
||||
```py
|
||||
tokenizer.chat_template = open("template.jinja").read()
|
||||
```
|
||||
|
||||
## Templates for tools
|
||||
|
||||
There isn't a specific format for writing templates for tools but it is best to follow the standard API. This ensures the template is widely accessible across models without requiring users to write custom code to use tools with your model.
|
||||
|
||||
> [!WARNING]
|
||||
> Formatting such as whitespace and special tokens are model-specific. Make sure everything exactly matches the format a model was trained with.
|
||||
|
||||
The following section lists elements of the standard API for writing templates for tools.
|
||||
|
||||
### Tool definitions
|
||||
|
||||
[Tools](./chat_extras) are passed as Python functions or a JSON schema. When functions are passed, a JSON schema is automatically generated and passed to the template. When a template accesses the `tools` variable, it is always a list of JSON schemas.
|
||||
|
||||
Even though a template always receive tools as a JSON schema, you may need to radically change this format when rendering them to match the format a model was trained with. For example, [Command-R](./model_doc/cohere) was trained with tools defined with Python function headers. The template internally converts JSON schema types and renders the input tools as Python headers.
|
||||
|
||||
The example below shows how a tool is defined in JSON schema format.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "multiply",
|
||||
"description": "A function that multiplies two numbers",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"a": {
|
||||
"type": "number",
|
||||
"description": "The first number to multiply"
|
||||
},
|
||||
"b": {
|
||||
"type": "number",
|
||||
"description": "The second number to multiply"
|
||||
}
|
||||
},
|
||||
"required": ["a", "b"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
An example of handling tool definitions in a chat template is shown below. The specific tokens and layouts should be changed to match the ones the model was trained with.
|
||||
|
||||
```jinja
|
||||
{%- if tools %}
|
||||
{%- for tool in tools %}
|
||||
{{- '<tool>' + tool['function']['name'] + '\n' }}
|
||||
{%- for argument in tool['function']['parameters']['properties'] %}
|
||||
{{- argument + ': ' + tool['function']['parameters']['properties'][argument]['description'] + '\n' }}
|
||||
{%- endfor %}
|
||||
{{- '\n</tool>' }}
|
||||
{%- endif %}
|
||||
{%- endif %}
|
||||
```
|
||||
|
||||
### Tool calls
|
||||
|
||||
In addition to rendering the tool definitions, you also need to render **tool calls** and **tool responses** in the template.
|
||||
|
||||
Tool calls are generally passed in the `tool_calls` key of an `"assistant”` message. This is always a list even though most tool-calling models only support single tool calls, which means the list usually only contains a single element.
|
||||
|
||||
```json
|
||||
{
|
||||
"role": "assistant",
|
||||
"tool_calls": [
|
||||
{
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "multiply",
|
||||
"arguments": {
|
||||
"a": 5,
|
||||
"b": 6
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
A common pattern for handling tool calls is shown below. You can use this as a starting point, but make sure you template actually matches the format the model was trained with!
|
||||
|
||||
```jinja
|
||||
{%- if message['role'] == 'assistant' and 'tool_calls' in message %}
|
||||
{%- for tool_call in message['tool_calls'] %}
|
||||
{{- '<tool_call>' + tool_call['function']['name'] + '\n' + tool_call['function']['arguments']|tojson + '\n</tool_call>' }}
|
||||
{%- endif %}
|
||||
{%- endfor %}
|
||||
{%- endif %}
|
||||
```
|
||||
|
||||
### Tool responses
|
||||
|
||||
Tool responses are message dicts with the `tool` role. They are much simpler than tool calls, and usually only contain the `role`, `name` and `content` keys.
|
||||
|
||||
```json
|
||||
{
|
||||
"role": "tool",
|
||||
"name": "multiply",
|
||||
"content": "30"
|
||||
}
|
||||
```
|
||||
|
||||
Some templates may not even need the `name` key, in which case, you can write your template to only read the `content` key.
|
||||
|
||||
```jinja
|
||||
{%- if message['role'] == 'tool' %}
|
||||
{{- "<tool_result>" + message['content'] + "</tool_result>" }}
|
||||
{%- endif %}
|
||||
```
|
||||
|
||||
## Contribute
|
||||
|
||||
Once a template is ready, set it to the `chat_template` attribute in the tokenizer and test it with [`~PreTrainedTokenizerBase.apply_chat_template`]. If it works as expected, then upload it to the Hub with [`~PreTrainedTokenizer.push_to_hub`].
|
||||
|
||||
Even if you're not the model owner, it is still helpful to add a template for a model with an empty or incorrect chat template. Open a [pull request](https://hf.co/docs/hub/repositories-pull-requests-discussions) on the model repository to add the template!
|
||||
|
||||
```py
|
||||
tokenizer.chat_template = template
|
||||
tokenizer.push_to_hub("amazing_company/cool_model", commit_message="Add chat template", create_pr=True)
|
||||
```
|
||||
@@ -0,0 +1,68 @@
|
||||
<!--⚠️ Note that this file is in Markdown but contains specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
-->
|
||||
|
||||
# Community
|
||||
|
||||
This page regroups resources around 🤗 Transformers developed by the community.
|
||||
|
||||
## Community resources
|
||||
|
||||
| Resource | Description | Author |
|
||||
|:----------|:-------------|------:|
|
||||
| [Hugging Face Transformers Glossary Flashcards](https://www.darigovresearch.com/huggingface-transformers-glossary-flashcards) | A set of flashcards based on the [Transformers Docs Glossary](glossary) that has been put into a form which can be easily learned/revised using [Anki](https://apps.ankiweb.net/) an open source, cross platform app specifically designed for long term knowledge retention. See this [Introductory video on how to use the flashcards](https://www.youtube.com/watch?v=Dji_h7PILrw). | [Darigov Research](https://www.darigovresearch.com/) |
|
||||
|
||||
## Community notebooks
|
||||
|
||||
| Notebook | Description | Author | |
|
||||
|:----------|:-------------|:-------------|------:|
|
||||
| [Fine-tune a pre-trained Transformer to generate lyrics](https://github.com/AlekseyKorshuk/huggingartists) | How to generate lyrics in the style of your favorite artist by fine-tuning a GPT-2 model | [Aleksey Korshuk](https://github.com/AlekseyKorshuk) | [](https://colab.research.google.com/github/AlekseyKorshuk/huggingartists/blob/master/huggingartists-demo.ipynb) |
|
||||
| [Train T5 on TPU](https://github.com/patil-suraj/exploring-T5/blob/master/T5_on_TPU.ipynb) | How to train T5 on SQUAD with Transformers and Nlp | [Suraj Patil](https://github.com/patil-suraj) |[](https://colab.research.google.com/github/patil-suraj/exploring-T5/blob/master/T5_on_TPU.ipynb#scrollTo=QLGiFCDqvuil) |
|
||||
| [Fine-tune T5 for Classification and Multiple Choice](https://github.com/patil-suraj/exploring-T5/blob/master/t5_fine_tuning.ipynb) | How to fine-tune T5 for classification and multiple choice tasks using a text-to-text format with PyTorch Lightning | [Suraj Patil](https://github.com/patil-suraj) | [](https://colab.research.google.com/github/patil-suraj/exploring-T5/blob/master/t5_fine_tuning.ipynb) |
|
||||
| [Fine-tune DialoGPT on New Datasets and Languages](https://github.com/ncoop57/i-am-a-nerd/blob/master/_notebooks/2020-05-12-chatbot-part-1.ipynb) | How to fine-tune the DialoGPT model on a new dataset for open-dialog conversational chatbots | [Nathan Cooper](https://github.com/ncoop57) | [](https://colab.research.google.com/github/ncoop57/i-am-a-nerd/blob/master/_notebooks/2020-05-12-chatbot-part-1.ipynb) |
|
||||
| [Long Sequence Modeling with Reformer](https://github.com/patrickvonplaten/notebooks/blob/master/PyTorch_Reformer.ipynb) | How to train on sequences as long as 500,000 tokens with Reformer | [Patrick von Platen](https://github.com/patrickvonplaten) | [](https://colab.research.google.com/github/patrickvonplaten/notebooks/blob/master/PyTorch_Reformer.ipynb) |
|
||||
| [Fine-tune BART for Summarization](https://github.com/ohmeow/ohmeow_website/blob/master/posts/2021-05-25-mbart-sequence-classification-with-blurr.ipynb) | How to fine-tune BART for summarization with fastai using blurr | [Wayde Gilliam](https://ohmeow.com/) | [](https://colab.research.google.com/github/ohmeow/ohmeow_website/blob/master/posts/2021-05-25-mbart-sequence-classification-with-blurr.ipynb) |
|
||||
| [Fine-tune a pre-trained Transformer on anyone's tweets](https://colab.research.google.com/github/borisdayma/huggingtweets/blob/master/huggingtweets-demo.ipynb) | How to generate tweets in the style of your favorite Twitter account by fine-tuning a GPT-2 model | [Boris Dayma](https://github.com/borisdayma) | [](https://colab.research.google.com/github/borisdayma/huggingtweets/blob/master/huggingtweets-demo.ipynb) |
|
||||
| [Optimize 🤗 Hugging Face models with Weights & Biases](https://colab.research.google.com/github/wandb/examples/blob/master/colabs/huggingface/Optimize_Hugging_Face_models_with_Weights_%26_Biases.ipynb) | A complete tutorial showcasing W&B integration with Hugging Face | [Boris Dayma](https://github.com/borisdayma) | [](https://colab.research.google.com/github/wandb/examples/blob/master/colabs/huggingface/Optimize_Hugging_Face_models_with_Weights_%26_Biases.ipynb) |
|
||||
| [Pretrain Longformer](https://github.com/allenai/longformer/blob/master/scripts/convert_model_to_long.ipynb) | How to build a "long" version of existing pretrained models | [Iz Beltagy](https://beltagy.net) | [](https://colab.research.google.com/github/allenai/longformer/blob/master/scripts/convert_model_to_long.ipynb) |
|
||||
| [Fine-tune Longformer for QA](https://github.com/patil-suraj/Notebooks/blob/master/longformer_qa_training.ipynb) | How to fine-tune longformer model for QA task | [Suraj Patil](https://github.com/patil-suraj) | [](https://colab.research.google.com/github/patil-suraj/Notebooks/blob/master/longformer_qa_training.ipynb) |
|
||||
| [Evaluate Model with 🤗nlp](https://github.com/patrickvonplaten/notebooks/blob/master/How_to_evaluate_Longformer_on_TriviaQA_using_NLP.ipynb) | How to evaluate longformer on TriviaQA with `nlp` | [Patrick von Platen](https://github.com/patrickvonplaten) | [](https://colab.research.google.com/drive/1m7eTGlPmLRgoPkkA7rkhQdZ9ydpmsdLE?usp=sharing) |
|
||||
| [Fine-tune T5 for Sentiment Span Extraction](https://github.com/enzoampil/t5-intro/blob/master/t5_qa_training_pytorch_span_extraction.ipynb) | How to fine-tune T5 for sentiment span extraction using a text-to-text format with PyTorch Lightning | [Lorenzo Ampil](https://github.com/enzoampil) | [](https://colab.research.google.com/github/enzoampil/t5-intro/blob/master/t5_qa_training_pytorch_span_extraction.ipynb) |
|
||||
| [Fine-tune DistilBert for Multiclass Classification](https://github.com/abhimishra91/transformers-tutorials/blob/master/transformers_multiclass_classification.ipynb) | How to fine-tune DistilBert for multiclass classification with PyTorch | [Abhishek Kumar Mishra](https://github.com/abhimishra91) | [](https://colab.research.google.com/github/abhimishra91/transformers-tutorials/blob/master/transformers_multiclass_classification.ipynb)|
|
||||
|[Fine-tune BERT for Multi-label Classification](https://github.com/abhimishra91/transformers-tutorials/blob/master/transformers_multi_label_classification.ipynb)|How to fine-tune BERT for multi-label classification using PyTorch|[Abhishek Kumar Mishra](https://github.com/abhimishra91) |[](https://colab.research.google.com/github/abhimishra91/transformers-tutorials/blob/master/transformers_multi_label_classification.ipynb)|
|
||||
|[Fine-tune T5 for Summarization](https://github.com/abhimishra91/transformers-tutorials/blob/master/transformers_summarization_wandb.ipynb)|How to fine-tune T5 for summarization in PyTorch and track experiments with WandB|[Abhishek Kumar Mishra](https://github.com/abhimishra91) |[](https://colab.research.google.com/github/abhimishra91/transformers-tutorials/blob/master/transformers_summarization_wandb.ipynb)|
|
||||
|[Speed up Fine-Tuning in Transformers with Dynamic Padding / Bucketing](https://github.com/ELS-RD/transformers-notebook/blob/master/Divide_Hugging_Face_Transformers_training_time_by_2_or_more.ipynb)|How to speed up fine-tuning by a factor of 2 using dynamic padding / bucketing|[Michael Benesty](https://github.com/pommedeterresautee) |[](https://colab.research.google.com/drive/1CBfRU1zbfu7-ijiOqAAQUA-RJaxfcJoO?usp=sharing)|
|
||||
|[Pretrain Reformer for Masked Language Modeling](https://github.com/patrickvonplaten/notebooks/blob/master/Reformer_For_Masked_LM.ipynb)| How to train a Reformer model with bi-directional self-attention layers | [Patrick von Platen](https://github.com/patrickvonplaten) | [](https://colab.research.google.com/drive/1tzzh0i8PgDQGV3SMFUGxM7_gGae3K-uW?usp=sharing)|
|
||||
|[Expand and Fine Tune Sci-BERT](https://github.com/lordtt13/word-embeddings/blob/master/COVID-19%20Research%20Data/COVID-SciBERT.ipynb)| How to increase vocabulary of a pretrained SciBERT model from AllenAI on the CORD dataset and pipeline it. | [Tanmay Thakur](https://github.com/lordtt13) | [](https://colab.research.google.com/drive/1rqAR40goxbAfez1xvF3hBJphSCsvXmh8)|
|
||||
|[Fine Tune BlenderBotSmall for Summarization using the Trainer API](https://github.com/lordtt13/transformers-experiments/blob/master/Custom%20Tasks/fine-tune-blenderbot_small-for-summarization.ipynb)| How to fine-tune BlenderBotSmall for summarization on a custom dataset, using the Trainer API. | [Tanmay Thakur](https://github.com/lordtt13) | [](https://colab.research.google.com/drive/19Wmupuls7mykSGyRN_Qo6lPQhgp56ymq?usp=sharing)|
|
||||
|[Fine-tune Electra and interpret with Integrated Gradients](https://github.com/elsanns/xai-nlp-notebooks/blob/master/electra_fine_tune_interpret_captum_ig.ipynb) | How to fine-tune Electra for sentiment analysis and interpret predictions with Captum Integrated Gradients | [Eliza Szczechla](https://elsanns.github.io) | [](https://colab.research.google.com/github/elsanns/xai-nlp-notebooks/blob/master/electra_fine_tune_interpret_captum_ig.ipynb)|
|
||||
|[fine-tune a non-English GPT-2 Model with Trainer class](https://github.com/philschmid/fine-tune-GPT-2/blob/master/Fine_tune_a_non_English_GPT_2_Model_with_Huggingface.ipynb) | How to fine-tune a non-English GPT-2 Model with Trainer class | [Philipp Schmid](https://www.philschmid.de) | [](https://colab.research.google.com/github/philschmid/fine-tune-GPT-2/blob/master/Fine_tune_a_non_English_GPT_2_Model_with_Huggingface.ipynb)|
|
||||
|[Fine-tune a DistilBERT Model for Multi Label Classification task](https://github.com/DhavalTaunk08/Transformers_scripts/blob/master/Transformers_multilabel_distilbert.ipynb) | How to fine-tune a DistilBERT Model for Multi Label Classification task | [Dhaval Taunk](https://github.com/DhavalTaunk08) | [](https://colab.research.google.com/github/DhavalTaunk08/Transformers_scripts/blob/master/Transformers_multilabel_distilbert.ipynb)|
|
||||
|[Fine-tune ALBERT for sentence-pair classification](https://github.com/NadirEM/nlp-notebooks/blob/master/Fine_tune_ALBERT_sentence_pair_classification.ipynb) | How to fine-tune an ALBERT model or another BERT-based model for the sentence-pair classification task | [Nadir El Manouzi](https://github.com/NadirEM) | [](https://colab.research.google.com/github/NadirEM/nlp-notebooks/blob/master/Fine_tune_ALBERT_sentence_pair_classification.ipynb)|
|
||||
|[Fine-tune Roberta for sentiment analysis](https://github.com/DhavalTaunk08/NLP_scripts/blob/master/sentiment_analysis_using_roberta.ipynb) | How to fine-tune a Roberta model for sentiment analysis | [Dhaval Taunk](https://github.com/DhavalTaunk08) | [](https://colab.research.google.com/github/DhavalTaunk08/NLP_scripts/blob/master/sentiment_analysis_using_roberta.ipynb)|
|
||||
|[Evaluating Question Generation Models](https://github.com/flexudy-pipe/qugeev) | How accurate are the answers to questions generated by your seq2seq transformer model? | [Pascal Zoleko](https://github.com/zolekode) | [](https://colab.research.google.com/drive/1bpsSqCQU-iw_5nNoRm_crPq6FRuJthq_?usp=sharing)|
|
||||
|[Leverage BERT for Encoder-Decoder Summarization on CNN/Dailymail](https://github.com/patrickvonplaten/notebooks/blob/master/BERT2BERT_for_CNN_Dailymail.ipynb) | How to warm-start a *EncoderDecoderModel* with a *google-bert/bert-base-uncased* checkpoint for summarization on CNN/Dailymail | [Patrick von Platen](https://github.com/patrickvonplaten) | [](https://colab.research.google.com/github/patrickvonplaten/notebooks/blob/master/BERT2BERT_for_CNN_Dailymail.ipynb)|
|
||||
|[Leverage RoBERTa for Encoder-Decoder Summarization on BBC XSum](https://github.com/patrickvonplaten/notebooks/blob/master/RoBERTaShared_for_BBC_XSum.ipynb) | How to warm-start a shared *EncoderDecoderModel* with a *FacebookAI/roberta-base* checkpoint for summarization on BBC/XSum | [Patrick von Platen](https://github.com/patrickvonplaten) | [](https://colab.research.google.com/github/patrickvonplaten/notebooks/blob/master/RoBERTaShared_for_BBC_XSum.ipynb)|
|
||||
|[Fine-tune TAPAS on Sequential Question Answering (SQA)](https://github.com/NielsRogge/Transformers-Tutorials/blob/master/TAPAS/Fine_tuning_TapasForQuestionAnswering_on_SQA.ipynb) | How to fine-tune *TapasForQuestionAnswering* with a *tapas-base* checkpoint on the Sequential Question Answering (SQA) dataset | [Niels Rogge](https://github.com/nielsrogge) | [](https://colab.research.google.com/github/NielsRogge/Transformers-Tutorials/blob/master/TAPAS/Fine_tuning_TapasForQuestionAnswering_on_SQA.ipynb)|
|
||||
|[Evaluate TAPAS on Table Fact Checking (TabFact)](https://github.com/NielsRogge/Transformers-Tutorials/blob/master/TAPAS/Evaluating_TAPAS_on_the_Tabfact_test_set.ipynb) | How to evaluate a fine-tuned *TapasForSequenceClassification* with a *tapas-base-finetuned-tabfact* checkpoint using a combination of the 🤗 datasets and 🤗 transformers libraries | [Niels Rogge](https://github.com/nielsrogge) | [](https://colab.research.google.com/github/NielsRogge/Transformers-Tutorials/blob/master/TAPAS/Evaluating_TAPAS_on_the_Tabfact_test_set.ipynb)|
|
||||
|[Fine-tuning mBART for translation](https://colab.research.google.com/github/vasudevgupta7/huggingface-tutorials/blob/main/translation_training.ipynb) | How to fine-tune mBART using Seq2SeqTrainer for Hindi to English translation | [Vasudev Gupta](https://github.com/vasudevgupta7) | [](https://colab.research.google.com/github/vasudevgupta7/huggingface-tutorials/blob/main/translation_training.ipynb)|
|
||||
|[Fine-tune LayoutLM on FUNSD (a form understanding dataset)](https://github.com/NielsRogge/Transformers-Tutorials/blob/master/LayoutLM/Fine_tuning_LayoutLMForTokenClassification_on_FUNSD.ipynb) | How to fine-tune *LayoutLMForTokenClassification* on the FUNSD dataset for information extraction from scanned documents | [Niels Rogge](https://github.com/nielsrogge) | [](https://colab.research.google.com/github/NielsRogge/Transformers-Tutorials/blob/master/LayoutLM/Fine_tuning_LayoutLMForTokenClassification_on_FUNSD.ipynb)|
|
||||
|[Fine-Tune DistilGPT2 and Generate Text](https://colab.research.google.com/github/tripathiaakash/DistilGPT2-Tutorial/blob/main/distilgpt2_fine_tuning.ipynb) | How to fine-tune DistilGPT2 and generate text | [Aakash Tripathi](https://github.com/tripathiaakash) | [](https://colab.research.google.com/github/tripathiaakash/DistilGPT2-Tutorial/blob/main/distilgpt2_fine_tuning.ipynb)|
|
||||
|[Fine-Tune LED on up to 8K tokens](https://github.com/patrickvonplaten/notebooks/blob/master/Fine_tune_Longformer_Encoder_Decoder_(LED)_for_Summarization_on_pubmed.ipynb) | How to fine-tune LED on pubmed for long-range summarization | [Patrick von Platen](https://github.com/patrickvonplaten) | [](https://colab.research.google.com/github/patrickvonplaten/notebooks/blob/master/Fine_tune_Longformer_Encoder_Decoder_(LED)_for_Summarization_on_pubmed.ipynb)|
|
||||
|[Evaluate LED on Arxiv](https://github.com/patrickvonplaten/notebooks/blob/master/LED_on_Arxiv.ipynb) | How to effectively evaluate LED on long-range summarization | [Patrick von Platen](https://github.com/patrickvonplaten) | [](https://colab.research.google.com/github/patrickvonplaten/notebooks/blob/master/LED_on_Arxiv.ipynb)|
|
||||
|[Fine-tune LayoutLM on RVL-CDIP (a document image classification dataset)](https://github.com/NielsRogge/Transformers-Tutorials/blob/master/LayoutLM/Fine_tuning_LayoutLMForSequenceClassification_on_RVL_CDIP.ipynb) | How to fine-tune *LayoutLMForSequenceClassification* on the RVL-CDIP dataset for scanned document classification | [Niels Rogge](https://github.com/nielsrogge) | [](https://colab.research.google.com/github/NielsRogge/Transformers-Tutorials/blob/master/LayoutLM/Fine_tuning_LayoutLMForSequenceClassification_on_RVL_CDIP.ipynb)|
|
||||
|[Wav2Vec2 CTC decoding with GPT2 adjustment](https://github.com/voidful/huggingface_notebook/blob/main/xlsr_gpt.ipynb) | How to decode CTC sequence with language model adjustment | [Eric Lam](https://github.com/voidful) | [](https://colab.research.google.com/drive/1e_z5jQHYbO2YKEaUgzb1ww1WwiAyydAj?usp=sharing)|
|
||||
|[Fine-tune BART for summarization in two languages with Trainer class](https://github.com/elsanns/xai-nlp-notebooks/blob/master/fine_tune_bart_summarization_two_langs.ipynb) | How to fine-tune BART for summarization in two languages with Trainer class | [Eliza Szczechla](https://github.com/elsanns) | [](https://colab.research.google.com/github/elsanns/xai-nlp-notebooks/blob/master/fine_tune_bart_summarization_two_langs.ipynb)|
|
||||
|[Evaluate Big Bird on Trivia QA](https://github.com/patrickvonplaten/notebooks/blob/master/Evaluating_Big_Bird_on_TriviaQA.ipynb) | How to evaluate BigBird on long document question answering on Trivia QA | [Patrick von Platen](https://github.com/patrickvonplaten) | [](https://colab.research.google.com/github/patrickvonplaten/notebooks/blob/master/Evaluating_Big_Bird_on_TriviaQA.ipynb)|
|
||||
| [Create video captions using Wav2Vec2](https://github.com/Muennighoff/ytclipcc/blob/main/wav2vec_youtube_captions.ipynb) | How to create YouTube captions from any video by transcribing the audio with Wav2Vec | [Niklas Muennighoff](https://github.com/Muennighoff) |[](https://colab.research.google.com/github/Muennighoff/ytclipcc/blob/main/wav2vec_youtube_captions.ipynb) |
|
||||
| [Fine-tune the Vision Transformer on CIFAR-10 using PyTorch Lightning](https://github.com/NielsRogge/Transformers-Tutorials/blob/master/VisionTransformer/Fine_tuning_the_Vision_Transformer_on_CIFAR_10_with_PyTorch_Lightning.ipynb) | How to fine-tune the Vision Transformer (ViT) on CIFAR-10 using HuggingFace Transformers, Datasets and PyTorch Lightning | [Niels Rogge](https://github.com/nielsrogge) |[](https://colab.research.google.com/github/NielsRogge/Transformers-Tutorials/blob/master/VisionTransformer/Fine_tuning_the_Vision_Transformer_on_CIFAR_10_with_PyTorch_Lightning.ipynb) |
|
||||
| [Fine-tune the Vision Transformer on CIFAR-10 using the 🤗 Trainer](https://github.com/NielsRogge/Transformers-Tutorials/blob/master/VisionTransformer/Fine_tuning_the_Vision_Transformer_on_CIFAR_10_with_the_%F0%9F%A4%97_Trainer.ipynb) | How to fine-tune the Vision Transformer (ViT) on CIFAR-10 using HuggingFace Transformers, Datasets and the 🤗 Trainer | [Niels Rogge](https://github.com/nielsrogge) |[](https://colab.research.google.com/github/NielsRogge/Transformers-Tutorials/blob/master/VisionTransformer/Fine_tuning_the_Vision_Transformer_on_CIFAR_10_with_the_%F0%9F%A4%97_Trainer.ipynb) |
|
||||
| [Evaluate LUKE on Open Entity, an entity typing dataset](https://github.com/studio-ousia/luke/blob/master/notebooks/huggingface_open_entity.ipynb) | How to evaluate *LukeForEntityClassification* on the Open Entity dataset | [Ikuya Yamada](https://github.com/ikuyamada) |[](https://colab.research.google.com/github/studio-ousia/luke/blob/master/notebooks/huggingface_open_entity.ipynb) |
|
||||
| [Evaluate LUKE on TACRED, a relation extraction dataset](https://github.com/studio-ousia/luke/blob/master/notebooks/huggingface_tacred.ipynb) | How to evaluate *LukeForEntityPairClassification* on the TACRED dataset | [Ikuya Yamada](https://github.com/ikuyamada) |[](https://colab.research.google.com/github/studio-ousia/luke/blob/master/notebooks/huggingface_tacred.ipynb) |
|
||||
| [Evaluate LUKE on CoNLL-2003, an important NER benchmark](https://github.com/studio-ousia/luke/blob/master/notebooks/huggingface_conll_2003.ipynb) | How to evaluate *LukeForEntitySpanClassification* on the CoNLL-2003 dataset | [Ikuya Yamada](https://github.com/ikuyamada) |[](https://colab.research.google.com/github/studio-ousia/luke/blob/master/notebooks/huggingface_conll_2003.ipynb) |
|
||||
| [Evaluate BigBird-Pegasus on PubMed dataset](https://github.com/vasudevgupta7/bigbird/blob/main/notebooks/bigbird_pegasus_evaluation.ipynb) | How to evaluate *BigBirdPegasusForConditionalGeneration* on PubMed dataset | [Vasudev Gupta](https://github.com/vasudevgupta7) | [](https://colab.research.google.com/github/vasudevgupta7/bigbird/blob/main/notebooks/bigbird_pegasus_evaluation.ipynb) |
|
||||
| [Speech Emotion Classification with Wav2Vec2](https://github.com/m3hrdadfi/soxan/blob/main/notebooks/Emotion_recognition_in_Greek_speech_using_Wav2Vec2.ipynb) | How to leverage a pretrained Wav2Vec2 model for Emotion Classification on the MEGA dataset | [Mehrdad Farahani](https://github.com/m3hrdadfi) | [](https://colab.research.google.com/github/m3hrdadfi/soxan/blob/main/notebooks/Emotion_recognition_in_Greek_speech_using_Wav2Vec2.ipynb) |
|
||||
| [Detect objects in an image with DETR](https://github.com/NielsRogge/Transformers-Tutorials/blob/master/DETR/DETR_minimal_example_(with_DetrFeatureExtractor).ipynb) | How to use a trained *DetrForObjectDetection* model to detect objects in an image and visualize attention | [Niels Rogge](https://github.com/NielsRogge) | [](https://colab.research.google.com/github/NielsRogge/Transformers-Tutorials/blob/master/DETR/DETR_minimal_example_(with_DetrFeatureExtractor).ipynb) |
|
||||
| [Fine-tune DETR on a custom object detection dataset](https://github.com/NielsRogge/Transformers-Tutorials/blob/master/DETR/Fine_tuning_DetrForObjectDetection_on_custom_dataset_(balloon).ipynb) | How to fine-tune *DetrForObjectDetection* on a custom object detection dataset | [Niels Rogge](https://github.com/NielsRogge) | [](https://colab.research.google.com/github/NielsRogge/Transformers-Tutorials/blob/master/DETR/Fine_tuning_DetrForObjectDetection_on_custom_dataset_(balloon).ipynb) |
|
||||
| [Finetune T5 for Named Entity Recognition](https://github.com/ToluClassics/Notebooks/blob/main/T5_Ner_Finetuning.ipynb) | How to fine-tune *T5* on a Named Entity Recognition Task | [Ogundepo Odunayo](https://github.com/ToluClassics) | [](https://colab.research.google.com/drive/1obr78FY_cBmWY5ODViCmzdY6O1KB65Vc?usp=sharing) |
|
||||
| [Fine-Tuning Open-Source LLM using QLoRA with MLflow and PEFT](https://github.com/mlflow/mlflow/blob/master/docs/source/llms/transformers/tutorials/fine-tuning/transformers-peft.ipynb) | How to use [QLoRA](https://github.com/artidoro/qlora) and [PEFT](https://huggingface.co/docs/peft/en/index) to fine-tune an LLM in a memory-efficient way, while using [MLflow](https://mlflow.org/docs/latest/llms/transformers/index.html) to manage experiment tracking | [Yuki Watanabe](https://github.com/B-Step62) | [](https://colab.research.google.com/github/mlflow/mlflow/blob/master/docs/source/llms/transformers/tutorials/fine-tuning/transformers-peft.ipynb) |
|
||||
@@ -0,0 +1,60 @@
|
||||
<!--Copyright 2026 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Axolotl
|
||||
|
||||
[Axolotl](https://docs.axolotl.ai/) is a fine-tuning and post-training framework for large language models. It supports adapter-based tuning, ND-parallel distributed training, GRPO, and QAT. Through [TRL](./trl), Axolotl also handles preference learning, reinforcement learning, and reward modeling workflows.
|
||||
|
||||
Define your training run in a YAML config file.
|
||||
|
||||
```yaml
|
||||
base_model: NousResearch/Nous-Hermes-llama-1b-v1
|
||||
model_type: AutoModelForCausalLM
|
||||
tokenizer_type: AutoTokenizer
|
||||
|
||||
datasets:
|
||||
- path: tatsu-lab/alpaca
|
||||
type: alpaca
|
||||
|
||||
output_dir: ./outputs
|
||||
sequence_len: 512
|
||||
micro_batch_size: 1
|
||||
gradient_accumulation_steps: 1
|
||||
num_epochs: 1
|
||||
learning_rate: 2.0e-5
|
||||
```
|
||||
|
||||
Launch training with the [train](https://docs.axolotl.ai/docs/cli.html#train) command.
|
||||
|
||||
```bash
|
||||
axolotl train my_config.yml
|
||||
```
|
||||
|
||||
## Transformers integration
|
||||
|
||||
Axolotl's [ModelLoader](https://docs.axolotl.ai/docs/api/loaders.model.html#axolotl.loaders.model.ModelLoader) wraps the Transformers load flow.
|
||||
|
||||
- The model config builds from [`AutoConfig.from_pretrained`]. Preload setup configures the [device map](https://huggingface.co/docs/accelerate/concept_guides/big_model_inference#designing-a-device-map), [quantization config](../main_classes/quantization), and [attention backend](../attention_interface).
|
||||
|
||||
- `ModelLoader` automatically selects the appropriate [`AutoModel`] class ([`AutoModelForCausalLM`], [`AutoModelForImageTextToText`], [`AutoModelForSequenceClassification`]) or a model-specific class from the multimodal mapping. Weights load with the selected loader's `from_pretrained`. When `reinit_weights` is set, Axolotl uses `from_config` for random initialization.
|
||||
|
||||
- Axolotl uses Transformers, [PEFT](https://huggingface.co/docs/peft/index), and [bitsandbytes](https://huggingface.co/docs/bitsandbytes/index) to apply adapters after model initialization when PEFT-based techniques such as LoRA and QLoRA are enabled. A patch manager applies additional optimizations before and after model loading.
|
||||
|
||||
- [AxolotlTrainer](https://docs.axolotl.ai/docs/api/core.trainers.base.html#axolotl.core.trainers.base.AxolotlTrainer) extends [`Trainer`], adding Axolotl mixins while using the [`Trainer`] training loop and APIs.
|
||||
|
||||
## Resources
|
||||
|
||||
- [Axolotl](https://docs.axolotl.ai/) docs
|
||||
@@ -0,0 +1,43 @@
|
||||
<!--Copyright 2026 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Candle
|
||||
|
||||
[Candle](https://github.com/huggingface/candle) is a machine learning framework providing native Rust implementations of Transformers models. It natively supports [safetensors](https://huggingface.co/docs/safetensors/en/index) to load Transformers models directly.
|
||||
|
||||
```rust
|
||||
/// load model config
|
||||
let config: Config =
|
||||
serde_json::from_reader(std::fs::File::open(config_filename)?)?;
|
||||
|
||||
/// load safetensors and memory-maps them
|
||||
let vb = unsafe {
|
||||
VarBuilder::from_mmaped_safetensors(&filenames, dtype, &device)?
|
||||
};
|
||||
|
||||
/// materialize tensors from VarBuilder into model class
|
||||
let model = Model::new(args.use_flash_attn, &config, vb)?;
|
||||
```
|
||||
|
||||
## Transformers integration
|
||||
|
||||
1. The [hf-hub](https://github.com/huggingface/hf-hub) crate checks your local [Hugging Face cache](../installation#cache-directory) for a model. If it isn't there, it downloads model weights and configs from the Hub.
|
||||
2. [VarBuilder](https://github.com/huggingface/candle/blob/f526033db7ea880c7189628a2dc00e3e2008a9e7/candle-nn/src/var_builder.rs#L38) lazily loads the safetensor files. It maps state-dict key names to Rust structs representing model layers. This mirrors how Transformers organizes its weights.
|
||||
3. Candle parses `config.json` to extract model metadata and instantiates the matching Rust model class with weights from `VarBuilder`.
|
||||
|
||||
## Resources
|
||||
|
||||
- [Candle](https://github.com/huggingface/candle) documentation
|
||||
@@ -0,0 +1,92 @@
|
||||
<!--Copyright 2026 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# ExecuTorch
|
||||
|
||||
[ExecuTorch](https://docs.pytorch.org/executorch/stable/index.html) is a lightweight runtime for model inference on edge devices. It exports a PyTorch model into a portable, ahead-of-time format. A small C++ runtime plans memory and dispatches operations to hardware-specific backends. Execution and memory behavior is known before the model runs on device, so inference overhead is low.
|
||||
|
||||
Export a Transformers model with the [optimum-executorch](https://huggingface.co/docs/optimum-executorch/en/index) library.
|
||||
|
||||
<hfoptions id="export">
|
||||
<hfoption id="CLI">
|
||||
|
||||
```bash
|
||||
optimum-cli export executorch \
|
||||
--model "HuggingFaceTB/SmolLM2-135M-Instruct" \
|
||||
--task "text-generation" \
|
||||
--recipe "xnnpack" \
|
||||
--output_dir="./smollm2_exported"
|
||||
```
|
||||
|
||||
</hfoption>
|
||||
<hfoption id="Python">
|
||||
|
||||
```py
|
||||
from transformers import AutoTokenizer
|
||||
from optimum.executorch import ExecuTorchModelForCausalLM
|
||||
|
||||
model = ExecuTorchModelForCausalLM.from_pretrained(
|
||||
"HuggingFaceTB/SmolLM2-135M-Instruct",
|
||||
recipe="xnnpack",
|
||||
)
|
||||
model.save_pretrained("./smollm2_exported")
|
||||
tokenizer = AutoTokenizer.from_pretrained("HuggingFaceTB/SmolLM2-135M-Instruct")
|
||||
```
|
||||
|
||||
</hfoption>
|
||||
</hfoptions>
|
||||
|
||||
## Transformers integration
|
||||
|
||||
The export process uses several Transformers components.
|
||||
|
||||
1. [`~PreTrainedModel.from_pretrained`] loads the model weights in safetensors format.
|
||||
2. Optimum applies graph optimizations and runs [torch.export](https://docs.pytorch.org/docs/stable/export.html) to create a `model.pte` file targeting your hardware backend.
|
||||
3. [`AutoTokenizer`] or [`AutoProcessor`] loads the tokenizer or processor files and runs during inference.
|
||||
4. At runtime, a C++ runner class executes the `.pte` file on the ExecuTorch runtime.
|
||||
|
||||
```c++
|
||||
#include <executorch/extension/llm/runner/text_llm_runner.h>
|
||||
|
||||
using namespace executorch::extension::llm;
|
||||
|
||||
int main() {
|
||||
// Load tokenizer and create runner
|
||||
auto tokenizer = load_tokenizer("path/to/tokenizer.json", nullptr, std::nullopt, 0, 0);
|
||||
auto runner = create_text_llm_runner("path/to/model.pte", std::move(tokenizer));
|
||||
|
||||
// Load the model
|
||||
runner->load();
|
||||
|
||||
// Configure generation
|
||||
GenerationConfig config;
|
||||
config.max_new_tokens = 100;
|
||||
config.temperature = 0.8f;
|
||||
|
||||
// Generate text with streaming output
|
||||
runner->generate("The capital of France is", config,
|
||||
[](const std::string& token) { std::cout << token << std::flush; },
|
||||
nullptr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
## Resources
|
||||
|
||||
- [ExecuTorch](https://docs.pytorch.org/executorch/stable/index.html) docs
|
||||
- [torch.export](https://docs.pytorch.org/docs/stable/export.html) docs
|
||||
- [Exporting to production](../serialization#executorch) guide
|
||||
@@ -0,0 +1,61 @@
|
||||
<!--Copyright 2025 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# llama.cpp
|
||||
|
||||
[llama.cpp](https://github.com/ggml-org/llama.cpp) is a C/C++ inference engine for deploying large language models locally. It's lightweight and doesn't require Python, CUDA, or other heavy server infrastructure. llama.cpp uses the [GGUF](https://huggingface.co/blog/ngxson/common-ai-model-formats#gguf) file format. GGUF supports quantized model weights and memory-mapping to reduce memory bandwidth on your device.
|
||||
|
||||
> [!TIP]
|
||||
> Browse the [Hub](https://huggingface.co/models?apps=llama.cpp&sort=trending) for models already available in GGUF format.
|
||||
|
||||
Convert any Transformers model to GGUF format with the [convert_hf_to_gguf.py](https://github.com/ggml-org/llama.cpp/blob/master/convert_hf_to_gguf.py) script.
|
||||
|
||||
```bash
|
||||
python3 convert_hf_to_gguf.py ./models/openai/gpt-oss-20b \
|
||||
--outfile gpt-oss-20b.gguf \
|
||||
```
|
||||
|
||||
Deploy the model locally from the command line with [llama-cli](https://github.com/ggml-org/llama.cpp/tree/master#llama-cli) or start a web UI with [llama-server](https://github.com/ggml-org/llama.cpp/tree/master#llama-server). Add the `-hf` flag to indicate the model is from the Hub.
|
||||
|
||||
<hfoptions id="deploy">
|
||||
<hfoption id="llama-cli">
|
||||
|
||||
```bash
|
||||
llama-cli -hf ggml-org/gpt-oss-20b-GGUF
|
||||
```
|
||||
|
||||
</hfoption>
|
||||
<hfoption id="llama-server">
|
||||
|
||||
```bash
|
||||
llama-server -hf ggml-org/gpt-oss-20b-GGUF
|
||||
```
|
||||
|
||||
</hfoption>
|
||||
</hfoptions>
|
||||
|
||||
## Transformers integration
|
||||
|
||||
1. [`AutoConfig.from_pretrained`] loads the model's `config.json` file to extract metadata.
|
||||
2. [`AutoTokenizer.from_pretrained`] extracts the vocabulary and tokenizer configuration.
|
||||
3. Based on the `architectures` field in the config, the script selects a converter class from its internal registry. The registry maps Transformers architecture names (like [`LlamaForCausalLM`]) to corresponding converter classes.
|
||||
4. The converter maps Transformers tensor names (for example, `model.layers.0.self_attn.q_proj.weight`) to GGUF tensor names, transforms tensors, and packages the vocabulary.
|
||||
5. The output is a single GGUF file containing the model weights, tokenizer, and metadata.
|
||||
|
||||
## Resources
|
||||
|
||||
- [llama.cpp](https://github.com/ggml-org/llama.cpp) documentation
|
||||
- [Introduction to ggml](https://huggingface.co/blog/introduction-to-ggml) blog post
|
||||
@@ -0,0 +1,54 @@
|
||||
<!--Copyright 2026 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# MLX
|
||||
|
||||
[MLX](https://ml-explore.github.io/mlx/build/html/index.html) is an array framework for machine learning on Apple silicon that also works with CUDA. On Apple silicon, arrays stay in shared memory to avoid data copies between CPU and GPU. Lazy computation enables graph manipulation and optimizations. Native [safetensors](https://huggingface.co/docs/safetensors/en/index) support means Transformers language models run directly on MLX.
|
||||
|
||||
Install the [mlx-lm](https://github.com/ml-explore/mlx-lm) library.
|
||||
|
||||
```bash
|
||||
pip install mlx-lm transformers
|
||||
```
|
||||
|
||||
Load any Transformers language model from the Hub as long as the model architecture is [supported](https://huggingface.co/mlx-community/models). No weight conversion is required.
|
||||
|
||||
```py
|
||||
from mlx_lm import load, generate
|
||||
|
||||
model, tokenizer = load("openai/gpt-oss-20b")
|
||||
output = generate(
|
||||
model,
|
||||
tokenizer,
|
||||
prompt="The capital of France is",
|
||||
max_tokens=100,
|
||||
)
|
||||
print(output)
|
||||
```
|
||||
|
||||
## Transformers integration
|
||||
|
||||
- [mlx_lm.load](https://github.com/ml-explore/mlx-lm?tab=readme-ov-file#python-api) loads safetensor weights and returns a model and tokenizer.
|
||||
- MLX loads weight arrays keyed by tensor names and maps them into an MLX [nn.Module](https://ml-explore.github.io/mlx/build/html/python/nn/module.html#) parameter tree. This matches how Transformers checkpoints are organized.
|
||||
|
||||
> [!TIP]
|
||||
> The MLX Transformers integration is bidirectional. Transformers can also load and run MLX weights from the Hub.
|
||||
|
||||
## Resources
|
||||
|
||||
- [MLX](https://ml-explore.github.io/mlx/build/html/index.html) documentation
|
||||
- [mlx-lm](https://github.com/ml-explore/mlx-lm) repository containing MLX LLM implementations
|
||||
- [mlx-vlm](https://github.com/Blaizzy/mlx-vlm) community library with VLM implementations
|
||||
@@ -0,0 +1,40 @@
|
||||
<!--Copyright 2026 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Nanotron
|
||||
|
||||
[Nanotron](https://github.com/huggingface/nanotron) is a distributed training framework with tensor, parallel, and data parallelism (3D parallelism). It is designed for large-scale training workloads across hundreds of GPUs.
|
||||
|
||||
Convert any Transformers model to an optimized Nanotron transformer model implementation for pretraining with the [convert_hf_to_nanotron.py](https://github.com/huggingface/nanotron/blob/main/examples/llama/convert_hf_to_nanotron.py) script.
|
||||
|
||||
```bash
|
||||
torchrun --nproc_per_node=1 examples/llama/convert_hf_to_nanotron.py \
|
||||
--checkpoint_path=meta-llama/Llama-2-7b-hf \
|
||||
--save_path=./llama-7b-nanotron
|
||||
```
|
||||
|
||||
## Transformers integration
|
||||
|
||||
1. Load a supported Transformers model, like [`Llama`], with the [`~LlamaForCausalLM.from_pretrained`] function. This reads the `config.json` file from the checkpoint directory and creates a [`LlamaConfig`].
|
||||
2. Nanotron maps [`LlamaConfig`] to it's own config format and creates a Nanotron model.
|
||||
3. Convert Transformers weights to Nanotron. A weight mapping guides how to map Nanotron parameter names to Transformers parameter names. This includes handling transformations such as fusing the QKV projections and the gate/up projections.
|
||||
|
||||
Nanotron also relies on [`AutoTokenizer`] for turning text into token ids during preprocessing and generation.
|
||||
|
||||
## Resources
|
||||
|
||||
- [Nanontron](https://github.com/huggingface/nanotron) repository
|
||||
- [Ultrascale Playbook](https://huggingface.co/spaces/nanotron/ultrascale-playbook) describes how to efficiently scale training with Nanotron
|
||||
@@ -0,0 +1,72 @@
|
||||
<!--Copyright 2026 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# NeMo Automodel
|
||||
|
||||
[NeMo Automodel](https://github.com/NVIDIA-NeMo/Automodel) is an open-source PyTorch DTensor-native training library from NVIDIA. It supports large and small scale pretraining and fine-tuning for [LLMs](https://docs.nvidia.com/nemo/automodel/latest/model-coverage/large-language-models/overview) and [VLMs](https://docs.nvidia.com/nemo/automodel/latest/model-coverage/vision-language-models/overview) for fast experimentation in research and production environments, with parallelism strategies including FSDP2, tensor, pipeline, expert, and context parallelism. For high throughput, it integrates kernels from DeepEP and TransformerEngine.
|
||||
|
||||
Define your training run in a YAML config file (see full [config file](https://github.com/NVIDIA-NeMo/Automodel/blob/106e5162ef5b5d7269a3ba1ef62bfa8941b26cc6/examples/llm_finetune/nemotron/nemotron_nano_v3_hellaswag_peft.yaml)).
|
||||
|
||||
```yaml
|
||||
# Instantiate a Nemotron V3 Nano model
|
||||
model:
|
||||
_target_: nemo_automodel.NeMoAutoModelForCausalLM.from_pretrained
|
||||
pretrained_model_name_or_path: nvidia/NVIDIA-Nemotron-3-Nano-30B-A3B-BF16
|
||||
|
||||
# Run SFT on HellaSwag
|
||||
dataset:
|
||||
_target_: nemo_automodel.components.datasets.llm.hellaswag.HellaSwag
|
||||
path_or_dataset: rowan/hellaswag
|
||||
split: train
|
||||
|
||||
# Train PEFT adapters
|
||||
peft:
|
||||
_target_: nemo_automodel.components._peft.lora.PeftConfig
|
||||
exclude_modules: ["*.out_proj"] # mamba layers use custom kernels that take in the out_proj.weight directly, thus lora doesn't work here.
|
||||
dim: 8
|
||||
alpha: 32
|
||||
use_triton: True
|
||||
|
||||
# Use EP + FSDP2 for training
|
||||
distributed:
|
||||
strategy: fsdp2
|
||||
dp_size: none
|
||||
tp_size: 1
|
||||
cp_size: 1
|
||||
ep_size: 4
|
||||
|
||||
# ... other parameters
|
||||
```
|
||||
|
||||
Launch training with `torchrun` using the command below.
|
||||
|
||||
```bash
|
||||
torchrun --nproc-per-node=4 examples/llm_finetune/finetune.py -c /path/to/yaml
|
||||
```
|
||||
|
||||
## Transformers integration
|
||||
|
||||
- Any LLM or VLM supported in Transformers can also be instantiated through NeMo Automodel. See the [full model coverage](https://docs.nvidia.com/nemo/automodel/latest/model-coverage/overview).
|
||||
- Built on top of Hugging Face models with [`AutoModel.from_pretrained`], with dynamic high-performance layer swaps and support for more refined parallelisms like Expert Parallelism (EP).
|
||||
- Detects the architecture field in [`AutoConfig.from_pretrained`] to automatically load custom implementations like Nemotron Nano V3.
|
||||
- Follows the Transformers API closely for drop-in compatibility.
|
||||
|
||||
## Resources
|
||||
|
||||
- [NeMo Automodel](https://github.com/NVIDIA-NeMo/Automodel)
|
||||
- [NeMo Transformers API](https://docs.nvidia.com/nemo/automodel/latest/get-started/hf-compatibility)
|
||||
- NeMo Automodel dense models and Mixture-of-Expert (MoE) [benchmarks](https://docs.nvidia.com/nemo/automodel/latest/performance/performance-summary)
|
||||
- See the NeMo [pretraining](./nemo_automodel_pretraining) guide to learn how to use NeMo for pretraining
|
||||
@@ -0,0 +1,67 @@
|
||||
<!--Copyright 2026 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# NeMo Automodel
|
||||
|
||||
[NeMo Automodel](https://github.com/NVIDIA-NeMo/Automodel) is an open-source PyTorch DTensor-native training library from NVIDIA. It supports large and small scale pretraining and fine-tuning for [LLMs](https://docs.nvidia.com/nemo/automodel/latest/model-coverage/large-language-models/overview) and [VLMs](https://docs.nvidia.com/nemo/automodel/latest/model-coverage/vision-language-models/overview) for fast experimentation in research and production environments, with parallelism strategies including FSDP2, tensor, pipeline, expert, and context parallelism. For high throughput, it integrates kernels from DeepEP and TransformerEngine.
|
||||
|
||||
```py
|
||||
# Instantiating Nemotron V3 Nano with Expert Parallelism, FSDP2, and TransformerEngine + DeepEP kernels.
|
||||
import os
|
||||
|
||||
import torch
|
||||
import torch.distributed as dist
|
||||
|
||||
from nemo_automodel import NeMoAutoModelForCausalLM
|
||||
from nemo_automodel.recipes._dist_utils import create_distributed_setup_from_config
|
||||
|
||||
dist.init_process_group(backend="nccl")
|
||||
torch.cuda.set_device(int(os.environ.get("LOCAL_RANK", 0)))
|
||||
torch.manual_seed(1111)
|
||||
|
||||
dist_setup = create_distributed_setup_from_config(
|
||||
{
|
||||
"strategy": "fsdp2",
|
||||
"ep_size": 8,
|
||||
},
|
||||
)
|
||||
model = NeMoAutoModelForCausalLM.from_pretrained(
|
||||
"nvidia/NVIDIA-Nemotron-3-Nano-30B-A3B-BF16",
|
||||
dtype=torch.bfloat16,
|
||||
distributed_setup=dist_setup,
|
||||
)
|
||||
print(model)
|
||||
dist.destroy_process_group()
|
||||
```
|
||||
Launch the script with `torchrun` using the command below.
|
||||
|
||||
```bash
|
||||
torchrun --nproc-per-node=8 /path/to/script
|
||||
```
|
||||
|
||||
## Transformers integration
|
||||
|
||||
- Any LLM or VLM supported in Transformers can also be instantiated through NeMo Automodel. See the [full model coverage](https://docs.nvidia.com/nemo/automodel/latest/model-coverage/overview).
|
||||
- Built on top of Hugging Face models with [`AutoModel.from_pretrained`], with dynamic high-performance layer swaps and support for more refined parallelisms like Expert Parallelism (EP).
|
||||
- Detects the architecture field in [`AutoConfig.from_pretrained`] to automatically load custom implementations like Nemotron Nano V3.
|
||||
- Follows the Transformers API closely for drop-in compatibility.
|
||||
|
||||
## Resources
|
||||
|
||||
- [NeMo Automodel](https://github.com/NVIDIA-NeMo/Automodel)
|
||||
- [NeMo Transformers API](https://docs.nvidia.com/nemo/automodel/latest/get-started/hf-compatibility)
|
||||
- NeMo Automodel dense models and Mixture-of-Expert (MoE) [benchmarks](https://docs.nvidia.com/nemo/automodel/latest/performance/performance-summary)
|
||||
- See the NeMo [fine-tuning](./nemo_automodel_finetuning) guide to learn how to use NeMo for fine-tuning
|
||||
@@ -0,0 +1,58 @@
|
||||
<!--Copyright 2025 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# SGLang
|
||||
|
||||
[SGLang](https://docs.sglang.ai) is a low-latency, high-throughput inference engine for large language models (LLMs). It also includes a frontend language for building agentic workflows.
|
||||
|
||||
Set `model_impl="transformers"` to load a Transformers modeling backend.
|
||||
|
||||
```py
|
||||
import sglang as sgl
|
||||
|
||||
llm = sgl.Engine("meta-llama/Llama-3.2-1B-Instruct", model_impl="transformers")
|
||||
print(llm.generate(["The capital of France is"], {"max_new_tokens": 20})[0])
|
||||
```
|
||||
|
||||
Pass `--model-impl transformers` to the `sglang.launch_server` command for online serving.
|
||||
|
||||
```bash
|
||||
python3 -m sglang.launch_server \
|
||||
--model-path meta-llama/Llama-3.2-1B-Instruct \
|
||||
--model-impl transformers \
|
||||
--host 0.0.0.0 \
|
||||
--port 30000
|
||||
```
|
||||
|
||||
## Transformers integration
|
||||
|
||||
Setting `model_impl="transformers"` tells SGLang to skip its native model matching and use the Transformers model directly.
|
||||
|
||||
1. [`PreTrainedConfig.from_pretrained`] loads the model's `config.json` from the Hub or your Hugging Face cache.
|
||||
2. [`AutoModel.from_config`] resolves the model class based on the config.
|
||||
3. During loading, `_attn_implementation` is set to `"sglang"`. This routes attention calls through SGLang's RadixAttention kernels.
|
||||
4. SGLang's parallel linear class replaces linear layers to support tensor parallelism.
|
||||
5. The [load_weights](https://github.com/sgl-project/sglang/blob/main/python/sglang/srt/models/transformers.py#L277) function populates the model with weights from safetensors files.
|
||||
|
||||
The model benefits from all SGLang optimizations while using the Transformers model structure.
|
||||
|
||||
> [!WARNING]
|
||||
> Compatible models require `_supports_attention_backend=True` so SGLang can control attention execution. See the [Building a compatible model backend for inference](./transformers_as_backend#model-implementation) guide for details.
|
||||
|
||||
## Resources
|
||||
|
||||
- [SGLang docs](https://docs.sglang.ai/supported_models/transformers_fallback.html) has more usage examples and tips for using Transformers as a backend.
|
||||
- [Transformers backend integration in SGLang](https://huggingface.co/blog/transformers-backend-sglang) blog post explains what this integration enables.
|
||||
@@ -0,0 +1,41 @@
|
||||
<!--Copyright 2026 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# TensorRT-LLM
|
||||
|
||||
[TensorRT-LLM](https://github.com/NVIDIA/TensorRT-LLM) is optimizes LLM inference on NVIDIA GPUs. It compiles models into a TensorRT engine with in-flight batching, paged KV caching, and tensor parallelism. [AutoDeploy](https://nvidia.github.io/TensorRT-LLM/torch/auto_deploy/auto-deploy.html) accepts Transformers models without requiring any changes. It automatically converts the model to an optimized runtime.
|
||||
|
||||
Pass a model id from the Hub to [build_and_run_ad.py](https://github.com/NVIDIA/TensorRT-LLM/blob/main/examples/auto_deploy/build_and_run_ad.py) to run a Transformers model.
|
||||
|
||||
```bash
|
||||
cd examples/auto_deploy
|
||||
python build_and_run_ad.py --model meta-llama/Llama-3.2-1B
|
||||
```
|
||||
|
||||
Under the hood, AutoDeploy creates an [LLM](https://nvidia.github.io/TensorRT-LLM/llm-api/reference.html#tensorrt_llm.llmapi.LLM) class. It loads the model configuration with [`AutoConfig.from_pretrained`] and extracts any parallelism metadata stored in `tp_plan`. [`AutoModelForCausalLM.from_pretrained`] loads the model with the config and enables Transformers' built-in tensor parallelism.
|
||||
|
||||
```py
|
||||
from tensorrt_llm._torch.auto_deploy import LLM
|
||||
|
||||
llm = LLM(model="meta-llama/Llama-3.2-1B")
|
||||
```
|
||||
|
||||
TensorRT-LLM extracts the model graph with `torch.export` and applies optimizations. It replaces Transformers attention with TensorRT-LLM [attention kernels](https://github.com/NVIDIA/TensorRT-LLM/tree/main/tensorrt_llm/_torch/attention_backend) and compiles the model into an optimized execution backend.
|
||||
|
||||
## Resources
|
||||
|
||||
- [TensorRT-LLM docs](https://nvidia.github.io/TensorRT-LLM/) for more detailed usage guides.
|
||||
- [AutoDeploy guide](https://nvidia.github.io/TensorRT-LLM/torch/auto_deploy/auto-deploy.html) explains how it works with advanced examples.
|
||||
@@ -0,0 +1,60 @@
|
||||
<!--Copyright 2026 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# torchtitan
|
||||
|
||||
[torchtitan](https://github.com/pytorch/torchtitan) is PyTorch's distributed training framework for large language models. It supports Fully Sharded Data Parallelism (FSDP), tensor, pipeline, and context parallelism (4D parallelism). torchtitan is fully compatible with [torch.compile](../perf_torch_compile), enabling kernel fusion and graph optimizations that significantly reduce memory overhead and speed up training.
|
||||
|
||||
> [!NOTE]
|
||||
> Only dense models are supported at the moment.
|
||||
|
||||
Use a Transformers model directly in torchtitan's distributed training infrastructure.
|
||||
|
||||
```py
|
||||
import torch
|
||||
from torchtitan.config.job_config import JobConfig
|
||||
from torchtitan.experiments.transformers_modeling_backend.job_config import (
|
||||
HFTransformers,
|
||||
)
|
||||
from torchtitan.experiments.transformers_modeling_backend.model.args import (
|
||||
TitanDenseModelArgs,
|
||||
HFTransformerModelArgs,
|
||||
)
|
||||
from torchtitan.experiments.transformers_modeling_backend.model.model import (
|
||||
HFTransformerModel,
|
||||
)
|
||||
|
||||
job_config = JobConfig()
|
||||
|
||||
job_config.hf_transformers = HFTransformers(model="Qwen/Qwen2.5-7B")
|
||||
|
||||
titan_args = TitanDenseModelArgs()
|
||||
model_args = HFTransformerModelArgs(titan_dense_args=titan_args).update_from_config(
|
||||
job_config
|
||||
)
|
||||
|
||||
model = HFTransformerModel(model_args)
|
||||
```
|
||||
|
||||
## Transformers integration
|
||||
|
||||
1. [`AutoConfig.from_pretrained`] loads the config for a given model. The config values are copied into torchtitan style args in `HFTransformerModelArgs`.
|
||||
2. torchtitan's `HFTransformerModel` wrapper scans the `architecture` field in the config and instantiates and loads the corresponding model class, like [`LlamaForCausalLM`].
|
||||
3. The `forward` path uses native Transformers components while leaning on torchtitan's parallelization and optimization methods. torchtitan treats the Transformers model as a torchtitan model without needing to rewrite anything.
|
||||
|
||||
## Resources
|
||||
|
||||
- [torchtitan](https://github.com/pytorch/torchtitan) repository
|
||||
@@ -0,0 +1,141 @@
|
||||
<!--Copyright 2025 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Building a compatible model backend for inference
|
||||
|
||||
Transformers models are compatible with inference engines like [vLLM](https://github.com/vllm-project/vllm) and [SGLang](https://docs.sglang.ai). Use the same Transformers model anywhere and avoid reimplementing a model from scratch for each inference engine. This also helps with models that an engine does not natively reimplement, as long as the model supports the attention backend interface described below.
|
||||
|
||||
This guide shows you how to implement a model in Transformers that works as a backend for any inference engine.
|
||||
|
||||
## Model implementation
|
||||
|
||||
1. Follow the model [contribution guidelines](../add_new_model) or the [custom model contribution guidelines](../custom_models). The model must have a valid `config.json` in its directory and a valid `auto_map` field pointing to the model class in the config.
|
||||
|
||||
2. Use the [`AttentionInterface`] class for custom and optimized attention functions. This interface unlocks each inference engine's performance features.
|
||||
|
||||
Use `ALL_ATTENTION_FUNCTIONS` when defining the attention layer and propagate `**kwargs` from the base `MyModel` class to the attention layers. Set `_supports_attention_backend` to `True` in [`PreTrainedModel`].
|
||||
|
||||
Expand the code below for an example.
|
||||
|
||||
<details>
|
||||
<summary>modeling_my_model.py</summary>
|
||||
|
||||
```python
|
||||
from transformers import PreTrainedModel
|
||||
from transformers.modeling_utils import ALL_ATTENTION_FUNCTIONS
|
||||
from torch import nn
|
||||
|
||||
class MyAttention(nn.Module):
|
||||
|
||||
def forward(self, hidden_states, **kwargs):
|
||||
...
|
||||
attention_interface = ALL_ATTENTION_FUNCTIONS[self.config._attn_implementation]
|
||||
attn_output, attn_weights = attention_interface(
|
||||
self,
|
||||
query_states,
|
||||
key_states,
|
||||
value_states,
|
||||
**kwargs,
|
||||
)
|
||||
...
|
||||
|
||||
class MyModel(PreTrainedModel):
|
||||
_supports_attention_backend = True
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
3. Enable optional tensor or pipeline parallelism by adding the following keys to [`PreTrainedConfig`].
|
||||
|
||||
* `base_model_tp_plan` enables [tensor parallelism](../perf_infer_gpu_multi) by mapping fully qualified layer name patterns to tensor parallel styles. Supports only the `"colwise"` and `"rowwise"` partitioning strategies.
|
||||
* `base_model_pp_plan` enables pipeline parallelism by mapping direct child layer names to tuples of lists of strings. The first element of the tuple contains the names of the input arguments. The last element contains the variable names of the layer outputs in the modeling code.
|
||||
|
||||
Expand the code below for an example.
|
||||
|
||||
<details>
|
||||
<summary>configuration_my_model.py</summary>
|
||||
|
||||
```python
|
||||
|
||||
from transformers import PreTrainedConfig
|
||||
|
||||
class MyConfig(PreTrainedConfig):
|
||||
base_model_tp_plan = {
|
||||
"layers.*.self_attn.k_proj": "colwise",
|
||||
"layers.*.self_attn.v_proj": "colwise",
|
||||
"layers.*.self_attn.o_proj": "rowwise",
|
||||
"layers.*.mlp.gate_proj": "colwise",
|
||||
"layers.*.mlp.up_proj": "colwise",
|
||||
"layers.*.mlp.down_proj": "rowwise",
|
||||
}
|
||||
base_model_pp_plan = {
|
||||
"embed_tokens": (["input_ids"], ["inputs_embeds"]),
|
||||
"layers": (["hidden_states", "attention_mask"], ["hidden_states"]),
|
||||
"norm": (["hidden_states"], ["hidden_states"]),
|
||||
}
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
## Multimodal models
|
||||
|
||||
Multimodal models require additional changes beyond the [vision language model contribution checklist](../contributing#vision-language-model-contribution-checklist). These changes ensure multimodal inputs are properly processed.
|
||||
|
||||
1. The [`ProcessorMixin`] class must include the `self.image_token` and `self.image_token_ids` attributes. These placeholder tokens indicate image positions in the input. The same token appears in the input prompt for images and in the model code to scatter image features.
|
||||
|
||||
2. The [`ProcessorMixin`] class must include a `self._get_num_multimodal_tokens` method. This method computes the number of placeholder tokens required for multimodal inputs with given sizes. It returns a [`MultiModalData`] object. Placeholders between `<image>` tokens, such as row or column tokens, don't count as image placeholders. Count only tokens replaced by image features later in the modeling code.
|
||||
|
||||
3. The [`ProcessorMixin`] class must check the value of `return_mm_token_type_ids` and return `mm_token_type_ids`. This indicates whether each position is a text token (`0`), image placeholder token (`1`), or a video placeholder token (`2`). Multimodal token type id sequences must be contiguous with no breaks between consecutive tokens. Treat special tokens for beginning, ending, row, and column tokens as placeholders.
|
||||
|
||||
Expand the code below for an example.
|
||||
|
||||
<details>
|
||||
<summary>modeling_my_multimodal_model.py</summary>
|
||||
|
||||
```python
|
||||
class MyMultimodalProcessor(ProcessorMixin):
|
||||
|
||||
def __call__(self, images=None, text=None, **kwargs):
|
||||
if return_mm_token_type_ids:
|
||||
mm_token_type_ids = np.zeros_like(input_ids)
|
||||
mm_token_type_ids[input_ids == self.image_token_id] = 1
|
||||
text_inputs["mm_token_type_ids"] = mm_token_type_ids.tolist()
|
||||
return BatchFeature(data={**text_inputs, **image_inputs}, tensor_type=return_tensors)
|
||||
|
||||
def _get_num_multimodal_tokens(self, image_sizes=None, **kwargs):
|
||||
"""
|
||||
Computes the number of placeholder tokens needed for multimodal inputs with the given sizes.
|
||||
Args:
|
||||
image_sizes (`list[list[int]]`, *optional*):
|
||||
The input sizes formatted as (height, width) per each image.
|
||||
Returns:
|
||||
`MultiModalData`: A `MultiModalData` object holding number of tokens per each of the provided
|
||||
input modalities, along with other useful data.
|
||||
"""
|
||||
vision_data = {}
|
||||
if image_sizes is not None:
|
||||
num_image_tokens = [256] * len(image_sizes) # 256 placeholder tokens for each image always
|
||||
num_image_patches = [1] * len(image_sizes) # no patching, thus each image is processed as a single base image
|
||||
vision_data.update({"num_image_tokens": num_image_tokens, "num_image_patches": num_image_patches})
|
||||
return MultiModalData(**vision_data)
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
## Resources
|
||||
|
||||
* Read the [Transformers backend integration in vLLM](https://blog.vllm.ai/2025/04/11/transformers-backend.html) blog post for more details.
|
||||
* Read the [Transformers backend integration in SGLang](https://huggingface.co/blog/transformers-backend-sglang) blog post for more details.
|
||||
@@ -0,0 +1,47 @@
|
||||
<!--Copyright 2026 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# TRL
|
||||
|
||||
[TRL](https://huggingface.co/docs/trl/index) is a post-training framework for foundation models. It includes methods like SFT, GRPO, and DPO. Each method has a dedicated trainer that builds on the [`Trainer`] class and scales from a single GPU to multi-node clusters.
|
||||
|
||||
```py
|
||||
from datasets import load_dataset
|
||||
from trl import GRPOTrainer
|
||||
from trl.rewards import accuracy_reward
|
||||
|
||||
dataset = load_dataset("trl-lib/DeepMath-103K", split="train")
|
||||
|
||||
trainer = GRPOTrainer(
|
||||
model="Qwen/Qwen2-0.5B-Instruct",
|
||||
reward_funcs=accuracy_reward,
|
||||
train_dataset=dataset,
|
||||
)
|
||||
trainer.train()
|
||||
```
|
||||
|
||||
## Transformers integration
|
||||
|
||||
TRL extends Transformers APIs and adds method-specific settings.
|
||||
|
||||
- TRL trainers build on [`Trainer`]. Method-specific trainers like [`~trl.GRPOTrainer`] add generation, reward scoring, and loss computation. Config classes extend [`TrainingArguments`] with method-specific fields.
|
||||
|
||||
- Model loading uses [`AutoConfig.from_pretrained`], then instantiates the model class from the config with that class' `from_pretrained`.
|
||||
|
||||
## Resources
|
||||
|
||||
- [TRL](https://huggingface.co/docs/trl/index) docs
|
||||
- [Fine Tuning with TRL](https://huggingface.co/datasets/trl-lib/documentation-images/resolve/main/Fine%20tuning%20with%20TRL%20(Oct%2025).pdf) talk
|
||||
@@ -0,0 +1,70 @@
|
||||
<!--Copyright 2026 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Unsloth
|
||||
|
||||
[Unsloth](https://unsloth.ai/docs) is a fine-tuning and reinforcement framework that speeds up training and reduces memory usage for large language models. It supports training in 4-bit, 8-bit, and 16-bit precision with custom RoPE and Triton kernels. Unsloth works with Llama, Mistral, Gemma, Qwen, and other model families.
|
||||
|
||||
```py
|
||||
from datasets import load_dataset
|
||||
from transformers import TrainingArguments
|
||||
from unsloth import FastLanguageModel
|
||||
from unsloth.trainer import UnslothTrainer
|
||||
|
||||
model, tokenizer = FastLanguageModel.from_pretrained(
|
||||
model_name="unsloth/Llama-3.2-1B-Instruct",
|
||||
max_seq_length=2048,
|
||||
load_in_4bit=True,
|
||||
)
|
||||
|
||||
model = FastLanguageModel.get_peft_model(
|
||||
model,
|
||||
r=16,
|
||||
lora_alpha=16,
|
||||
target_modules=["q_proj", "k_proj", "v_proj", "o_proj", "gate_proj", "up_proj", "down_proj"],
|
||||
)
|
||||
|
||||
dataset = load_dataset("trl-lib/Capybara", split="train[:500]")
|
||||
dataset = dataset.map(lambda x: {"text": x["conversations"][0]["value"]})
|
||||
|
||||
trainer = UnslothTrainer(
|
||||
model=model,
|
||||
tokenizer=tokenizer,
|
||||
train_dataset=dataset,
|
||||
dataset_text_field="text",
|
||||
max_seq_length=2048,
|
||||
args=TrainingArguments(
|
||||
output_dir="outputs",
|
||||
per_device_train_batch_size=2,
|
||||
num_train_epochs=1,
|
||||
),
|
||||
)
|
||||
|
||||
trainer.train()
|
||||
```
|
||||
|
||||
## Transformers integration
|
||||
|
||||
Unsloth wraps Transformers APIs and patches internal methods for speed.
|
||||
|
||||
- `FastLanguageModel.from_pretrained` loads config with [`AutoConfig.from_pretrained`]. It then loads a base model with [`AutoModelForCausalLM.from_pretrained`]. Before loading, Unsloth patches attention, decoder layer, and rotary embedding classes inside a Transformers model.
|
||||
|
||||
- `UnslothTrainer` extends TRL's [`~trl.SFTTrainer`]. Unsloth patches [`~Trainer.compute_loss`] and [`~Trainer.training_step`] to fix gradient accumulation in older Transformers versions.
|
||||
|
||||
## Resources
|
||||
|
||||
- [Unsloth](https://unsloth.ai/docs) docs
|
||||
- [Make LLM Fine-tuning 2x faster with Unsloth and TRL](https://huggingface.co/blog/unsloth-trl) blog post
|
||||
@@ -0,0 +1,50 @@
|
||||
<!--Copyright 2025 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# vLLM
|
||||
|
||||
[vLLM](https://github.com/vllm-project/vllm) is a high-throughput inference engine for serving LLMs at scale. It continuously batches requests and keeps KV cache memory compact with PagedAttention.
|
||||
|
||||
Set `model_impl="transformers"` to load a model using the Transformers modeling backend.
|
||||
|
||||
```py
|
||||
from vllm import LLM
|
||||
|
||||
llm = LLM(model="meta-llama/Llama-3.2-1B", model_impl="transformers")
|
||||
print(llm.generate(["The capital of France is"]))
|
||||
```
|
||||
|
||||
Pass `--model-impl transformers` to the `vllm serve` command for online serving.
|
||||
|
||||
```bash
|
||||
vllm serve meta-llama/Llama-3.2-1B \
|
||||
--task generate \
|
||||
--model-impl transformers
|
||||
```
|
||||
|
||||
## Transformers integration
|
||||
|
||||
1. [`AutoConfig.from_pretrained`] loads the model's `config.json` from the Hub or your Hugging Face cache. vLLM checks the `architectures` field against its internal model registry to determine which vLLM model class to use.
|
||||
2. If the model isn't in the registry, vLLM calls [`AutoModel.from_config`] to load the Transformers model implementation instead.
|
||||
3. [`AutoTokenizer.from_pretrained`] loads the tokenizer files. vLLM caches some tokenizer internals to reduce overhead during inference.
|
||||
4. Model weights download from the Hub in safetensors format.
|
||||
|
||||
Setting `model_impl="transformers"` bypasses the vLLM model registry and loads directly from Transformers. vLLM replaces most model modules (MoE, attention, linear layers) with its own optimized versions while keeping the Transformers model structure.
|
||||
|
||||
## Resources
|
||||
|
||||
- [vLLM docs](https://docs.vllm.ai/en/latest/models/supported_models.html#transformers) for more usage examples and tips.
|
||||
- [Integration with Hugging Face](https://docs.vllm.ai/en/latest/design/huggingface_integration/) explains how vLLM integrates with Transformers.
|
||||
@@ -0,0 +1,469 @@
|
||||
<!--Copyright 2025 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Continuous batching
|
||||
|
||||
Continuous batching maximizes GPU utilization by dynamically rescheduling the batch at every generation step. As requests finish, new ones join immediately instead of waiting for the whole batch to complete. The GPU stays full and throughput stays high.
|
||||
|
||||
> [!TIP]
|
||||
> For production deployments, use [transformers serve](./serve-cli/serving_optims#continuous-batching). It builds on [`ContinuousBatchingManager`] and exposes an OpenAI-compatible HTTP endpoint.
|
||||
|
||||
## generate_batch
|
||||
|
||||
Continuous batching is supported through [`~ContinuousMixin.generate_batch`]. Pass a list of tokenized prompts and get back results for all of them when they're done. `generate_batch` handles scheduling internally and blocks until all requests are complete.
|
||||
|
||||
For serving and streaming use cases, use [ContinuousBatchingManager](#continuousbatchingmanager) directly to manage requests.
|
||||
|
||||
```py
|
||||
import torch
|
||||
from transformers import AutoModelForCausalLM, AutoTokenizer
|
||||
from transformers.generation import ContinuousBatchingConfig, GenerationConfig
|
||||
|
||||
model = AutoModelForCausalLM.from_pretrained(
|
||||
"Qwen/Qwen3-4B",
|
||||
attn_implementation="flash_attention_2",
|
||||
device_map="cuda",
|
||||
dtype=torch.bfloat16,
|
||||
)
|
||||
tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen3-4B")
|
||||
|
||||
prompts = [
|
||||
"Whats up?",
|
||||
"Name a cat breed.",
|
||||
"Write a detailed history of quantum mechanics.",
|
||||
]
|
||||
inputs = [tokenizer.encode(p) for p in prompts]
|
||||
|
||||
generation_config = GenerationConfig(
|
||||
max_new_tokens=64,
|
||||
eos_token_id=tokenizer.eos_token_id,
|
||||
)
|
||||
|
||||
outputs = model.generate_batch(inputs=inputs, generation_config=generation_config)
|
||||
|
||||
for request_id, output in outputs.items():
|
||||
text = tokenizer.decode(output.generated_tokens, skip_special_tokens=True)
|
||||
print(f"[{request_id}] {text}")
|
||||
```
|
||||
|
||||
|
||||
## ContinuousBatchingManager
|
||||
|
||||
[`ContinuousBatchingManager`] runs a background thread and lets you submit requests and retrieve results independently. Every generation step, it checks for finished requests and schedules new ones to join the batch. This is useful for streaming, real-time serving, or submitting requests as they arrive.
|
||||
|
||||
Use [`~ContinuousMixin.continuous_batching_context_manager`] to start and stop the manager safely. The example below contains variable length inputs. As soon as the shortest prompt is complete, it leaves the batch while the longer prompts continue generating. With static batching, you'd have to pad them all to the same length. Continuous batching frees up the completed prompt so you can start processing the next prompt immediately.
|
||||
|
||||
```py
|
||||
with model.continuous_batching_context_manager(generation_config=generation_config) as manager:
|
||||
manager.add_request(
|
||||
input_ids=tokenizer.encode("Write a detailed history of quantum mechanics."),
|
||||
request_id="long",
|
||||
max_new_tokens=512,
|
||||
)
|
||||
manager.add_request(
|
||||
input_ids=tokenizer.encode("What's up?"),
|
||||
request_id="short_0",
|
||||
max_new_tokens=32,
|
||||
)
|
||||
manager.add_request(
|
||||
input_ids=tokenizer.encode("Name a cat breed."),
|
||||
request_id="short_1",
|
||||
max_new_tokens=32,
|
||||
)
|
||||
|
||||
for result in manager:
|
||||
text = tokenizer.decode(result.generated_tokens, skip_special_tokens=True)
|
||||
print(f"[{result.request_id}] {text}")
|
||||
```
|
||||
|
||||
You could also call [`~ContinuousMixin.init_continuous_batching`] to manage the lifecycle yourself.
|
||||
|
||||
```py
|
||||
manager = model.init_continuous_batching(generation_config=generation_config)
|
||||
manager.start()
|
||||
|
||||
# submit and retrieve requests...
|
||||
```
|
||||
|
||||
### Shutting down the manager
|
||||
|
||||
The manager runs a background thread and holds distributed resources. Shutdown happens in two stages so you can choose what to do with in-flight work.
|
||||
|
||||
Call [`~ContinuousBatchingManager.stop`] to halt the background thread. By default, the manager stops accepting new submissions and waits for queued and active requests to finish before the thread exits.
|
||||
|
||||
```py
|
||||
manager.stop()
|
||||
```
|
||||
|
||||
Pass `hard_stop=True` to abandon pending work immediately. Queued and active requests are failed with a `RuntimeError` instead of finishing.
|
||||
|
||||
```py
|
||||
manager.stop(hard_stop=True)
|
||||
```
|
||||
|
||||
Once `stop` is called, [`~ContinuousBatchingManager.add_request`] and [`~ContinuousBatchingManager.add_requests`] drop new submissions and log a warning. You can still call `start` again to run another generation session with the same manager.
|
||||
|
||||
Call [`~ContinuousBatchingManager.destroy`] to release distributed resources. `destroy` stops the manager first if it's still running, and the manager cannot be restarted afterwards. Use it when you're done with continuous batching for the lifetime of the process.
|
||||
|
||||
```py
|
||||
manager.destroy()
|
||||
```
|
||||
|
||||
[`~ContinuousMixin.continuous_batching_context_manager`] handles this process. It calls `stop` on exit and `destroy` unless you pass `persistent_manager=True` to cache the manager on the model for the next session.
|
||||
|
||||
### Adding requests
|
||||
|
||||
[`~ContinuousBatchingManager.add_request`] submits a single request. Provide a `request_id` or let the manager generate one automatically.
|
||||
|
||||
```py
|
||||
manager.add_request(input_ids=input_ids, request_id="my_request")
|
||||
```
|
||||
|
||||
[`~ContinuousBatchingManager.add_requests`] submits a batch at once. It sorts inputs automatically to maximize prefix cache hits when block sharing is enabled.
|
||||
|
||||
```py
|
||||
manager.add_requests(inputs=inputs)
|
||||
```
|
||||
|
||||
Cancel a request with [`~ContinuousBatchingManager.cancel_request`].
|
||||
|
||||
```py
|
||||
manager.cancel_request(request_id="my_request")
|
||||
```
|
||||
|
||||
### Per-request sampling parameters
|
||||
|
||||
Enable `per_request_processors` to apply `temperature`, `top_k`, and `top_p` independently per request within the same forward pass to allow different sampling parameters for different requests (creative, high-temperature outputs versus precise, low-temperature ones for example).
|
||||
|
||||
```py
|
||||
cb_config = ContinuousBatchingConfig(per_request_processors=True)
|
||||
|
||||
# each request gets its own sampling parameters
|
||||
manager.add_request(input_ids=inputs_a, temperature=0.9, top_p=0.95)
|
||||
manager.add_request(input_ids=inputs_b, temperature=0.1, top_k=10)
|
||||
```
|
||||
|
||||
Each parameter in [`GenerationConfig`] must be a non-default value in order to create the associated logits processor at runtime. For example, set `temperature` to a value other than `None` or `1` to support per-request temperature control. Requests with temperatures of `1` can still be created afterwards.
|
||||
|
||||
### Retrieving results
|
||||
|
||||
Iterate over the manager to receive results as they arrive.
|
||||
|
||||
```py
|
||||
for result in manager:
|
||||
print(tokenizer.decode(result.generated_tokens, skip_special_tokens=True))
|
||||
```
|
||||
|
||||
[`~ContinuousBatchingManager.get_result`] fetches the next result from the output queue. Pass a `request_id` to filter for a specific request. If the next result in the queue doesn't match, it's requeued and the method returns `None`.
|
||||
|
||||
```py
|
||||
# next available result
|
||||
result = manager.get_result()
|
||||
|
||||
# filter for a specific request
|
||||
result = manager.get_result(request_id="my_request")
|
||||
```
|
||||
|
||||
### Streaming
|
||||
|
||||
Set `streaming=True` on a request, then use [`~ContinuousBatchingManager.request_id_iter`] to iterate over partial outputs as tokens are generated.
|
||||
|
||||
```py
|
||||
from transformers.generation.continuous_batching import RequestStatus
|
||||
|
||||
manager.add_request(input_ids=input_ids, request_id="streamed", streaming=True)
|
||||
|
||||
for chunk in manager.request_id_iter(request_id="streamed"):
|
||||
token = tokenizer.decode(chunk.generated_tokens[-1:], skip_special_tokens=True)
|
||||
print(token, end="", flush=True)
|
||||
if chunk.status == RequestStatus.FINISHED:
|
||||
break
|
||||
```
|
||||
|
||||
## ContinuousBatchingConfig
|
||||
|
||||
[`ContinuousBatchingConfig`] controls the KV cache, scheduling, CUDA graphs, memory usage, and more. Pass it alongside [`GenerationConfig`] to customize continuous batching.
|
||||
|
||||
By default, `max_batch_tokens` is `8192`, bounded by available GPU memory and never below `256`, while `num_blocks` fills the remaining memory. Use the table below to help you pick the appropriate features.
|
||||
|
||||
| Feature | Memory | Throughput | Latency |
|
||||
|---|---|---|---|
|
||||
| `max_memory_percent` / `block_size` | ✓ controls KV budget | | |
|
||||
| `max_batch_tokens` | ↑ larger input buffers | ✓ bigger prefill batches | ✓ TTFT when prefill-bound |
|
||||
| `scheduler` | | ✓ scheduling policy | ✓ TTFT |
|
||||
| CUDA graphs | ↑ graph storage | ✓ less dispatch overhead | ✓ |
|
||||
| Async batching | ↑ ~2× I/O buffers | ✓ overlaps CPU/GPU | |
|
||||
| Compilation | ↑ warmup-time only | ✓ faster forward passes | ✓ |
|
||||
| Decode fast path | ↑ block table per request | ✓ faster decode-only steps | ✓ |
|
||||
| CPU offloading | ↑ pinned CPU memory | ✓ skips some re-prefills | |
|
||||
| Prefix caching | ↓ shared KV blocks | ✓ skips redundant prefill | ✓ TTFT |
|
||||
| Paged attention | ↓ no fragmentation | ✓ dynamic batch membership | |
|
||||
| Sliding window | ↓ bounded KV per layer | | |
|
||||
| Per-request processors | | ✓ mixed sampling params per batch | |
|
||||
| `max_requests_per_batch` | ↓ caps logits buffer | ✓ bounds batch size | |
|
||||
| `safety_margin` | | | ✓ protects decode latency |
|
||||
|
||||
```py
|
||||
from transformers.generation import ContinuousBatchingConfig
|
||||
|
||||
cb_config = ContinuousBatchingConfig(
|
||||
max_memory_percent=0.8, # fraction of free GPU memory to use for the KV cache
|
||||
block_size=256, # KV cache block size in tokens
|
||||
scheduler_type="fifo", # "fifo" or "prefill_first"
|
||||
)
|
||||
|
||||
outputs = model.generate_batch(
|
||||
inputs=inputs,
|
||||
generation_config=generation_config,
|
||||
continuous_batching_config=cb_config,
|
||||
)
|
||||
```
|
||||
|
||||
### KV cache block size
|
||||
|
||||
`block_size` sets how many tokens each KV cache block holds. It must be at least 4, and `generate_batch` raises a `ValueError` for any smaller value. The cache reserves two extra blocks for padding and sentinel bookkeeping, so very small blocks spend a large fraction of memory on this fixed overhead. Larger blocks cut bookkeeping but waste space when a sequence doesn't fill its last block. The default of 256 matches the `flash_attn_with_kvcache` decode kernel and works well in most cases. Keep `block_size` well above the minimum for an efficient cache.
|
||||
|
||||
```py
|
||||
cb_config = ContinuousBatchingConfig(block_size=128)
|
||||
```
|
||||
|
||||
### Prefill batch size
|
||||
|
||||
`max_batch_tokens` sets the token budget for a single forward pass, the maximum number of query tokens the model processes at once. A larger budget packs more prompt tokens into each prefill, which raises prefill throughput and lowers time-to-first-token on prompt-heavy workloads. The scheduler splits prompts that exceed the budget across steps. See [chunked prefill](./continuous_batching_architecture#chunked-prefill) for how oversized prompts are handled.
|
||||
|
||||
By default, `max_batch_tokens` is `8192`. The value is bounded by available GPU memory so the per-batch input tensors don't crowd out the KV cache, and it never falls below `256`. On a GPU with little free memory, the bound lowers it below `8192`.
|
||||
|
||||
`max_batch_tokens` and `num_blocks` draw from the same memory budget, so they trade off against each other. A larger token budget allocates bigger input buffers and leaves fewer KV cache blocks for concurrent or long requests. Raise `max_batch_tokens` to push prefill throughput when you have more memory available, and lower it to free memory for more KV blocks or to avoid out-of-memory errors.
|
||||
|
||||
```py
|
||||
cb_config = ContinuousBatchingConfig(max_batch_tokens=16384)
|
||||
```
|
||||
|
||||
### Batch and scheduling limits
|
||||
|
||||
`max_requests_per_batch` caps how many requests run in a single forward pass. The model produces a logits tensor sized by the number of batch tokens and the vocabulary size, and it's cast to `fp32` for sampling, which doubles the footprint. Each request only needs one next-token prediction, so a smaller cap keeps this tensor smaller and avoids out-of-memory errors on prefill-heavy batches with large vocabularies. By default it's set to the number of prompts submitted, with a fallback of 1024, then capped to fit `max_batch_tokens` and `num_blocks`.
|
||||
|
||||
```py
|
||||
cb_config = ContinuousBatchingConfig(max_requests_per_batch=256)
|
||||
```
|
||||
|
||||
`safety_margin` reserves a fraction of the KV cache for active requests. When free blocks fall below `safety_margin * num_blocks`, the scheduler stops admitting new prefills and only continues decoding the requests already in progress. This prioritizes finishing active work over starting new requests, which protects decode latency and delays [offloading](./continuous_batching_architecture#offloading). The value must fall between `0` and `1`, where `0` disables the margin.
|
||||
|
||||
```py
|
||||
cb_config = ContinuousBatchingConfig(safety_margin=0.15)
|
||||
```
|
||||
|
||||
The default depends on the scheduler. For the FIFO scheduler, it's `0.15` and for `prefill_first`, it's `0.0`. See [Admission](./continuous_batching_architecture#admission) for how the margin interacts with scheduling.
|
||||
|
||||
### Log probabilities
|
||||
|
||||
[`ContinuousBatchingConfig`] returns each generated token's log probability when `return_logprobs=True`. This is useful for RL where logprobs are an input to some of the training loops.
|
||||
|
||||
```py
|
||||
cb_config = ContinuousBatchingConfig(return_logprobs=True)
|
||||
|
||||
# generate_batch()
|
||||
|
||||
for request_id, output in outputs.items():
|
||||
for token_id, log_prob in zip(output.generated_tokens, output.logprobs):
|
||||
token = tokenizer.decode([token_id])
|
||||
print(f"{token} | logprob: {log_prob}")
|
||||
```
|
||||
|
||||
### CUDA graphs
|
||||
|
||||
CUDA graphs eliminate CPU dispatch overhead by recording the GPU execution graph once and replaying it for batches with matching shapes. Enable them explicitly with `use_cuda_graph=True`.
|
||||
|
||||
```py
|
||||
cb_config = ContinuousBatchingConfig(use_cuda_graph=True)
|
||||
```
|
||||
|
||||
When active, the manager pads query and KV lengths to fixed intervals so shapes repeat and graphs reuse. Smaller values of `q_padding_interval_size` and `kv_padding_interval_size` reduce wasted compute on padding, but this means there are more unique shapes the graph has to record and store which costs more memory.
|
||||
|
||||
```py
|
||||
cb_config = ContinuousBatchingConfig(
|
||||
use_cuda_graph=True,
|
||||
q_padding_interval_size=64,
|
||||
kv_padding_interval_size=16384,
|
||||
)
|
||||
```
|
||||
|
||||
### Async batching
|
||||
|
||||
Async batching overlaps CPU scheduling of the next batch with GPU computation of the current one. It requires CUDA graphs and roughly doubles the VRAM used for input tensors.
|
||||
|
||||
```py
|
||||
cb_config = ContinuousBatchingConfig(
|
||||
use_cuda_graph=True,
|
||||
use_async_batching=True,
|
||||
)
|
||||
```
|
||||
|
||||
### Compilation
|
||||
|
||||
`default_compile_level` applies `torch.compile` to the model's forward passes. Compilation trades a one-time warmup cost for faster forward passes during generation. Higher levels run more aggressive optimization, which improves throughput but lengthens warmup. Keep the level low for tests and benchmark iteration, and raise it for long-running serving workloads where the warmup cost is paid back over many requests.
|
||||
|
||||
The level ranges from `0` to `3`. Level `0` is the default and skips compilation entirely.
|
||||
|
||||
| Level | `mode` | `dynamic` | Trade-off |
|
||||
|---|---|---|---|
|
||||
| 0 | — | — | No compilation (default), fastest startup |
|
||||
| 1 | `default` | `True` | Modest speedup, short warmup |
|
||||
| 2 | `max-autotune-no-cudagraphs` | `True` | More speedup, longer warmup |
|
||||
| 3 | `max-autotune-no-cudagraphs` | `False` | Best throughput, longest warmup |
|
||||
|
||||
```py
|
||||
cb_config = ContinuousBatchingConfig(default_compile_level=1)
|
||||
```
|
||||
|
||||
The level supplies a default [`CompileConfig`] to the varlen and decode execution paths. It only applies to a path that has no explicit config, so `varlen_compile_config` and `decode_compile_config` take precedence when set. Under FlashAttention, the varlen path skips compilation because `max_seqlen_k` triggers frequent recompilation, so the level affects only the decode path in that case.
|
||||
|
||||
### Decode fast path
|
||||
|
||||
When a batch contains only decode requests (one query token per sequence), the manager can dispatch to the `flash_attn_with_kvcache` kernel instead of the variable-length kernel. This is faster than the varlen path because the kernel reads and writes the paged KV cache in-place through a block table rather than going through a manual update. See [Paged attention](./paged_attention) for kernel-level details.
|
||||
|
||||
The fast path is sized by `max_blocks_per_request`, which dimensions the per-request block table. By default this is auto-inferred. If `max_prompt_length` and `max_generated_length` are set on the manager, the block table is sized to fit the maximum sequence length. Otherwise, a fallback default (32 blocks per request) is used.
|
||||
|
||||
Set `max_blocks_per_request` to a specific value to size the block table explicitly. This is useful when you know the maximum sequence length per request and want to bound the block table memory cost.
|
||||
|
||||
```py
|
||||
cb_config = ContinuousBatchingConfig(max_blocks_per_request=64)
|
||||
```
|
||||
|
||||
Set `max_blocks_per_request=0` to disable the fast path and force every batch through the varlen kernel. This recovers the pre-default behavior and is useful when the fast path is unavailable for your attention implementation (the manager also disables it automatically when the underlying kernel can't be used).
|
||||
|
||||
```py
|
||||
cb_config = ContinuousBatchingConfig(max_blocks_per_request=0)
|
||||
```
|
||||
|
||||
The fast path relies on the `flash_attn_with_kvcache` kernel, which is available for two device and attention implementation combinations.
|
||||
|
||||
| Device | `attn_implementation` |
|
||||
|---|---|
|
||||
| CUDA | `flash_attention_2` or `flash_attention_3` |
|
||||
| XPU | [flash_attention_2](https://huggingface.co/kernels-community/flash-attn2) |
|
||||
|
||||
For any other combination, or when the kernel can't be imported, the manager falls back to the varlen path. It logs a warning only when you set `max_blocks_per_request` explicitly.
|
||||
|
||||
### CPU offloading
|
||||
|
||||
CPU offloading copies evicted KV cache blocks to a pre-allocated pinned CPU buffer when the GPU KV cache is full. After cache space becomes available, the manager copies the blocks back to the GPU and resumes the request without recomputing its prompt and generated tokens.
|
||||
|
||||
Set `cpu_offload_space` to the CPU swap space in GiB. The default value, `0.0`, disables CPU offloading.
|
||||
|
||||
```py
|
||||
cb_config = ContinuousBatchingConfig(cpu_offload_space=8.0)
|
||||
```
|
||||
|
||||
By default, `cpu_offload_space_safety_threshold=0.8` limits the requested space to 80% of available system RAM when `psutil` is installed. Set `cpu_offload_space=None` to size the swap pool from the safety threshold.
|
||||
|
||||
### Tensor parallel timeout
|
||||
|
||||
Under tensor parallelism, the manager creates a CPU communication group to coordinate request submissions, cancellations, and shutdown across ranks. `cpu_group_timeout` limits how long a collective on this group can block before the process crashes. If one rank stalls, the timeout prevents the others from waiting forever.
|
||||
|
||||
Set a longer timeout for workloads that issue infrequent collectives, or pass `None` to disable it.
|
||||
|
||||
```py
|
||||
cb_config = ContinuousBatchingConfig(cpu_group_timeout=600.0)
|
||||
```
|
||||
|
||||
### Prefix caching
|
||||
|
||||
When multiple requests share a common prefix, like a system prompt, the manager reuses their KV cache blocks instead of recomputing them. This is enabled by default and requires all model layers to use full attention (it's automatically disabled for sliding window models).
|
||||
|
||||
```py
|
||||
cb_config = ContinuousBatchingConfig(
|
||||
allow_block_sharing=True, # default
|
||||
)
|
||||
```
|
||||
|
||||
## Paged attention
|
||||
|
||||
Continuous batching requires a paged attention backend. Set `attn_implementation` when loading the model. If you load a model with a non-paged backend (`"flash_attention_2"`), the `"paged|"` prefix is added automatically when continuous batching starts.
|
||||
|
||||
| Backend | `attn_implementation` | Requirements |
|
||||
|---|---|---|
|
||||
| FlashAttention | <code>"paged|flash_attention_2"</code> | `flash-attn` package |
|
||||
| SDPA (PyTorch native) | <code>"paged|sdpa"</code> | None |
|
||||
| Eager | <code>"paged|eager"</code> | None |
|
||||
|
||||
```py
|
||||
model = AutoModelForCausalLM.from_pretrained(
|
||||
"Qwen/Qwen3-4B",
|
||||
attn_implementation="paged|flash_attention_2",
|
||||
device_map="cuda",
|
||||
dtype=torch.bfloat16,
|
||||
)
|
||||
```
|
||||
|
||||
## Tensor parallelism
|
||||
|
||||
For models too large to fit on a single GPU, shard the weights across devices with tensor parallelism. Load the model with `tp_plan="auto"` and continuous batching reads the tensor parallel size from the model to size the paged KV cache per shard. See [Tensor parallelism](./tensor_parallelism) for the list of supported architectures and how sharding works.
|
||||
|
||||
```py
|
||||
import torch
|
||||
from transformers import AutoModelForCausalLM, AutoTokenizer
|
||||
from transformers.generation import ContinuousBatchingConfig, GenerationConfig
|
||||
|
||||
model = AutoModelForCausalLM.from_pretrained(
|
||||
"Qwen/Qwen3-32B",
|
||||
attn_implementation="paged|flash_attention_2",
|
||||
tp_plan="auto",
|
||||
)
|
||||
tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen3-32B")
|
||||
|
||||
inputs = [tokenizer.encode(p) for p in ["Whats up?", "Name a cat breed."]]
|
||||
generation_config = GenerationConfig(max_new_tokens=64, eos_token_id=tokenizer.eos_token_id)
|
||||
|
||||
outputs = model.generate_batch(inputs=inputs, generation_config=generation_config)
|
||||
```
|
||||
|
||||
Launch the script with `torchrun`, setting `--nproc-per-node` to the number of GPUs you want to shard across.
|
||||
|
||||
```shell
|
||||
torchrun --nproc-per-node 4 cb_tp.py
|
||||
```
|
||||
|
||||
The tensor parallel size must divide the model's `num_key_value_heads` (check the model config). The paged cache raises an error at startup otherwise, so choose an appropriate `--nproc-per-node`.
|
||||
|
||||
> [!WARNING]
|
||||
> Don't set `device_map` with `tp_plan`. The two conflict because `device_map` places whole modules on specific GPUs, while `tp_plan` shards those same parameters across all GPUs.
|
||||
|
||||
## Sliding window attention
|
||||
|
||||
Models with sliding window attention (Mistral, Gemma 2) work with continuous batching. To manually configure a sliding window for fine-tuning or custom experiments, set it in the model config before loading.
|
||||
|
||||
```py
|
||||
from transformers import AutoConfig, AutoModelForCausalLM
|
||||
|
||||
config = AutoConfig.from_pretrained("google/gemma-2-2b")
|
||||
config.sliding_window = 4096
|
||||
|
||||
model = AutoModelForCausalLM.from_pretrained(
|
||||
"google/gemma-2-2b",
|
||||
config=config,
|
||||
attn_implementation="paged|sdpa",
|
||||
device_map="cuda",
|
||||
dtype=torch.bfloat16,
|
||||
)
|
||||
```
|
||||
|
||||
Prefix caching is disabled automatically when sliding window attention is active.
|
||||
|
||||
## Next steps
|
||||
|
||||
- The [Continuous batching blog post](https://huggingface.co/blog/continuous_batching) covers KV caching, chunked prefill, and dynamic scheduling with performance benchmark numbers.
|
||||
- For a deeper look at how the continuous batching system works, see the [Continuous batching architecture](./continuous_batching_architecture) doc.
|
||||
@@ -0,0 +1,188 @@
|
||||
<!--Copyright 2026 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Continuous batching architecture
|
||||
|
||||
Traditional batching processes a fixed group of requests together and waits for the slowest one to finish before starting the next group. This causes the GPU to idle between batches.
|
||||
|
||||
With continuous batching, at every generation step, the scheduler checks for finished requests and replaces them immediately with waiting ones. Short requests are kicked out as soon as they're done, and the GPU stays occupied the entire time. The result is significantly higher throughput and lower average latency.
|
||||
|
||||
## Request lifecycle
|
||||
|
||||
A request moves through four states from submission to completion.
|
||||
|
||||
```text
|
||||
WAIT IN QUEUE LOAD PROMPT INTO KV STREAM OUTPUT DONE
|
||||
┌────────────────┐ ┌─────────────────────┐ ┌─────────────────┐ ┌────────┐
|
||||
│ PENDING │───▶│ PREFILLING │───▶│ DECODING │───▶│FINISHED│
|
||||
│ ○ ○ ○ · · · │ │ ████████░░░░░░░░░░ │ │ → → → → · · │ │ ✓ │
|
||||
└────────────────┘ └─────────────────────┘ └─────────────────┘ └────────┘
|
||||
others ahead prompt chunks +1 token/step
|
||||
```
|
||||
|
||||
1. Pending — the request is queued and waiting to be scheduled.
|
||||
2. Prefilling — prompt tokens are processed in a forward pass.
|
||||
3. Decoding — output tokens are generated one at a time.
|
||||
4. Finished — generation is complete and the result is available.
|
||||
|
||||
A request is moved from pending to prefilling when the scheduler finds enough token budget and cache space to admit the request. If the prompt is too long to fit in a single step, the scheduler splits it across multiple forward passes (chunk prefill).
|
||||
|
||||
## Chunked prefill
|
||||
|
||||
Processing a long prompt in a single step is expensive because it blocks other requests from generating. Chunked prefill solves this by splitting large prefills across multiple steps.
|
||||
|
||||
```text
|
||||
Blocking (long prefill blocks the batch)
|
||||
Step: 1 2 3 4
|
||||
Req A [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓] ← one huge prefill
|
||||
Req B ················ wait ················
|
||||
Req C ················ wait ················
|
||||
|
||||
Chunked (same prompt split and interleave with decode)
|
||||
Step: 1 2 3 4
|
||||
Req A [▓▓ pre] [▓▓ pre] [▓▓ pre] [→ dec]
|
||||
Req B [→ dec] [→ dec] [▓▓ pre] [→ dec]
|
||||
Req C [→ dec] · idle · [→ dec] · idle ·
|
||||
```
|
||||
|
||||
When a new request's prompt exceeds the available token budget (set by `max_batch_tokens` in [`ContinuousBatchingConfig`]), the scheduler processes as many tokens as possible and holds the rest. On subsequent steps, it continues from where it left off, interleaving prefill work with ongoing decode steps. This keeps the batch productive and reduces time-to-first-token for other requests.
|
||||
|
||||
## Scheduler
|
||||
|
||||
The scheduler decides which requests join each forward pass based on two budgets and a request cap.
|
||||
|
||||
- Token budget — the maximum number of query tokens processed in a single forward pass, set by `max_batch_tokens` in [`ContinuousBatchingConfig`].
|
||||
- Cache budget — the total number of KV pages that can be read in a single pass, which is bounded by the total cache size.
|
||||
- Request cap — the maximum number of requests in a single forward pass, set by `max_requests_per_batch`. The logits tensor scales with the vocabulary size, so this cap bounds peak memory for large-vocabulary models.
|
||||
|
||||
### FIFO
|
||||
|
||||
[`FIFOScheduler`] is the default scheduler. It fills the batch in priority order. Active decode requests are processed first, then active prefill requests, and then new waiting requests in arrival order. This maximizes throughput by pushing existing requests through before pulling in new ones.
|
||||
|
||||
### PrefillFirst
|
||||
|
||||
[`PrefillFirstScheduler`] completes chunked prefill operations before resuming decode. This reduces fragmentation for workloads dominated by long prompts.
|
||||
|
||||
Set the scheduler in [`ContinuousBatchingConfig`].
|
||||
|
||||
```py
|
||||
cb_config = ContinuousBatchingConfig(scheduler_type="prefill_first")
|
||||
```
|
||||
|
||||
## Memory management
|
||||
|
||||
The KV cache is paged so requests of different lengths can share a fixed memory pool without fragmentation. The cache divides memory into fixed-size blocks, and each request holds a list of block IDs that the attention kernel reads from and writes to.
|
||||
|
||||
```text
|
||||
Paged KV cache (num_blocks × block_size tokens per block)
|
||||
|
||||
0 1 2 3 4 5 6 7 8 9 …
|
||||
┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐
|
||||
│ B │ · │ A │ B │ · │ A │ · │ A │ · │ · │
|
||||
└───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘
|
||||
A request A: 2, 5, 7 B request B: 0, 3 · free: 1, 4, 6, 8, 9, …
|
||||
```
|
||||
|
||||
A page holds the key/value state for one token in one layer. A block is a span of `block_size` pages (default 256) and is the unit of allocation. Blocks are allocated per layer group. Layers within a group share a block ID, which keeps bookkeeping uniform for mixed-attention models.
|
||||
|
||||
The cache reserves two extra blocks on top of `num_blocks` for padding tokens to read from and write to, plus a sentinel index for sliding window groups. This reservation requires `block_size` to be at least 4, so the manager rejects smaller values.
|
||||
|
||||
### Cache sizing
|
||||
|
||||
The manager infers the number of blocks at startup from free GPU memory. The manager solves an equation that accounts for KV tensors, attention masks, activations, and bookkeeping indices, then sizes the pool to fit inside `max_memory_percent` (default 0.9) of the available memory.
|
||||
|
||||
You can pin the values explicitly in [`ContinuousBatchingConfig`].
|
||||
|
||||
```py
|
||||
cb_config = ContinuousBatchingConfig(
|
||||
block_size=256,
|
||||
num_blocks=4096,
|
||||
max_batch_tokens=512,
|
||||
max_memory_percent=0.8,
|
||||
)
|
||||
```
|
||||
|
||||
### Admission
|
||||
|
||||
Before a request joins the batch, the scheduler checks that enough free blocks exist for every layer group. If any group would fall short, the request is rejected and nothing is allocated.
|
||||
|
||||
To avoid filling the cache until [offloading](#offloading) is the only option, the scheduler enforces a `safety_margin`. Once free blocks fall below `safety_margin * num_blocks`, new prefills are held back and only active decodes continue. The FIFO scheduler defaults to `0.15` (15% of blocks held in reserve), while `prefill_first` defaults to `0.0`. Set `safety_margin` in [`ContinuousBatchingConfig`] to tune it, where `0` disables the margin.
|
||||
|
||||
### Prefix caching
|
||||
|
||||
When two requests share a prompt prefix, they can share the blocks that hold the KV for that prefix. Each completed block is content-hashed. A later request with a matching prefix reuses the block and skips the prefill for those tokens. Shared blocks are reference-counted and only return to the free pool once every request using them has finished.
|
||||
|
||||
Prefix caching is enabled by default and is active only when a model has exclusively full-attention layers. Set `allow_block_sharing=False` in [`ContinuousBatchingConfig`] for workloads with short prompts and long generations, where the bookkeeping outweighs the savings.
|
||||
|
||||
### Eviction
|
||||
|
||||
Freed blocks aren't wiped and they stay "initialized" with their content and hash intact so a later prefix match can reuse them. When the uninitialized pool runs low, the manager lazily demotes the most recent initialized block back to uninitialized, dropping their hash. The prefix cache is a best-effort layer that the allocator discards to keep serving new requests.
|
||||
|
||||
### Soft reset
|
||||
|
||||
A soft reset is the fallback path for [offloading](#offloading). When the manager can't copy a request's KV cache to the CPU swap pool, because CPU offloading is disabled or the pool is full, it soft resets the request instead. It appends the request's generated tokens to its original prompt, frees its cache blocks, and adds it back to the queue. The [Offloading](#offloading) section covers which requests are chosen.
|
||||
|
||||
When the cache has space again, the request resumes from where it left off with its generation history encoded in the prompt.
|
||||
|
||||
## CUDA graphs
|
||||
|
||||
Every generation step involves CPU overhead, from assembling the batch to dispatching GPU kernels and reading the results. CUDA graphs eliminate the overhead by recording the full GPU execution sequence once and replaying it for batches with matching shapes.
|
||||
|
||||
Because the batch shapes change every step, the continuous batching system handles this with padding and caching.
|
||||
|
||||
1. Query lengths are padded to the nearest multiple of `q_padding_interval_size`.
|
||||
2. KV lengths are padded to the nearest multiple of `kv_padding_interval_size`.
|
||||
3. Recorded graphs are stored in a cache.
|
||||
|
||||
When a batch's padded shape matches a cached graph, the graph replays without any CPU dispatch. New shapes trigger a new graph capture.
|
||||
|
||||
CUDA graphs require static control flow and are incompatible with attention masks. They're auto-detected by default and disabled when conditions aren't met.
|
||||
|
||||
## Async batching
|
||||
|
||||
Async batching uses two I/O buffer pairs and two CUDA streams to overlap CPU and GPU work.
|
||||
|
||||
```text
|
||||
Sequential
|
||||
CPU ── [prep N] ·········idle········· [prep N+1] ·········idle·········
|
||||
GPU ·········idle········· [compute N] ·········idle········· [compute N+1]
|
||||
|
||||
Async
|
||||
CPU ── [prep N] [prep N+1] [prep N+2] ──
|
||||
GPU ── ········ [compute N] [compute N+1] ──
|
||||
```
|
||||
|
||||
While the GPU computes batch N, the CPU prepares batch N+1. However, overlapping the two requires roughly double the VRAM.
|
||||
|
||||
Async batching requires CUDA graphs to be active, since graph replay provides the stable tensor addresses needed for stream overlap to be correct.
|
||||
|
||||
## Offloading
|
||||
|
||||
Requests that generate long outputs can grow until the KV cache has no room to allocate the next block. Rather than crash, the manager offloads active requests back to the waiting queue to free blocks for the requests that remain.
|
||||
|
||||
Offloading is demand-driven. The scheduler reports the *stalled* requests, the active requests that failed to allocate the blocks they need, along with how many blocks each one demands. The manager offloads the fewest requests needed to free enough blocks to cover that demand. It offloads newest first, so requests already scheduled into the current batch keep their cache, and the last remaining active request is never offloaded.
|
||||
|
||||
Two situations trigger offloading.
|
||||
|
||||
- A batch is scheduled, but some active requests stalled. The manager offloads enough of the stalled requests that the next batch can allocate blocks for the rest.
|
||||
- The cache is full and no batch can be scheduled at all. The manager offloads requests and retries scheduling in a loop within the same step, until a batch fits or no request can be offloaded. It no longer waits for the next forward pass to recover.
|
||||
|
||||
An offloaded request takes one of two paths. When `cpu_offload_space` is greater than `0.0`, the manager copies the request's KV cache blocks to a pre-allocated pinned CPU buffer, batching every request that fits the swap pool into a single transfer. After GPU cache space becomes available, the manager copies the blocks back to the GPU and resumes the request without recomputing its prompt and generated tokens. Requests that don't fit the pool, or every offloaded request when CPU offloading is disabled, fall back to a [soft reset](#soft-reset).
|
||||
|
||||
## Next steps
|
||||
|
||||
- The [Continuous batching blog post](https://huggingface.co/blog/continuous_batching) covers KV caching, chunked prefill, and dynamic scheduling with performance benchmark numbers.
|
||||
- For usage examples, see the [Continuous batching](./continuous_batching) doc.
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
../../../CONTRIBUTING.md
|
||||
@@ -0,0 +1,119 @@
|
||||
<!--Copyright 2024 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Chat basics
|
||||
|
||||
Chat models are conversational models you can send a message to and receive a response. Most language models from mid-2023 onwards are chat models and may be referred to as "instruct" or "instruction-tuned" models. Models that do not support chat are often referred to as "base" or "pretrained" models.
|
||||
|
||||
Larger and newer models are generally more capable, but models specialized in certain domains (medical, legal text, non-English languages, etc.) can often outperform these larger models. Try leaderboards like [OpenLLM](https://hf.co/spaces/HuggingFaceH4/open_llm_leaderboard) and [LMSys Chatbot Arena](https://chat.lmsys.org/?leaderboard) to help you identify the best model for your use case.
|
||||
|
||||
This guide shows you how to quickly load chat models in Transformers from the command line, how to build and format a conversation, and how to chat using the [`TextGenerationPipeline`].
|
||||
|
||||
## chat CLI
|
||||
|
||||
After you've [installed Transformers](./installation), you can chat with a model directly from the command line. The command below launches an interactive session with a model, with a few base commands listed at the start of the session.
|
||||
|
||||
> For the following commands, please make sure [`transformers serve` is running](https://huggingface.co/docs/transformers/main/en/serving).
|
||||
|
||||
```bash
|
||||
transformers chat Qwen/Qwen2.5-0.5B-Instruct
|
||||
```
|
||||
|
||||
<div class="flex justify-center">
|
||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/transformers-chat-cli.png"/>
|
||||
</div>
|
||||
|
||||
You can launch the CLI with arbitrary `generate` flags, with the format `arg_1=value_1 arg_2=value_2 ...`
|
||||
|
||||
```bash
|
||||
transformers chat Qwen/Qwen2.5-0.5B-Instruct do_sample=False max_new_tokens=10
|
||||
```
|
||||
|
||||
For a full list of options, run the command below.
|
||||
|
||||
```bash
|
||||
transformers chat -h
|
||||
```
|
||||
|
||||
The chat is implemented on top of the [AutoClass](./model_doc/auto), using tooling from [text generation](./llm_tutorial) and [chat](./chat_templating). It uses the `transformers serve` CLI under the hood ([docs](./serve-cli/serving)).
|
||||
|
||||
## TextGenerationPipeline
|
||||
|
||||
[`TextGenerationPipeline`] is a high-level text generation class with a "chat mode". Chat mode is enabled when a conversational model is detected and the chat prompt is [properly formatted](./llm_tutorial#wrong-prompt-format).
|
||||
|
||||
Chat models accept a list of messages (the chat history) as the input. Each message is a dictionary with `role` and `content` keys.
|
||||
To start the chat, add a single `user` message. You can also optionally include a `system` message to give the model directions on how to behave.
|
||||
|
||||
```py
|
||||
chat = [
|
||||
{"role": "system", "content": "You are a helpful science assistant."},
|
||||
{"role": "user", "content": "Hey, can you explain gravity to me?"}
|
||||
]
|
||||
```
|
||||
|
||||
Create the [`TextGenerationPipeline`] and pass `chat` to it. For large models, setting [device_map="auto"](./models#big-model-inference) helps load the model quicker and automatically places it on the fastest device available.
|
||||
|
||||
```py
|
||||
import torch
|
||||
from transformers import pipeline
|
||||
|
||||
pipeline = pipeline(task="text-generation", model="HuggingFaceTB/SmolLM2-1.7B-Instruct", dtype="auto", device_map="auto")
|
||||
response = pipeline(chat, max_new_tokens=512)
|
||||
print(response[0]["generated_text"][-1]["content"])
|
||||
```
|
||||
|
||||
If this works successfully, you should see a response from the model! If you want to continue the conversation,
|
||||
you need to update the chat history with the model's response. You can do this either by appending the text
|
||||
to `chat` (use the `assistant` role), or by reading `response[0]["generated_text"]`, which contains
|
||||
the full chat history, including the most recent response.
|
||||
|
||||
Once you have the model's response, you can continue the conversation by appending a new `user` message to the chat history.
|
||||
|
||||
```py
|
||||
chat = response[0]["generated_text"]
|
||||
chat.append(
|
||||
{"role": "user", "content": "Woah! But can it be reconciled with quantum mechanics?"}
|
||||
)
|
||||
response = pipeline(chat, max_new_tokens=512)
|
||||
print(response[0]["generated_text"][-1]["content"])
|
||||
```
|
||||
|
||||
By repeating this process, you can continue the conversation as long as you like, at least until the model runs out of context window
|
||||
or you run out of memory.
|
||||
|
||||
## Performance and memory usage
|
||||
|
||||
Transformers load models in full `float32` precision by default, and for a 8B model, this requires ~32GB of memory! Use the `torch_dtype="auto"` argument, which generally uses `bfloat16` for models that were trained with it, to reduce your memory usage.
|
||||
|
||||
> [!TIP]
|
||||
> Refer to the [Quantization](./quantization/overview) docs for more information about the different quantization backends available.
|
||||
|
||||
To lower memory usage even lower, you can quantize the model to 8-bit or 4-bit with [bitsandbytes](https://hf.co/docs/bitsandbytes/index). Create a [`BitsAndBytesConfig`] with your desired quantization settings and pass it to the pipelines `model_kwargs` parameter. The example below quantizes a model to 8-bits.
|
||||
|
||||
```py
|
||||
from transformers import pipeline, BitsAndBytesConfig
|
||||
|
||||
quantization_config = BitsAndBytesConfig(load_in_8bit=True)
|
||||
pipeline = pipeline(task="text-generation", model="meta-llama/Meta-Llama-3-8B-Instruct", device_map="auto", model_kwargs={"quantization_config": quantization_config})
|
||||
```
|
||||
|
||||
In general, model size and performance are directly correlated. Larger models are slower in addition to requiring more memory because each active parameter must be read from memory for every generated token.
|
||||
This is a bottleneck for LLM text generation and the main options for improving generation speed are to either quantize a model or use hardware with higher memory bandwidth. Adding more compute power doesn't meaningfully help.
|
||||
|
||||
You can also try techniques like [speculative decoding](./generation_strategies#speculative-decoding), where a smaller model generates candidate tokens that are verified by the larger model. If the candidate tokens are correct, the larger model can generate more than one token at a time. This significantly alleviates the bandwidth bottleneck and improves generation speed.
|
||||
|
||||
> [!TIP]
|
||||
Mixture-of-Expert (MoE) models such as [Mixtral](./model_doc/mixtral), [Qwen2MoE](./model_doc/qwen2_moe), and [GPT-OSS](./model_doc/gpt_oss) have lots of parameters, but only "activate" a small fraction of them to generate each token. As a result, MoE models generally have much lower memory bandwidth requirements and can be faster than a regular LLM of the same size. However, techniques like speculative decoding are ineffective with MoE models because more parameters become activated with each new speculated token.
|
||||
@@ -0,0 +1,297 @@
|
||||
<!--Copyright 2024 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Customizing models
|
||||
|
||||
Transformers models are designed to be customizable. A models code is fully contained in the [model](https://github.com/huggingface/transformers/tree/main/src/transformers/models) subfolder of the Transformers repository. Each folder contains a `modeling.py` and a `configuration.py` file. Copy these files to start customizing a model.
|
||||
|
||||
> [!TIP]
|
||||
> It may be easier to start from scratch if you're creating an entirely new model. But for models that are very similar to an existing one in Transformers, it is faster to reuse or subclass the same configuration and model class.
|
||||
|
||||
This guide will show you how to customize a ResNet model, enable [AutoClass](./models#autoclass) support, and share it on the Hub.
|
||||
|
||||
## Configuration
|
||||
|
||||
A configuration, given by the base [`PreTrainedConfig`] class, contains all the necessary information to build a model. This is where you'll configure the attributes of the custom ResNet model. Different attributes gives different ResNet model types.
|
||||
|
||||
The main rules for customizing a configuration are:
|
||||
|
||||
1. A custom configuration must subclass [`PreTrainedConfig`]. This ensures a custom model has all the functionality of a Transformers' model such as [`~PreTrainedConfig.from_pretrained`], [`~PreTrainedConfig.save_pretrained`], and [`~PreTrainedConfig.push_to_hub`].
|
||||
2. The [`PreTrainedConfig`] `__init__` must accept any `kwargs` and they must be passed to the superclass `__init__`. [`PreTrainedConfig`] has more fields than the ones set in your custom configuration, so when you load a configuration with [`~PreTrainedConfig.from_pretrained`], those fields need to be accepted by your configuration and passed to the superclass.
|
||||
|
||||
> [!TIP]
|
||||
> It is useful to check the validity of some of the parameters. In the example below, a check is implemented to ensure `block_type` and `stem_type` belong to one of the predefined values.
|
||||
>
|
||||
> Add `model_type` to the configuration class to enable [AutoClass](./models#autoclass) support.
|
||||
|
||||
```py
|
||||
from transformers import PreTrainedConfig
|
||||
from typing import List
|
||||
|
||||
class ResnetConfig(PreTrainedConfig):
|
||||
model_type = "resnet"
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
block_type="bottleneck",
|
||||
layers: list[int] = [3, 4, 6, 3],
|
||||
num_classes: int = 1000,
|
||||
input_channels: int = 3,
|
||||
cardinality: int = 1,
|
||||
base_width: int = 64,
|
||||
stem_width: int = 64,
|
||||
stem_type: str = "",
|
||||
avg_down: bool = False,
|
||||
**kwargs,
|
||||
):
|
||||
if block_type not in ["basic", "bottleneck"]:
|
||||
raise ValueError(f"`block_type` must be 'basic' or bottleneck', got {block_type}.")
|
||||
if stem_type not in ["", "deep", "deep-tiered"]:
|
||||
raise ValueError(f"`stem_type` must be '', 'deep' or 'deep-tiered', got {stem_type}.")
|
||||
|
||||
self.block_type = block_type
|
||||
self.layers = layers
|
||||
self.num_classes = num_classes
|
||||
self.input_channels = input_channels
|
||||
self.cardinality = cardinality
|
||||
self.base_width = base_width
|
||||
self.stem_width = stem_width
|
||||
self.stem_type = stem_type
|
||||
self.avg_down = avg_down
|
||||
super().__init__(**kwargs)
|
||||
```
|
||||
|
||||
Save the configuration to a JSON file in your custom model folder, `custom-resnet`, with [`~PreTrainedConfig.save_pretrained`].
|
||||
|
||||
```py
|
||||
resnet50d_config = ResnetConfig(block_type="bottleneck", stem_width=32, stem_type="deep", avg_down=True)
|
||||
resnet50d_config.save_pretrained("custom-resnet")
|
||||
```
|
||||
|
||||
## Model
|
||||
|
||||
With the custom ResNet configuration, you can now create and customize the model. The model subclasses the base [`PreTrainedModel`] class. Like [`PreTrainedConfig`], inheriting from [`PreTrainedModel`] and initializing the superclass with the configuration extends Transformers' functionalities such as saving and loading to the custom model.
|
||||
|
||||
Transformers' models follow the convention of accepting a `config` object in the `__init__` method. This passes the entire `config` to the model sublayers, instead of breaking the `config` object into multiple arguments that are individually passed to the sublayers.
|
||||
|
||||
Writing models this way produces simpler code with a clear source of truth for any hyperparameters. It also makes it easier to reuse code from other Transformers' models.
|
||||
|
||||
You'll create two ResNet models, a barebones ResNet model that outputs the hidden states and a ResNet model with an image classification head.
|
||||
|
||||
<hfoptions id="resnet">
|
||||
<hfoption id="ResnetModel">
|
||||
|
||||
Define a mapping between the block types and classes. Everything else is created by passing the configuration class to the ResNet model class.
|
||||
|
||||
> [!TIP]
|
||||
> Add `config_class` to the model class to enable [AutoClass](#autoclass-support) support.
|
||||
|
||||
```py
|
||||
from transformers import PreTrainedModel
|
||||
from timm.models.resnet import BasicBlock, Bottleneck, ResNet
|
||||
from .configuration_resnet import ResnetConfig
|
||||
|
||||
BLOCK_MAPPING = {"basic": BasicBlock, "bottleneck": Bottleneck}
|
||||
|
||||
class ResnetModel(PreTrainedModel):
|
||||
config_class = ResnetConfig
|
||||
|
||||
def __init__(self, config):
|
||||
super().__init__(config)
|
||||
block_layer = BLOCK_MAPPING[config.block_type]
|
||||
self.model = ResNet(
|
||||
block_layer,
|
||||
config.layers,
|
||||
num_classes=config.num_classes,
|
||||
in_chans=config.input_channels,
|
||||
cardinality=config.cardinality,
|
||||
base_width=config.base_width,
|
||||
stem_width=config.stem_width,
|
||||
stem_type=config.stem_type,
|
||||
avg_down=config.avg_down,
|
||||
)
|
||||
|
||||
def forward(self, tensor):
|
||||
return self.model.forward_features(tensor)
|
||||
```
|
||||
|
||||
</hfoption>
|
||||
<hfoption id="ResnetModelForImageClassification">
|
||||
|
||||
The `forward` method needs to be rewritten to calculate the loss for each logit if labels are available. Otherwise, the ResNet model class is the same.
|
||||
|
||||
> [!TIP]
|
||||
> Add `config_class` to the model class to enable [AutoClass](#autoclass-support) support.
|
||||
|
||||
```py
|
||||
import torch
|
||||
|
||||
class ResnetModelForImageClassification(PreTrainedModel):
|
||||
config_class = ResnetConfig
|
||||
|
||||
def __init__(self, config):
|
||||
super().__init__(config)
|
||||
block_layer = BLOCK_MAPPING[config.block_type]
|
||||
self.model = ResNet(
|
||||
block_layer,
|
||||
config.layers,
|
||||
num_classes=config.num_classes,
|
||||
in_chans=config.input_channels,
|
||||
cardinality=config.cardinality,
|
||||
base_width=config.base_width,
|
||||
stem_width=config.stem_width,
|
||||
stem_type=config.stem_type,
|
||||
avg_down=config.avg_down,
|
||||
)
|
||||
|
||||
def forward(self, tensor, labels=None):
|
||||
logits = self.model(tensor)
|
||||
if labels is not None:
|
||||
loss = torch.nn.functional.cross_entropy(logits, labels)
|
||||
return {"loss": loss, "logits": logits}
|
||||
return {"logits": logits}
|
||||
```
|
||||
|
||||
</hfoption>
|
||||
</hfoptions>
|
||||
|
||||
A model can return any output format. Returning a dictionary (like `ResnetModelForImageClassification`) with losses when labels are available makes the custom model compatible with [`Trainer`]. For other output formats, you'll need your own training loop or a different library for training.
|
||||
|
||||
Instantiate the custom model class with the configuration.
|
||||
|
||||
```py
|
||||
resnet50d = ResnetModelForImageClassification(resnet50d_config)
|
||||
```
|
||||
|
||||
At this point, you can load pretrained weights into the model or train it from scratch. In this guide, you'll load pretrained weights.
|
||||
|
||||
Load the pretrained weights from the [timm](https://hf.co/docs/timm/index) library, and then transfer those weights to the custom model with [load_state_dict](https://pytorch.org/docs/stable/generated/torch.nn.Module.html#torch.nn.Module.load_state_dict).
|
||||
|
||||
```py
|
||||
import timm
|
||||
|
||||
pretrained_model = timm.create_model("resnet50d", pretrained=True)
|
||||
resnet50d.model.load_state_dict(pretrained_model.state_dict())
|
||||
```
|
||||
|
||||
## AutoClass
|
||||
|
||||
The [AutoClass](./models#model-classes) API is a shortcut for automatically loading the correct architecture for a given model. It is convenient to enable this for users loading your custom model.
|
||||
|
||||
Make sure you have the `model_type` attribute (must be different from existing model types) in the configuration class and `config_class` attribute in the model class. Use the [`~AutoConfig.register`] method to add the custom configuration and model to the [AutoClass](./models#model-classes) API.
|
||||
|
||||
> [!TIP]
|
||||
> The first argument to [`AutoConfig.register`] must match the `model_type` attribute in the custom configuration class, and the first argument to [`AutoModel.register`] must match the `config_class` of the custom model class.
|
||||
|
||||
```py
|
||||
from transformers import AutoConfig, AutoModel, AutoModelForImageClassification
|
||||
|
||||
AutoConfig.register("resnet", ResnetConfig)
|
||||
AutoModel.register(ResnetConfig, ResnetModel)
|
||||
AutoModelForImageClassification.register(ResnetConfig, ResnetModelForImageClassification)
|
||||
```
|
||||
|
||||
Your custom model code is now compatible with the [AutoClass](./models#autoclass) API. Users can load the model with the [AutoModel](./model_doc/auto#automodel) or [`AutoModelForImageClassification`] classes.
|
||||
|
||||
## Upload
|
||||
|
||||
Upload a custom model to the [Hub](https://hf.co/models) to allow other users to easily load and use it.
|
||||
|
||||
Ensure the model directory is structured correctly as shown below. The directory should contain:
|
||||
|
||||
- `modeling.py`: Contains the code for `ResnetModel` and `ResnetModelForImageClassification`. This file can rely on relative imports to other files as long as they're in the same directory.
|
||||
|
||||
> [!WARNING]
|
||||
> When copying a Transformers' model file, replace all relative imports at the top of the `modeling.py` file to import from Transformers instead.
|
||||
|
||||
- `configuration.py`: Contains the code for `ResnetConfig`.
|
||||
- `__init__.py`: Can be empty, this file allows Python `resnet_model` to be used as a module.
|
||||
|
||||
```bash
|
||||
.
|
||||
└── resnet_model
|
||||
├── __init__.py
|
||||
├── configuration_resnet.py
|
||||
└── modeling_resnet.py
|
||||
```
|
||||
|
||||
To share the model, import the ResNet model and configuration.
|
||||
|
||||
```py
|
||||
from resnet_model.configuration_resnet import ResnetConfig
|
||||
from resnet_model.modeling_resnet import ResnetModel, ResnetModelForImageClassification
|
||||
```
|
||||
|
||||
Copy the code from the model and configuration files. To make sure the AutoClass objects are saved with [`~PreTrainedModel.save_pretrained`], call the [`~PreTrainedConfig.register_for_auto_class`] method. This modifies the configuration JSON file to include the AutoClass objects and mapping.
|
||||
|
||||
For a model, pick the appropriate `AutoModelFor` class based on the task.
|
||||
|
||||
```py
|
||||
ResnetConfig.register_for_auto_class()
|
||||
ResnetModel.register_for_auto_class("AutoModel")
|
||||
ResnetModelForImageClassification.register_for_auto_class("AutoModelForImageClassification")
|
||||
```
|
||||
|
||||
To map more than one task to the model, edit `auto_map` in the configuration JSON file directly.
|
||||
|
||||
```json
|
||||
"auto_map": {
|
||||
"AutoConfig": "<your-repo-name>--<config-name>",
|
||||
"AutoModel": "<your-repo-name>--<config-name>",
|
||||
"AutoModelFor<Task>": "<your-repo-name>--<config-name>",
|
||||
},
|
||||
```
|
||||
|
||||
Create the configuration and model and load pretrained weights into it.
|
||||
|
||||
```py
|
||||
resnet50d_config = ResnetConfig(block_type="bottleneck", stem_width=32, stem_type="deep", avg_down=True)
|
||||
resnet50d = ResnetModelForImageClassification(resnet50d_config)
|
||||
|
||||
pretrained_model = timm.create_model("resnet50d", pretrained=True)
|
||||
resnet50d.model.load_state_dict(pretrained_model.state_dict())
|
||||
```
|
||||
|
||||
The model is ready to be pushed to the Hub now. Log in to your Hugging Face account from the command line or notebook.
|
||||
|
||||
<hfoptions id="push">
|
||||
<hfoption id="huggingface-CLI">
|
||||
|
||||
```bash
|
||||
hf auth login
|
||||
```
|
||||
|
||||
</hfoption>
|
||||
<hfoption id="notebook">
|
||||
|
||||
```py
|
||||
from huggingface_hub import notebook_login
|
||||
|
||||
notebook_login()
|
||||
```
|
||||
|
||||
</hfoption>
|
||||
</hfoptions>
|
||||
|
||||
Call [`~PreTrainedModel.push_to_hub`] on the model to upload the model to the Hub.
|
||||
|
||||
```py
|
||||
resnet50d.push_to_hub("custom-resnet50d")
|
||||
```
|
||||
|
||||
The pretrained weights, configuration, `modeling.py` and `configuration.py` files should all be uploaded to the Hub now in a [repository](https://hf.co/sgugger/custom-resnet50d) under your namespace.
|
||||
|
||||
Because a custom model doesn't use the same modeling code as a Transformers' model, you need to add `trust_remote_code=True` in [`~PreTrainedModel.from_pretrained`] to load it. Refer to the load [custom models](./models#custom-models) section for more information.
|
||||
@@ -0,0 +1,172 @@
|
||||
<!--Copyright 2026 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Customizing tokenizers
|
||||
|
||||
Tokenizers are decoupled from their learned vocabularies. This allows you to initialize an empty tokenizer for training or create one directly with your own vocabulary. The underlying tokenization pipeline remains the same (normalizer, pre-tokenizer, tokenization algorithm) so you don't need to recreate it from scratch.
|
||||
|
||||
This guide shows how to train and create a custom tokenizer.
|
||||
|
||||
## Training a tokenizer
|
||||
|
||||
An empty trainable tokenizer replaces the vocabulary with a new target vocabulary. This is useful for adapting to a new domain like finance, a low-resource language, or code.
|
||||
|
||||
Create an empty tokenizer and load a dataset.
|
||||
|
||||
```py
|
||||
from datasets import load_dataset
|
||||
from transformers import GemmaTokenizer
|
||||
|
||||
tokenizer = GemmaTokenizer()
|
||||
dataset = load_dataset("Josephgflowers/Finance-Instruct-500k", split="train")
|
||||
```
|
||||
|
||||
Use the [`TokenizersBackend.train_new_from_iterator`] method to train the tokenizer. This method accepts a generator function to return chunks of text from the dataset instead of loading everything into memory at once. The `vocab_size` argument sets the tokenizers vocabulary size.
|
||||
|
||||
```py
|
||||
def batch_iterator(batch_size=1000):
|
||||
for i in range(0, len(dataset), batch_size):
|
||||
yield dataset[i : i + batch_size]["assistant"]
|
||||
|
||||
trained_tokenizer = tokenizer.train_new_from_iterator(
|
||||
batch_iterator(),
|
||||
vocab_size=32000,
|
||||
)
|
||||
encoded = trained_tokenizer("The stock market rallied today.")
|
||||
print(encoded["input_ids"])
|
||||
[5866, 11503, 98, 5885, 8617, 13381, 30]
|
||||
```
|
||||
|
||||
Add new special tokens with the `new_special_tokens` argument or use `special_tokens_map` to rename the old special tokens to the new special tokens.
|
||||
|
||||
Save the new finance tokenizer with [`~PreTrainedTokenizerBase.save_pretrained`] or save and upload it to the Hub with [`~PreTrainedTokenizerBase.push_to_hub`]. This creates a `tokenizer.json` file that captures the newly trained vocabulary, merge rules, and full pipeline configuration.
|
||||
|
||||
```py
|
||||
trained_tokenizer.save_pretrained("./finance-gemma-tokenizer")
|
||||
trained_tokenizer.push_to_hub("finance-gemma-tokenizer")
|
||||
```
|
||||
|
||||
## Custom vocabulary
|
||||
|
||||
An empty tokenizer supports custom vocabulary with the `vocab` and `merges` arguments.
|
||||
|
||||
- `vocab` is the complete set of tokens a tokenizer knows and each entry maps a token to its input id.
|
||||
- `merges` defines how the BPE algorithm should combine adjacent tokens.
|
||||
|
||||
```py
|
||||
from transformers import GemmaTokenizer
|
||||
|
||||
vocab={
|
||||
"<pad>": 0,
|
||||
"</s>": 1,
|
||||
"<s>": 2,
|
||||
"<unk>": 3,
|
||||
"<mask>": 4,
|
||||
"▁the": 5,
|
||||
"▁stock": 6,
|
||||
"▁market": 7,
|
||||
"▁": 8,
|
||||
"r": 9,
|
||||
"a": 10,
|
||||
"l": 11,
|
||||
"i": 12,
|
||||
"e": 13,
|
||||
"d": 14,
|
||||
"ra": 15,
|
||||
"li": 16,
|
||||
"lie": 17,
|
||||
"lied": 18,
|
||||
"ral": 19,
|
||||
"ralli": 20,
|
||||
"rallie": 21,
|
||||
"rallied": 22,
|
||||
}
|
||||
merges=[
|
||||
("r", "a"), # r + a → ra
|
||||
("l", "i"), # l + i → li
|
||||
("li", "e"), # li + e → lie
|
||||
("lie", "d"), # lie + d → lied
|
||||
("ra", "l"), # ra + l → ral
|
||||
("ral", "li"), # ral + li → ralli
|
||||
("ralli", "e"), # ralli + e → rallie
|
||||
("rallie", "d"), # rallie + d → rallied
|
||||
]
|
||||
|
||||
tokenizer = GemmaTokenizer(vocab=vocab, merges=merges)
|
||||
encoded = tokenizer("the stock market rallied")
|
||||
print(encoded["input_ids"])
|
||||
```
|
||||
|
||||
## Subclassing TokenizersBackend
|
||||
|
||||
Tokenizers supports four different [backends](./fast_tokenizers#backends). Generally, you should use the [`TokenizersBackend`] to define a new tokenizer because it's faster.
|
||||
|
||||
> [!TIP]
|
||||
> The [`PythonBackend`] is a pure Python tokenizer that does not rely on backends like Rust, SentencePiece, or mistral-common. You should only use [`PythonBackend`] if you're building a very specialized tokenizer that can't be expressed by the Rust backend.
|
||||
|
||||
1. Subclass the [`TokenizersBackend`] with class attributes like padding side and the tokenization algorithm to use.
|
||||
2. Define the tokenization pipeline in the `__init__`. This includes the tokenization algorithm to use, how to split the raw text before the algorithm, and how to decode the tokens back to text.
|
||||
|
||||
```py
|
||||
from tokenizers import Tokenizer, decoders, pre_tokenizers
|
||||
from tokenizers.models import BPE
|
||||
from transformers import TokenizersBackend
|
||||
|
||||
class NewTokenizer(TokenizersBackend):
|
||||
padding_side = "left"
|
||||
model = BPE
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
vocab=None,
|
||||
merges=None,
|
||||
unk_token="<unk>",
|
||||
bos_token="<s>",
|
||||
eos_token="</s>",
|
||||
pad_token="<pad>",
|
||||
):
|
||||
self._vocab = vocab or {
|
||||
str(unk_token): 0,
|
||||
str(bos_token): 1,
|
||||
str(eos_token): 2,
|
||||
str(pad_token): 3,
|
||||
}
|
||||
self._merges = merges or []
|
||||
|
||||
self._tokenizer = Tokenizer(
|
||||
BPE(vocab=self._vocab, merges=self._merges, fuse_unk=True)
|
||||
)
|
||||
self._tokenizer.pre_tokenizer = pre_tokenizers.ByteLevel(add_prefix_space=False)
|
||||
self._tokenizer.decoder = decoders.ByteLevel()
|
||||
|
||||
super().__init__(
|
||||
unk_token=unk_token,
|
||||
bos_token=bos_token,
|
||||
eos_token=eos_token,
|
||||
pad_token=pad_token,
|
||||
)
|
||||
```
|
||||
|
||||
Train or save the new empty tokenizer.
|
||||
|
||||
```py
|
||||
tokenizer = NewTokenizer()
|
||||
|
||||
# train on new corpus
|
||||
tokenizer.train_new_from_iterator()
|
||||
# save tokenizer
|
||||
tokenizer.save_pretrained("./new-tokenizer")
|
||||
```
|
||||
@@ -0,0 +1,121 @@
|
||||
<!--Copyright 2026 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Data collators
|
||||
|
||||
A data collator assembles individual dataset samples into a batch for the model. It can also dynamically pad samples to the longest sequence in *each batch*, which is more efficient than padding to a global maximum length.
|
||||
|
||||
```md
|
||||
Dataset[0] → {"input_ids": [101, 2003], "labels": 1}
|
||||
Dataset[1] → {"input_ids": [101, 2003, 1996], "labels": 0}
|
||||
Dataset[2] → {"input_ids": [101, 7592], "labels": 1}
|
||||
↓ collator
|
||||
{
|
||||
"input_ids": tensor([[101, 2003, 0], # padded to longest
|
||||
[101, 2003, 1996],
|
||||
[101, 7592, 0]]),
|
||||
"labels": tensor([1, 0, 1])
|
||||
}
|
||||
```
|
||||
|
||||
Transformers provides data collators for various tasks (see all available [data collators](./main_classes/data_collator)). Create a custom data collator with:
|
||||
|
||||
- [DataCollatorWithPadding](#datacollatorwithpadding) when you need standard tokenizer-based padding plus extra fields.
|
||||
- [DataCollatorMixin](#datacollatormixin) when you need custom padding logic, multiple paired inputs per sample, or a batch structure the tokenizer can't produce on its own.
|
||||
|
||||
## DataCollatorWithPadding
|
||||
|
||||
For simple use cases like adding an extra field, subclass [`DataCollatorWithPadding`] and extend its `__call__` method. The example below adds a `"score"` field.
|
||||
|
||||
1. Remove the custom field first because [`~PreTrainedTokenizerBase.pad`] doesn't recognize it.
|
||||
2. Call the parent class to handle `input_ids` and `attention_mask`.
|
||||
3. Add the `"score"` field back to the batch.
|
||||
|
||||
```py
|
||||
import torch
|
||||
from dataclasses import dataclass
|
||||
from transformers import DataCollatorWithPadding, PreTrainedTokenizerBase
|
||||
|
||||
@dataclass
|
||||
class DataCollatorWithScore(DataCollatorWithPadding):
|
||||
tokenizer: PreTrainedTokenizerBase
|
||||
|
||||
def __call__(self, features):
|
||||
scores = [f.pop("score") for f in features]
|
||||
|
||||
batch = super().__call__(features)
|
||||
batch["score"] = torch.tensor(scores, dtype=torch.float)
|
||||
|
||||
return batch
|
||||
```
|
||||
|
||||
Pass the custom data collator to [`Trainer`] like any other data collator.
|
||||
|
||||
```py
|
||||
trainer = Trainer(
|
||||
...,
|
||||
data_collator=DataCollatorWithScore(tokenizer=tokenizer),
|
||||
)
|
||||
```
|
||||
|
||||
## DataCollatorMixin
|
||||
|
||||
Subclass [`DataCollatorMixin`] for full control over batch assembly and implement your own `__call__` method. Build custom padding logic, handle multiple input types, or create entirely new batch structures. The [DataCollatorForPreference](https://github.com/huggingface/trl/blob/cfbdd3bea4448cde878c0da0de49551f553c61fe/trl/trainer/reward_trainer.py#L126) example below uses [`DataCollatorMixin`] because each training sample has a chosen and rejected response, and the model needs to see both.
|
||||
|
||||
1. Separate `chosen_ids` and `rejected_ids` because [`~trl.trainer.utils.pad`] expects flat lists.
|
||||
2. Concatenate the input pair into a single list.
|
||||
3. Generate `attention_mask` with [torch.ones_like](https://docs.pytorch.org/docs/stable/generated/torch.ones_like.html) instead of the tokenizer because the collator works with raw token ID lists.
|
||||
4. Pad `input_ids` and `attention_mask`.
|
||||
|
||||
```py
|
||||
import torch
|
||||
from transformers import DataCollatorMixin
|
||||
from trl.trainer.utils import pad
|
||||
|
||||
class DataCollatorForPreference(DataCollatorMixin):
|
||||
pad_token_id: int
|
||||
pad_to_multiple_of: int | None = None
|
||||
|
||||
def __call__(self, examples: list[dict]) -> dict:
|
||||
chosen_input_ids = [torch.tensor(ex["chosen_ids"]) for ex in examples]
|
||||
rejected_input_ids = [torch.tensor(ex["rejected_ids"]) for ex in examples]
|
||||
|
||||
input_ids = chosen_input_ids + rejected_input_ids
|
||||
attention_mask = [torch.ones_like(ids) for ids in input_ids]
|
||||
|
||||
output = {
|
||||
"input_ids": pad(
|
||||
input_ids,
|
||||
padding_value=self.pad_token_id,
|
||||
padding_side="right",
|
||||
pad_to_multiple_of=self.pad_to_multiple_of,
|
||||
),
|
||||
"attention_mask": pad(
|
||||
attention_mask,
|
||||
padding_value=0,
|
||||
padding_side="right",
|
||||
pad_to_multiple_of=self.pad_to_multiple_of,
|
||||
),
|
||||
}
|
||||
|
||||
...
|
||||
|
||||
return output
|
||||
```
|
||||
|
||||
## Next steps
|
||||
|
||||
- See all available [data collators](./main_classes/data_collator) for common tasks like token classification.
|
||||
@@ -0,0 +1,82 @@
|
||||
<!--Copyright 2026 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# DDP
|
||||
|
||||
[DistributedDataParallel (DDP)](https://docs.pytorch.org/tutorials/beginner/ddp_series_theory.html) maintains a full copy of a model on each GPU. Each GPU processes a non-overlapping shard of data with a forward and backward pass. Before the optimizer step, an all-reduce averages gradients across all GPUs so every model copy stays identical. Use DDP when your model fits on a single GPU.
|
||||
|
||||
```text
|
||||
┌─────────────────┐
|
||||
│ training data │
|
||||
└────────┬────────┘
|
||||
┌──────────────────┼──────────────────┐
|
||||
│ shard 0 │ shard 1 │ shard 2
|
||||
▼ ▼ ▼
|
||||
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
|
||||
│ model │ │ model │ │ model │
|
||||
│ (copy 0) │ │ (copy 1) │ │ (copy 2) │
|
||||
│ GPU 0 │ │ GPU 1 │ │ GPU 2 │
|
||||
└──────┬──────┘ └──────┬──────┘ └──────┬──────┘
|
||||
│ grads │ grads │ grads
|
||||
└──────────────────┼──────────────────┘
|
||||
all-reduce
|
||||
(average gradients)
|
||||
┌──────────────────┼──────────────────┐
|
||||
▼ ▼ ▼
|
||||
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
|
||||
│ optimizer │ │ optimizer │ │ optimizer │
|
||||
│ step │ │ step │ │ step │
|
||||
└─────────────┘ └─────────────┘ └─────────────┘
|
||||
(identical) (identical) (identical)
|
||||
```
|
||||
|
||||
DDP activates automatically when you launch with a multi-process launcher like [Accelerate](./accelerate).
|
||||
|
||||
```cli
|
||||
# 4 GPUs on one machine
|
||||
accelerate launch --num_processes 4 train.py
|
||||
```
|
||||
|
||||
## Configure DDP
|
||||
|
||||
Pass these [`TrainingArguments`] to control DDP behavior.
|
||||
|
||||
- [`~TrainingArguments.gradient_accumulation_steps`] determines when to perform the all-reduce. [`Trainer`] skips the all-reduce on intermediate accumulation steps and runs it only on the final micro-batch. For example, with `gradient_accumulation_steps=4`, the all-reduce runs every 4 backward passes.
|
||||
- [`~TrainingArguments.ddp_find_unused_parameters`] traverses the autograd graph at the end of the forward pass for parameters that won't receive a gradient and marks them as ready so they don't block the all-reduce. Don't use with [`~TrainingArguments.gradient_checkpointing`] because gradient checkpointing discards intermediate activations and recomputes them on the fly.
|
||||
- [`~TrainingArguments.ddp_bucket_cap_mb`] is the bucket size for batching gradients into a single all-reduce during the backward pass. A larger bucket means fewer all-reduce calls and less launch overhead.
|
||||
- [`~TrainingArguments.ddp_broadcast_buffers`] synchronizes model buffers (such as BatchNorm running statistics) from rank 0 to all other ranks at the start of every forward pass. Disable if your model only uses LayerNorm. Don't use with [`~TrainingArguments.gradient_checkpointing`].
|
||||
- [`~TrainingArguments.ddp_backend`] sets the communication backend. Use `"nccl"` for NVIDIA GPUs (default and fastest), `"gloo"` for CPU training or debugging, and `"xccl"`, `"hccl"`, or `"cncl"` for other hardware.
|
||||
- [`~TrainingArguments.ddp_timeout`] sets the time limit for all processes and operations (all-reduce, broadcast) to complete. If a process hangs, like when loading a large model slowly, the timeout raises an error instead of blocking indefinitely.
|
||||
|
||||
```py
|
||||
from transformers import TrainingArguments
|
||||
|
||||
args = TrainingArguments(
|
||||
...,
|
||||
gradient_accumulation_steps=4,
|
||||
ddp_backend="nccl",
|
||||
ddp_find_unused_parameters=False,
|
||||
ddp_bucket_cap_mb=25,
|
||||
ddp_broadcast_buffers=True,
|
||||
ddp_timeout=1800,
|
||||
)
|
||||
```
|
||||
|
||||
## Next steps
|
||||
|
||||
- See [FSDP](./fsdp) for training models too large to fit on a single GPU.
|
||||
- See [DeepSpeed](./deepspeed) for ZeRO optimization and offloading.
|
||||
- Read the [Data Parallelism](https://nanotron-ultrascale-playbook.static.hf.space/index.html#data_parallelism) chapter from The Ultra-Scale Playbook for more information about how DDP works.
|
||||
@@ -0,0 +1,429 @@
|
||||
<!--Copyright 2024 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Debugging
|
||||
|
||||
Debugging distributed training problems typically falls into one of these categories: numerical issues, communication failures, runtime errors, and build errors.
|
||||
|
||||
## Underflow and overflow detection
|
||||
|
||||
Underflow and overflow occur when activations or weights reach `inf` or `nan`, or when `loss=NaN`. To detect these, enable the `DebugUnderflowOverflow` module in [`TrainingArguments.debug`], or import and add it to your own training loop.
|
||||
|
||||
<hfoptions id="overflow">
|
||||
<hfoption id="Trainer">
|
||||
|
||||
```py
|
||||
from transformers import TrainingArguments
|
||||
|
||||
args = TrainingArguments(
|
||||
debug="underflow_overflow",
|
||||
...
|
||||
)
|
||||
```
|
||||
|
||||
</hfoption>
|
||||
<hfoption id="PyTorch training loop">
|
||||
|
||||
```py
|
||||
from transformers.debug_utils import DebugUnderflowOverflow
|
||||
|
||||
debug_overflow = DebugUnderflowOverflow(model)
|
||||
```
|
||||
|
||||
</hfoption>
|
||||
</hfoptions>
|
||||
|
||||
[`~debug_utils.DebugUnderflowOverflow`] inserts hooks into the model to test input and output variables and the corresponding model weights after each forward call. When `inf` or `nan` is detected in at least one element of the activations or weights, the module prints a report like the one below.
|
||||
|
||||
The example below is for fp16 mixed precision training with [google/mt5-small](https://huggingface.co/google/mt5-small).
|
||||
|
||||
```shell
|
||||
Detected inf/nan during batch_number=0
|
||||
Last 21 forward frames:
|
||||
abs min abs max metadata
|
||||
encoder.block.1.layer.1.DenseReluDense.dropout Dropout
|
||||
0.00e+00 2.57e+02 input[0]
|
||||
0.00e+00 2.85e+02 output
|
||||
[...]
|
||||
encoder.block.2.layer.0 T5LayerSelfAttention
|
||||
6.78e-04 3.15e+03 input[0]
|
||||
2.65e-04 3.42e+03 output[0]
|
||||
None output[1]
|
||||
2.25e-01 1.00e+04 output[2]
|
||||
encoder.block.2.layer.1.layer_norm T5LayerNorm
|
||||
8.69e-02 4.18e-01 weight
|
||||
2.65e-04 3.42e+03 input[0]
|
||||
1.79e-06 4.65e+00 output
|
||||
encoder.block.2.layer.1.DenseReluDense.wi_0 Linear
|
||||
2.17e-07 4.50e+00 weight
|
||||
1.79e-06 4.65e+00 input[0]
|
||||
2.68e-06 3.70e+01 output
|
||||
encoder.block.2.layer.1.DenseReluDense.wi_1 Linear
|
||||
8.08e-07 2.66e+01 weight
|
||||
1.79e-06 4.65e+00 input[0]
|
||||
1.27e-04 2.37e+02 output
|
||||
encoder.block.2.layer.1.DenseReluDense.dropout Dropout
|
||||
0.00e+00 8.76e+03 input[0]
|
||||
0.00e+00 9.74e+03 output
|
||||
encoder.block.2.layer.1.DenseReluDense.wo Linear
|
||||
1.01e-06 6.44e+00 weight
|
||||
0.00e+00 9.74e+03 input[0]
|
||||
3.18e-04 6.27e+04 output
|
||||
encoder.block.2.layer.1.DenseReluDense T5DenseGatedGeluDense
|
||||
1.79e-06 4.65e+00 input[0]
|
||||
3.18e-04 6.27e+04 output
|
||||
encoder.block.2.layer.1.dropout Dropout
|
||||
3.18e-04 6.27e+04 input[0]
|
||||
0.00e+00 inf output
|
||||
```
|
||||
|
||||
The first line shows the batch number where the error occurred. In this case, it occurred on batch 0.
|
||||
|
||||
Each frame describes the module it reports on. For example, the frame below reports on `encoder.block.2.layer.1.layer_norm`, the layer norm in the first layer of the encoder's second block. The forward calls are to `T5LayerNorm`.
|
||||
|
||||
```shell
|
||||
encoder.block.2.layer.1.layer_norm T5LayerNorm
|
||||
8.69e-02 4.18e-01 weight
|
||||
2.65e-04 3.42e+03 input[0]
|
||||
1.79e-06 4.65e+00 output
|
||||
```
|
||||
|
||||
The last frame reports on the `Dropout.forward` function, which calls the `dropout` attribute inside the `DenseReluDense` class. The overflow (`inf`) occurred in the encoder's second block on the first batch. The largest input element was 6.27e+04.
|
||||
|
||||
```shell
|
||||
encoder.block.2.layer.1.DenseReluDense T5DenseGatedGeluDense
|
||||
1.79e-06 4.65e+00 input[0]
|
||||
3.18e-04 6.27e+04 output
|
||||
encoder.block.2.layer.1.dropout Dropout
|
||||
3.18e-04 6.27e+04 input[0]
|
||||
0.00e+00 inf output
|
||||
```
|
||||
|
||||
`T5DenseGatedGeluDense.forward` output activations reached a maximum of 6.27e+04, which is close to fp16's maximum of 6.4e+04. In the next step, `Dropout` renormalizes the weights after zeroing some elements, pushing the maximum above 6.4e+04 and causing the overflow.
|
||||
|
||||
Now that you know where the error is happening, investigate the modeling code in [modeling_t5.py](https://github.com/huggingface/transformers/blob/main/src/transformers/models/t5/modeling_t5.py).
|
||||
|
||||
```py
|
||||
class T5DenseGatedGeluDense(nn.Module):
|
||||
def __init__(self, config):
|
||||
super().__init__()
|
||||
self.wi_0 = nn.Linear(config.d_model, config.d_ff, bias=False)
|
||||
self.wi_1 = nn.Linear(config.d_model, config.d_ff, bias=False)
|
||||
self.wo = nn.Linear(config.d_ff, config.d_model, bias=False)
|
||||
self.dropout = nn.Dropout(config.dropout_rate)
|
||||
self.gelu_act = ACT2FN["gelu_new"]
|
||||
|
||||
def forward(self, hidden_states):
|
||||
hidden_gelu = self.gelu_act(self.wi_0(hidden_states))
|
||||
hidden_linear = self.wi_1(hidden_states)
|
||||
hidden_states = hidden_gelu * hidden_linear
|
||||
hidden_states = self.dropout(hidden_states)
|
||||
hidden_states = self.wo(hidden_states)
|
||||
return hidden_states
|
||||
```
|
||||
|
||||
One fix is to switch to fp32 a few steps before the values grew too large, so numbers don't overflow when multiplied or summed. Another option is to disable mixed precision training (`amp`) temporarily.
|
||||
|
||||
```py
|
||||
import torch
|
||||
|
||||
def forward(self, hidden_states):
|
||||
device_type = hidden_states.device.type
|
||||
if torch.is_autocast_enabled(device_type):
|
||||
with torch.amp.autocast(device_type, enabled=False):
|
||||
return self._forward(hidden_states)
|
||||
else:
|
||||
return self._forward(hidden_states)
|
||||
```
|
||||
|
||||
The report only covers inputs and outputs of full frames. To analyze intermediate values inside any `forward` function, add `detect_overflow` after each forward call to track `inf` or `nan` in `forwarded_states`.
|
||||
|
||||
```py
|
||||
from transformers.debug_utils import detect_overflow
|
||||
|
||||
class T5LayerFF(nn.Module):
|
||||
[...]
|
||||
|
||||
def forward(self, hidden_states):
|
||||
forwarded_states = self.layer_norm(hidden_states)
|
||||
detect_overflow(forwarded_states, "after layer_norm")
|
||||
forwarded_states = self.DenseReluDense(forwarded_states)
|
||||
detect_overflow(forwarded_states, "after DenseReluDense")
|
||||
return hidden_states + self.dropout(forwarded_states)
|
||||
```
|
||||
|
||||
Configure the number of frames printed by [`~debug_utils.DebugUnderflowOverflow`].
|
||||
|
||||
```py
|
||||
from transformers.debug_utils import DebugUnderflowOverflow
|
||||
|
||||
debug_overflow = DebugUnderflowOverflow(model, max_frames_to_save=100)
|
||||
```
|
||||
|
||||
### Batch tracing
|
||||
|
||||
[`~debug_utils.DebugUnderflowOverflow`] can also trace the absolute minimum and maximum values in each batch with underflow and overflow detection disabled. This helps you locate where values start diverging in your model.
|
||||
|
||||
The example below traces batches 1 and 3 (batches are zero-indexed).
|
||||
|
||||
```py
|
||||
debug_overflow = DebugUnderflowOverflow(model, trace_batch_nums=[1, 3])
|
||||
```
|
||||
|
||||
```shell
|
||||
*** Starting batch number=1 ***
|
||||
abs min abs max metadata
|
||||
shared Embedding
|
||||
1.01e-06 7.92e+02 weight
|
||||
0.00e+00 2.47e+04 input[0]
|
||||
5.36e-05 7.92e+02 output
|
||||
[...]
|
||||
decoder.dropout Dropout
|
||||
1.60e-07 2.27e+01 input[0]
|
||||
0.00e+00 2.52e+01 output
|
||||
decoder T5Stack
|
||||
not a tensor output
|
||||
lm_head Linear
|
||||
1.01e-06 7.92e+02 weight
|
||||
0.00e+00 1.11e+00 input[0]
|
||||
6.06e-02 8.39e+01 output
|
||||
T5ForConditionalGeneration
|
||||
not a tensor output
|
||||
|
||||
*** Starting batch number=3 ***
|
||||
abs min abs max metadata
|
||||
shared Embedding
|
||||
1.01e-06 7.92e+02 weight
|
||||
0.00e+00 2.78e+04 input[0]
|
||||
5.36e-05 7.92e+02 output
|
||||
[...]
|
||||
```
|
||||
|
||||
[`~debug_utils.DebugUnderflowOverflow`] reports many frames, which makes it easier to spot where values diverge. If you know the problem is around batch 150, focus the trace on batches 149 and 150 to compare where the numbers start to differ.
|
||||
|
||||
You can also stop the trace after a specific batch number, for example batch 3.
|
||||
|
||||
```py
|
||||
debug_overflow = DebugUnderflowOverflow(model, trace_batch_nums=[1, 3], abort_after_batch_num=3)
|
||||
```
|
||||
|
||||
## Communication
|
||||
|
||||
Distributed training requires inter-process and inter-node communication, which is a common source of errors.
|
||||
|
||||
Download the script below to diagnose network issues, then run it to test GPU communication. The command below tests two GPUs. Adjust `--nproc_per_node` and `--nnodes` for your system.
|
||||
|
||||
```bash
|
||||
wget https://raw.githubusercontent.com/huggingface/transformers/main/scripts/distributed/torch-distributed-gpu-test.py
|
||||
python -m torch.distributed.run --nproc_per_node 2 --nnodes 1 torch-distributed-gpu-test.py
|
||||
```
|
||||
|
||||
The script prints `OK` if both GPUs communicate and allocate memory successfully. See the diagnostic script for more details and a recipe for running it in a SLURM environment.
|
||||
|
||||
Set `NCCL_DEBUG=INFO` to get detailed NCCL debugging output.
|
||||
|
||||
```bash
|
||||
NCCL_DEBUG=INFO python -m torch.distributed.run --nproc_per_node 2 --nnodes 1 torch-distributed-gpu-test.py
|
||||
```
|
||||
|
||||
## DeepSpeed
|
||||
|
||||
When you hit an error, first check whether DeepSpeed is the cause. Retry your setup without DeepSpeed, and if the error persists, report the issue. For issues unrelated to the Transformers integration, open an issue on the DeepSpeed [repository](https://github.com/microsoft/DeepSpeed).
|
||||
|
||||
For issues related to the Transformers integration, include the following information.
|
||||
|
||||
* The full DeepSpeed config file.
|
||||
* The command line arguments for [`Trainer`] or the [`TrainingArguments`] if you're scripting the [`Trainer`] setup yourself (don't dump the entire [`TrainingArguments`] which contains many irrelevant entries).
|
||||
* The outputs of these commands.
|
||||
|
||||
```bash
|
||||
python -c 'import torch; print(f"torch: {torch.__version__}")'
|
||||
python -c 'import transformers; print(f"transformers: {transformers.__version__}")'
|
||||
python -c 'import deepspeed; print(f"deepspeed: {deepspeed.__version__}")'
|
||||
```
|
||||
|
||||
* A link to a Google Colab notebook to reproduce the issue.
|
||||
* A standard or non-custom dataset or an existing example to reproduce the issue.
|
||||
|
||||
### Process killed at startup
|
||||
|
||||
If the DeepSpeed process is killed during launch without a traceback, the program tried to allocate more CPU memory than is available or allowed. The OS kernel terminates the process in either case.
|
||||
|
||||
Check whether your config file has `offload_optimizer`, `offload_param`, or both configured to offload to the CPU.
|
||||
|
||||
If you have NVMe and ZeRO-3 set up, try offloading to the NVMe instead. [Estimate](https://deepspeed.readthedocs.io/en/latest/memory.html) the memory requirements of your model first.
|
||||
|
||||
### NaN loss
|
||||
|
||||
NaN loss often occurs when a model is pretrained in bf16 and then it is used with fp16 (this is especially common with TPU-trained models). Use fp32 or bf16 if your hardware supports it (TPUs, Ampere GPUs or newer).
|
||||
|
||||
fp16 can also cause overflow. If your config file looks like the one below, you may see overflow errors in the logs.
|
||||
|
||||
```json
|
||||
{
|
||||
"fp16": {
|
||||
"enabled": "auto",
|
||||
"loss_scale": 0,
|
||||
"loss_scale_window": 1000,
|
||||
"initial_scale_power": 16,
|
||||
"hysteresis": 2,
|
||||
"min_loss_scale": 1
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The `OVERFLOW!` error below means the DeepSpeed loss scaler couldn't find a scaling coefficient to overcome the loss overflow. Try a higher `initial_scale_power` value (32 usually works).
|
||||
|
||||
```bash
|
||||
0%| | 0/189 [00:00<?, ?it/s]
|
||||
[deepscale] OVERFLOW! Rank 0 Skipping step. Attempted loss scale: 262144, reducing to 262144
|
||||
1%|▌ | 1/189 [00:00<01:26, 2.17it/s]
|
||||
[deepscale] OVERFLOW! Rank 0 Skipping step. Attempted loss scale: 262144, reducing to 131072.0
|
||||
1%|█▏
|
||||
[...]
|
||||
[deepscale] OVERFLOW! Rank 0 Skipping step. Attempted loss scale: 1, reducing to 1
|
||||
14%|████████████████▌ | 27/189 [00:14<01:13, 2.21it/s]
|
||||
[deepscale] OVERFLOW! Rank 0 Skipping step. Attempted loss scale: 1, reducing to 1
|
||||
15%|█████████████████▏ | 28/189 [00:14<01:13, 2.18it/s]
|
||||
[deepscale] OVERFLOW! Rank 0 Skipping step. Attempted loss scale: 1, reducing to 1
|
||||
15%|█████████████████▊ | 29/189 [00:15<01:13, 2.18it/s]
|
||||
[deepscale] OVERFLOW! Rank 0 Skipping step. Attempted loss scale: 1, reducing to 1
|
||||
[...]
|
||||
```
|
||||
|
||||
## DeepSpeed CUDA
|
||||
|
||||
DeepSpeed compiles CUDA C++ code, which is a common source of build errors for PyTorch extensions that require CUDA. These errors depend on how CUDA is installed on your system.
|
||||
|
||||
```bash
|
||||
pip install deepspeed
|
||||
```
|
||||
|
||||
> [!TIP]
|
||||
> For any other installation issues, [open an issue](https://github.com/microsoft/DeepSpeed/issues) with the DeepSpeed team.
|
||||
|
||||
### Non-identical toolkits
|
||||
|
||||
PyTorch ships with its own CUDA toolkit, but DeepSpeed requires an identical CUDA version installed system-wide. If you installed PyTorch with `cudatoolkit==10.2` in your Python environment, you'll also need CUDA 10.2 installed everywhere.
|
||||
|
||||
The exact location varies by system, but `/usr/local/cuda-10.2` is the most common path on Unix systems. Once CUDA is set up and added to your `PATH`, find the installation location with this command.
|
||||
|
||||
```bash
|
||||
which nvcc
|
||||
```
|
||||
|
||||
### Multiple toolkits
|
||||
|
||||
Your system may have more than one CUDA toolkit installed.
|
||||
|
||||
```text
|
||||
/usr/local/cuda-10.2
|
||||
/usr/local/cuda-11.0
|
||||
```
|
||||
|
||||
Package installers typically set paths to the last installed version. If the build fails because it can't find the right CUDA version, configure `PATH` and `LD_LIBRARY_PATH` to point to the correct path.
|
||||
|
||||
Check these environment variables first.
|
||||
|
||||
```bash
|
||||
echo $PATH
|
||||
echo $LD_LIBRARY_PATH
|
||||
```
|
||||
|
||||
`PATH` lists executable locations. `LD_LIBRARY_PATH` lists shared library locations. Earlier entries take priority, and `:` separates multiple entries. Prepend the correct CUDA path to prioritize it.
|
||||
|
||||
```bash
|
||||
# adjust the version and full path if needed
|
||||
export PATH=/usr/local/cuda-10.2/bin:$PATH
|
||||
export LD_LIBRARY_PATH=/usr/local/cuda-10.2/lib64:$LD_LIBRARY_PATH
|
||||
```
|
||||
|
||||
Also verify the assigned directories exist. The `lib64` sub-directory contains CUDA `.so` objects like `libcudart.so`. Check the actual filenames and update accordingly.
|
||||
|
||||
### Older versions
|
||||
|
||||
Older CUDA versions sometimes require older compiler versions. For example, if CUDA requires `gcc-7` but your system only has `gcc-9`, the build will fail. Install the required older compiler and create a symlink so the CUDA build system can find it.
|
||||
|
||||
```bash
|
||||
# adjust the path to your system
|
||||
sudo ln -s /usr/bin/gcc-7 /usr/local/cuda-10.2/bin/gcc
|
||||
sudo ln -s /usr/bin/g++-7 /usr/local/cuda-10.2/bin/g++
|
||||
```
|
||||
|
||||
### Prebuild
|
||||
|
||||
If you're still having trouble installing DeepSpeed or building it at runtime, prebuild the DeepSpeed modules first. Run the commands below for a local build.
|
||||
|
||||
```bash
|
||||
git clone https://github.com/deepspeedai/DeepSpeed/
|
||||
cd DeepSpeed
|
||||
rm -rf build
|
||||
TORCH_CUDA_ARCH_LIST="8.6" DS_BUILD_CPU_ADAM=1 DS_BUILD_UTILS=1 pip install . \
|
||||
--global-option="build_ext" --global-option="-j8" --no-cache -v \
|
||||
--disable-pip-version-check 2>&1 | tee build.log
|
||||
```
|
||||
|
||||
> [!TIP]
|
||||
> Add `DS_BUILD_AIO=1` to the build command to use NVMe offload. Make sure you install the libaio-dev package system-wide.
|
||||
|
||||
Next, set your GPU architecture in `TORCH_CUDA_ARCH_LIST`. A complete list of NVIDIA GPUs and their architectures is on the [CUDA GPUs page](https://developer.nvidia.com/cuda-gpus). To check the PyTorch version that corresponds to your architecture, run the command below.
|
||||
|
||||
```bash
|
||||
python -c "import torch; print(torch.cuda.get_arch_list())"
|
||||
```
|
||||
|
||||
Find the architecture for a GPU with the following command.
|
||||
|
||||
<hfoptions id="arch">
|
||||
<hfoption id="same GPUs">
|
||||
|
||||
```bash
|
||||
CUDA_VISIBLE_DEVICES=0 python -c "import torch; print(torch.cuda.get_device_capability())"
|
||||
```
|
||||
|
||||
</hfoption>
|
||||
<hfoption id="specific GPU">
|
||||
|
||||
Run the following command to find the architecture for GPU `0`. The output shows `major` and `minor` values that together form the GPU architecture. The example below shows architecture `8.6`.
|
||||
|
||||
```bash
|
||||
CUDA_VISIBLE_DEVICES=0 python -c "import torch; \
|
||||
print(torch.cuda.get_device_properties(torch.device('cuda')))
|
||||
"_CudaDeviceProperties(name='GeForce RTX 3090', major=8, minor=6, total_memory=24268MB, multi_processor_count=82)"
|
||||
```
|
||||
|
||||
</hfoption>
|
||||
</hfoptions>
|
||||
|
||||
For a result of `8, 6`, set `TORCH_CUDA_ARCH_LIST="8.6"`. For multiple GPUs with different architectures, list them like `TORCH_CUDA_ARCH_LIST="6.1;8.6"`.
|
||||
|
||||
You can omit `TORCH_CUDA_ARCH_LIST` and let the build program detect the GPU architecture automatically, but it might not match the actual GPU on the target machine. Explicitly setting the architecture is more reliable.
|
||||
|
||||
For training on multiple machines with the same setup, build a binary wheel.
|
||||
|
||||
```bash
|
||||
git clone https://github.com/deepspeedai/DeepSpeed/
|
||||
cd DeepSpeed
|
||||
rm -rf build
|
||||
TORCH_CUDA_ARCH_LIST="8.6" DS_BUILD_CPU_ADAM=1 DS_BUILD_UTILS=1 \
|
||||
python setup.py build_ext -j8 bdist_wheel
|
||||
```
|
||||
|
||||
This generates a binary wheel like `dist/deepspeed-0.3.13+8cd046f-cp38-cp38-linux_x86_64.whl`. Install it locally or on another machine.
|
||||
|
||||
```bash
|
||||
pip install deepspeed-0.3.13+8cd046f-cp38-cp38-linux_x86_64.whl
|
||||
```
|
||||
@@ -0,0 +1,298 @@
|
||||
<!--Copyright 2024 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# DeepSpeed ZeRO
|
||||
|
||||
[DeepSpeed](https://www.deepspeed.ai/) ZeRO (Zero Redundancy Optimizer) eliminates memory redundancy across distributed training by sharding optimizer states, gradients, and parameters across GPUs. ZeRO has three stages, each sharding more state than the last. DeepSpeed also supports offloading to CPU or NVMe memory for further savings. Every additional stage and offload level reduces peak memory, at the cost of more inter-GPU communication.
|
||||
|
||||
```text
|
||||
params grads opt states
|
||||
┌──────────┐ ┌──────────┐ ┌──────────┐
|
||||
ZeRO-1 │██████████│ │██████████│ │███░░░░░░░│ GPU 0
|
||||
│██████████│ │██████████│ │░░░███░░░░│ GPU 1
|
||||
│██████████│ │██████████│ │░░░░░░████│ GPU 2
|
||||
└──────────┘ └──────────┘ └──────────┘
|
||||
┌──────────┐ ┌──────────┐ ┌──────────┐
|
||||
ZeRO-2 │██████████│ │███░░░░░░░│ │███░░░░░░░│ GPU 0
|
||||
│██████████│ │░░░███░░░░│ │░░░███░░░░│ GPU 1
|
||||
│██████████│ │░░░░░░████│ │░░░░░░████│ GPU 2
|
||||
└──────────┘ └──────────┘ └──────────┘
|
||||
┌──────────┐ ┌──────────┐ ┌──────────┐
|
||||
ZeRO-3 │███░░░░░░░│ │███░░░░░░░│ │███░░░░░░░│ GPU 0
|
||||
│░░░███░░░░│ │░░░███░░░░│ │░░░███░░░░│ GPU 1
|
||||
│░░░░░░████│ │░░░░░░████│ │░░░░░░████│ GPU 2
|
||||
└──────────┘ └──────────┘ └──────────┘
|
||||
█ resident ░ held on another GPU
|
||||
```
|
||||
|
||||
ZeRO-2 shards gradients and optimizer states with lower communication overhead than ZeRO-3. Use ZeRO-3 only when your model doesn't fit across GPUs with ZeRO-2.
|
||||
|
||||
## Installation
|
||||
|
||||
Install DeepSpeed from PyPI, or install Transformers with the `deepspeed` extra.
|
||||
|
||||
```shell
|
||||
pip install deepspeed
|
||||
pip install transformers[deepspeed]
|
||||
```
|
||||
|
||||
If you run into CUDA-related install errors, check the [DeepSpeed CUDA](./debugging#deepspeed-cuda) docs. [Installing from source](https://www.deepspeed.ai/tutorials/advanced-install/#install-deepspeed-from-source) is the more reliable option because it matches your exact hardware and includes features not yet available in the PyPI release.
|
||||
|
||||
## Configure
|
||||
|
||||
[`Trainer`] integrates DeepSpeed through the [`~TrainingArguments#deepspeed`] argument, which accepts a JSON config file. Alternatively, use an [Accelerate config file](./accelerate#accelerate-config-file) instead of [`TrainingArguments`].
|
||||
|
||||
<hfoptions id="launch">
|
||||
<hfoption id="TrainingArguments">
|
||||
|
||||
Use `"auto"` in your config for values you want DeepSpeed to fill from [`TrainingArguments`]. If you want to explicitly specify a value, make sure you use the *same* value for both the DeepSpeed argument and [`TrainingArguments`].
|
||||
|
||||
> [!NOTE]
|
||||
> See the [DeepSpeed Configuration JSON](https://www.deepspeed.ai/docs/config-json/) reference for a complete list of DeepSpeed config options.
|
||||
|
||||
```json
|
||||
"train_micro_batch_size_per_gpu": "auto", // ← per_device_train_batch_size in TrainingArguments
|
||||
"gradient_accumulation_steps": "auto", // ← gradient_accumulation_steps in TrainingArguments
|
||||
"optimizer.params.lr": "auto", // ← learning_rate in TrainingArguments
|
||||
"fp16.enabled": "auto", // ← fp16 flag in TrainingArguments
|
||||
```
|
||||
|
||||
Pass the config to the `deepspeed` argument.
|
||||
|
||||
```py
|
||||
from transformers import TrainingArguments
|
||||
|
||||
args = TrainingArguments(
|
||||
deepspeed="path/to/deepspeed_config.json",
|
||||
...
|
||||
)
|
||||
```
|
||||
|
||||
```cli
|
||||
# DeepSpeed launcher
|
||||
deepspeed --num_gpus 4 train.py
|
||||
|
||||
# torchrun
|
||||
torchrun --nproc_per_node 4 train.py
|
||||
|
||||
# Accelerate
|
||||
accelerate launch --num_processes 4 train.py
|
||||
```
|
||||
|
||||
</hfoption>
|
||||
<hfoption id="Accelerate config file">
|
||||
|
||||
> [!NOTE]
|
||||
> Accelerate ignores the [`deepspeed`] argument in [`TrainingArguments`].
|
||||
|
||||
Run the [accelerate config](https://huggingface.co/docs/accelerate/en/package_reference/cli#accelerate-config) command and answer questions about your hardware and training setup to create a `default_config.yaml` file in your cache.
|
||||
|
||||
```yaml
|
||||
distributed_type: DEEPSPEED
|
||||
deepspeed_config:
|
||||
deepspeed_config_file: path/to/ds_config.json
|
||||
machine_rank: 0
|
||||
num_machines: 1
|
||||
num_processes: 4
|
||||
```
|
||||
|
||||
Run [accelerate launch](https://huggingface.co/docs/accelerate/en/package_reference/cli#accelerate-launch) with a [`Trainer`]-based script.
|
||||
|
||||
```shell
|
||||
accelerate launch --config_file deepspeed_config.yaml train.py
|
||||
```
|
||||
|
||||
</hfoption>
|
||||
</hfoptions>
|
||||
|
||||
## ZeRO stages
|
||||
|
||||
Select a ZeRO stage config to use as a starting point.
|
||||
|
||||
<hfoptions id="zero">
|
||||
<hfoption id="ZeRO-1">
|
||||
|
||||
```json
|
||||
{
|
||||
"bf16": { "enabled": "auto" },
|
||||
"zero_optimization": { "stage": 1 },
|
||||
"gradient_clipping": "auto",
|
||||
"train_micro_batch_size_per_gpu": "auto",
|
||||
"train_batch_size": "auto",
|
||||
"gradient_accumulation_steps": "auto"
|
||||
}
|
||||
```
|
||||
|
||||
</hfoption>
|
||||
<hfoption id="ZeRO-2">
|
||||
|
||||
```json
|
||||
{
|
||||
"bf16": { "enabled": "auto" },
|
||||
"zero_optimization": {
|
||||
"stage": 2,
|
||||
"overlap_comm": true,
|
||||
"allgather_bucket_size": 2e8,
|
||||
"reduce_bucket_size": 2e8,
|
||||
"contiguous_gradients": true
|
||||
},
|
||||
"gradient_clipping": "auto",
|
||||
"train_micro_batch_size_per_gpu": "auto",
|
||||
"train_batch_size": "auto",
|
||||
"gradient_accumulation_steps": "auto"
|
||||
}
|
||||
```
|
||||
|
||||
</hfoption>
|
||||
<hfoption id="ZeRO-3">
|
||||
|
||||
> [!WARNING]
|
||||
> ZeRO-3 shards parameters during initialization. You must instantiate [`TrainingArguments`] before loading your model — if the model is already on each GPU before DeepSpeed is configured, no memory is saved.
|
||||
|
||||
```json
|
||||
{
|
||||
"bf16": { "enabled": "auto" },
|
||||
"zero_optimization": {
|
||||
"stage": 3,
|
||||
"overlap_comm": true,
|
||||
"contiguous_gradients": true,
|
||||
"reduce_bucket_size": "auto",
|
||||
"stage3_prefetch_bucket_size": "auto",
|
||||
"stage3_param_persistence_threshold": "auto",
|
||||
"stage3_gather_16bit_weights_on_model_save": true,
|
||||
"offload_optimizer": { "device": "cpu", "pin_memory": true }, // optional offloading
|
||||
"offload_param": { "device": "cpu", "pin_memory": true } // optional offloading
|
||||
},
|
||||
"gradient_clipping": "auto",
|
||||
"train_micro_batch_size_per_gpu": "auto",
|
||||
"train_batch_size": "auto",
|
||||
"gradient_accumulation_steps": "auto"
|
||||
}
|
||||
```
|
||||
|
||||
</hfoption>
|
||||
</hfoptions>
|
||||
|
||||
The following fields are important for customizing training.
|
||||
|
||||
- `zero_optimization` sets the ZeRO stage.
|
||||
|
||||
```json
|
||||
{ "zero_optimization": { "stage": 3 } }
|
||||
```
|
||||
|
||||
- Set the batch size and gradient accumulation arguments to `"auto"`. If you manually set these to values that disagree with [`TrainingArguments`], training continues silently with the wrong values.
|
||||
|
||||
```json
|
||||
{
|
||||
"train_micro_batch_size_per_gpu": "auto",
|
||||
"train_batch_size": "auto",
|
||||
"gradient_accumulation_steps": "auto",
|
||||
"gradient_clipping": "auto"
|
||||
}
|
||||
```
|
||||
|
||||
- `bf16` sets the training precision. Set it to `"auto"` so it mirrors the `bf16` flag in [`TrainingArguments`].
|
||||
|
||||
```json
|
||||
{ "bf16": { "enabled": "auto" } }
|
||||
```
|
||||
|
||||
- `stage3_gather_16bit_weights_on_model_save` performs an all-gather across all GPUs before saving, reconstructing the full tensors from their shards. This is a ZeRO-3 argument.
|
||||
|
||||
```json
|
||||
{
|
||||
"zero_optimization": {
|
||||
"stage": 3,
|
||||
"stage3_gather_16bit_weights_on_model_save": true,
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- Set `overlap_comm` to `true` to hide all-reduce latency behind the backward pass. `allgather_bucket_size` and `reduce_bucket_size` trade communication speed for GPU memory. Lower values use less memory but slow communication.
|
||||
|
||||
```json
|
||||
{
|
||||
"zero_optimization": {
|
||||
"stage": 2,
|
||||
"overlap_comm": true,
|
||||
"allgather_bucket_size": 2e8,
|
||||
"reduce_bucket_size": 2e8,
|
||||
"contiguous_gradients": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- `offload_optimizer` offloads the optimizer to CPU memory. To save even more memory, also offload model parameters with `offload_param` (ZeRO-3 only). Set `pin_memory` to `true` to speed up CPU-GPU transfers, but this locks RAM that is unavailable to other processes.
|
||||
|
||||
```json
|
||||
{
|
||||
"zero_optimization": {
|
||||
"stage": 3,
|
||||
"offload_optimizer": { "device": "cpu", "pin_memory": true },
|
||||
"offload_param": { "device": "cpu", "pin_memory": true }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- `optimizer` and `scheduler` default to the optimizer and scheduler configured in [`TrainingArguments`]. Set to `"auto"` so DeepSpeed reads the values from [`TrainingArguments`] unless you need a DeepSpeed-native optimizer like LAMB.
|
||||
|
||||
```json
|
||||
{
|
||||
"optimizer": {
|
||||
"type": "AdamW",
|
||||
"params": { "lr": "auto", "betas": "auto", "eps": "auto", "weight_decay": "auto" }
|
||||
},
|
||||
"scheduler": {
|
||||
"type": "WarmupDecayLR",
|
||||
"params": { "total_num_steps": "auto", "warmup_min_lr": "auto", "warmup_max_lr": "auto", "warmup_num_steps": "auto" }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
If you're offloading the optimizer, set `zero_force_ds_cpu_optimizer` to `false` to use DeepSpeed's CPU Adam optimizer.
|
||||
|
||||
```json
|
||||
{
|
||||
"zero_force_ds_cpu_optimizer": false
|
||||
}
|
||||
```
|
||||
|
||||
## Checkpoints
|
||||
|
||||
DeepSpeed saves checkpoints in a sharded format that can't be loaded directly with [`~PreTrainedModel.from_pretrained`]. Set [`~TrainingArguments.load_best_model_at_end`] to `True` to have Trainer track and reload the best checkpoint at the end of training.
|
||||
|
||||
```py
|
||||
from transformers import TrainingArguments, Trainer
|
||||
|
||||
args = TrainingArguments(
|
||||
deepspeed="ds_config_zero3.json",
|
||||
load_best_model_at_end=True,
|
||||
...
|
||||
)
|
||||
# after training, save a normal transformers checkpoint
|
||||
trainer.save_model("./best-model")
|
||||
```
|
||||
|
||||
Setting `save_only_model=True` skips saving the full optimizer state, which means you can't reload the best model at the end of training. Also set `stage3_gather_16bit_weights_on_model_save: true` to reconstruct full weights from their shards. This is required for saving a consolidated 16-bit model artifact or 16-bit state dict with ZeRO-3. Transformers raises an error when `save_only_model=True` is combined with `load_best_model_at_end=True`.
|
||||
|
||||
> [!TIP]
|
||||
> For resuming across different parallelism configurations, see DeepSpeed's [Universal Checkpointing](https://www.deepspeed.ai/tutorials/universal-checkpointing) guide.
|
||||
|
||||
## Next steps
|
||||
|
||||
- Read the [Zero Redundancy Optimizer](https://nanotron-ultrascale-playbook.static.hf.space/index.html#zero_redundancy_optimizer_(zero)) chapter from The Ultra-Scale Playbook to learn more about how ZeRO works.
|
||||
- Read the ZeRO papers: [Memory Optimizations Toward Training Trillion Parameter Models](https://hf.co/papers/1910.02054), [Democratizing Billion-Scale Model Training](https://hf.co/papers/2101.06840), and [Breaking the GPU Memory Wall for Extreme Scale Deep Learning](https://hf.co/papers/2104.07857).
|
||||
@@ -0,0 +1,159 @@
|
||||
<!--Copyright 2026 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Ulysses sequence parallelism
|
||||
|
||||
Ulysses sequence parallelism (SP) trains on very long sequences by splitting them across multiple GPUs. To compute attention correctly, an all-to-all collective swaps the sharding dimension from sequence to attention heads. Each GPU then has the full sequence and computes attention locally over a subset of heads. A second all-to-all returns to the sequence-sharded layout so the rest of the forward pass continues locally on each chunk.
|
||||
|
||||
```text
|
||||
GPU 0 GPU 1
|
||||
┌───────────────┐ ┌───────────────┐
|
||||
forward │ tokens 0..N/2 │ │ tokens N/2..N │ ← each GPU holds half the sequence
|
||||
(seq-sharded) │ all H heads │ │ all H heads │
|
||||
└───────┬───────┘ └───────┬───────┘
|
||||
└───────── all-to-all ──────┘
|
||||
┌───────────────┐ ┌───────────────┐
|
||||
attention │ all N tokens │ │ all N tokens │ ← now each GPU has the full sequence
|
||||
(head-sharded) │ heads 0..H/2 │ │ heads H/2..H │ ← but only half the heads
|
||||
└───────┬───────┘ └───────┬───────┘
|
||||
└───────── all-to-all ──────┘
|
||||
┌───────────────┐ ┌───────────────┐
|
||||
forward │ tokens 0..N/2 │ │ tokens N/2..N │ ← back to seq-sharded
|
||||
(seq-sharded) │ all H heads │ │ all H heads │
|
||||
└───────────────┘ └───────────────┘
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> This guide covers the Ulysses sequence parallelism component of [ALST](https://www.deepspeed.ai/tutorials/ulysses-alst-sequence-parallelism/) (Arctic Long Sequence Training). The full ALST system also includes TiledMLP and activation checkpoint offloading, which aren't available in Transformers. See the [DeepSpeed ALST tutorial](https://www.deepspeed.ai/tutorials/ulysses-alst-sequence-parallelism/) for the complete system.
|
||||
|
||||
## Configure
|
||||
|
||||
Sequence parallelism requires Accelerate v1.12.0 and at least 2 GPUs. Configure sequence parallelism in Accelerate's [`~accelerate.ParallelismConfig`] and pass it to [`~TrainingArguments#parallelism_config`] or an [Accelerate config file](./accelerate#accelerate-config-file).
|
||||
|
||||
<hfoptions id="launch">
|
||||
<hfoption id="parallelism_config">
|
||||
|
||||
```py
|
||||
from accelerate.utils import ParallelismConfig, DeepSpeedSequenceParallelConfig
|
||||
|
||||
parallelism_config = ParallelismConfig(
|
||||
sp_backend="deepspeed",
|
||||
sp_size=4,
|
||||
dp_replicate_size=1,
|
||||
sp_handler=DeepSpeedSequenceParallelConfig(
|
||||
sp_seq_length_is_variable=True,
|
||||
sp_attn_implementation="flash_attention_2",
|
||||
),
|
||||
)
|
||||
|
||||
training_args = TrainingArguments(
|
||||
...,
|
||||
deepspeed="path/to/deepspeed_config.json",
|
||||
parallelism_config=parallelism_config,
|
||||
)
|
||||
```
|
||||
|
||||
Run [accelerate launch](https://huggingface.co/docs/accelerate/en/package_reference/cli#accelerate-launch) with a [`Trainer`]-based script.
|
||||
|
||||
```shell
|
||||
accelerate launch --num_processes 4 train.py \
|
||||
--output_dir output_dir \
|
||||
--per_device_train_batch_size 1 \
|
||||
--gradient_accumulation_steps 1
|
||||
```
|
||||
|
||||
</hfoption>
|
||||
<hfoption id="Accelerate config file">
|
||||
|
||||
Run the [accelerate config](https://huggingface.co/docs/accelerate/en/package_reference/cli#accelerate-config) command and answer questions about your hardware and training setup to create a `default_config.yaml` file in your cache.
|
||||
|
||||
```yaml
|
||||
distributed_type: DEEPSPEED
|
||||
deepspeed_config:
|
||||
deepspeed_config_file: path/to/ds_config.json
|
||||
machine_rank: 0
|
||||
num_machines: 1
|
||||
num_processes: 4
|
||||
parallelism_config:
|
||||
parallelism_config_sp_size: 4
|
||||
parallelism_config_dp_replicate_size: 1
|
||||
parallelism_config_sp_backend: deepspeed
|
||||
parallelism_config_sp_seq_length_is_variable: true
|
||||
parallelism_config_sp_attn_implementation: flash_attention_2
|
||||
```
|
||||
|
||||
Run [accelerate launch](https://huggingface.co/docs/accelerate/en/package_reference/cli#accelerate-launch) with a [`Trainer`]-based script.
|
||||
|
||||
```shell
|
||||
accelerate launch --config_file alst_config.yaml train.py \
|
||||
--output_dir output_dir \
|
||||
--per_device_train_batch_size 1 \
|
||||
--gradient_accumulation_steps 1
|
||||
```
|
||||
|
||||
</hfoption>
|
||||
</hfoptions>
|
||||
|
||||
The following fields are important for configuring sequence parallelism.
|
||||
|
||||
> [!TIP]
|
||||
> The [`Trainer`] automatically handles DataLoader sharding, `position_ids` generation, label shifting, and loss aggregation across SP ranks. If you're writing a custom training loop, see the Accelerate [Sequence Parallelism](https://huggingface.co/docs/accelerate/concept_guides/sequence_parallelism) guide instead.
|
||||
|
||||
- `sp_backend` must be set to `"deepspeed"` to use Ulysses sequence parallelism.
|
||||
|
||||
- `sp_size` is the number of GPUs that process a single sequence in parallel. Each SP rank receives a unique data stream from the DataLoader, unlike tensor parallelism where all ranks receive identical data. The effective `dp_world_size = world_size / sp_size`, so with 4 GPUs and `sp_size=4`, `dp_world_size=1` for batch size calculations. Sequences must also be padded to a multiple of `sp_size`. Set `pad_to_multiple_of` in your data collator accordingly.
|
||||
|
||||
> [!WARNING]
|
||||
> The number of attention heads must be divisible by `sp_size`. A model with 32 heads supports `sp_size` of 1, 2, 4, 8, 16, or 32.
|
||||
|
||||
```py
|
||||
from transformers import DataCollatorForLanguageModeling
|
||||
|
||||
data_collator = DataCollatorForLanguageModeling(
|
||||
tokenizer=tokenizer,
|
||||
mlm=False,
|
||||
pad_to_multiple_of=sp_size,
|
||||
)
|
||||
```
|
||||
|
||||
- `sp_seq_length_is_variable` controls variable sequence length handling. Set it to `True` (recommended) for varying lengths between batches. Set it to `False` when all sequences pad to a fixed length specified by `sp_seq_length`.
|
||||
|
||||
- `sp_attn_implementation` sets the attention backend. Supported values are `"sdpa"`, `"flash_attention_2"`, or `"flash_attention_3"`. FlashAttention is recommended, especially when packing multiple samples in a batch. SDPA can attend incorrectly across sample boundaries when samples are packed. Eager attention isn't supported because its 4D `attention_mask` is discarded for memory and scaling reasons.
|
||||
|
||||
## Combining with data parallelism
|
||||
|
||||
Sequence parallelism and data parallelism use the same GPUs, and SP doesn't require additional hardware. To run both, set `dp_replicate_size` or `dp_shard_size` so that `dp_replicate_size × dp_shard_size × sp_size` equals your total GPU count.
|
||||
|
||||
For example, with 8 GPUs and `sp_size=4`, set `dp_replicate_size=2` (2 × 1 × 4 = 8).
|
||||
|
||||
```py
|
||||
parallelism_config = ParallelismConfig(
|
||||
sp_backend="deepspeed",
|
||||
sp_size=4,
|
||||
dp_replicate_size=2,
|
||||
sp_handler=DeepSpeedSequenceParallelConfig(
|
||||
sp_seq_length_is_variable=True,
|
||||
sp_attn_implementation="flash_attention_2",
|
||||
),
|
||||
)
|
||||
```
|
||||
|
||||
## Next steps
|
||||
|
||||
- The Accelerate [Sequence Parallelism](https://huggingface.co/docs/accelerate/concept_guides/sequence_parallelism) guide covers the Ulysses implementation in more depth and shows how to write a custom training loop.
|
||||
- The [DeepSpeed ALST tutorial](https://www.deepspeed.ai/tutorials/ulysses-alst-sequence-parallelism/) covers the full ALST system, including TiledMLP and activation checkpoint offloading.
|
||||
- The [parallelism methods](./perf_train_gpu_many) guide shows how to combine sequence parallelism with other strategies like ZeRO.
|
||||
- The [Ulysses Sequence Parallelism: Training with Million-Token Contexts](https://huggingface.co/blog/ulysses-sp) blog post explains how Ulysses works and how it's integrated in Accelerate, Trainer, and SFTTrainer.
|
||||
@@ -0,0 +1,46 @@
|
||||
<!--Copyright 2025 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Expert parallelism
|
||||
|
||||
[Expert parallelism](https://huggingface.co/spaces/nanotron/ultrascale-playbook?section=expert_parallelism) is a parallelism strategy for [mixture-of-experts (MoE) models](https://huggingface.co/blog/moe). Each expert's feedforward layer lives on a different hardware accelerator. A router dispatches tokens to the appropriate experts and gathers the results. This approach scales models to far larger parameter counts without increasing computation cost because each token activates only a few experts.
|
||||
|
||||
## DistributedConfig
|
||||
|
||||
Enable expert parallelism with the [`DistributedConfig`] class and the `enable_expert_parallel` argument.
|
||||
|
||||
```py
|
||||
import torch
|
||||
from transformers import AutoModelForCausalLM, AutoTokenizer
|
||||
from transformers.distributed.configuration_utils import DistributedConfig
|
||||
|
||||
distributed_config = DistributedConfig(enable_expert_parallel=True)
|
||||
|
||||
model = AutoModelForCausalLM.from_pretrained(
|
||||
"openai/gpt-oss-120b",
|
||||
distributed_config=distributed_config,
|
||||
)
|
||||
```
|
||||
|
||||
> [!TIP]
|
||||
> Expert parallelism automatically enables [tensor parallelism](./perf_infer_gpu_multi) for attention layers.
|
||||
|
||||
This argument switches to the `ep_plan` (expert parallel plan) defined in each MoE model's config file. The [`GroupedGemmParallel`] class splits expert weights so each device loads only its local experts. The `ep_router` routes tokens to experts and an all-reduce operation combines their outputs.
|
||||
|
||||
Launch your inference script with [torchrun](https://pytorch.org/docs/stable/elastic/run.html) and specify how many devices to use. The number of devices must evenly divide the total number of experts.
|
||||
|
||||
```zsh
|
||||
torchrun --nproc-per-node 8 your_script.py
|
||||
```
|
||||
@@ -0,0 +1,225 @@
|
||||
<!--Copyright 2025 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Experts backends
|
||||
|
||||
All Mixture-of-Experts (MoE) implementations perform the same high-level computation. For each token, a router selects *k* experts. The token hidden state is then projected through the selected experts' parameters and aggregated with routing weights. The difference between experts backends is *how* those expert matrix multiplications execute.
|
||||
|
||||
The [`ExpertsInterface`] provides optimized experts backends. It decouples the experts implementation from the model code to simplify experimentation with different functions. Add new backends through the same interface.
|
||||
|
||||
|
||||
| experts backend | description | GPU | CPU |
|
||||
| --- | --- | --- | --- |
|
||||
| `"eager"` | Reference implementation that loops over selected experts and applies projections on their tokens. | Reasonable baseline performance without requiring compilation. | Slower than `grouped_mm` but faster than `batched_mm`. |
|
||||
| `"batched_mm"` | Duplicates selected expert parameters for each token and projects all tokens in a single batched GEMM using [torch.bmm](https://docs.pytorch.org/docs/stable/generated/torch.bmm.html). | Fastest for small inputs, especially with compilation. Uses more memory due to parameter duplication. | Not recommended (significantly slower than other backends). |
|
||||
| `"grouped_mm"` | Orders tokens by selected experts and uses [torch.nn.functional.grouped_mm](https://docs.pytorch.org/docs/stable/generated/torch.nn.functional.grouped_mm.html) to project all tokens in a single grouped GEMM (requires PyTorch 2.9+). | Best for larger inputs and more memory efficient as it avoids duplicating expert parameters. Fast with compilation. | Most efficient backend for all input sizes. |
|
||||
| `"deepgemm"` | Sorts tokens by selected expert and projects all tokens in a single TMA-aligned grouped GEMM using the [DeepGEMM](https://github.com/deepseek-ai/DeepGEMM) kernels from [kernels-community/deep-gemm](https://huggingface.co/kernels-community/deep-gemm). | Native backend for DeepSeek models on Hopper (SM90+) and Blackwell (SM100+); supports `bfloat16` and FP8/FP4-quantized experts. | Not supported (CUDA-only). |
|
||||
| `"deepgemm_megamoe"` | Fuses expert-parallel dispatch, the gated MLP (up projection, SwiGLU, down projection), and the EP combine into a single DeepGEMM Mega MoE kernel, overlapping NVLink transfers with tensor-core compute. | Blackwell (SM100+) only, for FP4-quantized experts run with expert parallelism. | Not supported (CUDA-only). |
|
||||
| `"sonicmoe"` | Fuses the routed `bfloat16` MoE forward (router dispatch, gated up projection, activation, down projection) into CuteDSL grouped-GEMM kernels (from the [quack](https://github.com/Dao-AILab/quack) library) from [kernels-community/sonic-moe](https://huggingface.co/kernels-community/sonic-moe). | State-of-the-art throughput on Hopper (SM90+) for `bfloat16` experts with a gated activation (SwiGLU/GeGLU/ReGLU), especially for training. | Not supported (CUDA-only). |
|
||||
|
||||
The `"batched_mm"` and `"grouped_mm"` backends also run FP8 and FP4 (`int8`-packed) quantized experts through the Triton finegrained-fp8 kernel, reading either `float32` or UE8M0 scales. They act as the fallback for quantized checkpoints when the `"deepgemm"` backend is unavailable.
|
||||
|
||||
## Decode-stage switching
|
||||
|
||||
On GPU, a model loaded with `experts_implementation="grouped_mm"` automatically switches to `"batched_mm"` for the decode stage of generation, which is significantly faster on lower token counts. The original backend is restored once generation finishes. On CPU, `grouped_mm` stays active throughout generation because it's more efficient at every input size.
|
||||
|
||||
The switch reaches MoE layers in the top-level model and in any sub-config backbone, such as the `text_config` of a vision-language model. Only `grouped_mm` entries switch to `batched_mm`. Experts running any other backend keep it.
|
||||
|
||||
## Set an experts backend
|
||||
|
||||
Use the `experts_implementation` argument in [`~PreTrainedModel.from_pretrained`] to instantiate a model with a specific experts backend.
|
||||
|
||||
```py
|
||||
from transformers import AutoModelForCausalLM
|
||||
|
||||
model = AutoModelForCausalLM.from_pretrained(
|
||||
"Qwen/Qwen1.5-MoE-A2.7B",
|
||||
dtype="bfloat16",
|
||||
experts_implementation="batched_mm",
|
||||
)
|
||||
```
|
||||
|
||||
Switch between experts backends at runtime without reloading the model using [`~PreTrainedModel.set_experts_implementation`].
|
||||
|
||||
```py
|
||||
model.set_experts_implementation("eager")
|
||||
```
|
||||
|
||||
Read the backend that's currently running with [`~PreTrainedModel.get_experts_implementation`]. It returns a `dict` with one entry for the model, and one entry per sub-config.
|
||||
|
||||
```py
|
||||
model.get_experts_implementation()
|
||||
# {"": "grouped_mm", "text_config": "grouped_mm", "vision_config": "eager"}
|
||||
```
|
||||
|
||||
## Backbone-specific experts backend
|
||||
|
||||
Multimodal models can have multiple sub-configs (for example, different backbones). You can set a different experts backend per sub-config by passing a `dict` to `experts_implementation` at load time.
|
||||
|
||||
Keys in the mapping must match sub-config names.
|
||||
|
||||
```py
|
||||
from transformers import AutoModelForImageTextToText
|
||||
|
||||
experts_implementation_per_backbone = {
|
||||
"text_config": "grouped_mm",
|
||||
"vision_config": "eager",
|
||||
}
|
||||
|
||||
model = AutoModelForImageTextToText.from_pretrained(
|
||||
"Qwen/Qwen3-VL-Moe",
|
||||
experts_implementation=experts_implementation_per_backbone,
|
||||
)
|
||||
```
|
||||
|
||||
Set the experts backend globally with an empty key.
|
||||
|
||||
```py
|
||||
model = AutoModelForCausalLM.from_pretrained(
|
||||
"Qwen/Qwen1.5-MoE-A2.7B",
|
||||
experts_implementation={"": "batched_mm"},
|
||||
)
|
||||
```
|
||||
|
||||
## DeepGEMM
|
||||
|
||||
The `"deepgemm"` backend routes expert matmuls through the [DeepGEMM](https://github.com/deepseek-ai/DeepGEMM) kernels distributed by [kernels-community/deep-gemm](https://huggingface.co/kernels-community/deep-gemm). It works with unquantized `bfloat16` experts and with FP8/FP4-quantized experts loaded through [Fine-grained FP8](./quantization/finegrained_fp8).
|
||||
|
||||
The `"deepgemm"` backend requires:
|
||||
|
||||
- CUDA GPU with compute capability ≥ 9.0 (Hopper or newer).
|
||||
- CUDA runtime 12.3 or later on Hopper, 12.9 or later on Blackwell.
|
||||
- `nvcc`/`nvrtc` available on the system for the kernel's JIT compilation.
|
||||
- The [kernels](https://github.com/huggingface/kernels) package.
|
||||
|
||||
```py
|
||||
from transformers import AutoModelForCausalLM
|
||||
|
||||
model = AutoModelForCausalLM.from_pretrained(
|
||||
"deepseek-ai/DeepSeek-V3",
|
||||
dtype="bfloat16",
|
||||
experts_implementation="deepgemm",
|
||||
)
|
||||
```
|
||||
|
||||
The kernel is loaded lazily on the first forward.
|
||||
|
||||
### FP8 and FP4 quantized experts
|
||||
|
||||
DeepSeek-style checkpoints are usually pre-quantized and carry their own quantization config, so you don't need to pass a [`FineGrainedFP8Config`]. The `"deepgemm"` backend automatically picks the FP8 (or FP4 on Blackwell) grouped-GEMM kernel. DeepGEMM requires dynamic per-row activation scales (`activation_scheme="dynamic"`) and rejects static (per-tensor) activation quantization.
|
||||
|
||||
```py
|
||||
from transformers import AutoModelForCausalLM
|
||||
|
||||
model = AutoModelForCausalLM.from_pretrained(
|
||||
"deepseek-ai/DeepSeek-V3",
|
||||
experts_implementation="deepgemm",
|
||||
)
|
||||
```
|
||||
|
||||
For FP4-packed expert weights (DeepSeek V4-style), the GPU must be SM100+ (Blackwell). The checkpoint config typically sets `expert_dtype="fp4"` and `scale_fmt="ue8m0"`.
|
||||
|
||||
> [!NOTE]
|
||||
> On Blackwell (SM100+), the `"deepgemm"` and `"deepgemm_megamoe"` experts kernels require power-of-two UE8M0 expert scales. A checkpoint quantized with plain `float32` scales (`scale_fmt="float"`) raises a `ValueError` on the first forward instead of silently corrupting the output. Load a checkpoint quantized with `scale_fmt="ue8m0"`, or switch to `grouped_mm` or `batched_mm`, which consume `float32` block scales directly. Hopper (SM90+) consumes `float32` scales on the DeepGEMM path without conversion.
|
||||
|
||||
The main reason to pass a [`FineGrainedFP8Config`] for a pre-quantized checkpoint is to dequantize it back to `bfloat16`, in which case the experts run in `bfloat16` rather than on the FP8/FP4 DeepGEMM path.
|
||||
|
||||
```py
|
||||
from transformers import AutoModelForCausalLM, FineGrainedFP8Config
|
||||
|
||||
model = AutoModelForCausalLM.from_pretrained(
|
||||
"deepseek-ai/DeepSeek-V3",
|
||||
quantization_config=FineGrainedFP8Config(dequantize=True),
|
||||
experts_implementation="deepgemm",
|
||||
)
|
||||
```
|
||||
|
||||
### Fused Mega MoE on Blackwell
|
||||
|
||||
On Blackwell (SM100+), set `experts_implementation="deepgemm_megamoe"` to run a single fused kernel that combines expert-parallel dispatch, the up projection, SwiGLU, the down projection, and the EP combine, overlapping NVLink transfers with tensor-core compute.
|
||||
|
||||
This backend requires:
|
||||
|
||||
- A Blackwell GPU (compute capability ≥ 10.0) with CUDA runtime 12.9 or later.
|
||||
- FP4-packed expert weights paired with UE8M0 weight scales (the pre-quantized checkpoint typically declares `expert_dtype="fp4"` and `scale_fmt="ue8m0"` in its config).
|
||||
- A `torch.distributed` process group for the expert-parallel group, which the tensor-parallel wrapping supplies automatically.
|
||||
|
||||
```py
|
||||
from transformers import AutoModelForCausalLM
|
||||
|
||||
model = AutoModelForCausalLM.from_pretrained(
|
||||
"deepseek-ai/DeepSeek-V4",
|
||||
experts_implementation="deepgemm_megamoe",
|
||||
tp_plan="auto",
|
||||
)
|
||||
```
|
||||
|
||||
## SonicMoE
|
||||
|
||||
The `"sonicmoe"` backend fuses the routed MoE forward (dispatch, gated up projection, activation, down projection) into a set of highly optimized CuteDSL grouped-GEMM kernels, built on the [quack](https://github.com/Dao-AILab/quack) library and distributed by [kernels-community/sonic-moe](https://huggingface.co/kernels-community/sonic-moe).
|
||||
|
||||
The `"sonicmoe"` backend requires:
|
||||
|
||||
- CUDA GPU with compute capability ≥ 9.0 (Hopper or newer).
|
||||
- The [kernels](https://github.com/huggingface/kernels) package and the `nvidia-cutlass-dsl` package.
|
||||
- Experts with a gated activation (`silu`, `gelu`, or `relu`, mapped to SwiGLU/GeGLU/ReGLU).
|
||||
|
||||
```py
|
||||
from transformers import AutoModelForCausalLM
|
||||
|
||||
model = AutoModelForCausalLM.from_pretrained(
|
||||
"Qwen/Qwen1.5-MoE-A2.7B",
|
||||
dtype="bfloat16",
|
||||
experts_implementation="sonicmoe",
|
||||
)
|
||||
```
|
||||
|
||||
If the requirements aren't met, the forward raises `ImportError` and you should pick a different `experts_implementation`.
|
||||
|
||||
## torch.compile
|
||||
|
||||
The `"eager"`, `"batched_mm"`, and `"grouped_mm"` backends are compatible with `torch.compile` to varying degrees. The following table summarizes their compatibility. The `"deepgemm"`, `"deepgemm_megamoe"`, and `"sonicmoe"` backends route through external CUDA kernels and aren't covered by this table.
|
||||
|
||||
|
||||
| Implementation | compilation modes | dtypes | `fullgraph=True` |
|
||||
| ----------------------- | ------------------------------------ | -------------------------------- | ---------------- |
|
||||
| `grouped_mm` | `None`, `max-autotune-no-cudagraphs` | `bfloat16` | Yes |
|
||||
| `grouped_mm` (fallback) | `None`, `max-autotune-no-cudagraphs` | `bfloat16`, `float16`, `float32` | Yes |
|
||||
| `batched_mm` | all | `bfloat16`, `float16`, `float32` | Yes |
|
||||
| `eager` | all | `bfloat16`, `float16`, `float32` | No |
|
||||
|
||||
|
||||
Notes:
|
||||
|
||||
- The `grouped_mm` experts backend currently only supports `bfloat16` when compiled with `torch.compile`. Additionally, it is not compatible with CUDA graphs, so you must use `mode=None` or `mode="max-autotune-no-cudagraphs"` when compiling.
|
||||
- The `eager` experts backend uses a data-dependent operation to find which experts are used in a forward pass. This operation is not compatible with full graph compilation (`fullgraph=True`).
|
||||
|
||||
```py
|
||||
import torch
|
||||
from transformers import AutoModelForCausalLM
|
||||
|
||||
model = AutoModelForCausalLM.from_pretrained(
|
||||
"Qwen/Qwen1.5-MoE-A2.7B",
|
||||
dtype="bfloat16",
|
||||
experts_implementation="grouped_mm",
|
||||
).eval().cuda()
|
||||
|
||||
# Works for grouped_mm (no CUDA graphs)
|
||||
model.forward = torch.compile(model.forward, mode="max-autotune-no-cudagraphs")
|
||||
```
|
||||
|
||||
## Benchmarks
|
||||
|
||||
This [benchmark](https://github.com/user-attachments/files/24125816/bench.py) compares different input sizes and experts implementations with and without `torch.compile`.
|
||||
@@ -0,0 +1,520 @@
|
||||
<!--Copyright 2026 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Exporters
|
||||
|
||||
Export any [`PreTrainedModel`] to ONNX, ExecuTorch, or a standalone PyTorch program — same model,
|
||||
same two lines of code, any runtime.
|
||||
|
||||
```python
|
||||
exporter = DynamoExporter()
|
||||
config = DynamoConfig(dynamic=True) # or OnnxExporter, ExecutorchExporter
|
||||
exported = exporter.export(model, inputs, config=config)
|
||||
```
|
||||
|
||||
Because the exporters live inside Transformers, they evolve with the models. Every architecture
|
||||
change, new attention pattern, or custom cache type is supported at export time from day one —
|
||||
no waiting for a downstream library to catch up.
|
||||
|
||||
<Tip warning={true}>
|
||||
|
||||
The exporters are **experimental**. Many of the patches in this module work around specific
|
||||
upstream bugs (torch, onnxscript, onnxruntime, executorch) and will be removed as soon as the
|
||||
fix lands upstream. Until the API stabilises, treat the patches as tied to the versions used in
|
||||
the test suite — pin those versions in production tooling, and expect both new patches and
|
||||
removals as we follow upstream.
|
||||
|
||||
</Tip>
|
||||
|
||||
| Exporter | Output | Runtime |
|
||||
| ---------------------- | -------------------------- | --------------------------------------------- |
|
||||
| [`DynamoExporter`] | `ExportedProgram` | Any PyTorch runtime, AOT compilation |
|
||||
| [`OnnxExporter`] | `ONNXProgram` | Any ONNX runtime (ORT, TensorRT, OpenVINO, …) |
|
||||
| [`ExecutorchExporter`] | `ExecutorchProgramManager` | Mobile and edge devices (ExecuTorch) |
|
||||
|
||||
[`AutoHfExporter`] picks the right exporter from a config and [`AutoExportConfig`] picks the right
|
||||
config class from a dict — the same auto-class idiom the rest of `transformers` uses, useful when
|
||||
the backend is selected at runtime rather than hard-coded in the call site.
|
||||
|
||||
## Installation
|
||||
|
||||
<hfoptions id="exporters-install">
|
||||
<hfoption id="Dynamo">
|
||||
|
||||
```bash
|
||||
pip install transformers "torch==2.12.0"
|
||||
```
|
||||
|
||||
</hfoption>
|
||||
<hfoption id="ONNX">
|
||||
|
||||
```bash
|
||||
pip install transformers "torch==2.12.0" "onnx==1.21.0" "onnxscript==0.7.0" onnxruntime
|
||||
```
|
||||
|
||||
</hfoption>
|
||||
<hfoption id="ExecuTorch">
|
||||
|
||||
```bash
|
||||
pip install transformers "torch==2.12.0" "executorch==1.3.1"
|
||||
```
|
||||
|
||||
</hfoption>
|
||||
</hfoptions>
|
||||
|
||||
<Tip>
|
||||
The versions above are the ones the exporter test suite is pinned against — newer / older releases
|
||||
often work but the exporter patches target a specific API surface, so for production tooling pin
|
||||
these and expect [`HfExporter`] to log a warning when it detects drift.
|
||||
</Tip>
|
||||
|
||||
## Quick start
|
||||
|
||||
All exporters share the same interface: create an exporter with a config, call `.export(model, inputs)`.
|
||||
Switch between runtimes by swapping the exporter class — nothing else changes.
|
||||
|
||||
<hfoptions id="exporters-quickstart">
|
||||
<hfoption id="Dynamo">
|
||||
|
||||
```python
|
||||
from transformers import AutoModelForCausalLM, AutoTokenizer
|
||||
from transformers.exporters import DynamoExporter, DynamoConfig
|
||||
|
||||
model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen3-0.6B")
|
||||
tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen3-0.6B")
|
||||
inputs = tokenizer("Hello, world!", return_tensors="pt")
|
||||
|
||||
exporter = DynamoExporter()
|
||||
config = DynamoConfig(dynamic=True)
|
||||
exported = exporter.export(model, inputs, config=config)
|
||||
|
||||
# run the exported graph directly
|
||||
outputs = exported.module()(**inputs)
|
||||
```
|
||||
|
||||
</hfoption>
|
||||
<hfoption id="ONNX">
|
||||
|
||||
```python
|
||||
from transformers import AutoModelForCausalLM, AutoTokenizer
|
||||
from transformers.exporters import OnnxExporter, OnnxConfig
|
||||
|
||||
model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen3-0.6B")
|
||||
tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen3-0.6B")
|
||||
inputs = tokenizer("Hello, world!", return_tensors="pt")
|
||||
|
||||
exporter = OnnxExporter()
|
||||
config = OnnxConfig(dynamic=True)
|
||||
onnx_program = exporter.export(model, inputs, config=config)
|
||||
|
||||
# save and load with ONNX Runtime
|
||||
onnx_program.save("model.onnx")
|
||||
|
||||
import onnxruntime as ort
|
||||
|
||||
session = ort.InferenceSession("model.onnx")
|
||||
ort_inputs = {k: v.numpy() for k, v in inputs.items()}
|
||||
outputs = session.run(None, ort_inputs)
|
||||
```
|
||||
|
||||
</hfoption>
|
||||
<hfoption id="ExecuTorch">
|
||||
|
||||
```python
|
||||
from transformers import AutoModelForCausalLM, AutoTokenizer
|
||||
from transformers.exporters import ExecutorchExporter, ExecutorchConfig
|
||||
|
||||
model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen3-0.6B")
|
||||
tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen3-0.6B")
|
||||
inputs = tokenizer("Hello, world!", return_tensors="pt")
|
||||
|
||||
exporter = ExecutorchExporter()
|
||||
config = ExecutorchConfig(backend="xnnpack", dynamic=True)
|
||||
et_program = exporter.export(model, inputs, config=config)
|
||||
|
||||
# save for on-device deployment
|
||||
et_program.save("model.pte")
|
||||
|
||||
# load and run via the ExecuTorch Python runtime
|
||||
from executorch.runtime import Runtime
|
||||
|
||||
program = Runtime.get().load_program("model.pte")
|
||||
method = program.load_method("forward")
|
||||
outputs = method.execute(list(inputs.values()))
|
||||
```
|
||||
|
||||
</hfoption>
|
||||
</hfoptions>
|
||||
|
||||
## Dynamic shapes
|
||||
|
||||
The quick-start examples above already pass `dynamic=True`, which marks every tensor
|
||||
dimension as dynamic so the exported graph accepts inputs of any size at runtime without
|
||||
retracing.
|
||||
|
||||
For fine-grained control over which dimensions are dynamic, pass explicit `dynamic_shapes`
|
||||
instead. This is forwarded directly to `torch.export.export` — see the
|
||||
[torch.export documentation](https://pytorch.org/docs/stable/export.html) for the expected format.
|
||||
|
||||
<hfoptions id="explicit-dynamic-shapes">
|
||||
<hfoption id="Dynamo">
|
||||
|
||||
```python
|
||||
import torch
|
||||
from transformers import AutoModelForCausalLM, AutoTokenizer
|
||||
from transformers.exporters import DynamoExporter, DynamoConfig
|
||||
|
||||
model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen3-0.6B")
|
||||
tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen3-0.6B")
|
||||
inputs = tokenizer(["Hello, world!", "Hi"], padding=True, return_tensors="pt")
|
||||
|
||||
batch = torch.export.Dim("batch", min=1, max=32)
|
||||
seq = torch.export.Dim("seq", min=1, max=2048)
|
||||
|
||||
exporter = DynamoExporter()
|
||||
config = DynamoConfig(
|
||||
dynamic_shapes={"input_ids": {0: batch, 1: seq}, "attention_mask": {0: batch, 1: seq}},
|
||||
# Emit data-dependent shape guards as runtime asserts instead of failing the export when a
|
||||
# guard wouldn't hold across the explicit symbolic range — most LLMs need this under fine-grained
|
||||
# ``Dim(min=, max=)`` bounds. Not needed with ``dynamic=True`` / ``Dim.AUTO``, where torch.export
|
||||
# infers shape relations instead of verifying them against user-stated bounds.
|
||||
prefer_deferred_runtime_asserts_over_guards=True,
|
||||
)
|
||||
exported = exporter.export(model, inputs, config=config)
|
||||
```
|
||||
|
||||
</hfoption>
|
||||
<hfoption id="ONNX">
|
||||
|
||||
```python
|
||||
import torch
|
||||
from transformers import AutoModelForCausalLM, AutoTokenizer
|
||||
from transformers.exporters import OnnxExporter, OnnxConfig
|
||||
|
||||
model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen3-0.6B")
|
||||
tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen3-0.6B")
|
||||
inputs = tokenizer(["Hello, world!", "Hi"], padding=True, return_tensors="pt")
|
||||
|
||||
batch = torch.export.Dim("batch", min=1, max=32)
|
||||
seq = torch.export.Dim("seq", min=1, max=2048)
|
||||
|
||||
exporter = OnnxExporter()
|
||||
config = OnnxConfig(
|
||||
dynamic_shapes={"input_ids": {0: batch, 1: seq}, "attention_mask": {0: batch, 1: seq}},
|
||||
# Emit data-dependent shape guards as runtime asserts instead of failing the export when a
|
||||
# guard wouldn't hold across the explicit symbolic range — most LLMs need this under fine-grained
|
||||
# ``Dim(min=, max=)`` bounds. Not needed with ``dynamic=True`` / ``Dim.AUTO``, where torch.export
|
||||
# infers shape relations instead of verifying them against user-stated bounds.
|
||||
prefer_deferred_runtime_asserts_over_guards=True,
|
||||
)
|
||||
onnx_program = exporter.export(model, inputs, config=config)
|
||||
```
|
||||
|
||||
</hfoption>
|
||||
<hfoption id="ExecuTorch">
|
||||
|
||||
```python
|
||||
import torch
|
||||
from transformers import AutoModelForCausalLM, AutoTokenizer
|
||||
from transformers.exporters import ExecutorchExporter, ExecutorchConfig
|
||||
|
||||
model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen3-0.6B")
|
||||
tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen3-0.6B")
|
||||
inputs = tokenizer(["Hello, world!", "Hi"], padding=True, return_tensors="pt")
|
||||
|
||||
batch = torch.export.Dim("batch", min=1, max=32)
|
||||
seq = torch.export.Dim("seq", min=1, max=2048)
|
||||
|
||||
exporter = ExecutorchExporter()
|
||||
config = ExecutorchConfig(
|
||||
backend="xnnpack",
|
||||
dynamic_shapes={"input_ids": {0: batch, 1: seq}, "attention_mask": {0: batch, 1: seq}},
|
||||
# Emit data-dependent shape guards as runtime asserts instead of failing the export when a
|
||||
# guard wouldn't hold across the explicit symbolic range — most LLMs need this under fine-grained
|
||||
# ``Dim(min=, max=)`` bounds. Not needed with ``dynamic=True`` / ``Dim.AUTO``, where torch.export
|
||||
# infers shape relations instead of verifying them against user-stated bounds.
|
||||
prefer_deferred_runtime_asserts_over_guards=True,
|
||||
)
|
||||
et_program = exporter.export(model, inputs, config=config)
|
||||
```
|
||||
|
||||
</hfoption>
|
||||
</hfoptions>
|
||||
|
||||
## Generative models
|
||||
|
||||
For autoregressive generation, the model's `forward` has different shapes at the prefill step
|
||||
(full prompt, no KV cache) versus the decode step (single token, populated KV cache). Exporters
|
||||
expose [`~HfExporter.export_for_generation`] which splits both stages and exports each.
|
||||
For multi-modal generative models it additionally splits the prefill into vision/audio encoder,
|
||||
projector, language model, and `lm_head`. Encoder and language-model discovery uses the canonical
|
||||
[`~PreTrainedModel.get_encoder`] (`modality="image"` / `"audio"`) and
|
||||
[`~PreTrainedModel.get_decoder`] accessors, so any new architecture that wires those up
|
||||
correctly works out of the box. Projector lookup falls back to a heuristic name list
|
||||
(`multi_modal_projector`, `connector`, `embed_vision`, `embed_audio`); new architectures
|
||||
should align their projector attribute to one of these canonical names rather than growing
|
||||
the list.
|
||||
|
||||
<hfoptions id="generate">
|
||||
<hfoption id="Dynamo">
|
||||
|
||||
```python
|
||||
from transformers import AutoModelForImageTextToText, AutoProcessor
|
||||
from transformers.exporters import DynamoExporter, DynamoConfig
|
||||
|
||||
model = AutoModelForImageTextToText.from_pretrained("Qwen/Qwen2-VL-2B-Instruct")
|
||||
processor = AutoProcessor.from_pretrained("Qwen/Qwen2-VL-2B-Instruct")
|
||||
messages = [{"role": "user", "content": [{"type": "image", "url": "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/pipeline-cat-chonk.jpeg"}, {"type": "text", "text": "Describe this image."}]}]
|
||||
text = processor.apply_chat_template(messages, add_generation_prompt=True, tokenize=False)
|
||||
inputs = processor(text=text, images=messages[0]["content"][0]["url"], return_tensors="pt").to(model.device)
|
||||
|
||||
exporter = DynamoExporter()
|
||||
config = DynamoConfig(dynamic=True)
|
||||
components = exporter.export_for_generation(model, inputs, config=config)
|
||||
# components = {"image_encoder": ExportedProgram, "language_model": ExportedProgram, "lm_head": ExportedProgram, "decode": ExportedProgram}
|
||||
```
|
||||
|
||||
</hfoption>
|
||||
<hfoption id="ONNX">
|
||||
|
||||
```python
|
||||
from transformers import AutoModelForImageTextToText, AutoProcessor
|
||||
from transformers.exporters import OnnxExporter, OnnxConfig
|
||||
|
||||
model = AutoModelForImageTextToText.from_pretrained("Qwen/Qwen2-VL-2B-Instruct")
|
||||
processor = AutoProcessor.from_pretrained("Qwen/Qwen2-VL-2B-Instruct")
|
||||
messages = [{"role": "user", "content": [{"type": "image", "url": "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/pipeline-cat-chonk.jpeg"}, {"type": "text", "text": "Describe this image."}]}]
|
||||
text = processor.apply_chat_template(messages, add_generation_prompt=True, tokenize=False)
|
||||
inputs = processor(text=text, images=messages[0]["content"][0]["url"], return_tensors="pt").to(model.device)
|
||||
|
||||
exporter = OnnxExporter()
|
||||
config = OnnxConfig(dynamic=True)
|
||||
components = exporter.export_for_generation(model, inputs, config=config)
|
||||
# components = {"image_encoder": ONNXProgram, "language_model": ONNXProgram, "lm_head": ONNXProgram, "decode": ONNXProgram}
|
||||
```
|
||||
|
||||
</hfoption>
|
||||
<hfoption id="ExecuTorch">
|
||||
|
||||
```python
|
||||
from transformers import AutoModelForImageTextToText, AutoProcessor
|
||||
from transformers.exporters import ExecutorchExporter, ExecutorchConfig
|
||||
|
||||
model = AutoModelForImageTextToText.from_pretrained("Qwen/Qwen2-VL-2B-Instruct")
|
||||
processor = AutoProcessor.from_pretrained("Qwen/Qwen2-VL-2B-Instruct")
|
||||
messages = [{"role": "user", "content": [{"type": "image", "url": "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/pipeline-cat-chonk.jpeg"}, {"type": "text", "text": "Describe this image."}]}]
|
||||
text = processor.apply_chat_template(messages, add_generation_prompt=True, tokenize=False)
|
||||
inputs = processor(text=text, images=messages[0]["content"][0]["url"], return_tensors="pt").to(model.device)
|
||||
|
||||
exporter = ExecutorchExporter()
|
||||
config = ExecutorchConfig(backend="xnnpack", dynamic=True)
|
||||
components = exporter.export_for_generation(model, inputs, config=config)
|
||||
# components = {"image_encoder": ExecutorchProgramManager, "language_model": ..., "lm_head": ..., "decode": ...}
|
||||
```
|
||||
|
||||
</hfoption>
|
||||
</hfoptions>
|
||||
|
||||
<Tip warning={true}>
|
||||
|
||||
The exported components are **independent graphs**, not a turnkey inference pipeline.
|
||||
The caller is responsible for running each encoder, projecting embeddings, and orchestrating
|
||||
the generation loop. We are actively working to reduce the glue required between components.
|
||||
|
||||
</Tip>
|
||||
|
||||
<details>
|
||||
<summary>What <code>export_for_generation</code> does under the hood</summary>
|
||||
|
||||
[`~exporters.utils.decompose_for_generation`] runs `model.generate(**inputs, max_new_tokens=2)`
|
||||
once and hooks `model.forward` to capture the real prefill and decode kwargs (and the
|
||||
per-submodule kwargs via hooks on each encoder / projector / language model if the model is
|
||||
multi-modal). That's why it works for any architecture — decoder-only, SSM, encoder-decoder,
|
||||
multi-modal — without per-model glue. `export_for_generation` is a one-liner over it.
|
||||
|
||||
The capture runs the model eagerly on `inputs`, so pass **small but representative** values —
|
||||
one short prompt, a single small image, a few audio frames. The exported program isn't tied
|
||||
to those sizes (dynamic shapes still flow through), but smaller capture inputs make
|
||||
`decompose_for_generation` cheaper and keep symbolic-shape inference tractable.
|
||||
|
||||
Call `decompose_for_generation` directly when you want to do something between decomposing
|
||||
and exporting — run an eager forward for verification, swap a submodule's inputs, skip a stage:
|
||||
|
||||
```python
|
||||
from transformers.exporters.utils import decompose_for_generation
|
||||
|
||||
components = decompose_for_generation(model, inputs)
|
||||
# {"image_encoder": (submodel, fwd_kwargs), "language_model": (...), ..., "decode": (...)}
|
||||
|
||||
exported = {}
|
||||
for name, (submodel, subinputs) in components.items():
|
||||
eager_outputs = submodel(**subinputs)
|
||||
exported[name] = exporter.export(submodel,subinputs, config=config)
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
## Limitations and workarounds
|
||||
|
||||
`torch.export`, `torch.onnx.export`, and ExecuTorch each have rough edges around specific
|
||||
PyTorch patterns. The exporters work around these with a small set of reversible patches
|
||||
and FX-level fixes applied at well-defined points in the export flow. None of this is
|
||||
visible from the public `export()` API, but the most common things to know:
|
||||
|
||||
- Flash-attention and flex-attention are not exportable on any backend; `sdpa` is the preferred
|
||||
setting and `eager` also works (slower). Set one of them on the model before calling `export()`
|
||||
if it's using something else.
|
||||
- `grouped_mm` traces fine through `DynamoExporter` and is auto-translated for `OnnxExporter`;
|
||||
for `ExecutorchExporter` with the XNNPACK backend, the exporter swaps MoE experts to
|
||||
`batched_mm` because XNNPACK has no `_grouped_mm.out` kernel.
|
||||
- A short list of models (`EXPORT_SKIP_MODEL_CLASSES`) is skipped from the export sweep when
|
||||
the model itself is fundamentally non-exportable; each entry carries a TODO with the
|
||||
model-side change needed.
|
||||
|
||||
<details>
|
||||
<summary>Export pipeline — internals (per-backend stages and how to extend)</summary>
|
||||
|
||||
Each exporter's source file labels its stages as `# ── Stage N: … ─────` blocks; the
|
||||
tables below mirror that layout 1:1, so the file you read and the doc you read are the
|
||||
same map.
|
||||
|
||||
Two lifecycles are used consistently:
|
||||
|
||||
- **Patches** (registered via `@register_patch(backend, *dotted_paths)`, installed via
|
||||
`apply_patches(backend)`) reversibly swap an attribute (a `torch` op, an ExecuTorch
|
||||
internal, a model class method) for the duration of the export. Pass multiple paths
|
||||
to a single decorator to share the same factory across targets — useful when the
|
||||
same method shape needs to be patched on several classes (e.g. `_update_mamba_mask`
|
||||
on Jamba/Bamba/…). Originals are restored on exit, even if the body raises.
|
||||
- **Fixes** (registered via `@register_fx_node_fix(backend)` /
|
||||
`@register_fx_program_fix(backend)`, applied via `apply_fx_node_fixes(backend, gm)` /
|
||||
`apply_fx_program_fixes(backend, ep)`; ONNX-IR fixes still listed in `_IR_FIXES` and
|
||||
applied via `apply_onnx_ir_fixes`) mutate the in-progress graph or program in place.
|
||||
There's no revert — they're meant to permanently repair the artifact before the next
|
||||
pipeline step.
|
||||
|
||||
Every patch / fix sits in a backend-keyed registry (`_PATCHES`, `_FX_NODE_FIXES`,
|
||||
`_FX_PROGRAM_FIXES` in [exporters/utils.py](https://github.com/huggingface/transformers/blob/main/src/transformers/exporters/utils.py)).
|
||||
Adding a new one is *write a function and decorate it* — nothing else.
|
||||
|
||||
### `DynamoExporter`
|
||||
|
||||
The base exporter has one patch stage and four structural helpers. They run in this order
|
||||
inside `DynamoExporter.export`, against the original `nn.Module`:
|
||||
|
||||
| # | Stage | Section in [exporter_dynamo.py](https://github.com/huggingface/transformers/blob/main/src/transformers/exporters/exporter_dynamo.py) | What it does | How to extend |
|
||||
| ----- | -------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **1** | **Forward-signature patch** (`patch_forward_signature`) | `# ── Stage 1: Model signature patch ──` | Replaces `model.forward` with an explicit flat-arg signature derived from the inputs dict, so `torch.export` doesn't bundle `**kwargs` into a single tuple. This is the entry contract `torch.export` reads before tracing. | Internal — no extension knob. |
|
||||
| **2** | **Model patches** (`_PATCHES["dynamo"]` via `apply_patches("dynamo")`) | `# ── Stage 2: Model patches ──` | Reversible class-attribute swaps applied during tracing. Each `_patch_*(original) → replacement` factory targets one or more `Class.method` paths and replaces a non-exportable model pattern (data-dependent loops, in-place ops, mask checks, chunked-attention `split → zip → cat`) with an export-safe equivalent. | Define `_patch_*(original)` and decorate with `@register_patch("dynamo", *dotted_paths)`. Pass multiple paths to share the same factory across classes (e.g. `_update_mamba_mask` on Jamba/Bamba/…). Examples: mamba/linear-attn mask, NLLB classifier cast, chunked-vision attention. |
|
||||
| **3** | **Pytree registration** (`register_cache_pytrees_for_model`) | `# ── Stage 3: Pytree registration ──` | Registers flatten/unflatten via `torch.utils._pytree.register_pytree_node` for every captured `Cache` / `ModelOutput`. Reflection-driven, tuned for tensor containers (not a general serialiser). | Usually automatic. If a type isn't reflectable, add a branch to `_flatten_to_context` / `_unflatten_from_context`. |
|
||||
| **4** | **Dynamic shapes** (`get_auto_dynamic_shapes`) | `# ── Stage 4: Dynamic shapes ──` | Auto-assigns `Dim.AUTO` to every tensor and cache leaf when `DynamoConfig.dynamic=True` and the user did not pass `dynamic_shapes` explicitly. | Override per-export via `DynamoConfig.dynamic_shapes`. |
|
||||
| **5** | **State cleanup** (`reset_model_state` / `_STATEFUL_CACHE_ATTRS`) | `# ── Stage 5: Model state cleanup ──` | Resets non-`Cache` tensor attributes set inside `forward` (e.g. glm_moe_dsa `_cached_keys`, wav2vec2_bert `cached_rotary_positional_embedding`) that `torch.export` leaves as FakeTensors, so a follow-up eager forward is safe. | Append the attribute name to `_STATEFUL_CACHE_ATTRS`. |
|
||||
|
||||
### `OnnxExporter`
|
||||
|
||||
`OnnxExporter` extends `DynamoExporter` with five numbered stages applied around
|
||||
`torch.onnx.export`. The labels match the `# ── Stage N: … ──` headers in the source:
|
||||
|
||||
| # | Stage | Section in [exporter_onnx.py](https://github.com/huggingface/transformers/blob/main/src/transformers/exporters/exporter_onnx.py) | When it runs | Lifecycle | What it does | How to extend |
|
||||
| ----- | ----------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------ | ------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- |
|
||||
| **1** | **Torch patches** (`_PATCHES["onnx"]`) | `# ── Stage 1: Torch patches ──` | During `torch.export` / `torch.onnx.export` | Reversible (`apply_patches("onnx")`) | Reversible swaps of `torch` ops (`where`, `unsqueeze`, `scaled_dot_product_attention`, `searchsorted`, …) that the ONNX decomposer can't lower as-is. Each `_patch_*(original)` closes over the original. | Define `_patch_*(original)` and decorate with `@register_patch("onnx", "dotted.path")`. |
|
||||
| **2** | **ONNX patches** (`_PATCHES["onnx"]`) | `# ── Stage 2: ONNX patches ──` | During `torch.onnx.export` | Reversible (`apply_patches("onnx")`) | Hooks the private `_prepare_exported_program_for_export` step so the FX node fixes (stage 3) run again right after `run_decompositions` — any new symbolic-guard nodes the ONNX decomposition introduces get repaired before the FX → ONNX lowering picks them up. | Same registry as stage 1 — define `_patch_*(original)` and decorate with `@register_patch("onnx", "dotted.path")`. |
|
||||
| **3** | **FX node fixes** (`_FX_NODE_FIXES["onnx"]`) | `# ── Stage 3: FX node fixes ──` | After `torch.export`, again after `run_decompositions` | In-place (`apply_fx_node_fixes("onnx", gm)`) | Per-node rewrites on the `GraphModule` to drop or replace nodes the ONNX decomposer can't lower (alias ops, in-place views, `_assert_*`, dead comparisons, in-place `triu_`, `fill_diagonal_`, `sort(stable=True)`). DCE runs automatically at the end of the walk. | Define `_fix_*(gm, node) → bool` (return `True` to consume) and decorate with `@register_fx_node_fix("onnx")`. |
|
||||
| **4** | **ONNX translations** (`_ONNX_TRANSLATION_TABLE`) | `# ── Stage 4: ONNX translations ──` | During FX → ONNX lowering | n/a (translation table) | Overrides `torchlib`'s default lowering for specific aten ops where the default is buggy or missing. Currently `aten.index_put` (bool-mask path), `aten.bincount` (`OneHot + ReduceSum`), and `aten._grouped_mm` / `transformers.grouped_mm_fallback` (MoE grouped-matmul → unrolled `Slice + MatMul + Concat`). | Implement an `_aten_*` onnxscript function and add it to `_ONNX_TRANSLATION_TABLE`. |
|
||||
| **5** | **ONNX IR fixes** (`_IR_FIXES` / `apply_onnx_ir_fixes`) | `# ── Stage 5: ONNX IR fixes ──` | After `torch.onnx.export` returns | In-place (`apply_onnx_ir_fixes`) | Post-export rewrites on the `ONNXProgram` IR to work around ORT validation/runtime bugs (e.g. forcing `TopK(sorted=True)`). Applied to both the top-level graph and every function. | Implement `_fix_ir_*(graph_like)` and append to `_IR_FIXES`. |
|
||||
|
||||
A complete inventory of patches in the file is one grep away:
|
||||
|
||||
```bash
|
||||
grep -nE "^def (_patch_|_fix_|_aten_)" src/transformers/exporters/exporter_onnx.py
|
||||
```
|
||||
|
||||
### `ExecutorchExporter`
|
||||
|
||||
`ExecutorchExporter` extends `DynamoExporter` with four numbered stages applied around
|
||||
`to_edge_transform_and_lower` and `to_executorch`:
|
||||
|
||||
| # | Stage | Section in [exporter_executorch.py](https://github.com/huggingface/transformers/blob/main/src/transformers/exporters/exporter_executorch.py) | When it runs | Lifecycle | What it does | How to extend |
|
||||
| ----- | ------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------- | ------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **1** | **Backend preparation** (`_BACKEND_PREPARE`) | `# ── Stage 1: Backend preparation ──` | Before `torch.export` | n/a (one-shot) | `prepare_for_xnnpack` moves the model to CPU/fp32 and selects `XnnpackPartitioner`; `prepare_for_cuda` moves to CUDA/bf16 and selects `CudaPartitioner`. Returns `(model, sample_inputs, partitioner)`. | Implement `prepare_for_<name>` and register it in `_BACKEND_PREPARE`. |
|
||||
| **2** | **Torch patches** (`_PATCHES["executorch"]`) | `# ── Stage 2: Torch patches ──` | During `torch.export` tracing | Reversible (`apply_patches("executorch")`) | Replaces `torch` ops the ExecuTorch backends can't accept (`split_copy`, `chunk`, `topk(k>dim)`, non-divisible `avg_pool2d`, `dropout`, in-place `view`, GQA-shaped SDPA) with decomposed equivalents. | Define `_patch_*(original)` and decorate with `@register_patch("executorch", "dotted.path")`. |
|
||||
| **3** | **ExecuTorch patches** (`_PATCHES["executorch"]`) | `# ── Stage 3: ExecuTorch patches ──` | During `to_edge_transform_and_lower` / `to_executorch` | Reversible (`apply_patches("executorch")`) | Reversibly swaps ExecuTorch internals that crash on legitimate dynamic-shape patterns: `SpecPropPass.update_placeholder_tensor_specs`, `PruneEmptyTensorsPass.remove_empty_tensors_from_cat`, `eval_upper_bound`, `dim_order_from_stride` (rebound on every importer), XNNPACK squeeze/unsqueeze define-node, complex-dtype validator, edge-dialect sym-op allowlist. | Same registry as stage 2 — define `_patch_*(original)` and decorate with `@register_patch("executorch", "dotted.path")`. |
|
||||
| **4** | **FX program fixes** (`_FX_PROGRAM_FIXES["executorch"]`) | `# ── Stage 4: FX program fixes ──` | After `torch.export`, before `to_edge_transform_and_lower` | In-place (`apply_fx_program_fixes("executorch", ep)`) | Repair the `ExportedProgram` where the fix needs program-level context: widen `int_oo` upper bounds in `range_constraints`, fill missing placeholder `meta["val"]` from `state_dict`. | Define `_fix_*(exported_program) → None` and decorate with `@register_fx_program_fix("executorch")`. |
|
||||
| **5** | **FX node fixes** (`_FX_NODE_FIXES["executorch"]`) | `# ── Stage 5: FX node fixes ──` | After stage 4, before `to_edge_transform_and_lower` | In-place (`apply_fx_node_fixes("executorch", gm)`) | Per-node rewrites: swap Python sym ops for `executorch_prim.*` equivalents, rewrite `pow` as `mul` chain, normalize amax/max negative dim, force contiguous clone. DCE runs automatically at the end of the walk. | Define `_fix_*(gm, node) → bool` (return `True` to consume) and decorate with `@register_fx_node_fix("executorch")`. |
|
||||
|
||||
### When to patch the exporter vs. fix the model
|
||||
|
||||
The split is intentional:
|
||||
|
||||
- **Modeling change** if the pattern blocks export across multiple backends — data-dependent
|
||||
loops, stateful caches outside `Cache`, hand-written split-loop attention. Fix it once in
|
||||
the model and every exporter benefits.
|
||||
- **Exporter patch** if the issue is a single backend's lowering bug — a missing ONNX
|
||||
translation, an ORT validation quirk, an FX decomposition that emits a dead op. Keep the
|
||||
workaround in the exporter and the modeling code stays clean.
|
||||
|
||||
### Known upstream workarounds
|
||||
|
||||
A small number of model classes hit confirmed bugs in `onnxscript`'s graph optimizer
|
||||
(constant folding crashing on `SplitToSequence`, FPN initialisers being dropped). For those,
|
||||
ONNX optimisation is selectively disabled via
|
||||
[`ONNX_DISABLE_OPTIMIZE_MODEL_CLASSES`](https://github.com/huggingface/transformers/blob/main/tests/exporters/test_utils.py)
|
||||
in the test suite — each entry is annotated with the upstream issue it works around. This
|
||||
list is **expected to shrink** as upstream bugs land; it is not an extension point for
|
||||
arbitrary skipping, and new entries should reference a specific upstream bug.
|
||||
|
||||
A second list, [`EXPORT_SKIP_MODEL_CLASSES`](https://github.com/huggingface/transformers/blob/main/tests/exporters/test_utils.py),
|
||||
opts a handful of model classes out of the entire export sweep when the model itself is
|
||||
fundamentally non-exportable as-is (data-dependent control flow that can't be vectorised,
|
||||
modules treated as forward arguments, …). Same expectations: every entry carries a TODO
|
||||
naming the underlying model change needed; the list should shrink, not grow.
|
||||
|
||||
</details>
|
||||
|
||||
## API reference
|
||||
|
||||
### Exporter classes
|
||||
|
||||
[[autodoc]] transformers.exporters.exporter_dynamo.DynamoExporter
|
||||
- export
|
||||
|
||||
[[autodoc]] transformers.exporters.exporter_onnx.OnnxExporter
|
||||
- export
|
||||
|
||||
[[autodoc]] transformers.exporters.exporter_executorch.ExecutorchExporter
|
||||
- export
|
||||
|
||||
### Configuration
|
||||
|
||||
[[autodoc]] transformers.exporters.configs.DynamoConfig
|
||||
|
||||
[[autodoc]] transformers.exporters.configs.OnnxConfig
|
||||
|
||||
[[autodoc]] transformers.exporters.configs.ExecutorchConfig
|
||||
|
||||
### Utilities
|
||||
|
||||
[[autodoc]] transformers.exporters.utils.get_leaf_tensors
|
||||
|
||||
[[autodoc]] transformers.exporters.utils.prepare_for_export
|
||||
|
||||
[[autodoc]] transformers.exporters.utils.decompose_prefill_decode
|
||||
|
||||
[[autodoc]] transformers.exporters.utils.decompose_multimodal
|
||||
|
||||
[[autodoc]] transformers.exporters.utils.decompose_for_generation
|
||||
|
||||
[[autodoc]] transformers.exporters.utils.is_multimodal
|
||||
@@ -0,0 +1,287 @@
|
||||
<!--Copyright 2026 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Tokenizers
|
||||
|
||||
A tokenizer converts text into tensors, which are the inputs to a model. It normalizes and splits text, applies the tokenization algorithm, adds special tokens, and decodes output ids back into text.
|
||||
|
||||
```py
|
||||
from transformers import AutoTokenizer
|
||||
|
||||
tokenizer = AutoTokenizer.from_pretrained("google/gemma-2-2b")
|
||||
tokenizer("Sphinx of black quartz, judge my vow.", return_tensors="pt")
|
||||
{
|
||||
'input_ids': tensor([[ 2, 235277, 82913, 576, 2656, 30407, 235269, 11490, 970, 29871, 235265]]),
|
||||
'attention_mask': tensor([[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]])
|
||||
}
|
||||
```
|
||||
|
||||
This guide covers loading, encoding, decoding, batch processing, and the available tokenizer backends.
|
||||
|
||||
## Load a tokenizer
|
||||
|
||||
Load a tokenizer with the [`AutoTokenizer`] class or a model-specific tokenizer class.
|
||||
|
||||
<hfoptions id="tokenizers">
|
||||
<hfoption id="AutoTokenizer">
|
||||
|
||||
[`AutoTokenizer.from_pretrained`] reads the model config, resolves the correct tokenizer class, and returns an instance of it. You don't need to know the tokenizer class beforehand. Most tokenizers resolve to a subclass of [`TokenizersBackend`], a fast Rust-based tokenizer from the [Tokenizers](https://huggingface.co/docs/tokenizers/index) library.
|
||||
|
||||
Loading with [`AutoTokenizer`] is the recommended approach.
|
||||
|
||||
```py
|
||||
from transformers import AutoTokenizer
|
||||
|
||||
tokenizer = AutoTokenizer.from_pretrained("google/gemma-2-2b")
|
||||
```
|
||||
|
||||
</hfoption>
|
||||
<hfoption id="model-specific tokenizer">
|
||||
|
||||
A model-specific tokenization class is a pre-configured [`TokenizersBackend`] that uses the exact tokenization configuration (normalizer, pre-tokenizer, special token conventions, etc.) a model was trained with.
|
||||
|
||||
Use a model-specific class to initialize an empty tokenizer for training or to pass model-specific arguments like `vocab` or `merges` (see the [Customizing tokenizers](./custom_tokenizers) guide to learn how). An empty tokenizer is minimal and only contains a model's special tokens like `<pad>`, `<eos>`, or `<bos>`.
|
||||
|
||||
```py
|
||||
from transformers import GemmaTokenizer
|
||||
|
||||
tokenizer = GemmaTokenizer()
|
||||
corpus = [
|
||||
["Sphinx of black quartz, judge my vow."],
|
||||
["Pack my box with five dozen liquor jugs."],
|
||||
["How vexingly quick daft zebras jump!"],
|
||||
]
|
||||
new_tokenizer = tokenizer.train_new_from_iterator(corpus, vocab_size=1000)
|
||||
```
|
||||
|
||||
</hfoption>
|
||||
</hfoptions>
|
||||
|
||||
## Encode and decode
|
||||
|
||||
The [`TokenizersBackend.__call__`] method encodes text or a batch of text into `input_ids`, `attention_mask`, and other model inputs. It also controls padding, truncation, and special token insertion.
|
||||
|
||||
```py
|
||||
from transformers import AutoTokenizer
|
||||
|
||||
tokenizer = AutoTokenizer.from_pretrained("google/gemma-2-2b")
|
||||
tokenizer("Sphinx of black quartz, judge my vow.", return_tensors="pt")
|
||||
{
|
||||
'input_ids': tensor([[ 2, 235277, 82913, 576, 2656, 30407, 235269, 11490, 970, 29871, 235265]]),
|
||||
'attention_mask': tensor([[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]])
|
||||
}
|
||||
```
|
||||
|
||||
[`TokenizersBackend.encode`] is similar but only returns the `input_ids`.
|
||||
|
||||
```py
|
||||
from transformers import AutoTokenizer
|
||||
|
||||
tokenizer = AutoTokenizer.from_pretrained("google/gemma-2-2b")
|
||||
tokenizer.encode("Sphinx of black quartz, judge my vow.")
|
||||
[2, 235277, 82913, 576, 2656, 30407, 235269, 11490, 970, 29871, 235265]
|
||||
```
|
||||
|
||||
[`TokenizersBackend.decode`] converts a single sequence or batch of tokenized `input_ids` back to text.
|
||||
|
||||
```py
|
||||
tokenizer.decode(outputs["input_ids"])
|
||||
['<bos>Sphinx of black quartz, judge my vow.']
|
||||
```
|
||||
|
||||
[`TokenizersBackend.decode`] preserves the exact tokenization spacing. Set `clean_up_tokenization_spaces` to remove spaces before punctuation, and `skip_special_tokens` to strip special tokens from the output.
|
||||
|
||||
```py
|
||||
tokenizer.decode(outputs["input_ids"], skip_special_tokens=True)
|
||||
['Sphinx of black quartz, judge my vow.']
|
||||
```
|
||||
|
||||
## Special tokens
|
||||
|
||||
Special tokens mark structural boundaries in a sequence, like the beginning-of-sequence or padding positions. Each model defines its own set of special tokens. The tokenizer adds them when you call it.
|
||||
|
||||
```py
|
||||
tokenizer.encode("Sphinx of black quartz, judge my vow.")
|
||||
[2, 235277, 82913, 576, 2656, 30407, 235269, 11490, 970, 29871, 235265]
|
||||
tokenizer.decode(outputs["input_ids"])
|
||||
['<bos>Sphinx of black quartz, judge my vow.']
|
||||
```
|
||||
|
||||
Register additional named special tokens with the `extra_special_tokens` argument. Multimodal models use them as placeholders for images, video, or audio.
|
||||
|
||||
```py
|
||||
from transformers import AutoTokenizer
|
||||
|
||||
tokenizer = AutoTokenizer.from_pretrained(
|
||||
"google/gemma-3-4b-pt",
|
||||
extra_special_tokens={"image_token": "<image>"}
|
||||
)
|
||||
```
|
||||
|
||||
## Batch processing
|
||||
|
||||
Batch processing tokenizes multiple sequences in a single call. [`TokenizersBackend`] handles large batches faster because its Rust-based backend parallelizes work across threads.
|
||||
|
||||
```py
|
||||
from transformers import AutoTokenizer
|
||||
|
||||
tokenizer = AutoTokenizer.from_pretrained("google/gemma-2-2b")
|
||||
tokenizer(
|
||||
[
|
||||
"Sphinx of black quartz, judge my vow.",
|
||||
"Pack my box with five dozen liquor jugs.",
|
||||
"How vexingly quick daft zebras jump!"
|
||||
],
|
||||
return_tensors="pt"
|
||||
)
|
||||
```
|
||||
|
||||
Batch processing requires all sequences to share the same length. Padding and truncation are strategies to handle varying-length sequences.
|
||||
|
||||
### Padding
|
||||
|
||||
Padding appends special tokens so shorter sequences match the longest sequence in a batch. The attention mask marks padding positions as `0` so the model ignores them. Set `padding=True` to pad to the longest sequence or pass `max_length` to pad to a fixed size.
|
||||
|
||||
```py
|
||||
from transformers import AutoTokenizer
|
||||
|
||||
tokenizer = AutoTokenizer.from_pretrained("google/gemma-2-2b")
|
||||
tokenizer(
|
||||
[
|
||||
"Sphinx of black quartz, judge my vow.",
|
||||
"Pack my box with five dozen liquor jugs.",
|
||||
"How vexingly quick daft zebras jump!"
|
||||
],
|
||||
return_tensors="pt",
|
||||
padding=True,
|
||||
)
|
||||
{
|
||||
'input_ids': tensor([
|
||||
[ 2, 235277, 82913, 576, 2656, 30407, 235269, 11490, 970, 29871, 235265],
|
||||
[ 0, 2, 6519, 970, 3741, 675, 4105, 25955, 42184, 225789, 235265],
|
||||
[ 0, 2, 2299, 73378, 17844, 4320, 224463, 4949, 48977, 9902, 235341]
|
||||
]),
|
||||
'attention_mask': tensor([
|
||||
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
|
||||
[0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
|
||||
[0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
|
||||
])
|
||||
}
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> Large language models pad on the *left* side to avoid disrupting generation, which predicts the next token from the *right* side.
|
||||
|
||||
### Truncation
|
||||
|
||||
Truncation clips tokens so a sequence fits within a maximum length. Set `truncation=True` and specify `max_length` to enable it.
|
||||
|
||||
Padding and truncation work together. Short sequences gain padding tokens while long sequences lose trailing tokens. Together, they produce a packed rectangular tensor.
|
||||
|
||||
```py
|
||||
from transformers import AutoTokenizer
|
||||
|
||||
tokenizer = AutoTokenizer.from_pretrained("google/gemma-2-2b")
|
||||
tokenizer(
|
||||
[
|
||||
"Sphinx of black quartz, judge my vow.",
|
||||
"Pack my box with five dozen liquor jugs.",
|
||||
"How vexingly quick daft zebras jump!"
|
||||
],
|
||||
return_tensors="pt",
|
||||
padding=True,
|
||||
truncation=True,
|
||||
max_length=5
|
||||
)
|
||||
{
|
||||
'input_ids': tensor([
|
||||
[ 2, 235277, 82913, 576, 2656],
|
||||
[ 2, 6519, 970, 3741, 675],
|
||||
[ 2, 2299, 73378, 17844, 4320]
|
||||
]),
|
||||
'attention_mask': tensor([
|
||||
[1, 1, 1, 1, 1],
|
||||
[1, 1, 1, 1, 1],
|
||||
[1, 1, 1, 1, 1]
|
||||
])
|
||||
}
|
||||
```
|
||||
|
||||
## Backends
|
||||
|
||||
Each model tokenizer is defined in a single file and supports four tokenization backends.
|
||||
|
||||
| backend | implementation | description |
|
||||
|---|---|---|
|
||||
| [`TokenizersBackend`] | [Tokenizers](https://huggingface.co/docs/tokenizers) | default for most models |
|
||||
| [`SentencePieceBackend`] | [SentencePiece](https://github.com/google/sentencepiece) | models requiring SentencePiece |
|
||||
| [`PythonBackend`] | Python | models requiring specialized custom tokenizers |
|
||||
| [`MistralCommonBackend`] | [mistral-common](https://mistralai.github.io/mistral-common/) | Mistral and Pixtral models |
|
||||
|
||||
All backends inherit from [`PreTrainedTokenizerBase`] and share the same APIs for encoding, decoding, padding, truncation, saving, and loading. The difference is which tokenization pipeline runs underneath.
|
||||
|
||||
[`AutoTokenizer`] selects the best available backend when you call [`~AutoTokenizer.from_pretrained`].
|
||||
|
||||
1. It reads the `tokenizer_config.json` file for the `tokenizer_class` field.
|
||||
2. The registry matches `tokenizer_class` to a class name. The resolved class inherits from one of the four backends. For example, [`GemmaTokenizer`] inherits from [`TokenizersBackend`], and [`SiglipTokenizer`] inherits from [`SentencePieceBackend`].
|
||||
|
||||
Some models, like GLM, map directly to [`TokenizersBackend`] because the `tokenizer.json` file fully describes the pipeline. [`GemmaTokenizer`] exists as a subclass since it defines additional model-specific settings in Python that `tokenizer.json` doesn't capture.
|
||||
|
||||
```py
|
||||
TOKENIZER_MAPPING_NAMES = OrderedDict([
|
||||
("gemma2", "GemmaTokenizer" if is_tokenizers_available() else None),
|
||||
("glm", "TokenizersBackend" if is_tokenizers_available() else None),
|
||||
(
|
||||
"mistral",
|
||||
"MistralCommonBackend"
|
||||
if is_mistral_common_available()
|
||||
else ("TokenizersBackend" if is_tokenizers_available() else None),
|
||||
),
|
||||
("siglip", "SiglipTokenizer" if is_sentencepiece_available() else None),
|
||||
...
|
||||
]
|
||||
```
|
||||
|
||||
When a backend like mistral-common isn't installed, [`AutoTokenizer`] falls back to [`TokenizersBackend`].
|
||||
|
||||
Check which backend a tokenizer is using with the `backend` property.
|
||||
|
||||
```py
|
||||
from transformers import AutoTokenizer
|
||||
|
||||
tokenizer = AutoTokenizer.from_pretrained("google/gemma-2-2b")
|
||||
tokenizer.backend
|
||||
'tokenizers'
|
||||
```
|
||||
|
||||
## Inspect the tokenizer architecture
|
||||
|
||||
Inspect a tokenizer's internal components (normalizer, pre-tokenizer, model, decoder) with the `_tokenizer` attribute.
|
||||
|
||||
```py
|
||||
from transformers import AutoTokenizer
|
||||
|
||||
tokenizer = AutoTokenizer.from_pretrained("google/gemma-2-2b")
|
||||
print(tokenizer._tokenizer.normalizer)
|
||||
print(tokenizer._tokenizer.pre_tokenizer)
|
||||
print(tokenizer._tokenizer.model)
|
||||
print(tokenizer._tokenizer.decoder)
|
||||
```
|
||||
|
||||
## Resources
|
||||
|
||||
- The [Tokenization in Transformers v5](https://huggingface.co/blog/tokenizers) post discusses the motivation behind the new tokenization backends.
|
||||
- Review the [migration guide](https://github.com/huggingface/transformers/blob/main/MIGRATION_GUIDE_V5.md#tokenization) for an overview of the tokenization changes.
|
||||
@@ -0,0 +1,200 @@
|
||||
<!--Copyright 2024 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Feature extractors
|
||||
|
||||
Feature extractors preprocess audio data into the correct format for a given model. It takes the raw audio signal and converts it into a tensor that can be fed to a model. The tensor shape depends on the model, but the feature extractor will correctly preprocess the audio data for you given the model you're using. Feature extractors also include methods for padding, truncation, and resampling.
|
||||
|
||||
Call [`~AutoFeatureExtractor.from_pretrained`] to load a feature extractor and its preprocessor configuration from the Hugging Face [Hub](https://hf.co/models) or local directory. The feature extractor and preprocessor configuration is saved in a [preprocessor_config.json](https://hf.co/openai/whisper-tiny/blob/main/preprocessor_config.json) file.
|
||||
|
||||
Pass the audio signal, typically stored in `array`, to the feature extractor and set the `sampling_rate` parameter to the pretrained audio models sampling rate. It is important the sampling rate of the audio data matches the sampling rate of the data a pretrained audio model was trained on.
|
||||
|
||||
```py
|
||||
from transformers import AutoFeatureExtractor
|
||||
|
||||
feature_extractor = AutoFeatureExtractor.from_pretrained("facebook/wav2vec2-base")
|
||||
dataset = load_dataset("PolyAI/minds14", name="en-US", split="train")
|
||||
processed_sample = feature_extractor(dataset[0]["audio"]["array"], sampling_rate=16000)
|
||||
processed_sample
|
||||
{'input_values': [array([ 9.4472744e-05, 3.0777880e-03, -2.8888427e-03, ...,
|
||||
-2.8888427e-03, 9.4472744e-05, 9.4472744e-05], dtype=float32)]}
|
||||
```
|
||||
|
||||
The feature extractor returns an input, `input_values`, that is ready for the model to consume.
|
||||
|
||||
This guide walks you through the feature extractor classes and how to preprocess audio data.
|
||||
|
||||
## Feature extractor classes
|
||||
|
||||
Transformers feature extractors inherit from the base [`SequenceFeatureExtractor`] class which subclasses [`FeatureExtractionMixin`].
|
||||
|
||||
- [`SequenceFeatureExtractor`] provides a method to [`~SequenceFeatureExtractor.pad`] sequences to a certain length to avoid uneven sequence lengths.
|
||||
- [`FeatureExtractionMixin`] provides [`~FeatureExtractionMixin.from_pretrained`] and [`~FeatureExtractionMixin.save_pretrained`] to load and save a feature extractor.
|
||||
|
||||
There are two ways you can load a feature extractor, [`AutoFeatureExtractor`] and a model-specific feature extractor class.
|
||||
|
||||
<hfoptions id="feature-extractor-classes">
|
||||
<hfoption id="AutoFeatureExtractor">
|
||||
|
||||
The [AutoClass](./model_doc/auto) API automatically loads the correct feature extractor for a given model.
|
||||
|
||||
Use [`~AutoFeatureExtractor.from_pretrained`] to load a feature extractor.
|
||||
|
||||
```py
|
||||
from transformers import AutoFeatureExtractor
|
||||
|
||||
feature_extractor = AutoFeatureExtractor.from_pretrained("openai/whisper-tiny")
|
||||
```
|
||||
|
||||
</hfoption>
|
||||
<hfoption id="model-specific feature extractor">
|
||||
|
||||
Every pretrained audio model has a specific associated feature extractor for correctly processing audio data. When you load a feature extractor, it retrieves the feature extractors configuration (feature size, chunk length, etc.) from [preprocessor_config.json](https://hf.co/openai/whisper-tiny/blob/main/preprocessor_config.json).
|
||||
|
||||
A feature extractor can be loaded directly from its model-specific class.
|
||||
|
||||
```py
|
||||
from transformers import WhisperFeatureExtractor
|
||||
|
||||
feature_extractor = WhisperFeatureExtractor.from_pretrained("openai/whisper-tiny")
|
||||
```
|
||||
|
||||
</hfoption>
|
||||
</hfoptions>
|
||||
|
||||
## Preprocess
|
||||
|
||||
A feature extractor expects the input as a PyTorch tensor of a certain shape. The exact input shape can vary depending on the specific audio model you're using.
|
||||
|
||||
For example, [Whisper](https://huggingface.co/docs/transformers/model_doc/whisper) expects `input_features` to be a tensor of shape `(batch_size, feature_size, sequence_length)` but [Wav2Vec2](https://hf.co/docs/transformers/model_doc/wav2vec2) expects `input_values` to be a tensor of shape `(batch_size, sequence_length)`.
|
||||
|
||||
The feature extractor generates the correct input shape for whichever audio model you're using.
|
||||
|
||||
A feature extractor also sets the sampling rate (the number of audio signal values taken per second) of the audio files. The sampling rate of your audio data must match the sampling rate of the dataset a pretrained model was trained on. This value is typically given in the model card.
|
||||
|
||||
Load a dataset and feature extractor with [`~FeatureExtractionMixin.from_pretrained`].
|
||||
|
||||
```py
|
||||
from datasets import load_dataset, Audio
|
||||
from transformers import AutoFeatureExtractor
|
||||
|
||||
dataset = load_dataset("PolyAI/minds14", name="en-US", split="train")
|
||||
feature_extractor = AutoFeatureExtractor.from_pretrained("facebook/wav2vec2-base")
|
||||
```
|
||||
|
||||
Check out the first example from the dataset and access the `audio` column which contains `array`, the raw audio signal.
|
||||
|
||||
```py
|
||||
dataset[0]["audio"]["array"]
|
||||
array([ 0. , 0.00024414, -0.00024414, ..., -0.00024414,
|
||||
0. , 0. ])
|
||||
```
|
||||
|
||||
The feature extractor preprocesses `array` into the expected input format for a given audio model. Use the `sampling_rate` parameter to set the appropriate sampling rate.
|
||||
|
||||
```py
|
||||
processed_dataset = feature_extractor(dataset[0]["audio"]["array"], sampling_rate=16000)
|
||||
processed_dataset
|
||||
{'input_values': [array([ 9.4472744e-05, 3.0777880e-03, -2.8888427e-03, ...,
|
||||
-2.8888427e-03, 9.4472744e-05, 9.4472744e-05], dtype=float32)]}
|
||||
```
|
||||
|
||||
### Padding
|
||||
|
||||
Audio sequence lengths that are different is an issue because Transformers expects all sequences to have the same lengths so they can be batched. Uneven sequence lengths can't be batched.
|
||||
|
||||
```py
|
||||
dataset[0]["audio"]["array"].shape
|
||||
(86699,)
|
||||
|
||||
dataset[1]["audio"]["array"].shape
|
||||
(53248,)
|
||||
```
|
||||
|
||||
Padding adds a special *padding token* to ensure all sequences have the same length. The feature extractor adds a `0` - interpreted as silence - to `array` to pad it. Set `padding=True` to pad sequences to the longest sequence length in the batch.
|
||||
|
||||
```py
|
||||
def preprocess_function(examples):
|
||||
audio_arrays = [x["array"] for x in examples["audio"]]
|
||||
inputs = feature_extractor(
|
||||
audio_arrays,
|
||||
sampling_rate=16000,
|
||||
padding=True,
|
||||
)
|
||||
return inputs
|
||||
|
||||
processed_dataset = preprocess_function(dataset[:5])
|
||||
processed_dataset["input_values"][0].shape
|
||||
(86699,)
|
||||
|
||||
processed_dataset["input_values"][1].shape
|
||||
(86699,)
|
||||
```
|
||||
|
||||
### Truncation
|
||||
|
||||
Models can only process sequences up to a certain length before crashing.
|
||||
|
||||
Truncation is a strategy for removing excess tokens from a sequence to ensure it doesn't exceed the maximum length. Set `truncation=True` to truncate a sequence to the length in the `max_length` parameter.
|
||||
|
||||
```py
|
||||
def preprocess_function(examples):
|
||||
audio_arrays = [x["array"] for x in examples["audio"]]
|
||||
inputs = feature_extractor(
|
||||
audio_arrays,
|
||||
sampling_rate=16000,
|
||||
max_length=50000,
|
||||
truncation=True,
|
||||
)
|
||||
return inputs
|
||||
|
||||
processed_dataset = preprocess_function(dataset[:5])
|
||||
processed_dataset["input_values"][0].shape
|
||||
(50000,)
|
||||
|
||||
processed_dataset["input_values"][1].shape
|
||||
(50000,)
|
||||
```
|
||||
|
||||
### Resampling
|
||||
|
||||
The [Datasets](https://hf.co/docs/datasets/index) library can also resample audio data to match an audio models expected sampling rate. This method resamples the audio data on the fly when they're loaded which can be faster than resampling the entire dataset in-place.
|
||||
|
||||
The audio dataset you've been working on has a sampling rate of 8kHz and the pretrained model expects 16kHz.
|
||||
|
||||
```py
|
||||
dataset[0]["audio"]
|
||||
{'path': '/root/.cache/huggingface/datasets/downloads/extracted/f507fdca7f475d961f5bb7093bcc9d544f16f8cab8608e772a2ed4fbeb4d6f50/en-US~JOINT_ACCOUNT/602ba55abb1e6d0fbce92065.wav',
|
||||
'array': array([ 0. , 0.00024414, -0.00024414, ..., -0.00024414,
|
||||
0. , 0. ]),
|
||||
'sampling_rate': 8000}
|
||||
```
|
||||
|
||||
Call [`~datasets.Dataset.cast_column`] on the `audio` column to upsample the sampling rate to 16kHz.
|
||||
|
||||
```py
|
||||
dataset = dataset.cast_column("audio", Audio(sampling_rate=16000))
|
||||
```
|
||||
|
||||
When you load the dataset sample, it is now resampled to 16kHz.
|
||||
|
||||
```py
|
||||
dataset[0]["audio"]
|
||||
{'path': '/root/.cache/huggingface/datasets/downloads/extracted/f507fdca7f475d961f5bb7093bcc9d544f16f8cab8608e772a2ed4fbeb4d6f50/en-US~JOINT_ACCOUNT/602ba55abb1e6d0fbce92065.wav',
|
||||
'array': array([ 1.70562416e-05, 2.18727451e-04, 2.28099874e-04, ...,
|
||||
3.43842403e-05, -5.96364771e-06, -1.76846661e-05]),
|
||||
'sampling_rate': 16000}
|
||||
```
|
||||
@@ -0,0 +1,129 @@
|
||||
<!--Copyright 2024 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# FSDP2
|
||||
|
||||
[Fully Sharded Data Parallel (FSDP2)](https://docs.pytorch.org/tutorials/intermediate/FSDP_tutorial.html) shards the model, gradients, and optimizer states across GPUs. Before computation, each GPU gathers a complete set of parameters from all shards, then frees them afterward. Sharding lets you train models larger than a single GPU's memory, at the cost of more communication than [DDP](./ddp). Use FSDP when your model or optimizer states don't fit on a single GPU.
|
||||
|
||||
```text
|
||||
┌─────────────────┐
|
||||
│ training data │
|
||||
└────────┬────────┘
|
||||
┌──────────────────┼──────────────────┐
|
||||
│ shard 0 │ shard 1 │ shard 2
|
||||
▼ ▼ ▼
|
||||
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
|
||||
│ param │ │ param │ │ param │
|
||||
│ shard 0 │ │ shard 1 │ │ shard 2 │
|
||||
│ GPU 0 │ │ GPU 1 │ │ GPU 2 │
|
||||
└──────┬──────┘ └──────┬──────┘ └──────┬──────┘
|
||||
│ │ │
|
||||
└──────── all-gather (params) ────────┘
|
||||
│
|
||||
full params on each GPU
|
||||
│
|
||||
┌──────────────────┼──────────────────┐
|
||||
▼ ▼ ▼
|
||||
forward forward forward
|
||||
│ │ │
|
||||
└───── reduce-scatter (grads) ────────┘
|
||||
│
|
||||
┌──────────────────┼──────────────────┐
|
||||
▼ ▼ ▼
|
||||
grad shard 0 grad shard 1 grad shard 2
|
||||
optim shard 0 optim shard 1 optim shard 2
|
||||
step step step
|
||||
```
|
||||
|
||||
## Sharding strategies
|
||||
|
||||
FSDP2 controls sharding with [`~TrainingArguments.fsdp_config`]. Set `fsdp=True` to enable FSDP, and set `reshard_after_forward` in the FSDP config to choose the memory and throughput tradeoff.
|
||||
|
||||
| `reshard_after_forward` | behavior |
|
||||
|---|---|
|
||||
| `true` | reshard parameters after the forward pass to save more memory |
|
||||
| `false` | keep parameters gathered between forward and backward to avoid the re-all-gather, at the cost of higher peak memory |
|
||||
|
||||
`auto_wrap_policy` controls how modules are wrapped into FSDP units. It defaults to `"TRANSFORMER_BASED_WRAP"`, which wraps the model's transformer layers. Without wrapping (`"NO_WRAP"`), the entire model is one FSDP unit and you lose the memory benefit of sharding.
|
||||
|
||||
## Configure FSDP
|
||||
|
||||
These fields control how FSDP2 wraps, shards, and loads the model. `reshard_after_forward` and `auto_wrap_policy` are covered in [Sharding strategies](#sharding-strategies).
|
||||
|
||||
- `cpu_offload` offloads parameters and gradients to CPU when they aren't in use to save GPU memory.
|
||||
|
||||
- `transformer_layer_cls_to_wrap` defines the transformer layer to wrap into an FSDP unit when `auto_wrap_policy` is `"TRANSFORMER_BASED_WRAP"`. Each unit manages its own gather and scatter ops. Only the current unit's parameters are gathered during the forward pass. The previous units' parameters are released to save memory.
|
||||
|
||||
Wrapping only the top-level model yields no GPU memory savings. Wrapping every individual `Linear` layer makes inter-unit communication very expensive. Leave this field empty and FSDP reads the value from the model definition.
|
||||
|
||||
- `min_num_params` sets the minimum number of parameters per module for size-based wrapping. It is only used when `auto_wrap_policy` is `"SIZE_BASED_WRAP"`.
|
||||
|
||||
- `state_dict_type` controls the checkpoint format. Defaults to `"FULL_STATE_DICT"` for a single Transformers-compatible checkpoint. Use `"SHARDED_STATE_DICT"` for one checkpoint file per rank, which is faster for large models. Sharded checkpoints only load back into FSDP, so save a `"FULL_STATE_DICT"` for the final checkpoint you want to share or load outside FSDP.
|
||||
|
||||
- `cpu_ram_efficient_loading` loads the checkpoint from disk on rank 0 only. Other GPUs initialize an empty model and receive the weights by broadcast, avoiding multiple processes loading a large model into CPU RAM.
|
||||
|
||||
- `activation_checkpointing` recomputes activations during the backward pass instead of storing them. Use this instead of [gradient checkpointing](./grad_checkpointing) in [`TrainingArguments`]. Setting both raises an error.
|
||||
|
||||
Configure FSDP training with either an [Accelerate config file](./accelerate#accelerate-config-file) or an FSDP config file passed to `fsdp_config`.
|
||||
|
||||
<hfoptions id="launch">
|
||||
<hfoption id="Accelerate config file">
|
||||
|
||||
Run the [accelerate config](https://huggingface.co/docs/accelerate/en/package_reference/cli#accelerate-config) command and answer questions about your hardware and training setup. This creates a `default_config.yaml` file in your cache.
|
||||
|
||||
Run [accelerate launch](https://huggingface.co/docs/accelerate/en/package_reference/cli#accelerate-launch) with a [`Trainer`]-based script. The `fsdp_config` is unnecessary because the Accelerate config file covers the same settings.
|
||||
|
||||
```cli
|
||||
accelerate launch train.py
|
||||
```
|
||||
|
||||
</hfoption>
|
||||
<hfoption id="FSDP config file">
|
||||
|
||||
```json
|
||||
{
|
||||
"version": 2,
|
||||
"reshard_after_forward": true,
|
||||
"cpu_offload": false,
|
||||
"auto_wrap_policy": "TRANSFORMER_BASED_WRAP",
|
||||
"transformer_layer_cls_to_wrap": ["LlamaDecoderLayer"],
|
||||
"state_dict_type": "FULL_STATE_DICT",
|
||||
"cpu_ram_efficient_loading": true,
|
||||
"activation_checkpointing": true
|
||||
}
|
||||
```
|
||||
|
||||
Set `fsdp=True` and pass the FSDP config file to `fsdp_config`.
|
||||
|
||||
```py
|
||||
from transformers import TrainingArguments
|
||||
|
||||
TrainingArguments(
|
||||
...,
|
||||
fsdp=True,
|
||||
fsdp_config="path/to/fsdp.json",
|
||||
)
|
||||
```
|
||||
|
||||
</hfoption>
|
||||
</hfoptions>
|
||||
|
||||
## Next steps
|
||||
|
||||
- See [DDP](./ddp) for data-parallel training when your model fits on one GPU.
|
||||
- See [DeepSpeed](./deepspeed) for ZeRO optimization and NVMe offloading.
|
||||
- For FSDP on TPUs with PyTorch/XLA, set `xla`, `xla_fsdp_settings`, and `xla_fsdp_grad_ckpt` in [`~TrainingArguments.fsdp_config`].
|
||||
- Read the [FSDP chapter](https://nanotron-ultrascale-playbook.static.hf.space/index.html#zero-3:_adding_parameter_partitioning_(fsdp)) from The Ultra-Scale Playbook for more information about how FSDP works.
|
||||
@@ -0,0 +1,99 @@
|
||||
<!--Copyright 2026 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Fusion mapping (experimental feature)
|
||||
|
||||
Fusion mapping provides an opt-in way to replace model submodules at load time while preserving the original checkpoint format.
|
||||
|
||||
It builds on:
|
||||
|
||||
- [Monkey patching](./monkey_patching) to swap module classes before model instantiation.
|
||||
- [Dynamic weight loading](./weightconverter) to map weights between the original and fused runtime layouts.
|
||||
|
||||
> [!WARNING]
|
||||
> Fusion mapping is an experimental loading feature. It changes the runtime module structure and may affect model behavior. Use it only when you explicitly want a fused runtime layout.
|
||||
|
||||
## Quick start
|
||||
|
||||
Fusion is enabled through [`~PreTrainedModel.from_pretrained`] with `fusion_config`:
|
||||
|
||||
```python
|
||||
from transformers import AutoModelForImageTextToText
|
||||
|
||||
|
||||
model = AutoModelForImageTextToText.from_pretrained(
|
||||
"Qwen/Qwen2-VL-2B-Instruct",
|
||||
fusion_config={"patch_embeddings": True},
|
||||
)
|
||||
```
|
||||
|
||||
By default, no fusion is applied.
|
||||
If `fusion_config` is stored in the model config, `from_pretrained()` will reuse it automatically.
|
||||
|
||||
## How it works
|
||||
|
||||
Fusion registration happens before the model is instantiated:
|
||||
|
||||
1. [`~PreTrainedModel.from_pretrained`] uses the explicit `fusion_config` argument or falls back to `config.fusion_config`.
|
||||
2. The fusion registry validates the requested fusion names.
|
||||
3. Each enabled fusion meta-initializes the target model class, optionally filters candidate modules by name, and uses `is_fusable(...)` to discover compatible module classes.
|
||||
4. Fused replacement classes are registered through [`~transformers.monkey_patching.register_patch_mapping`].
|
||||
5. Matching [`~WeightTransform`] rules are generated from the config so checkpoint loading can map weights into the fused runtime layout.
|
||||
6. By default, [`~PreTrainedModel.save_pretrained`] uses the reverse conversion path to restore the original checkpoint layout. Pass `save_original_format=False` to keep the converted runtime layout instead.
|
||||
|
||||
This lets a fusion use a different runtime module structure while still loading from the original checkpoint format, and by default saving back to it as well.
|
||||
|
||||
Note: With the current monkey-patching mechanism, fusion registration is class-level: one compatible module class maps to one fused replacement class.
|
||||
|
||||
## Current fusion families
|
||||
|
||||
Currently, `fusion_config` supports one fusion family:
|
||||
|
||||
- `patch_embeddings`
|
||||
Enable with:
|
||||
|
||||
```python
|
||||
fusion_config = {"patch_embeddings": True}
|
||||
```
|
||||
|
||||
Effect:
|
||||
Replaces compatible `nn.Conv3d` patch embedding projections with equivalent flattened `nn.Linear` projections at runtime.
|
||||
|
||||
## Extending fusion mapping
|
||||
|
||||
To add a new fusion family:
|
||||
|
||||
1. Add an `is_fusable` predicate.
|
||||
This decides whether a discovered module is compatible with the fusion.
|
||||
2. Optionally add `target_modules_patterns`.
|
||||
This makes the discovery step more explicit by pre-filtering candidate module names before `is_fusable(...)`.
|
||||
3. Add a `make_fused_class` factory.
|
||||
This returns the runtime replacement class for a compatible module class.
|
||||
4. Add a `make_transforms` factory if the fused layout needs checkpoint conversion.
|
||||
This returns the [`~WeightTransform`] rules that map weights between the original and fused layouts for a given config.
|
||||
5. Register the new `ModuleFusionSpec` in [`fusion_mapping.py`](https://github.com/huggingface/transformers/blob/main/src/transformers/fusion_mapping.py).
|
||||
|
||||
Once registered, the new fusion becomes available through `fusion_config`.
|
||||
|
||||
## Internal API
|
||||
|
||||
[[autodoc]] fusion_mapping.ModuleFusionSpec
|
||||
|
||||
[[autodoc]] fusion_mapping.PatchEmbeddingsFusionSpec
|
||||
|
||||
[[autodoc]] fusion_mapping._register_module_fusion
|
||||
|
||||
[[autodoc]] fusion_mapping.register_fusion_patches
|
||||
@@ -0,0 +1,82 @@
|
||||
<!--Copyright 2025 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Generation features
|
||||
|
||||
The [`~GenerationMixin.generate`] API supports a couple features for building applications on top of it.
|
||||
|
||||
This guide will show you how to use these features.
|
||||
|
||||
## Streaming
|
||||
|
||||
Streaming starts returning text as soon as it is generated so you don't have to wait to see the entire generated response all at once. It is important in user-facing applications because it reduces perceived latency and allows users to see the generation progression.
|
||||
|
||||
<div class="flex justify-center">
|
||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/tgi/streaming-generation-visual-dark_360.gif"/>
|
||||
</div>
|
||||
|
||||
> [!TIP]
|
||||
> Learn more about streaming in the [Text Generation Inference](https://huggingface.co/docs/text-generation-inference/en/conceptual/streaming) docs.
|
||||
|
||||
Create an instance of [`TextStreamer`] with the tokenizer. Pass [`TextStreamer`] to the `streamer` parameter in [`~GenerationMixin.generate`] to stream the output one word at a time.
|
||||
|
||||
```py
|
||||
from transformers import AutoModelForCausalLM, AutoTokenizer, TextStreamer
|
||||
|
||||
tokenizer = AutoTokenizer.from_pretrained("openai-community/gpt2")
|
||||
model = AutoModelForCausalLM.from_pretrained("openai-community/gpt2")
|
||||
inputs = tokenizer(["The secret to baking a good cake is "], return_tensors="pt")
|
||||
streamer = TextStreamer(tokenizer)
|
||||
|
||||
_ = model.generate(**inputs, streamer=streamer, max_new_tokens=20)
|
||||
```
|
||||
|
||||
The `streamer` parameter is compatible with any class with a [`~TextStreamer.put`] and [`~TextStreamer.end`] method. [`~TextStreamer.put`] pushes new tokens and [`~TextStreamer.end`] flags the end of generation. You can create your own streamer class as long as they include these two methods, or you can use Transformers' basic streamer classes.
|
||||
|
||||
## Watermarking
|
||||
|
||||
Watermarking is useful for detecting whether text is generated. The [watermarking strategy](https://hf.co/papers/2306.04634) in Transformers randomly "colors" a subset of the tokens green. When green tokens are generated, they have a small bias added to their logits, and a higher probability of being generated. You can detect generated text by comparing the proportion of green tokens to the amount of green tokens typically found in human-generated text.
|
||||
|
||||
Watermarking is supported for any generative model in Transformers and doesn't require an extra classification model to detect the watermarked text.
|
||||
|
||||
Create a [`WatermarkingConfig`] with the bias value to add to the logits and watermarking algorithm. The example below uses the `"selfhash"` algorithm, where the green token selection only depends on the current token. Pass the [`WatermarkingConfig`] to [`~GenerationMixin.generate`].
|
||||
|
||||
> [!TIP]
|
||||
> The [`WatermarkDetector`] class detects the proportion of green tokens in generated text, which is why it is recommended to strip the prompt text, if it is much longer than the generated text. Padding can also have an effect on [`WatermarkDetector`].
|
||||
|
||||
```py
|
||||
from transformers import AutoTokenizer, AutoModelForCausalLM, WatermarkDetector, WatermarkingConfig
|
||||
|
||||
model = AutoModelForCausalLM.from_pretrained("openai-community/gpt2")
|
||||
tokenizer = AutoTokenizer.from_pretrained("openai-community/gpt2")
|
||||
tokenizer.pad_token_id = tokenizer.eos_token_id
|
||||
tokenizer.padding_side = "left"
|
||||
|
||||
inputs = tokenizer(["This is the beginning of a long story", "Alice and Bob are"], padding=True, return_tensors="pt")
|
||||
input_len = inputs["input_ids"].shape[-1]
|
||||
|
||||
watermarking_config = WatermarkingConfig(bias=2.5, seeding_scheme="selfhash")
|
||||
out = model.generate(**inputs, watermarking_config=watermarking_config, do_sample=False, max_length=20)
|
||||
```
|
||||
|
||||
Create an instance of [`WatermarkDetector`] and pass the model output to it to detect whether the text is machine-generated. The [`WatermarkDetector`] must have the same [`WatermarkingConfig`] used during generation.
|
||||
|
||||
```py
|
||||
detector = WatermarkDetector(model_config=model.config, device="cpu", watermarking_config=watermarking_config)
|
||||
detection_out = detector(out, return_dict=True)
|
||||
detection_out.prediction
|
||||
array([True, True])
|
||||
```
|
||||
@@ -0,0 +1,332 @@
|
||||
<!--Copyright 2024 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Generation strategies
|
||||
|
||||
A decoding strategy informs how a model should select the next generated token. There are many types of decoding strategies, and choosing the appropriate one has a significant impact on the quality of the generated text.
|
||||
|
||||
This guide will help you understand the different decoding strategies available in Transformers and how and when to use them.
|
||||
|
||||
## Basic decoding methods
|
||||
|
||||
These are well established decoding methods, and should be your starting point for text generation tasks.
|
||||
|
||||
### Greedy search
|
||||
|
||||
Greedy search is the default decoding strategy. It selects the next most likely token at each step. Unless specified in [`GenerationConfig`], this strategy generates a maximum of 20 new tokens.
|
||||
|
||||
Greedy search works well for tasks with relatively short outputs where creativity is not a priority. However, it breaks down when generating longer sequences because it begins to repeat itself.
|
||||
|
||||
```py
|
||||
import torch
|
||||
from transformers import AutoModelForCausalLM, AutoTokenizer
|
||||
from accelerate import Accelerator
|
||||
|
||||
device = Accelerator().device
|
||||
|
||||
tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-2-7b-hf")
|
||||
inputs = tokenizer("Hugging Face is an open-source company", return_tensors="pt").to(device)
|
||||
|
||||
model = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-2-7b-hf", dtype=torch.float16).to(device)
|
||||
# explicitly set to default length because Llama2 generation length is 4096
|
||||
outputs = model.generate(**inputs, max_new_tokens=20)
|
||||
tokenizer.batch_decode(outputs, skip_special_tokens=True)
|
||||
'Hugging Face is an open-source company that provides a suite of tools and services for building, deploying, and maintaining natural language processing'
|
||||
```
|
||||
|
||||
### Sampling
|
||||
|
||||
Sampling, or multinomial sampling, randomly selects a token based on the probability distribution over the entire model's vocabulary (as opposed to the most likely token, as in greedy search). This means every token with a non-zero probability has a chance to be selected. Sampling strategies reduce repetition and can generate more creative and diverse outputs.
|
||||
|
||||
Enable multinomial sampling with `do_sample=True` and `num_beams=1`.
|
||||
|
||||
```py
|
||||
import torch
|
||||
from transformers import AutoModelForCausalLM, AutoTokenizer
|
||||
from accelerate import Accelerator
|
||||
|
||||
device = Accelerator().device
|
||||
|
||||
tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-2-7b-hf")
|
||||
inputs = tokenizer("Hugging Face is an open-source company", return_tensors="pt").to(device)
|
||||
|
||||
model = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-2-7b-hf", dtype=torch.float16).to(device)
|
||||
# explicitly set to 100 because Llama2 generation length is 4096
|
||||
outputs = model.generate(**inputs, max_new_tokens=50, do_sample=True, num_beams=1)
|
||||
tokenizer.batch_decode(outputs, skip_special_tokens=True)
|
||||
'Hugging Face is an open-source company 🤗\nWe are open-source and believe that open-source is the best way to build technology. Our mission is to make AI accessible to everyone, and we believe that open-source is the best way to achieve that.'
|
||||
```
|
||||
|
||||
### Beam search
|
||||
|
||||
Beam search keeps track of several generated sequences (beams) at each time step. After a certain number of steps, it selects the sequence with the highest *overall* probability. Unlike greedy search, this strategy can "look ahead" and pick a sequence with a higher probability overall even if the initial tokens have a lower probability. It is best suited for input-grounded tasks, like describing an image or speech recognition. You can also use `do_sample=True` with beam search to sample at each step, but beam search will still greedily prune out low probability sequences between steps.
|
||||
|
||||
> [!TIP]
|
||||
> Check out the [beam search visualizer](https://huggingface.co/spaces/m-ric/beam_search_visualizer) to see how beam search works.
|
||||
|
||||
Enable beam search with the `num_beams` parameter (should be greater than 1 otherwise it's equivalent to greedy search).
|
||||
|
||||
```py
|
||||
import torch
|
||||
from transformers import AutoModelForCausalLM, AutoTokenizer
|
||||
from accelerate import Accelerator
|
||||
|
||||
device = Accelerator().device
|
||||
|
||||
tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-2-7b-hf")
|
||||
inputs = tokenizer("Hugging Face is an open-source company", return_tensors="pt").to(device)
|
||||
|
||||
model = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-2-7b-hf", dtype=torch.float16).to(device)
|
||||
# explicitly set to 100 because Llama2 generation length is 4096
|
||||
outputs = model.generate(**inputs, max_new_tokens=50, num_beams=2)
|
||||
tokenizer.batch_decode(outputs, skip_special_tokens=True)
|
||||
"['Hugging Face is an open-source company that develops and maintains the Hugging Face platform, which is a collection of tools and libraries for building and deploying natural language processing (NLP) models. Hugging Face was founded in 2018 by Thomas Wolf']"
|
||||
```
|
||||
|
||||
## Custom generation methods
|
||||
|
||||
Custom generation methods enable specialized behavior such as:
|
||||
|
||||
- have the model continue thinking if it is uncertain;
|
||||
- roll back generation if the model gets stuck;
|
||||
- handle special tokens with custom logic;
|
||||
- use specialized KV caches;
|
||||
|
||||
We enable custom generation methods through model repositories, assuming a specific model tag and file structure (see subsection below). This feature is an extension of [custom modeling code](./models.md#custom-models) and, like such, requires setting `trust_remote_code=True`.
|
||||
|
||||
If a model repository holds a custom generation method, the easiest way to try it out is to load the model and generate with it:
|
||||
|
||||
```py
|
||||
from transformers import AutoModelForCausalLM, AutoTokenizer
|
||||
|
||||
# `transformers-community/custom_generate_example` holds a copy of `Qwen/Qwen2.5-0.5B-Instruct`, but
|
||||
# with custom generation code -> calling `generate` uses the custom generation method!
|
||||
tokenizer = AutoTokenizer.from_pretrained("transformers-community/custom_generate_example")
|
||||
model = AutoModelForCausalLM.from_pretrained(
|
||||
"transformers-community/custom_generate_example", device_map="auto", trust_remote_code=True
|
||||
)
|
||||
|
||||
inputs = tokenizer(["The quick brown"], return_tensors="pt").to(model.device)
|
||||
# The custom generation method is a minimal greedy decoding implementation. It also prints a custom message at run time.
|
||||
gen_out = model.generate(**inputs)
|
||||
# you should now see its custom message, "✨ using a custom generation method ✨"
|
||||
print(tokenizer.batch_decode(gen_out, skip_special_tokens=True))
|
||||
'The quick brown fox jumps over a lazy dog, and the dog is a type of animal. Is'
|
||||
```
|
||||
|
||||
Model repositories with custom generation methods have a special property: their generation method can be loaded from **any** model through [`~GenerationMixin.generate`]'s `custom_generate` argument. This means anyone can create and share their custom generation method to potentially work with any Transformers model, without requiring users to install additional Python packages.
|
||||
|
||||
```py
|
||||
from transformers import AutoModelForCausalLM, AutoTokenizer
|
||||
|
||||
tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen2.5-0.5B-Instruct")
|
||||
model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen2.5-0.5B-Instruct", device_map="auto")
|
||||
|
||||
inputs = tokenizer(["The quick brown"], return_tensors="pt").to(model.device)
|
||||
# `custom_generate` replaces the original `generate` by the custom generation method defined in
|
||||
# `transformers-community/custom_generate_example`
|
||||
gen_out = model.generate(**inputs, custom_generate="transformers-community/custom_generate_example", trust_remote_code=True)
|
||||
print(tokenizer.batch_decode(gen_out, skip_special_tokens=True)[0])
|
||||
'The quick brown fox jumps over a lazy dog, and the dog is a type of animal. Is'
|
||||
```
|
||||
|
||||
You should read the `README.md` file of the repository containing the custom generation strategy to see what the new arguments and output type differences are, if they exist. Otherwise, you can assume it works like the base [`~GenerationMixin.generate`] method.
|
||||
|
||||
> [!TIP]
|
||||
> You can find all custom generation methods by [searching for their custom tag.](https://huggingface.co/models?other=custom_generate), `custom_generate`.
|
||||
|
||||
Consider the Hub repository [transformers-community/custom_generate_example](https://huggingface.co/transformers-community/custom_generate_example) as an example. The `README.md` states that it has an additional input argument, `left_padding`, which adds a number of padding tokens before the prompt.
|
||||
|
||||
```py
|
||||
gen_out = model.generate(
|
||||
**inputs, custom_generate="transformers-community/custom_generate_example", trust_remote_code=True, left_padding=5
|
||||
)
|
||||
print(tokenizer.batch_decode(gen_out)[0])
|
||||
'<|endoftext|><|endoftext|><|endoftext|><|endoftext|><|endoftext|>The quick brown fox jumps over the lazy dog.\n\nThe sentence "The quick'
|
||||
```
|
||||
|
||||
If the custom method has pinned Python requirements that your environment doesn't meet, you'll get an exception about missing requirements. For instance, [transformers-community/custom_generate_bad_requirements](https://huggingface.co/transformers-community/custom_generate_bad_requirements) has an impossible set of requirements defined in its `custom_generate/requirements.txt` file, and you'll see the error message below if you try to run it.
|
||||
|
||||
```text
|
||||
ImportError: Missing requirements in your local environment for `transformers-community/custom_generate_bad_requirements`:
|
||||
foo (installed: None)
|
||||
bar==0.0.0 (installed: None)
|
||||
torch>=99.0 (installed: 2.6.0)
|
||||
```
|
||||
|
||||
Updating your Python requirements accordingly will remove this error message.
|
||||
|
||||
### Creating a custom generation method
|
||||
|
||||
To create a new generation method, you need to create a new [**Model**](https://huggingface.co/new) repository and push a few files into it.
|
||||
|
||||
1. The model you've designed your generation method with.
|
||||
2. `custom_generate/generate.py`, which contains all the logic for your custom generation method.
|
||||
3. `custom_generate/requirements.txt`, used to optionally add new Python requirements and/or lock specific versions to correctly use your method.
|
||||
4. `README.md`, where you should add the `custom_generate` tag and document any new arguments or output type differences of your custom method here.
|
||||
|
||||
After you've added all required files, your repository should look like this
|
||||
|
||||
```text
|
||||
your_repo/
|
||||
├── README.md # include the 'custom_generate' tag
|
||||
├── config.json
|
||||
├── ...
|
||||
└── custom_generate/
|
||||
├── generate.py
|
||||
└── requirements.txt
|
||||
```
|
||||
|
||||
#### Adding the base model
|
||||
|
||||
The starting point for your custom generation method is a model repository just like any other. The model to add to this repository should be the model you've designed your method with, and it is meant to be part of a working self-contained model-generate pair. When the model in this repository is loaded, your custom generation method will override `generate`. Don't worry -- your generation method can still be loaded with any other Transformers model, as explained in the section above.
|
||||
|
||||
If you simply want to copy an existing model, you can do
|
||||
|
||||
```py
|
||||
from transformers import AutoModelForCausalLM, AutoTokenizer
|
||||
|
||||
tokenizer = AutoTokenizer.from_pretrained("source/model_repo")
|
||||
model = AutoModelForCausalLM.from_pretrained("source/model_repo")
|
||||
tokenizer.save_pretrained("your/generation_method", push_to_hub=True)
|
||||
model.save_pretrained("your/generation_method", push_to_hub=True)
|
||||
```
|
||||
|
||||
#### generate.py
|
||||
|
||||
This is the core of your generation method. It *must* contain a method named `generate`, and this method *must* contain a `model` argument as its first argument. `model` is the model instance, which means you have access to all attributes and methods in the model, including the ones defined in [`GenerationMixin`] (like the base `generate` method).
|
||||
|
||||
> [!WARNING]
|
||||
> `generate.py` must be placed in a folder named `custom_generate`, and not at the root level of the repository. The file paths for this feature are hardcoded.
|
||||
|
||||
Under the hood, when the base [`~GenerationMixin.generate`] method is called with a `custom_generate` argument, it first checks its Python requirements (if any), then locates the custom `generate` method in `generate.py`, and finally calls the custom `generate`. All received arguments and `model` are forwarded to your custom `generate` method, with the exception of the arguments used to trigger the custom generation (`trust_remote_code` and `custom_generate`).
|
||||
|
||||
This means your `generate` can have a mix of original and custom arguments (as well as a different output type) as shown below.
|
||||
|
||||
```py
|
||||
import torch
|
||||
|
||||
def generate(model, input_ids, generation_config=None, left_padding=None, **kwargs):
|
||||
generation_config = generation_config or model.generation_config # default to the model generation config
|
||||
cur_length = input_ids.shape[1]
|
||||
max_length = generation_config.max_length or cur_length + generation_config.max_new_tokens
|
||||
|
||||
# Example of custom argument: add `left_padding` (integer) pad tokens before the prompt
|
||||
if left_padding is not None:
|
||||
if not isinstance(left_padding, int) or left_padding < 0:
|
||||
raise ValueError(f"left_padding must be an integer larger than 0, but is {left_padding}")
|
||||
|
||||
pad_token = kwargs.pop("pad_token", None) or generation_config.pad_token_id or model.config.pad_token_id
|
||||
if pad_token is None:
|
||||
raise ValueError("pad_token is not defined")
|
||||
batch_size = input_ids.shape[0]
|
||||
pad_tensor = torch.full(size=(batch_size, left_padding), fill_value=pad_token).to(input_ids.device)
|
||||
input_ids = torch.cat((pad_tensor, input_ids), dim=1)
|
||||
cur_length = input_ids.shape[1]
|
||||
|
||||
# Simple greedy decoding loop
|
||||
while cur_length < max_length:
|
||||
logits = model(input_ids).logits
|
||||
next_token_logits = logits[:, -1, :]
|
||||
next_tokens = torch.argmax(next_token_logits, dim=-1)
|
||||
input_ids = torch.cat((input_ids, next_tokens[:, None]), dim=-1)
|
||||
cur_length += 1
|
||||
|
||||
return input_ids
|
||||
```
|
||||
|
||||
Follow the recommended practices below to ensure your custom generation method works as expected.
|
||||
|
||||
- Feel free to reuse the logic for validation and input preparation in the original [`~GenerationMixin.generate`].
|
||||
- Pin the `transformers` version in the requirements if you use any private method/attribute in `model`.
|
||||
- Consider adding model validation, input validation, or even a separate test file to help users sanity-check your code in their environment.
|
||||
|
||||
Your custom `generate` method can relative import code from the `custom_generate` folder. For example, if you have a `utils.py` file, you can import it like this:
|
||||
|
||||
```py
|
||||
from .utils import some_function
|
||||
```
|
||||
|
||||
Only relative imports from the same-level `custom_generate` folder are supported. Parent/sibling folder imports are not valid. The `custom_generate` argument also works locally with any directory that contains a `custom_generate` structure, which is the recommended workflow for developing your custom generation method.
|
||||
|
||||
```py
|
||||
gen_out = model.generate(**inputs, custom_generate="path/to/local/dir", trust_remote_code=True)
|
||||
```
|
||||
|
||||
> [!WARNING]
|
||||
> Loading a local directory still executes its `custom_generate/generate.py`, so it requires `trust_remote_code=True` just like a Hub repository. Only pass `trust_remote_code=True` for code you've written or reviewed.
|
||||
|
||||
#### requirements.txt
|
||||
|
||||
You can optionally specify additional Python requirements in a `requirements.txt` file inside the `custom_generate` folder. These are checked at runtime and an exception will be thrown if they're missing, nudging users to update their environment accordingly.
|
||||
|
||||
#### README.md
|
||||
|
||||
The root level `README.md` in the model repository usually describes the model therein. However, since the focus of the repository is the custom generation method, we highly recommend to shift its focus towards describing the custom generation method. In addition to a description of the method, we recommend documenting any input and/or output differences to the original [`~GenerationMixin.generate`]. This way, users can focus on what's new, and rely on Transformers docs for generic implementation details.
|
||||
|
||||
For discoverability, we highly recommend you to add the `custom_generate` tag to your repository. To do so, the top of your `README.md` file should look like the example below. After you push the file, you should see the tag in your repository!
|
||||
|
||||
```text
|
||||
---
|
||||
library_name: transformers
|
||||
tags:
|
||||
- custom_generate
|
||||
---
|
||||
|
||||
(your markdown content here)
|
||||
```
|
||||
|
||||
Recommended practices:
|
||||
|
||||
- Document input and output differences in [`~GenerationMixin.generate`].
|
||||
- Add self-contained examples to enable quick experimentation.
|
||||
- Describe soft-requirements such as if the method only works well with a certain family of models.
|
||||
|
||||
### Reusing `generate`'s input preparation
|
||||
|
||||
If you're adding a new decoding loop, you might want to preserve the input preparation present in `generate` (batch expansion, attention masks, logits processors, stopping criteria, etc.). You can also pass a **callable** to `custom_generate` to reuse [`~GenerationMixin.generate`]'s full preparation pipeline while overriding only the decoding loop.
|
||||
|
||||
```py
|
||||
def custom_loop(model, input_ids, attention_mask, logits_processor, stopping_criteria, generation_config, **model_kwargs):
|
||||
next_tokens = input_ids
|
||||
while input_ids.shape[1] < stopping_criteria[0].max_length:
|
||||
logits = model(next_tokens, attention_mask=attention_mask, **model_kwargs).logits
|
||||
next_token_logits = logits_processor(input_ids, logits[:, -1, :])
|
||||
next_tokens = torch.argmax(next_token_logits, dim=-1)[:, None]
|
||||
input_ids = torch.cat((input_ids, next_tokens), dim=-1)
|
||||
attention_mask = torch.cat((attention_mask, torch.ones_like(next_tokens)), dim=-1)
|
||||
return input_ids
|
||||
|
||||
output = model.generate(
|
||||
**inputs,
|
||||
custom_generate=custom_loop,
|
||||
max_new_tokens=10,
|
||||
)
|
||||
```
|
||||
|
||||
> [!TIP]
|
||||
> If you publish a `custom_generate` repository, your `generate` implementation can itself define a callable and pass it to `model.generate()`. This lets you customize the decoding loop while still benefiting from Transformers' built-in input preparation logic.
|
||||
|
||||
### Finding custom generation methods
|
||||
|
||||
You can find all custom generation methods by [searching for their custom tag.](https://huggingface.co/models?other=custom_generate), `custom_generate`. In addition to the tag, we curate two collections of `custom_generate` methods:
|
||||
|
||||
- [Custom generation methods - Community](https://huggingface.co/collections/transformers-community/custom-generation-methods-community-6888fb1da0efbc592d3a8ab6) -- a collection of powerful methods contributed by the community;
|
||||
- [Custom generation methods - Tutorials](https://huggingface.co/collections/transformers-community/custom-generation-methods-tutorials-6823589657a94940ea02cfec) -- a collection of reference implementations for methods that previously were part of `transformers`, as well as tutorials for `custom_generate`.
|
||||
|
||||
## Resources
|
||||
|
||||
Read the [How to generate text: using different decoding methods for language generation with Transformers](https://huggingface.co/blog/how-to-generate) blog post for an explanation of how common decoding strategies work.
|
||||
@@ -0,0 +1,54 @@
|
||||
<!--Copyright 2024 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# GGUF
|
||||
|
||||
[GGUF](https://github.com/ggerganov/ggml/blob/master/docs/gguf.md) is a file format used to store models for inference with [GGML](https://github.com/ggerganov/ggml), a fast and lightweight inference framework written in C and C++. GGUF is a single-file format containing the model metadata and tensors.
|
||||
|
||||
<div class="flex justify-center">
|
||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/hub/gguf-spec.png"/>
|
||||
</div>
|
||||
|
||||
The GGUF format also supports many quantized data types (refer to [quantization type table](https://hf.co/docs/hub/en/gguf#quantization-types) for a complete list of supported quantization types) which saves a significant amount of memory, making inference with large models like Whisper and Llama feasible on local and edge devices.
|
||||
|
||||
Transformers supports loading models stored in the GGUF format for further training or finetuning. The GGUF checkpoint is **dequantized to fp32** where the full model weights are available and compatible with PyTorch.
|
||||
|
||||
> [!TIP]
|
||||
> Models that support GGUF include Llama, Mistral, Qwen2, Qwen2Moe, Phi3, Bloom, Falcon, StableLM, GPT2, Starcoder2, and [more](https://github.com/huggingface/transformers/blob/main/src/transformers/integrations/ggml.py)
|
||||
|
||||
Add the `gguf_file` parameter to [`~PreTrainedModel.from_pretrained`] to specify the GGUF file to load.
|
||||
|
||||
```py
|
||||
# pip install gguf
|
||||
import torch
|
||||
from transformers import AutoTokenizer, AutoModelForCausalLM
|
||||
|
||||
model_id = "TheBloke/TinyLlama-1.1B-Chat-v1.0-GGUF"
|
||||
filename = "tinyllama-1.1b-chat-v1.0.Q6_K.gguf"
|
||||
|
||||
dtype = torch.float32 # could be torch.float16 or torch.bfloat16 too
|
||||
tokenizer = AutoTokenizer.from_pretrained(model_id, gguf_file=filename)
|
||||
model = AutoModelForCausalLM.from_pretrained(model_id, gguf_file=filename, dtype=dtype)
|
||||
```
|
||||
|
||||
Once you're done tinkering with the model, save and convert it back to the GGUF format with the [convert-hf-to-gguf.py](https://github.com/ggerganov/llama.cpp/blob/master/convert_hf_to_gguf.py) script.
|
||||
|
||||
```py
|
||||
tokenizer.save_pretrained("directory")
|
||||
model.save_pretrained("directory")
|
||||
|
||||
!python ${path_to_llama_cpp}/convert-hf-to-gguf.py ${directory}
|
||||
```
|
||||
@@ -0,0 +1,522 @@
|
||||
<!--Copyright 2020 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Glossary
|
||||
|
||||
This glossary defines general machine learning and 🤗 Transformers terms to help you better understand the
|
||||
documentation.
|
||||
|
||||
## A
|
||||
|
||||
### attention mask
|
||||
|
||||
The attention mask is an optional argument used when batching sequences together.
|
||||
|
||||
<Youtube id="M6adb1j2jPI"/>
|
||||
|
||||
This argument indicates to the model which tokens should be attended to, and which should not.
|
||||
|
||||
For example, consider these two sequences:
|
||||
|
||||
```python
|
||||
>>> from transformers import BertTokenizer
|
||||
|
||||
>>> tokenizer = BertTokenizer.from_pretrained("google-bert/bert-base-cased")
|
||||
|
||||
>>> sequence_a = "This is a short sequence."
|
||||
>>> sequence_b = "This is a rather long sequence. It is at least longer than the sequence A."
|
||||
|
||||
>>> encoded_sequence_a = tokenizer(sequence_a)["input_ids"]
|
||||
>>> encoded_sequence_b = tokenizer(sequence_b)["input_ids"]
|
||||
```
|
||||
|
||||
The encoded versions have different lengths:
|
||||
|
||||
```python
|
||||
>>> len(encoded_sequence_a), len(encoded_sequence_b)
|
||||
(8, 19)
|
||||
```
|
||||
|
||||
Therefore, we can't put them together in the same tensor as-is. The first sequence needs to be padded up to the length
|
||||
of the second one, or the second one needs to be truncated down to the length of the first one.
|
||||
|
||||
In the first case, the list of IDs will be extended by the padding indices. We can pass a list to the tokenizer and ask
|
||||
it to pad like this:
|
||||
|
||||
```python
|
||||
>>> padded_sequences = tokenizer([sequence_a, sequence_b], padding=True)
|
||||
```
|
||||
|
||||
We can see that 0s have been added on the right of the first sentence to make it the same length as the second one:
|
||||
|
||||
```python
|
||||
>>> padded_sequences["input_ids"]
|
||||
[[101, 1188, 1110, 170, 1603, 4954, 119, 102, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [101, 1188, 1110, 170, 1897, 1263, 4954, 119, 1135, 1110, 1120, 1655, 2039, 1190, 1103, 4954, 138, 119, 102]]
|
||||
```
|
||||
|
||||
This can then be converted into a tensor in PyTorch. The attention mask is a binary tensor indicating the
|
||||
position of the padded indices so that the model does not attend to them. For the [`BertTokenizer`], `1` indicates a
|
||||
value that should be attended to, while `0` indicates a padded value. This attention mask is in the dictionary returned
|
||||
by the tokenizer under the key "attention_mask":
|
||||
|
||||
```python
|
||||
>>> padded_sequences["attention_mask"]
|
||||
[[1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]]
|
||||
```
|
||||
|
||||
### autoencoding models
|
||||
|
||||
See [encoder models](#encoder-models) and [masked language modeling](#masked-language-modeling-mlm)
|
||||
|
||||
### autoregressive models
|
||||
|
||||
See [causal language modeling](#causal-language-modeling) and [decoder models](#decoder-models)
|
||||
|
||||
## B
|
||||
|
||||
### backbone
|
||||
|
||||
The backbone is the network (embeddings and layers) that outputs the raw hidden states or features. It is usually connected to a [head](#head) which accepts the features as its input to make a prediction. For example, [`ViTModel`] is a backbone without a specific head on top. Other models can also use [`ViTModel`] as a backbone such as [DPT](model_doc/dpt).
|
||||
|
||||
## C
|
||||
|
||||
### causal language modeling
|
||||
|
||||
A pretraining task where the model reads the texts in order and has to predict the next word. It's usually done by
|
||||
reading the whole sentence but using a mask inside the model to hide the future tokens at a certain timestep.
|
||||
|
||||
### channel
|
||||
|
||||
Color images are made up of some combination of values in three channels: red, green, and blue (RGB) and grayscale images only have one channel. In 🤗 Transformers, the channel can be the first or last dimension of an image's tensor: [`n_channels`, `height`, `width`] or [`height`, `width`, `n_channels`].
|
||||
|
||||
### connectionist temporal classification (CTC)
|
||||
|
||||
An algorithm which allows a model to learn without knowing exactly how the input and output are aligned; CTC calculates the distribution of all possible outputs for a given input and chooses the most likely output from it. CTC is commonly used in speech recognition tasks because speech doesn't always cleanly align with the transcript for a variety of reasons such as a speaker's different speech rates.
|
||||
|
||||
### convolution
|
||||
|
||||
A type of layer in a neural network where the input matrix is multiplied element-wise by a smaller matrix (kernel or filter) and the values are summed up in a new matrix. This is known as a convolutional operation which is repeated over the entire input matrix. Each operation is applied to a different segment of the input matrix. Convolutional neural networks (CNNs) are commonly used in computer vision.
|
||||
|
||||
## D
|
||||
|
||||
### DataParallel (DP)
|
||||
|
||||
Parallelism technique for training on multiple GPUs where the same setup is replicated multiple times, with each instance
|
||||
receiving a distinct data slice. The processing is done in parallel and all setups are synchronized at the end of each training step.
|
||||
|
||||
Learn more about how DataParallel works [here](perf_train_gpu_many#dataparallel-vs-distributeddataparallel).
|
||||
|
||||
### decoder input IDs
|
||||
|
||||
This input is specific to encoder-decoder models, and contains the input IDs that will be fed to the decoder. These
|
||||
inputs should be used for sequence to sequence tasks, such as translation or summarization, and are usually built in a
|
||||
way specific to each model.
|
||||
|
||||
Most encoder-decoder models (BART, T5) create their `decoder_input_ids` on their own from the `labels`. In such models,
|
||||
passing the `labels` is the preferred way to handle training.
|
||||
|
||||
Please check each model's docs to see how they handle these input IDs for sequence to sequence training.
|
||||
|
||||
### decoder models
|
||||
|
||||
Also referred to as autoregressive models, decoder models involve a pretraining task (called causal language modeling) where the model reads the texts in order and has to predict the next word. It's usually done by
|
||||
reading the whole sentence with a mask to hide future tokens at a certain timestep.
|
||||
|
||||
<Youtube id="d_ixlCubqQw"/>
|
||||
|
||||
### deep learning (DL)
|
||||
|
||||
Machine learning algorithms which use neural networks with several layers.
|
||||
|
||||
## E
|
||||
|
||||
### encoder models
|
||||
|
||||
Also known as autoencoding models, encoder models take an input (such as text or images) and transform them into a condensed numerical representation called an embedding. Oftentimes, encoder models are pretrained using techniques like [masked language modeling](#masked-language-modeling-mlm), which masks parts of the input sequence and forces the model to create more meaningful representations.
|
||||
|
||||
<Youtube id="H39Z_720T5s"/>
|
||||
|
||||
## F
|
||||
|
||||
### feature extraction
|
||||
|
||||
The process of selecting and transforming raw data into a set of features that are more informative and useful for machine learning algorithms. Some examples of feature extraction include transforming raw text into word embeddings and extracting important features such as edges or shapes from image/video data.
|
||||
|
||||
### feed forward chunking
|
||||
|
||||
In each residual attention block in transformers the self-attention layer is usually followed by 2 feed forward layers.
|
||||
The intermediate embedding size of the feed forward layers is often bigger than the hidden size of the model (e.g., for
|
||||
`google-bert/bert-base-uncased`).
|
||||
|
||||
For an input of size `[batch_size, sequence_length]`, the memory required to store the intermediate feed forward
|
||||
embeddings `[batch_size, sequence_length, config.intermediate_size]` can account for a large fraction of the memory
|
||||
use. The authors of [Reformer: The Efficient Transformer](https://huggingface.co/papers/2001.04451) noticed that since the
|
||||
computation is independent of the `sequence_length` dimension, it is mathematically equivalent to compute the output
|
||||
embeddings of both feed forward layers `[batch_size, config.hidden_size]_0, ..., [batch_size, config.hidden_size]_n`
|
||||
individually and concat them afterward to `[batch_size, sequence_length, config.hidden_size]` with `n = sequence_length`, which trades increased computation time against reduced memory use, but yields a mathematically
|
||||
**equivalent** result.
|
||||
|
||||
For models employing the function [`apply_chunking_to_forward`], the `chunk_size` defines the number of output
|
||||
embeddings that are computed in parallel and thus defines the trade-off between memory and time complexity. If
|
||||
`chunk_size` is set to 0, no feed forward chunking is done.
|
||||
|
||||
### finetuned models
|
||||
|
||||
Finetuning is a form of transfer learning which involves taking a pretrained model, freezing its weights, and replacing the output layer with a newly added [model head](#head). The model head is trained on your target dataset.
|
||||
|
||||
See the [Fine-tune a pretrained model](https://huggingface.co/docs/transformers/training) tutorial for more details, and learn how to fine-tune models with 🤗 Transformers.
|
||||
|
||||
## H
|
||||
|
||||
### head
|
||||
|
||||
The model head refers to the last layer of a neural network that accepts the raw hidden states and projects them onto a different dimension. There is a different model head for each task. For example:
|
||||
|
||||
* [`GPT2ForSequenceClassification`] is a sequence classification head - a linear layer - on top of the base [`GPT2Model`].
|
||||
* [`ViTForImageClassification`] is an image classification head - a linear layer on top of the final hidden state of the `CLS` token - on top of the base [`ViTModel`].
|
||||
* [`Wav2Vec2ForCTC`] is a language modeling head with [CTC](#connectionist-temporal-classification-ctc) on top of the base [`Wav2Vec2Model`].
|
||||
|
||||
## I
|
||||
|
||||
### image patch
|
||||
|
||||
Vision-based Transformers models split an image into smaller patches which are linearly embedded, and then passed as a sequence to the model. You can find the `patch_size` - or resolution - of the model in its configuration.
|
||||
|
||||
### inference
|
||||
|
||||
Inference is the process of evaluating a model on new data after training is complete. See the [Pipeline for inference](https://huggingface.co/docs/transformers/pipeline_tutorial) tutorial to learn how to perform inference with 🤗 Transformers.
|
||||
|
||||
### input IDs
|
||||
|
||||
The input ids are often the only required parameters to be passed to the model as input. They are token indices,
|
||||
numerical representations of tokens building the sequences that will be used as input by the model.
|
||||
|
||||
<Youtube id="VFp38yj8h3A"/>
|
||||
|
||||
Each tokenizer works differently but the underlying mechanism remains the same. Here's an example using the BERT
|
||||
tokenizer, which is a [WordPiece](https://huggingface.co/papers/1609.08144) tokenizer:
|
||||
|
||||
```python
|
||||
>>> from transformers import BertTokenizer
|
||||
|
||||
>>> tokenizer = BertTokenizer.from_pretrained("google-bert/bert-base-cased")
|
||||
|
||||
>>> sequence = "A Titan RTX has 24GB of VRAM"
|
||||
```
|
||||
|
||||
The tokenizer takes care of splitting the sequence into tokens available in the tokenizer vocabulary.
|
||||
|
||||
```python
|
||||
>>> tokenized_sequence = tokenizer.tokenize(sequence)
|
||||
```
|
||||
|
||||
The tokens are either words or subwords. Here for instance, "VRAM" wasn't in the model vocabulary, so it's been split
|
||||
in "V", "RA" and "M". To indicate those tokens are not separate words but parts of the same word, a double-hash prefix
|
||||
is added for "RA" and "M":
|
||||
|
||||
```python
|
||||
>>> print(tokenized_sequence)
|
||||
['A', 'Titan', 'R', '##T', '##X', 'has', '24', '##GB', 'of', 'V', '##RA', '##M']
|
||||
```
|
||||
|
||||
These tokens can then be converted into IDs which are understandable by the model. This can be done by directly feeding the sentence to the tokenizer, which leverages the Rust implementation of [🤗 Tokenizers](https://github.com/huggingface/tokenizers) for peak performance.
|
||||
|
||||
```python
|
||||
>>> inputs = tokenizer(sequence)
|
||||
```
|
||||
|
||||
The tokenizer returns a dictionary with all the arguments necessary for its corresponding model to work properly. The
|
||||
token indices are under the key `input_ids`:
|
||||
|
||||
```python
|
||||
>>> encoded_sequence = inputs["input_ids"]
|
||||
>>> print(encoded_sequence)
|
||||
[101, 138, 18696, 155, 1942, 3190, 1144, 1572, 13745, 1104, 159, 9664, 2107, 102]
|
||||
```
|
||||
|
||||
Note that the tokenizer automatically adds "special tokens" (if the associated model relies on them) which are special
|
||||
IDs the model sometimes uses.
|
||||
|
||||
If we decode the previous sequence of ids,
|
||||
|
||||
```python
|
||||
>>> decoded_sequence = tokenizer.decode(encoded_sequence)
|
||||
```
|
||||
|
||||
we will see
|
||||
|
||||
```python
|
||||
>>> print(decoded_sequence)
|
||||
[CLS] A Titan RTX has 24GB of VRAM [SEP]
|
||||
```
|
||||
|
||||
because this is the way a [`BertModel`] is going to expect its inputs.
|
||||
|
||||
## L
|
||||
|
||||
### labels
|
||||
|
||||
The labels are an optional argument which can be passed in order for the model to compute the loss itself. These labels
|
||||
should be the expected prediction of the model: it will use the standard loss in order to compute the loss between its
|
||||
predictions and the expected value (the label).
|
||||
|
||||
These labels are different according to the model head, for example:
|
||||
|
||||
- For sequence classification models, ([`BertForSequenceClassification`]), the model expects a tensor of dimension
|
||||
`(batch_size)` with each value of the batch corresponding to the expected label of the entire sequence.
|
||||
- For token classification models, ([`BertForTokenClassification`]), the model expects a tensor of dimension
|
||||
`(batch_size, seq_length)` with each value corresponding to the expected label of each individual token.
|
||||
- For masked language modeling, ([`BertForMaskedLM`]), the model expects a tensor of dimension `(batch_size,
|
||||
seq_length)` with each value corresponding to the expected label of each individual token: the labels being the token
|
||||
ID for the masked token, and values to be ignored for the rest (usually -100).
|
||||
- For sequence to sequence tasks, ([`BartForConditionalGeneration`], [`MBartForConditionalGeneration`]), the model
|
||||
expects a tensor of dimension `(batch_size, tgt_seq_length)` with each value corresponding to the target sequences
|
||||
associated with each input sequence. During training, both BART and T5 will make the appropriate
|
||||
`decoder_input_ids` and decoder attention masks internally. They usually do not need to be supplied. This does not
|
||||
apply to models leveraging the Encoder-Decoder framework.
|
||||
- For image classification models, ([`ViTForImageClassification`]), the model expects a tensor of dimension
|
||||
`(batch_size)` with each value of the batch corresponding to the expected label of each individual image.
|
||||
- For semantic segmentation models, ([`SegformerForSemanticSegmentation`]), the model expects a tensor of dimension
|
||||
`(batch_size, height, width)` with each value of the batch corresponding to the expected label of each individual pixel.
|
||||
- For object detection models, ([`DetrForObjectDetection`]), the model expects a list of dictionaries with a
|
||||
`class_labels` and `boxes` key where each value of the batch corresponds to the expected label and number of bounding boxes of each individual image.
|
||||
- For automatic speech recognition models, ([`Wav2Vec2ForCTC`]), the model expects a tensor of dimension `(batch_size,
|
||||
target_length)` with each value corresponding to the expected label of each individual token.
|
||||
|
||||
<Tip>
|
||||
|
||||
Each model's labels may be different, so be sure to always check the documentation of each model for more information
|
||||
about their specific labels!
|
||||
|
||||
</Tip>
|
||||
|
||||
The base models ([`BertModel`]) do not accept labels, as these are the base transformer models, simply outputting
|
||||
features.
|
||||
|
||||
### large language models (LLM)
|
||||
|
||||
A generic term that refers to transformer language models (GPT-3, BLOOM, OPT) that were trained on a large quantity of data. These models also tend to have a large number of learnable parameters (e.g. 175 billion for GPT-3).
|
||||
|
||||
## M
|
||||
|
||||
### masked language modeling (MLM)
|
||||
|
||||
A pretraining task where the model sees a corrupted version of the texts, usually done by
|
||||
masking some tokens randomly, and has to predict the original text.
|
||||
|
||||
### multimodal
|
||||
|
||||
A task that combines texts with another kind of inputs (for instance images).
|
||||
|
||||
## N
|
||||
|
||||
### Natural language generation (NLG)
|
||||
|
||||
All tasks related to generating text (for instance, [Write With Transformers](https://transformer.huggingface.co/), translation).
|
||||
|
||||
### Natural language processing (NLP)
|
||||
|
||||
A generic way to say "deal with texts".
|
||||
|
||||
### Natural language understanding (NLU)
|
||||
|
||||
All tasks related to understanding what is in a text (for instance classifying the
|
||||
whole text, individual words).
|
||||
|
||||
## P
|
||||
|
||||
### pipeline
|
||||
|
||||
A pipeline in 🤗 Transformers is an abstraction referring to a series of steps that are executed in a specific order to preprocess and transform data and return a prediction from a model. Some example stages found in a pipeline might be data preprocessing, feature extraction, and normalization.
|
||||
|
||||
For more details, see [Pipelines for inference](https://huggingface.co/docs/transformers/pipeline_tutorial).
|
||||
|
||||
### PipelineParallel (PP)
|
||||
|
||||
Parallelism technique in which the model is split up vertically (layer-level) across multiple GPUs, so that only one or
|
||||
several layers of the model are placed on a single GPU. Each GPU processes in parallel different stages of the pipeline
|
||||
and working on a small chunk of the batch. Learn more about how PipelineParallel works [here](perf_train_gpu_many#from-naive-model-parallelism-to-pipeline-parallelism).
|
||||
|
||||
### pixel values
|
||||
|
||||
A tensor of the numerical representations of an image that is passed to a model. The pixel values have a shape of [`batch_size`, `num_channels`, `height`, `width`], and are generated from an image processor.
|
||||
|
||||
### pooling
|
||||
|
||||
An operation that reduces a matrix into a smaller matrix, either by taking the maximum or average of the pooled dimension(s). Pooling layers are commonly found between convolutional layers to downsample the feature representation.
|
||||
|
||||
### position IDs
|
||||
|
||||
Contrary to RNNs that have the position of each token embedded within them, transformers are unaware of the position of
|
||||
each token. Therefore, the position IDs (`position_ids`) are used by the model to identify each token's position in the
|
||||
list of tokens.
|
||||
|
||||
They are an optional parameter. If no `position_ids` are passed to the model, the IDs are automatically created as
|
||||
absolute positional embeddings.
|
||||
|
||||
Absolute positional embeddings are selected in the range `[0, config.max_position_embeddings - 1]`. Some models use
|
||||
other types of positional embeddings, such as sinusoidal position embeddings or relative position embeddings.
|
||||
|
||||
### preprocessing
|
||||
|
||||
The task of preparing raw data into a format that can be easily consumed by machine learning models. For example, text is typically preprocessed by tokenization. To gain a better idea of what preprocessing looks like for other input types, check out the [Preprocess](https://huggingface.co/docs/transformers/preprocessing) tutorial.
|
||||
|
||||
### pretrained model
|
||||
|
||||
A model that has been pretrained on some data (for instance all of Wikipedia). Pretraining methods involve a
|
||||
self-supervised objective, which can be reading the text and trying to predict the next word (see [causal language
|
||||
modeling](#causal-language-modeling)) or masking some words and trying to predict them (see [masked language
|
||||
modeling](#masked-language-modeling-mlm)).
|
||||
|
||||
Speech and vision models have their own pretraining objectives. For example, Wav2Vec2 is a speech model pretrained on a contrastive task which requires the model to identify the "true" speech representation from a set of "false" speech representations. On the other hand, BEiT is a vision model pretrained on a masked image modeling task which masks some of the image patches and requires the model to predict the masked patches (similar to the masked language modeling objective).
|
||||
|
||||
## R
|
||||
|
||||
### recurrent neural network (RNN)
|
||||
|
||||
A type of model that uses a loop over a layer to process texts.
|
||||
|
||||
### representation learning
|
||||
|
||||
A subfield of machine learning which focuses on learning meaningful representations of raw data. Some examples of representation learning techniques include word embeddings, autoencoders, and Generative Adversarial Networks (GANs).
|
||||
|
||||
## S
|
||||
|
||||
### sampling rate
|
||||
|
||||
A measurement in hertz of the number of samples (the audio signal) taken per second. The sampling rate is a result of discretizing a continuous signal such as speech.
|
||||
|
||||
### self-attention
|
||||
|
||||
Each element of the input finds out which other elements of the input they should attend to.
|
||||
|
||||
### self-supervised learning
|
||||
|
||||
A category of machine learning techniques in which a model creates its own learning objective from unlabeled data. It differs from [unsupervised learning](#unsupervised-learning) and [supervised learning](#supervised-learning) in that the learning process is supervised, but not explicitly from the user.
|
||||
|
||||
One example of self-supervised learning is [masked language modeling](#masked-language-modeling-mlm), where a model is passed sentences with a proportion of its tokens removed and learns to predict the missing tokens.
|
||||
|
||||
### semi-supervised learning
|
||||
|
||||
A broad category of machine learning training techniques that leverages a small amount of labeled data with a larger quantity of unlabeled data to improve the accuracy of a model, unlike [supervised learning](#supervised-learning) and [unsupervised learning](#unsupervised-learning).
|
||||
|
||||
An example of a semi-supervised learning approach is "self-training", in which a model is trained on labeled data, and then used to make predictions on the unlabeled data. The portion of the unlabeled data that the model predicts with the most confidence gets added to the labeled dataset and used to retrain the model.
|
||||
|
||||
### sequence-to-sequence (seq2seq)
|
||||
|
||||
Models that generate a new sequence from an input, like translation models, or summarization models (such as
|
||||
[Bart](model_doc/bart) or [T5](model_doc/t5)).
|
||||
|
||||
### Sharded DDP
|
||||
|
||||
Another name for the foundational [ZeRO](#zero-redundancy-optimizer-zero) concept as used by various other implementations of ZeRO.
|
||||
|
||||
### stride
|
||||
|
||||
In [convolution](#convolution) or [pooling](#pooling), the stride refers to the distance the kernel is moved over a matrix. A stride of 1 means the kernel is moved one pixel over at a time, and a stride of 2 means the kernel is moved two pixels over at a time.
|
||||
|
||||
### supervised learning
|
||||
|
||||
A form of model training that directly uses labeled data to correct and instruct model performance. Data is fed into the model being trained, and its predictions are compared to the known labels. The model updates its weights based on how incorrect its predictions were, and the process is repeated to optimize model performance.
|
||||
|
||||
## T
|
||||
|
||||
### Tensor Parallelism (TP)
|
||||
|
||||
Parallelism technique for training on multiple GPUs in which each tensor is split up into multiple chunks, so instead of
|
||||
having the whole tensor reside on a single GPU, each shard of the tensor resides on its designated GPU. Shards gets
|
||||
processed separately and in parallel on different GPUs and the results are synced at the end of the processing step.
|
||||
This is what is sometimes called horizontal parallelism, as the splitting happens on horizontal level.
|
||||
Learn more about Tensor Parallelism [here](perf_train_gpu_many#tensor-parallelism).
|
||||
|
||||
### token
|
||||
|
||||
A part of a sentence, usually a word, but can also be a subword (non-common words are often split in subwords) or a
|
||||
punctuation symbol.
|
||||
|
||||
### token Type IDs
|
||||
|
||||
Some models' purpose is to do classification on pairs of sentences or question answering.
|
||||
|
||||
<Youtube id="0u3ioSwev3s"/>
|
||||
|
||||
These require two different sequences to be joined in a single "input_ids" entry, which usually is performed with the
|
||||
help of special tokens, such as the classifier (`[CLS]`) and separator (`[SEP]`) tokens. For example, the BERT model
|
||||
builds its two sequence input as such:
|
||||
|
||||
```python
|
||||
>>> # [CLS] SEQUENCE_A [SEP] SEQUENCE_B [SEP]
|
||||
```
|
||||
|
||||
We can use our tokenizer to automatically generate such a sentence by passing the two sequences to `tokenizer` as two
|
||||
arguments (and not a list, like before) like this:
|
||||
|
||||
```python
|
||||
>>> from transformers import BertTokenizer
|
||||
|
||||
>>> tokenizer = BertTokenizer.from_pretrained("google-bert/bert-base-cased")
|
||||
>>> sequence_a = "HuggingFace is based in NYC"
|
||||
>>> sequence_b = "Where is HuggingFace based?"
|
||||
|
||||
>>> encoded_dict = tokenizer(sequence_a, sequence_b)
|
||||
>>> decoded = tokenizer.decode(encoded_dict["input_ids"])
|
||||
```
|
||||
|
||||
which will return:
|
||||
|
||||
```python
|
||||
>>> print(decoded)
|
||||
[CLS] HuggingFace is based in NYC [SEP] Where is HuggingFace based? [SEP]
|
||||
```
|
||||
|
||||
This is enough for some models to understand where one sequence ends and where another begins. However, other models,
|
||||
such as BERT, also deploy token type IDs (also called segment IDs). They are represented as a binary mask identifying
|
||||
the two types of sequence in the model.
|
||||
|
||||
The tokenizer returns this mask as the "token_type_ids" entry:
|
||||
|
||||
```python
|
||||
>>> encoded_dict["token_type_ids"]
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1]
|
||||
```
|
||||
|
||||
The first sequence, the "context" used for the question, has all its tokens represented by a `0`, whereas the second
|
||||
sequence, corresponding to the "question", has all its tokens represented by a `1`.
|
||||
|
||||
Some models, like [`XLNetModel`] use an additional token represented by a `2`.
|
||||
|
||||
### transfer learning
|
||||
|
||||
A technique that involves taking a pretrained model and adapting it to a dataset specific to your task. Instead of training a model from scratch, you can leverage knowledge obtained from an existing model as a starting point. This speeds up the learning process and reduces the amount of training data needed.
|
||||
|
||||
### transformer
|
||||
|
||||
Self-attention based deep learning model architecture.
|
||||
|
||||
## U
|
||||
|
||||
### unsupervised learning
|
||||
|
||||
A form of model training in which data provided to the model is not labeled. Unsupervised learning techniques leverage statistical information of the data distribution to find patterns useful for the task at hand.
|
||||
|
||||
## Z
|
||||
|
||||
### Zero Redundancy Optimizer (ZeRO)
|
||||
|
||||
Parallelism technique which performs sharding of the tensors somewhat similar to [TensorParallel](#tensor-parallelism-tp),
|
||||
except the whole tensor gets reconstructed in time for a forward or backward computation, therefore the model doesn't need
|
||||
to be modified. This method also supports various offloading techniques to compensate for limited GPU memory.
|
||||
Learn more about ZeRO [here](perf_train_gpu_many#zero-data-parallelism).
|
||||
@@ -0,0 +1,65 @@
|
||||
<!---Copyright 2026 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
-->
|
||||
|
||||
# Gradient accumulation
|
||||
|
||||
Large batches produce large activations that exhaust GPU memory. Gradient accumulation lets you train with a larger effective batch size by spreading gradient computation across multiple mini-batches.
|
||||
|
||||
Gradients accumulate across *n* mini-batches before the optimizer updates the weights. For example, with a per-device batch size of 8 and 4 accumulation steps, the effective batch size is 32.
|
||||
|
||||
```text
|
||||
Step 1: mini-batch 1 → forward → backward → grads = G₁
|
||||
Step 2: mini-batch 2 → forward → backward → grads = G₁ + G₂
|
||||
Step 3: mini-batch 3 → forward → backward → grads = G₁ + G₂ + G₃
|
||||
Step 4: mini-batch 4 → forward → backward → grads = G₁ + G₂ + G₃ + G₄
|
||||
→ optimizer.step() ← same update as if batch_size × 4
|
||||
→ zero_grad()
|
||||
```
|
||||
|
||||
Use gradient accumulation only when a larger batch doesn't fit in memory. It doesn't improve throughput over training with a true large batch.
|
||||
|
||||
Accumulate gradients for `gradient_accumulation_steps` across `per_device_train_batch_size`.
|
||||
|
||||
```py
|
||||
from transformers import TrainingArguments
|
||||
|
||||
args = TrainingArguments(
|
||||
...,
|
||||
per_device_train_batch_size=8,
|
||||
gradient_accumulation_steps=4,
|
||||
)
|
||||
```
|
||||
|
||||
## Loss scaling
|
||||
|
||||
For a [custom loss function](./trainer_recipes#custom-loss-function), include `num_items_in_batch` so [`Trainer`] divides the loss by the number of prediction targets across all mini-batches. This normalizes by tokens rather than a fixed step count with `gradient_accumulation_steps`. Otherwise, [`Trainer`] divides loss by `gradient_accumulation_steps`.
|
||||
|
||||
```py
|
||||
import torch.nn.functional as F
|
||||
|
||||
def compute_loss(outputs, labels, num_items_in_batch=None):
|
||||
logits = outputs["logits"]
|
||||
loss = F.cross_entropy(logits, labels, reduction="sum")
|
||||
return loss / num_items_in_batch
|
||||
```
|
||||
|
||||
For causal LM models, `num_items_in_batch` counts the *shifted* labels. The loss shifts labels so the prediction at position `i` targets the token at position `i + 1`, which leaves position 0 of every sequence without a target. [`Trainer`] excludes those positions and counts over `labels[..., 1:]`, so the denominator matches the number of prediction targets the loss uses. When a data collator supplies `shift_labels` directly, such as a padding-free collator, [`Trainer`] counts over that tensor instead. Other loss types, like masked LM and classification, count the full label tensor.
|
||||
|
||||
## Next steps
|
||||
|
||||
- Read the [GPU memory usage](./model_memory_anatomy) doc to understand what is driving memory usage on the GPU during training.
|
||||
- See the [Gradient checkpointing](./grad_checkpointing) guide to learn how to reduce activation memory by recomputing activations instead of caching them.
|
||||
- See the [Mixed precision training](./mixed_precision_training) guide to learn how to use lower precision data types to reduce memory and speed up training.
|
||||
- Read the [Gradient Accumulation Fix](https://unsloth.ai/blog/gradient) blog post to learn how gradient accumulation is computed.
|
||||
@@ -0,0 +1,50 @@
|
||||
<!---Copyright 2026 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
-->
|
||||
|
||||
# Gradient checkpointing
|
||||
|
||||
The forward pass typically caches all intermediate activations for the backward pass to reuse. However, activations scale with batch size and sequence length. Gradient checkpointing only saves certain activations and discards the rest. This forces the backward pass to recompute some of the activations on-the-fly as they're needed.
|
||||
|
||||
```text
|
||||
Normal training:
|
||||
Forward: [L1]→[L2]→[L3]→[L4] (save ALL activations)
|
||||
Backward: ←uses cached activations everywhere
|
||||
|
||||
Gradient checkpointing:
|
||||
Forward: [L1]→[L2]→[L3]→[L4] (save only at checkpoints, discard the rest)
|
||||
Backward: ←reaches L2, recomputes L2→L3 from scratch, uses it, discards it
|
||||
```
|
||||
|
||||
Training will be ~20% slower because some activations need to be recomputed, but it reduces activation memory.
|
||||
|
||||
Set `gradient_checkpointing=True` to enable.
|
||||
|
||||
> [!TIP]
|
||||
> Use with [gradient accumulation](./grad_accumulation) to further reduce memory usage.
|
||||
|
||||
```py
|
||||
from transformers import TrainingArguments
|
||||
|
||||
args = TrainingArguments(
|
||||
...,
|
||||
gradient_checkpointing=True,
|
||||
)
|
||||
```
|
||||
|
||||
## Next steps
|
||||
|
||||
- Read the [GPU memory usage](./model_memory_anatomy) doc to understand what is driving memory usage on the GPU during training.
|
||||
- See the [Mixed precision training](./mixed_precision_training) guide to learn how to use lower precision data types to further reduce memory and speed up training.
|
||||
- See the [Kernels](./kernels) guide to learn how to speed up training with custom fused kernels.
|
||||
@@ -0,0 +1,207 @@
|
||||
<!--Copyright 2026 The HuggingFace Team. All rights reserved.
|
||||
Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved.
|
||||
|
||||
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.
|
||||
-->
|
||||
|
||||
# Heterogeneous model configurations
|
||||
|
||||
Most model configurations in Transformers describe a homogeneous stack: each layer has the same dimensions and contains
|
||||
the same submodules. Some checkpoints do not follow this pattern. For example, a model may use a smaller MLP in one
|
||||
layer, fewer key-value heads in another layer, or omit a submodule such as attention or the MLP from selected layers.
|
||||
|
||||
`per_layer_config` represents these layer-specific differences directly in the model configuration. Each entry stores
|
||||
only the attributes that differ from the global configuration. Attributes that are not overridden inherit their value
|
||||
from the global configuration.
|
||||
|
||||
This is useful for checkpoints that remain close to an existing architecture but are no longer layer-uniform, such as
|
||||
pruned, distilled, or NAS-derived (Neural Architecture Search) models. Instead of defining a new architecture for every
|
||||
such variant, `per_layer_config` records the layer-level differences in a few lines of config, at little to no
|
||||
config-side cost.
|
||||
|
||||
> [!NOTE]
|
||||
> Heterogeneous configurations are a power feature. If a heterogeneous layout becomes a common or prominent
|
||||
> architecture, we will strive to model it explicitly in the architecture implementation rather than rely on
|
||||
> `per_layer_config`. Prefer the explicit architecture when one exists.
|
||||
|
||||
Examples of heterogeneous checkpoints include:
|
||||
|
||||
| Model | Derived from |
|
||||
|---|---|
|
||||
| [`nvidia/Llama-3_3-Nemotron-Super-49B-v1_5`](https://huggingface.co/nvidia/Llama-3_3-Nemotron-Super-49B-v1_5) | [`meta-llama/Llama-3.3-70B-Instruct`](https://huggingface.co/meta-llama/Llama-3.3-70B-Instruct) |
|
||||
| [`nvidia/Llama-3_1-Nemotron-Ultra-253B-v1`](https://huggingface.co/nvidia/Llama-3_1-Nemotron-Ultra-253B-v1) | [`meta-llama/Llama-3.1-405B-Instruct`](https://huggingface.co/meta-llama/Llama-3.1-405B-Instruct) |
|
||||
| [`nvidia/gpt-oss-puzzle-88B`](https://huggingface.co/nvidia/gpt-oss-puzzle-88B) | [`openai/gpt-oss-120b`](https://huggingface.co/openai/gpt-oss-120b) |
|
||||
| [`nvidia/NVIDIA-Nemotron-Labs-3-Puzzle-75B-A9B-BF16`](https://huggingface.co/nvidia/NVIDIA-Nemotron-Labs-3-Puzzle-75B-A9B-BF16) | [`nvidia/NVIDIA-Nemotron-3-Super-120B-A12B-BF16`](https://huggingface.co/nvidia/NVIDIA-Nemotron-3-Super-120B-A12B-BF16) |
|
||||
|
||||
## Define per-layer overrides
|
||||
|
||||
Pass `per_layer_config` to a configuration as a mapping from layer indices to attribute overrides. Layer indices are
|
||||
zero-based. Only attributes that differ from the global configuration need to be specified.
|
||||
|
||||
The following example overrides four layers: layer 5 uses a smaller MLP, layer 11 uses
|
||||
fewer key-value heads, layer 23 skips the MLP, and layer 27 skips attention.
|
||||
|
||||
```py
|
||||
from transformers import LlamaConfig
|
||||
|
||||
|
||||
config = LlamaConfig(
|
||||
hidden_size=4096,
|
||||
intermediate_size=14336,
|
||||
num_hidden_layers=32,
|
||||
num_attention_heads=32,
|
||||
num_key_value_heads=8,
|
||||
per_layer_config={
|
||||
# Use a smaller MLP in one layer.
|
||||
5: {"intermediate_size": 8192},
|
||||
|
||||
# Use fewer key-value heads in another layer.
|
||||
11: {"num_key_value_heads": 4},
|
||||
|
||||
# Omit the MLP from a selected layer.
|
||||
23: {"skip": ["mlp"]},
|
||||
|
||||
# Omit attention from a selected layer.
|
||||
27: {"skip": ["attention"]},
|
||||
},
|
||||
)
|
||||
```
|
||||
|
||||
The submodules that can be skipped (for example, `"mlp"` and `"attention"`) are defined per architecture. `skip`
|
||||
accepts a list, so a layer can omit more than one submodule.
|
||||
|
||||
Accessing `config.per_layer_config[layer_idx]` returns a resolved layer configuration. The resolved configuration
|
||||
combines the global configuration with the overrides for that layer.
|
||||
|
||||
```py
|
||||
# Layer 0 does not define overrides, so it inherits the global values.
|
||||
config.per_layer_config[0].intermediate_size
|
||||
# 14336
|
||||
|
||||
config.per_layer_config[0].num_key_value_heads
|
||||
# 8
|
||||
|
||||
# Layer 5 overrides the MLP intermediate size.
|
||||
config.per_layer_config[5].intermediate_size
|
||||
# 8192
|
||||
|
||||
# Layer 11 overrides the number of key-value heads.
|
||||
config.per_layer_config[11].num_key_value_heads
|
||||
# 4
|
||||
|
||||
# Layer 23 skips the MLP.
|
||||
config.per_layer_config[23].skip
|
||||
# ["mlp"]
|
||||
|
||||
# Layer 27 skips attention.
|
||||
config.per_layer_config[27].skip
|
||||
# ["attention"]
|
||||
```
|
||||
|
||||
Configurations that use `per_layer_config` support the same [`~PreTrainedConfig.save_pretrained`] and
|
||||
[`~PreTrainedConfig.from_pretrained`] round trip as other configurations.
|
||||
|
||||
Each architecture defines in its code which attributes are used at the layer level. `per_layer_config` provides the mechanism for
|
||||
recording those layer-level differences and resolving them against the global config.
|
||||
|
||||
## Global attribute access
|
||||
|
||||
In a heterogeneous configuration, an attribute with per-layer overrides no longer has a single model-wide value.
|
||||
For example, `num_key_value_heads` may be `8` for most layers and `4` for selected layers, so reading
|
||||
`config.num_key_value_heads` outside a layer-specific context is not well-defined.
|
||||
|
||||
This matters because consumers that read such an attribute globally would silently apply the wrong value to the
|
||||
overridden layers. Code that allocates a key-value cache from a global `num_key_value_heads`, for instance,
|
||||
would be incorrect for the layers that override it.
|
||||
|
||||
By default, an `AmbiguousGlobalPerLayerAttributeError` will be raised for this access pattern, directing callers to use
|
||||
`config.per_layer_config[layer_idx]` instead. We raise this error instead of `AttributeError` because the attribute
|
||||
exists on the global config, but reading it there is ambiguous without layer-specific context.
|
||||
|
||||
Set `allow_global_per_layer_attribute_access=True` only when the caller intentionally needs the global fallback value
|
||||
and can safely handle heterogeneous configurations. In that case, global access is allowed, but a warning will be emitted once.
|
||||
|
||||
```py
|
||||
config = LlamaConfig(
|
||||
hidden_size=4096,
|
||||
intermediate_size=14336,
|
||||
num_hidden_layers=32,
|
||||
num_attention_heads=32,
|
||||
num_key_value_heads=8,
|
||||
allow_global_per_layer_attribute_access=True,
|
||||
per_layer_config={
|
||||
11: {"num_key_value_heads": 4},
|
||||
},
|
||||
)
|
||||
|
||||
config.num_key_value_heads
|
||||
# 8
|
||||
# Emits a warning_once message because num_key_value_heads has a per-layer override.
|
||||
```
|
||||
|
||||
## Serialization
|
||||
|
||||
`per_layer_config` is serialized sparsely by default. Layers without overrides are omitted, and overridden attributes
|
||||
that match the global value are also omitted.
|
||||
|
||||
```py
|
||||
from transformers import LlamaConfig
|
||||
|
||||
|
||||
config = LlamaConfig(
|
||||
hidden_size=4096,
|
||||
intermediate_size=14336,
|
||||
num_hidden_layers=4,
|
||||
num_attention_heads=32,
|
||||
num_key_value_heads=8,
|
||||
per_layer_config={
|
||||
0: {"num_key_value_heads": 8},
|
||||
2: {"num_key_value_heads": 4},
|
||||
},
|
||||
)
|
||||
|
||||
config.to_dict()["per_layer_config"]
|
||||
# {"2": {"num_key_value_heads": 4}}
|
||||
```
|
||||
|
||||
Set `serialize_explicit_per_layer_config=True` when the serialized configuration should include every layer for the
|
||||
attributes represented in `per_layer_config`. This can make the layer layout easier to inspect, even when some values
|
||||
match the global configuration.
|
||||
|
||||
```py
|
||||
explicit_config = LlamaConfig(
|
||||
hidden_size=4096,
|
||||
intermediate_size=14336,
|
||||
num_hidden_layers=4,
|
||||
num_attention_heads=32,
|
||||
num_key_value_heads=8,
|
||||
serialize_explicit_per_layer_config=True,
|
||||
per_layer_config={
|
||||
0: {"num_key_value_heads": 8},
|
||||
2: {"num_key_value_heads": 4},
|
||||
},
|
||||
)
|
||||
|
||||
serialized_per_layer_config = explicit_config.to_dict()["per_layer_config"]
|
||||
|
||||
serialized_per_layer_config
|
||||
# {
|
||||
# "0": {"num_key_value_heads": 8},
|
||||
# "1": {"num_key_value_heads": 8},
|
||||
# "2": {"num_key_value_heads": 4},
|
||||
# "3": {"num_key_value_heads": 8},
|
||||
# }
|
||||
```
|
||||
|
||||
Use sparse serialization for compact configs. Use explicit serialization when readability or downstream tooling benefits
|
||||
from seeing the full per-layer layout.
|
||||
@@ -0,0 +1,152 @@
|
||||
<!--Copyright 2024 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Customizing model components
|
||||
|
||||
Another way to customize a model is to modify their components, rather than writing a new model entirely, allowing you to tailor a model to your specific use case. For example, you can add new layers or optimize the attention mechanism of an architecture. Customizations are applied directly to a Transformers model so that you can continue to use features such as [`Trainer`], [`PreTrainedModel`], and the [PEFT](https://huggingface.co/docs/peft/en/index) library.
|
||||
|
||||
This guide will show you how to customize a models attention mechanism in order to apply [Low-Rank Adaptation (LoRA)](https://huggingface.co/docs/peft/conceptual_guides/adapter#low-rank-adaptation-lora) to it.
|
||||
|
||||
> [!TIP]
|
||||
> The [clear_import_cache](https://github.com/huggingface/transformers/blob/9985d06add07a4cc691dc54a7e34f54205c04d40/src/transformers/utils/import_utils.py#L2286) utility is very useful when you're iteratively modifying and developing model code. It removes all cached Transformers modules and allows Python to reload the modified code without constantly restarting your environment.
|
||||
>
|
||||
> ```py
|
||||
> from transformers import AutoModel
|
||||
> from transformers.utils.import_utils import clear_import_cache
|
||||
>
|
||||
> model = AutoModel.from_pretrained("bert-base-uncased")
|
||||
> # modifications to model code
|
||||
> # clear cache to reload modified code
|
||||
> clear_import_cache()
|
||||
> # re-import to use updated code
|
||||
> model = AutoModel.from_pretrained("bert-base-uncased")
|
||||
> ```
|
||||
|
||||
## Attention class
|
||||
|
||||
[Segment Anything](./model_doc/sam) is an image segmentation model, and it combines the query-key-value (`qkv`) projection in its attention mechanisms. To reduce the number of trainable parameters and computational overhead, you can apply LoRA to the `qkv` projection. This requires splitting the `qkv` projection so that you can separately target the `q` and `v` with LoRA.
|
||||
|
||||
1. Create a custom attention class, `SamVisionAttentionSplit`, by subclassing the original `SamVisionAttention` class. In the `__init__`, delete the combined `qkv` and create a separate linear layer for `q`, `k` and `v`.
|
||||
|
||||
```py
|
||||
import torch
|
||||
import torch.nn as nn
|
||||
from transformers.models.sam.modeling_sam import SamVisionAttention
|
||||
|
||||
class SamVisionAttentionSplit(SamVisionAttention, nn.Module):
|
||||
def __init__(self, config, window_size):
|
||||
super().__init__(config, window_size)
|
||||
# remove combined qkv
|
||||
del self.qkv
|
||||
# separate q, k, v projections
|
||||
self.q = nn.Linear(config.hidden_size, config.hidden_size, bias=config.qkv_bias)
|
||||
self.k = nn.Linear(config.hidden_size, config.hidden_size, bias=config.qkv_bias)
|
||||
self.v = nn.Linear(config.hidden_size, config.hidden_size, bias=config.qkv_bias)
|
||||
self._register_load_state_dict_pre_hook(self.split_q_k_v_load_hook)
|
||||
```
|
||||
|
||||
2. The `_split_qkv_load_hook` function splits the pretrained `qkv` weights into separate `q`, `k`, and `v` weights when loading the model to ensure compatibility with any pretrained model.
|
||||
|
||||
```py
|
||||
def split_q_k_v_load_hook(self, state_dict, prefix, *args):
|
||||
keys_to_delete = []
|
||||
for key in list(state_dict.keys()):
|
||||
if "qkv." in key:
|
||||
# split q, k, v from the combined projection
|
||||
q, k, v = state_dict[key].chunk(3, dim=0)
|
||||
# replace with individual q, k, v projections
|
||||
state_dict[key.replace("qkv.", "q.")] = q
|
||||
state_dict[key.replace("qkv.", "k.")] = k
|
||||
state_dict[key.replace("qkv.", "v.")] = v
|
||||
# mark the old qkv key for deletion
|
||||
keys_to_delete.append(key)
|
||||
|
||||
# remove old qkv keys
|
||||
for key in keys_to_delete:
|
||||
del state_dict[key]
|
||||
```
|
||||
|
||||
3. In the `forward` pass, `q`, `k`, and `v` are computed separately while the rest of the attention mechanism remains the same.
|
||||
|
||||
```py
|
||||
def forward(self, hidden_states: torch.Tensor, output_attentions=False) -> torch.Tensor:
|
||||
batch_size, height, width, _ = hidden_states.shape
|
||||
qkv_shapes = (batch_size * self.num_attention_heads, height * width, -1)
|
||||
query = self.q(hidden_states).reshape((batch_size, height * width,self.num_attention_heads, -1)).permute(0,2,1,3).reshape(qkv_shapes)
|
||||
key = self.k(hidden_states).reshape((batch_size, height * width,self.num_attention_heads, -1)).permute(0,2,1,3).reshape(qkv_shapes)
|
||||
value = self.v(hidden_states).reshape((batch_size, height * width,self.num_attention_heads, -1)).permute(0,2,1,3).reshape(qkv_shapes)
|
||||
|
||||
attn_weights = (query * self.scale) @ key.transpose(-2, -1)
|
||||
|
||||
attn_weights = torch.nn.functional.softmax(attn_weights, dtype=torch.float32, dim=-1).to(query.dtype)
|
||||
attn_probs = nn.functional.dropout(attn_weights, p=self.dropout, training=self.training)
|
||||
attn_output = (attn_probs @ value).reshape(batch_size, self.num_attention_heads, height, width, -1)
|
||||
attn_output = attn_output.permute(0, 2, 3, 1, 4).reshape(batch_size, height, width, -1)
|
||||
attn_output = self.proj(attn_output)
|
||||
|
||||
if output_attentions:
|
||||
outputs = (attn_output, attn_weights)
|
||||
else:
|
||||
outputs = (attn_output, None)
|
||||
return outputs
|
||||
```
|
||||
|
||||
Assign the custom `SamVisionAttentionSplit` class to the original models `SamVisionAttention` module to replace it. All instances of `SamVisionAttention` in the model is replaced with the split attention version.
|
||||
|
||||
Load the model with [`~PreTrainedModel.from_pretrained`].
|
||||
|
||||
```py
|
||||
from transformers import SamModel
|
||||
|
||||
# load the pretrained SAM model
|
||||
model = SamModel.from_pretrained("facebook/sam-vit-base")
|
||||
|
||||
# replace the attention class in the vision_encoder module
|
||||
for layer in model.vision_encoder.layers:
|
||||
if hasattr(layer, "attn"):
|
||||
layer.attn = SamVisionAttentionSplit(model.config.vision_config, model.config.vision_config.window_size)
|
||||
```
|
||||
|
||||
## LoRA
|
||||
|
||||
With separate `q`, `k`, and `v` projections, apply LoRA to `q` and `v`.
|
||||
|
||||
Create a [LoraConfig](https://huggingface.co/docs/peft/package_reference/config#peft.PeftConfig) and specify the rank `r`, `lora_alpha`, `lora_dropout`, `task_type`, and most importantly, the modules to target.
|
||||
|
||||
```py
|
||||
from peft import LoraConfig, get_peft_model
|
||||
|
||||
config = LoraConfig(
|
||||
r=16,
|
||||
lora_alpha=32,
|
||||
# apply LoRA to q and v
|
||||
target_modules=["q", "v"],
|
||||
lora_dropout=0.1,
|
||||
task_type="FEATURE_EXTRACTION"
|
||||
)
|
||||
```
|
||||
|
||||
Pass the model and [LoraConfig](https://huggingface.co/docs/peft/package_reference/config#peft.PeftConfig) to [get_peft_model](https://huggingface.co/docs/peft/package_reference/peft_model#peft.get_peft_model) to apply LoRA to the model.
|
||||
|
||||
```py
|
||||
model = get_peft_model(model, config)
|
||||
```
|
||||
|
||||
Call [print_trainable_parameters](https://huggingface.co/docs/peft/package_reference/peft_model#peft.PeftMixedModel.print_trainable_parameters) to view the number of parameters you're training as a result versus the total number of parameters.
|
||||
|
||||
```py
|
||||
model.print_trainable_parameters()
|
||||
"trainable params: 589,824 || all params: 94,274,096 || trainable%: 0.6256"
|
||||
```
|
||||
@@ -0,0 +1,128 @@
|
||||
<!--Copyright 2022 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Hyperparameter search
|
||||
|
||||
Hyperparameters like learning rate, batch size, and number of epochs significantly affect training results. [`Trainer.hyperparameter_search`] finds the best combination by running multiple trials, each with a different set of values, and returning the best one.
|
||||
|
||||
Each trial initializes a fresh model with `model_init`, samples new hyperparameters, runs a full training loop, and reports an objective to the search backend. The backend uses each objective to inform the next trial. After all trials complete, the best hyperparameters are returned in a [`~trainer.utils.BestRun`].
|
||||
|
||||
## Initializing a model
|
||||
|
||||
Start each trial with a fresh model to avoid the previous runs' state. `model_init` is called at the start of each trial and returns a new model instance, so every trial begins from the same initial weights.
|
||||
|
||||
```py
|
||||
from transformers import AutoModelForCausalLM
|
||||
|
||||
def model_init(trial):
|
||||
return AutoModelForCausalLM.from_pretrained("Qwen/Qwen3-0.6B")
|
||||
|
||||
trainer = Trainer(
|
||||
model_init=model_init,
|
||||
args=args,
|
||||
train_dataset=train_dataset,
|
||||
eval_dataset=eval_dataset,
|
||||
)
|
||||
```
|
||||
|
||||
Don't pass `model=` and `model_init=` together or [`Trainer`] raises an error.
|
||||
|
||||
## Define the search space
|
||||
|
||||
Create a function that defines the search space. The format depends on the backend. If you don't define a `hp_space` function, the default
|
||||
search covers `learning_rate`, `num_train_epochs`, and `per_device_train_batch_size`.
|
||||
|
||||
```bash
|
||||
# install one of these hyperparam search backends
|
||||
pip install optuna
|
||||
pip install wandb
|
||||
pip install ray[tune]
|
||||
```
|
||||
|
||||
<hfoptions id="backends">
|
||||
<hfoption id="Optuna">
|
||||
|
||||
[Optuna](https://optuna.readthedocs.io/en/stable/index.html) is a lightweight framework for hyperparameter optimization.
|
||||
|
||||
```py
|
||||
def hp_space(trial):
|
||||
return {
|
||||
"learning_rate": trial.suggest_float("learning_rate", 1e-6, 1e-4, log=True),
|
||||
"per_device_train_batch_size": trial.suggest_categorical("per_device_train_batch_size", [16, 32, 64, 128]),
|
||||
}
|
||||
```
|
||||
|
||||
</hfoption>
|
||||
<hfoption id="Ray Tune">
|
||||
|
||||
[Ray Tune](https://docs.ray.io/en/latest/tune/index.html) is a scalable hyperparameter tuning library that can also distribute trials across multiple machines.
|
||||
|
||||
```py
|
||||
from ray import tune
|
||||
|
||||
def hp_space(trial):
|
||||
return {
|
||||
"learning_rate": tune.loguniform(1e-6, 1e-4),
|
||||
"per_device_train_batch_size": tune.choice([16, 32, 64, 128]),
|
||||
}
|
||||
```
|
||||
|
||||
</hfoption>
|
||||
<hfoption id="Weights & Biases">
|
||||
|
||||
[Weights & Biases](https://docs.wandb.ai/) is an experiment tracking platform with built-in hyperparameter search. It supports Bayesian, random, and grid search strategies.
|
||||
|
||||
```py
|
||||
def hp_space(trial):
|
||||
return {
|
||||
"method": "random",
|
||||
"metric": {"name": "objective", "goal": "minimize"},
|
||||
"parameters": {
|
||||
"learning_rate": {"distribution": "uniform", "min": 1e-6, "max": 1e-4},
|
||||
"per_device_train_batch_size": {"values": [16, 32, 64, 128]},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
</hfoption>
|
||||
</hfoptions>
|
||||
|
||||
## Run the search
|
||||
|
||||
Provide an optional `compute_objective` function to define the optimization target. It defaults to `eval_loss` if present, or the sum of all metric values otherwise. Pass an explicit function to avoid relying on this fallback. The search `backend` optimizes the objective over `n_trials` runs in a given `direction`.
|
||||
|
||||
```py
|
||||
def compute_objective(metrics):
|
||||
return metrics["eval_loss"]
|
||||
|
||||
best_run = trainer.hyperparameter_search(
|
||||
hp_space=hp_space,
|
||||
compute_objective=compute_objective,
|
||||
n_trials=30, # how many trials to run
|
||||
direction="minimize", # or "maximize" for metrics like accuracy/F1
|
||||
backend="optuna", # "optuna", "ray", or "wandb"
|
||||
)
|
||||
```
|
||||
|
||||
[`~Trainer.hyperparameter_search`] returns a [`~trainer.utils.BestRun`] containing the objective value and best hyperparameter combination.
|
||||
|
||||
```py
|
||||
best_run = trainer.hyperparameter_search(...)
|
||||
|
||||
best_run.objective # 0.38 (best eval loss)
|
||||
best_run.hyperparameters # {"learning_rate": 5e-5, "num_train_epochs": 4, ...}
|
||||
```
|
||||
|
||||
Apply the best hyperparameters to [`TrainingArguments`] and retrain on the full dataset.
|
||||
@@ -0,0 +1,232 @@
|
||||
<!--Copyright 2024 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Image processors
|
||||
|
||||
Image processors convert images into pixel values, tensors that represent image colors and size. The pixel values are inputs to a vision model. To ensure a pretrained model receives the correct input, an image processor can perform the following operations to make sure an image is exactly like the images a model was pretrained on.
|
||||
|
||||
- center-crop or resize an image
|
||||
- normalize or rescale pixel values
|
||||
|
||||
Use [`~ImageProcessingMixin.from_pretrained`] to load an image processors configuration (image size, whether to normalize and rescale, etc.) from a vision model on the Hugging Face [Hub](https://hf.co) or local directory. The configuration for each pretrained model is saved in a [preprocessor_config.json](https://huggingface.co/google/vit-base-patch16-224/blob/main/preprocessor_config.json) file.
|
||||
|
||||
```py
|
||||
from transformers import AutoImageProcessor
|
||||
|
||||
image_processor = AutoImageProcessor.from_pretrained("google/vit-base-patch16-224")
|
||||
```
|
||||
|
||||
Pass an image to the image processor to transform it into pixel values, and set `return_tensors="pt"` to return PyTorch tensors. Feel free to print out the inputs to see what the image looks like as a tensor.
|
||||
|
||||
```py
|
||||
from PIL import Image
|
||||
import requests
|
||||
|
||||
url = "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/image_processor_example.png"
|
||||
image = Image.open(requests.get(url, stream=True).raw).convert("RGB")
|
||||
inputs = image_processor(image, return_tensors="pt")
|
||||
```
|
||||
|
||||
This guide covers the image processor class and how to preprocess images for vision models.
|
||||
|
||||
## Image processor classes
|
||||
|
||||
Image processors use a backend-based architecture with two backends:
|
||||
|
||||
- [`TorchvisionBackend`] — the default [torchvision-backed](https://pytorch.org/vision/stable/index.html) implementation. GPU-accelerated and up to 33x faster than the PIL backend for batches of [torch.Tensor](https://pytorch.org/docs/stable/tensors.html) inputs. All models support this backend; newer models only support this one.
|
||||
- [`PilBackend`] — the PIL/NumPy alternative. Portable and CPU-only. Only available for older models, where it is useful to reproduce the exact numerical outputs of the original implementation.
|
||||
|
||||
The active backend on a loaded processor can be inspected with its `backend` attribute (e.g., `processor.backend == "torchvision"`). Each image processor subclasses [`ImageProcessingMixin`] which provides the [`~ImageProcessingMixin.from_pretrained`] and [`~ImageProcessingMixin.save_pretrained`] methods.
|
||||
|
||||
There are two ways you can load an image processor: with [`AutoImageProcessor`] or directly from a model-specific class.
|
||||
|
||||
<hfoptions id="image-processor-classes">
|
||||
<hfoption id="AutoImageProcessor">
|
||||
|
||||
The [AutoClass](./model_doc/auto) API provides a convenient method to load an image processor without directly specifying the model the image processor is associated with.
|
||||
|
||||
Use [`~AutoImageProcessor.from_pretrained`] with the `backend` argument to select the backend. When `backend` is omitted (the default), torchvision is picked when it is installed and PIL is used otherwise. Note that `backend="pil"` is only supported for older models; newer models only expose the torchvision backend.
|
||||
|
||||
> [!NOTE]
|
||||
> A small set of older models (Chameleon, Flava, Idefics3, SmolVLM) use Lanczos interpolation. Their default backend depends on your torchvision version. With torchvision > 0.27, Lanczos is supported natively and these models default to torchvision. Older torchvision version falls back to BICUBIC, so the default is PIL to preserve the original outputs. Pass `backend="torchvision"` explicitly to override the default.
|
||||
|
||||
```py
|
||||
from transformers import AutoImageProcessor
|
||||
|
||||
# Default: picks torchvision if available, otherwise pil
|
||||
image_processor = AutoImageProcessor.from_pretrained("google/vit-base-patch16-224")
|
||||
|
||||
# Explicitly request the torchvision backend
|
||||
image_processor = AutoImageProcessor.from_pretrained("google/vit-base-patch16-224", backend="torchvision")
|
||||
|
||||
# Explicitly request the PIL backend (only for models that support it)
|
||||
image_processor = AutoImageProcessor.from_pretrained("google/vit-base-patch16-224", backend="pil")
|
||||
```
|
||||
|
||||
</hfoption>
|
||||
<hfoption id="model-specific image processor">
|
||||
|
||||
Each image processor is associated with a specific pretrained vision model, and its configuration contains the model's expected size and normalization parameters.
|
||||
|
||||
Load the torchvision backend processor directly from the model-specific class.
|
||||
|
||||
```py
|
||||
from transformers import ViTImageProcessor
|
||||
|
||||
image_processor = ViTImageProcessor.from_pretrained("google/vit-base-patch16-224")
|
||||
```
|
||||
|
||||
For models that support it, you can load the PIL backend with the `Pil`-suffixed class. This is useful when you need exact numerical parity with the original implementation.
|
||||
|
||||
```py
|
||||
from transformers import ViTImageProcessorPil
|
||||
|
||||
image_processor = ViTImageProcessorPil.from_pretrained("google/vit-base-patch16-224")
|
||||
```
|
||||
|
||||
</hfoption>
|
||||
</hfoptions>
|
||||
|
||||
## Torchvision backend processors
|
||||
|
||||
[`TorchvisionBackend`] is the **default** backend. Make sure [torchvision](https://pytorch.org/get-started/locally/#mac-installation) is installed, then load it with `backend="torchvision"` (or simply omit `backend`, since torchvision is selected automatically when available).
|
||||
|
||||
```py
|
||||
from transformers import AutoImageProcessor
|
||||
|
||||
processor = AutoImageProcessor.from_pretrained("facebook/detr-resnet-50", backend="torchvision")
|
||||
```
|
||||
|
||||
Control which device processing is performed on with the `device` argument. Processing is performed on the same device as the input by default if the inputs are tensors, otherwise it falls back to CPU. The example below runs processing on a GPU.
|
||||
|
||||
```py
|
||||
from torchvision.io import read_image
|
||||
from transformers import DetrImageProcessor
|
||||
|
||||
images = read_image("image.jpg")
|
||||
processor = DetrImageProcessor.from_pretrained("facebook/detr-resnet-50")
|
||||
images_processed = processor(images, return_tensors="pt", device="cuda")
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary>Benchmarks</summary>
|
||||
|
||||
The benchmarks are obtained from an [AWS EC2 g5.2xlarge](https://aws.amazon.com/ec2/instance-types/g5/) instance with a NVIDIA A10G Tensor Core GPU.
|
||||
|
||||
<div class="flex">
|
||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/benchmark_results_full_pipeline_detr_fast_padded.png" />
|
||||
</div>
|
||||
<div class="flex">
|
||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/benchmark_results_full_pipeline_detr_fast_batched_compiled.png" />
|
||||
</div>
|
||||
<div class="flex">
|
||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/benchmark_results_full_pipeline_rt_detr_fast_single.png" />
|
||||
</div>
|
||||
<div class="flex">
|
||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/benchmark_results_full_pipeline_rt_detr_fast_batched.png" />
|
||||
</div>
|
||||
</details>
|
||||
|
||||
## Preprocess
|
||||
|
||||
Transformers' vision models expects the input as PyTorch tensors of pixel values. An image processor handles the conversion of images to pixel values, which is represented by the batch size, number of channels, height, and width. To achieve this, an image is resized (center cropped) and the pixel values are normalized and rescaled to the models expected values.
|
||||
|
||||
Image preprocessing is not the same as *image augmentation*. Image augmentation makes changes (brightness, colors, rotatation, etc.) to an image for the purpose of either creating new training examples or prevent overfitting. Image preprocessing makes changes to an image for the purpose of matching a pretrained model's expected input format.
|
||||
|
||||
Typically, images are augmented (to increase performance) and then preprocessed before being passed to a model. You can use any library ([Albumentations](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/image_classification_albumentations.ipynb), [Kornia](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/image_classification_kornia.ipynb)) for augmentation and an image processor for preprocessing.
|
||||
|
||||
This guide uses the torchvision [transforms](https://pytorch.org/vision/stable/transforms.html) module for augmentation.
|
||||
|
||||
Start by loading a small sample of the [food101](https://hf.co/datasets/food101) dataset.
|
||||
|
||||
```py
|
||||
from datasets import load_dataset
|
||||
|
||||
dataset = load_dataset("ethz/food101", split="train[:100]")
|
||||
```
|
||||
|
||||
From the [transforms](https://pytorch.org/vision/stable/transforms.html) module, use the [Compose](https://pytorch.org/vision/master/generated/torchvision.transforms.Compose.html) API to chain together [RandomResizedCrop](https://pytorch.org/vision/main/generated/torchvision.transforms.RandomResizedCrop.html) and [ColorJitter](https://pytorch.org/vision/main/generated/torchvision.transforms.ColorJitter.html). These transforms randomly crop and resize an image, and randomly adjusts an images colors.
|
||||
|
||||
The image size to randomly crop to can be retrieved from the image processor. For some models, an exact height and width are expected while for others, only the `shortest_edge` is required.
|
||||
|
||||
```py
|
||||
from torchvision.transforms import RandomResizedCrop, ColorJitter, Compose
|
||||
|
||||
size = (
|
||||
image_processor.size["shortest_edge"]
|
||||
if "shortest_edge" in image_processor.size
|
||||
else (image_processor.size["height"], image_processor.size["width"])
|
||||
)
|
||||
_transforms = Compose([RandomResizedCrop(size), ColorJitter(brightness=0.5, hue=0.5)])
|
||||
```
|
||||
|
||||
Apply the transforms to the images and convert them to the RGB format. Then pass the augmented images to the image processor to return the pixel values.
|
||||
|
||||
The `do_resize` parameter is set to `False` because the images have already been resized in the augmentation step by [RandomResizedCrop](https://pytorch.org/vision/main/generated/torchvision.transforms.RandomResizedCrop.html). If you don't augment the images, then the image processor automatically resizes and normalizes the images with the `image_mean` and `image_std` values. These values are found in the preprocessor configuration file.
|
||||
|
||||
```py
|
||||
def transforms(examples):
|
||||
images = [_transforms(img.convert("RGB")) for img in examples["image"]]
|
||||
examples["pixel_values"] = image_processor(images, do_resize=False, return_tensors="pt")["pixel_values"]
|
||||
return examples
|
||||
```
|
||||
|
||||
Apply the combined augmentation and preprocessing function to the entire dataset on the fly with [`~datasets.Dataset.set_transform`].
|
||||
|
||||
```py
|
||||
dataset.set_transform(transforms)
|
||||
```
|
||||
|
||||
Convert the pixel values back into an image to see how the image has been augmented and preprocessed.
|
||||
|
||||
```py
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
img = dataset[0]["pixel_values"]
|
||||
plt.imshow(img.permute(1, 2, 0))
|
||||
```
|
||||
|
||||
<div class="flex gap-4">
|
||||
<div>
|
||||
<img class="rounded-xl" src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/vision-preprocess-tutorial.png" />
|
||||
<figcaption class="mt-2 text-center text-sm text-gray-500">before</figcaption>
|
||||
</div>
|
||||
<div>
|
||||
<img class="rounded-xl" src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/preprocessed_image.png" />
|
||||
<figcaption class="mt-2 text-center text-sm text-gray-500">after</figcaption>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
For other vision tasks like object detection or segmentation, the image processor includes post-processing methods to convert a models raw output into meaningful predictions like bounding boxes or segmentation maps.
|
||||
|
||||
### Padding
|
||||
|
||||
Some models, like [DETR](./model_doc/detr), applies [scale augmentation](https://paperswithcode.com/method/image-scale-augmentation) during training which can cause images in a batch to have different sizes. Images with different sizes can't be batched together.
|
||||
|
||||
To fix this, pad the images with the special padding token `0`. Use the [pad](https://github.com/huggingface/transformers/blob/9578c2597e2d88b6f0b304b5a05864fd613ddcc1/src/transformers/models/detr/image_processing_detr.py#L1151) method to pad the images, and define a custom collate function to batch them together.
|
||||
|
||||
```py
|
||||
def collate_fn(batch):
|
||||
pixel_values = [item["pixel_values"] for item in batch]
|
||||
encoding = image_processor.pad(pixel_values, return_tensors="pt")
|
||||
labels = [item["labels"] for item in batch]
|
||||
batch = {}
|
||||
batch["pixel_values"] = encoding["pixel_values"]
|
||||
batch["pixel_mask"] = encoding["pixel_mask"]
|
||||
batch["labels"] = labels
|
||||
return batch
|
||||
```
|
||||
@@ -0,0 +1,65 @@
|
||||
<!--Copyright 2024 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
-->
|
||||
|
||||
# Transformers
|
||||
|
||||
<h3 align="center">
|
||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/transformers_as_a_model_definition.png"/>
|
||||
</h3>
|
||||
|
||||
Transformers acts as the model-definition framework for state-of-the-art machine learning models in text, computer
|
||||
vision, audio, video, and multimodal models, for both inference and training.
|
||||
|
||||
It centralizes the model definition so that this definition is agreed upon across the ecosystem. `transformers` is the
|
||||
pivot across frameworks: if a model definition is supported, it will be compatible with the majority of training
|
||||
frameworks (Axolotl, Unsloth, DeepSpeed, FSDP, PyTorch-Lightning, ...), inference engines (vLLM, SGLang, TGI, ...),
|
||||
and adjacent modeling libraries (llama.cpp, mlx, ...) which leverage the model definition from `transformers`.
|
||||
|
||||
We pledge to help support new state-of-the-art models and democratize their usage by having their model definition be
|
||||
simple, customizable, and efficient.
|
||||
|
||||
There are over 1M+ Transformers [model checkpoints](https://huggingface.co/models?library=transformers&sort=trending) on the [Hugging Face Hub](https://huggingface.com/models) you can use.
|
||||
|
||||
Explore the [Hub](https://huggingface.com/) today to find a model and use Transformers to help you get started right away.
|
||||
|
||||
Explore the [Models Timeline](./models_timeline) to discover the latest text, vision, audio and multimodal model architectures in Transformers.
|
||||
|
||||
## Features
|
||||
|
||||
Transformers provides everything you need for inference or training with state-of-the-art pretrained models. Some of the main features include:
|
||||
|
||||
- [Pipeline](./pipeline_tutorial): Simple and optimized inference class for many machine learning tasks like text generation, image segmentation, automatic speech recognition, document question answering, and more.
|
||||
- [Trainer](./trainer): A comprehensive trainer that supports features such as mixed precision, torch.compile, and FlashAttention for training and distributed training for PyTorch models.
|
||||
- [generate](./llm_tutorial): Fast text generation with large language models (LLMs) and vision language models (VLMs), including support for streaming and multiple decoding strategies.
|
||||
|
||||
## Design
|
||||
|
||||
> [!TIP]
|
||||
> Read our [Philosophy](./philosophy) to learn more about Transformers' design principles.
|
||||
|
||||
Transformers is designed for developers and machine learning engineers and researchers. Its main design principles are:
|
||||
|
||||
1. Fast and easy to use: Every model is implemented from only three main classes (configuration, model, and preprocessor) and can be quickly used for inference or training with [`Pipeline`] or [`Trainer`].
|
||||
2. Pretrained models: Reduce your carbon footprint, compute cost and time by using a pretrained model instead of training an entirely new one. Each pretrained model is reproduced as closely as possible to the original model and offers state-of-the-art performance.
|
||||
|
||||
<div class="flex justify-center">
|
||||
<a target="_blank" href="https://huggingface.co/support">
|
||||
<img alt="HuggingFace Expert Acceleration Program" src="https://hf.co/datasets/huggingface/documentation-images/resolve/81d7d9201fd4ceb537fc4cebc22c29c37a2ed216/transformers/transformers-index.png" style="width: 100%; max-width: 600px; border: 1px solid #eee; border-radius: 4px; box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);">
|
||||
</a>
|
||||
</div>
|
||||
|
||||
## Learn
|
||||
|
||||
If you're new to Transformers or want to learn more about transformer models, we recommend starting with the [LLM course](https://huggingface.co/learn/llm-course/chapter1/1?fw=pt). This comprehensive course covers everything from the fundamentals of how transformer models work to practical applications across various tasks. You'll learn the complete workflow, from curating high-quality datasets to fine-tuning large language models and implementing reasoning capabilities. The course contains both theoretical and hands-on exercises to build a solid foundational knowledge of transformer models as you learn.
|
||||
@@ -0,0 +1,164 @@
|
||||
<!---
|
||||
Copyright 2024 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Installation
|
||||
|
||||
Transformers works with [PyTorch](https://pytorch.org/get-started/locally/). It has been tested on Python 3.10+ and PyTorch 2.4+.
|
||||
|
||||
## Virtual environment
|
||||
|
||||
[uv](https://docs.astral.sh/uv/) is an extremely fast Rust-based Python package and project manager and requires a [virtual environment](https://docs.astral.sh/uv/pip/environments/) by default to manage different projects and avoids compatibility issues between dependencies.
|
||||
|
||||
It can be used as a drop-in replacement for [pip](https://pip.pypa.io/en/stable/), but if you prefer to use pip, remove `uv` from the commands below.
|
||||
|
||||
> [!TIP]
|
||||
> Refer to the uv [installation](https://docs.astral.sh/uv/guides/install-python/) docs to install uv.
|
||||
|
||||
Create a virtual environment to install Transformers in.
|
||||
|
||||
```bash
|
||||
uv venv .env
|
||||
source .env/bin/activate
|
||||
```
|
||||
|
||||
## Python
|
||||
|
||||
Install Transformers with the following command.
|
||||
|
||||
[uv](https://docs.astral.sh/uv/) is a fast Rust-based Python package and project manager.
|
||||
|
||||
```bash
|
||||
uv pip install transformers
|
||||
```
|
||||
|
||||
For GPU acceleration, install the appropriate CUDA drivers for [PyTorch](https://pytorch.org/get-started/locally).
|
||||
|
||||
Run the command below to check if your system detects an NVIDIA GPU.
|
||||
|
||||
```bash
|
||||
nvidia-smi
|
||||
```
|
||||
|
||||
To install a CPU-only version of Transformers, run the following command.
|
||||
|
||||
```bash
|
||||
uv pip install torch --index-url https://download.pytorch.org/whl/cpu
|
||||
uv pip install transformers
|
||||
```
|
||||
|
||||
Test whether the install was successful with the following command. It should return a label and score for the provided text.
|
||||
|
||||
```bash
|
||||
python -c "from transformers import pipeline; print(pipeline('sentiment-analysis')('hugging face is the best'))"
|
||||
[{'label': 'POSITIVE', 'score': 0.9998704791069031}]
|
||||
```
|
||||
|
||||
### Source install
|
||||
|
||||
Installing from source installs the *latest* version rather than the *stable* version of the library. It ensures you have the most up-to-date changes in Transformers and it's useful for experimenting with the latest features or fixing a bug that hasn't been officially released in the stable version yet.
|
||||
|
||||
The downside is that the latest version may not always be stable. If you encounter any problems, please open a [GitHub Issue](https://github.com/huggingface/transformers/issues) so we can fix it as soon as possible.
|
||||
|
||||
Install from source with the following command.
|
||||
|
||||
```bash
|
||||
uv pip install git+https://github.com/huggingface/transformers
|
||||
```
|
||||
|
||||
Check if the install was successful with the command below. It should return a label and score for the provided text.
|
||||
|
||||
```bash
|
||||
python -c "from transformers import pipeline; print(pipeline('sentiment-analysis')('hugging face is the best'))"
|
||||
[{'label': 'POSITIVE', 'score': 0.9998704791069031}]
|
||||
```
|
||||
|
||||
### Editable install
|
||||
|
||||
An [editable install](https://pip.pypa.io/en/stable/topics/local-project-installs/#editable-installs) is useful if you're developing locally with Transformers. It links your local copy of Transformers to the Transformers [repository](https://github.com/huggingface/transformers) instead of copying the files. The files are added to Python's import path.
|
||||
|
||||
```bash
|
||||
git clone https://github.com/huggingface/transformers.git
|
||||
cd transformers
|
||||
uv pip install -e .
|
||||
```
|
||||
|
||||
> [!WARNING]
|
||||
> You must keep the local Transformers folder to keep using it.
|
||||
|
||||
Update your local version of Transformers with the latest changes in the main repository with the following command.
|
||||
|
||||
```bash
|
||||
cd ~/transformers/
|
||||
git pull
|
||||
```
|
||||
|
||||
## conda
|
||||
|
||||
[conda](https://docs.conda.io/projects/conda/en/stable/#) is a language-agnostic package manager. Install Transformers from the [conda-forge](https://anaconda.org/conda-forge/transformers) channel in your newly created virtual environment.
|
||||
|
||||
```bash
|
||||
conda install conda-forge::transformers
|
||||
```
|
||||
|
||||
## Set up
|
||||
|
||||
After installation, you can configure the Transformers cache location or set up the library for offline usage.
|
||||
|
||||
### Cache directory
|
||||
|
||||
When you load a pretrained model with [`~PreTrainedModel.from_pretrained`], the model is downloaded from the Hub and locally cached.
|
||||
|
||||
Every time you load a model, it checks whether the cached model is up-to-date. If it's the same, then the local model is loaded. If it's not the same, the newer model is downloaded and cached.
|
||||
|
||||
The default directory given by the shell environment variable `HF_HUB_CACHE` is `~/.cache/huggingface/hub`. On Windows, the default directory is `C:\Users\username\.cache\huggingface\hub`.
|
||||
|
||||
Cache a model in a different directory by changing the path in the following shell environment variables (listed by priority).
|
||||
|
||||
1. [HF_HUB_CACHE](https://hf.co/docs/huggingface_hub/package_reference/environment_variables#hfhubcache) (default)
|
||||
2. [HF_HOME](https://hf.co/docs/huggingface_hub/package_reference/environment_variables#hfhome)
|
||||
3. [XDG_CACHE_HOME](https://hf.co/docs/huggingface_hub/package_reference/environment_variables#xdgcachehome) + `/huggingface` (only if `HF_HOME` is not set)
|
||||
|
||||
### Offline mode
|
||||
|
||||
To use Transformers in an offline or firewalled environment requires the downloaded and cached files ahead of time. Download a model repository from the Hub with the [`~huggingface_hub.snapshot_download`] method.
|
||||
|
||||
> [!TIP]
|
||||
> Refer to the [Download files from the Hub](https://hf.co/docs/huggingface_hub/guides/download) guide for more options for downloading files from the Hub. You can download files from specific revisions, download from the CLI, and even filter which files to download from a repository.
|
||||
|
||||
```py
|
||||
from huggingface_hub import snapshot_download
|
||||
|
||||
snapshot_download(repo_id="meta-llama/Llama-2-7b-hf", repo_type="model")
|
||||
```
|
||||
|
||||
Set the environment variable `HF_HUB_OFFLINE=1` to prevent HTTP calls to the Hub when loading a model.
|
||||
|
||||
```bash
|
||||
HF_HUB_OFFLINE=1 \
|
||||
python examples/pytorch/language-modeling/run_clm.py --model_name_or_path meta-llama/Llama-2-7b-hf --dataset_name wikitext ...
|
||||
```
|
||||
|
||||
Another option for only loading cached files is to set `local_files_only=True` in [`~PreTrainedModel.from_pretrained`].
|
||||
|
||||
```py
|
||||
from transformers import LlamaForCausalLM
|
||||
|
||||
model = LlamaForCausalLM.from_pretrained("./path/to/local/directory", local_files_only=True)
|
||||
```
|
||||
@@ -0,0 +1,39 @@
|
||||
<!--Copyright 2023 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Utilities for `FeatureExtractors`
|
||||
|
||||
This page lists all the utility functions that can be used by the audio [`FeatureExtractor`] in order to compute special features from a raw audio using common algorithms such as *Short Time Fourier Transform* or *log mel spectrogram*.
|
||||
|
||||
Most of those are only useful if you are studying the code of the audio processors in the library.
|
||||
|
||||
## Audio Transformations
|
||||
|
||||
[[autodoc]] audio_utils.hertz_to_mel
|
||||
|
||||
[[autodoc]] audio_utils.mel_to_hertz
|
||||
|
||||
[[autodoc]] audio_utils.mel_filter_bank
|
||||
|
||||
[[autodoc]] audio_utils.optimal_fft_length
|
||||
|
||||
[[autodoc]] audio_utils.window_function
|
||||
|
||||
[[autodoc]] audio_utils.spectrogram
|
||||
|
||||
[[autodoc]] audio_utils.power_to_db
|
||||
|
||||
[[autodoc]] audio_utils.amplitude_to_db
|
||||
@@ -0,0 +1,45 @@
|
||||
<!--Copyright 2021 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# General Utilities
|
||||
|
||||
This page lists all of Transformers general utility functions that are found in the file `utils.py`.
|
||||
|
||||
Most of those are only useful if you are studying the general code in the library.
|
||||
|
||||
## Enums and namedtuples
|
||||
|
||||
[[autodoc]] utils.ExplicitEnum
|
||||
|
||||
[[autodoc]] utils.PaddingStrategy
|
||||
|
||||
[[autodoc]] utils.TensorType
|
||||
|
||||
## Special Decorators
|
||||
|
||||
[[autodoc]] utils.add_start_docstrings
|
||||
|
||||
[[autodoc]] utils.add_start_docstrings_to_model_forward
|
||||
|
||||
[[autodoc]] utils.add_end_docstrings
|
||||
|
||||
[[autodoc]] utils.add_code_sample_docstrings
|
||||
|
||||
[[autodoc]] utils.replace_return_docstrings
|
||||
|
||||
## Other Utilities
|
||||
|
||||
[[autodoc]] utils._LazyModule
|
||||
@@ -0,0 +1,284 @@
|
||||
<!--Copyright 2020 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Utilities for Generation
|
||||
|
||||
This page lists all the utility functions used by [`~generation.GenerationMixin.generate`].
|
||||
|
||||
## Generate Outputs
|
||||
|
||||
The output of [`~generation.GenerationMixin.generate`] is an instance of a subclass of
|
||||
[`~utils.ModelOutput`]. This output is a data structure containing all the information returned
|
||||
by [`~generation.GenerationMixin.generate`], but that can also be used as tuple or dictionary.
|
||||
|
||||
Here's an example:
|
||||
|
||||
```python
|
||||
from transformers import GPT2Tokenizer, GPT2LMHeadModel
|
||||
|
||||
tokenizer = GPT2Tokenizer.from_pretrained("openai-community/gpt2")
|
||||
model = GPT2LMHeadModel.from_pretrained("openai-community/gpt2")
|
||||
|
||||
inputs = tokenizer("Hello, my dog is cute and ", return_tensors="pt")
|
||||
generation_output = model.generate(**inputs, return_dict_in_generate=True, output_scores=True)
|
||||
```
|
||||
|
||||
The `generation_output` object is a [`~generation.GenerateDecoderOnlyOutput`], as we can
|
||||
see in the documentation of that class below, it means it has the following attributes:
|
||||
|
||||
- `sequences`: the generated sequences of tokens
|
||||
- `scores` (optional): the prediction scores of the language modelling head, for each generation step
|
||||
- `hidden_states` (optional): the hidden states of the model, for each generation step
|
||||
- `attentions` (optional): the attention weights of the model, for each generation step
|
||||
|
||||
Here we have the `scores` since we passed along `output_scores=True`, but we don't have `hidden_states` and
|
||||
`attentions` because we didn't pass `output_hidden_states=True` or `output_attentions=True`.
|
||||
|
||||
You can access each attribute as you would usually do, and if that attribute has not been returned by the model, you
|
||||
will get `None`. Here for instance `generation_output.scores` are all the generated prediction scores of the
|
||||
language modeling head, and `generation_output.attentions` is `None`.
|
||||
|
||||
When using our `generation_output` object as a tuple, it only keeps the attributes that don't have `None` values.
|
||||
Here, for instance, it has two elements, `loss` then `logits`, so
|
||||
|
||||
```python
|
||||
generation_output[:2]
|
||||
```
|
||||
|
||||
will return the tuple `(generation_output.sequences, generation_output.scores)` for instance.
|
||||
|
||||
When using our `generation_output` object as a dictionary, it only keeps the attributes that don't have `None`
|
||||
values. Here, for instance, it has two keys that are `sequences` and `scores`.
|
||||
|
||||
We document here all output types.
|
||||
|
||||
[[autodoc]] generation.GenerateDecoderOnlyOutput
|
||||
|
||||
[[autodoc]] generation.GenerateEncoderDecoderOutput
|
||||
|
||||
[[autodoc]] generation.GenerateBeamDecoderOnlyOutput
|
||||
|
||||
[[autodoc]] generation.GenerateBeamEncoderDecoderOutput
|
||||
|
||||
## LogitsProcessor
|
||||
|
||||
A [`LogitsProcessor`] can be used to modify the prediction scores of a language model head for
|
||||
generation.
|
||||
|
||||
[[autodoc]] AlternatingCodebooksLogitsProcessor
|
||||
- __call__
|
||||
|
||||
[[autodoc]] ClassifierFreeGuidanceLogitsProcessor
|
||||
- __call__
|
||||
|
||||
[[autodoc]] EncoderNoRepeatNGramLogitsProcessor
|
||||
- __call__
|
||||
|
||||
[[autodoc]] EncoderRepetitionPenaltyLogitsProcessor
|
||||
- __call__
|
||||
|
||||
[[autodoc]] EpsilonLogitsWarper
|
||||
- __call__
|
||||
|
||||
[[autodoc]] EtaLogitsWarper
|
||||
- __call__
|
||||
|
||||
[[autodoc]] ExponentialDecayLengthPenalty
|
||||
- __call__
|
||||
|
||||
[[autodoc]] ForcedBOSTokenLogitsProcessor
|
||||
- __call__
|
||||
|
||||
[[autodoc]] ForcedEOSTokenLogitsProcessor
|
||||
- __call__
|
||||
|
||||
[[autodoc]] InfNanRemoveLogitsProcessor
|
||||
- __call__
|
||||
|
||||
[[autodoc]] LogitNormalization
|
||||
- __call__
|
||||
|
||||
[[autodoc]] LogitsProcessor
|
||||
- __call__
|
||||
|
||||
[[autodoc]] LogitsProcessorList
|
||||
- __call__
|
||||
|
||||
[[autodoc]] MinLengthLogitsProcessor
|
||||
- __call__
|
||||
|
||||
[[autodoc]] MinNewTokensLengthLogitsProcessor
|
||||
- __call__
|
||||
|
||||
[[autodoc]] MinPLogitsWarper
|
||||
- __call__
|
||||
|
||||
[[autodoc]] NoBadWordsLogitsProcessor
|
||||
- __call__
|
||||
|
||||
[[autodoc]] NoRepeatNGramLogitsProcessor
|
||||
- __call__
|
||||
|
||||
[[autodoc]] PrefixConstrainedLogitsProcessor
|
||||
- __call__
|
||||
|
||||
[[autodoc]] RepetitionPenaltyLogitsProcessor
|
||||
- __call__
|
||||
|
||||
[[autodoc]] SequenceBiasLogitsProcessor
|
||||
- __call__
|
||||
|
||||
[[autodoc]] SuppressTokensAtBeginLogitsProcessor
|
||||
- __call__
|
||||
|
||||
[[autodoc]] SuppressTokensLogitsProcessor
|
||||
- __call__
|
||||
|
||||
[[autodoc]] SynthIDTextWatermarkLogitsProcessor
|
||||
- __call__
|
||||
|
||||
[[autodoc]] TemperatureLogitsWarper
|
||||
- __call__
|
||||
|
||||
[[autodoc]] TopHLogitsWarper
|
||||
- __call__
|
||||
|
||||
[[autodoc]] TopKLogitsWarper
|
||||
- __call__
|
||||
|
||||
[[autodoc]] TopPLogitsWarper
|
||||
- __call__
|
||||
|
||||
[[autodoc]] TypicalLogitsWarper
|
||||
- __call__
|
||||
|
||||
[[autodoc]] UnbatchedClassifierFreeGuidanceLogitsProcessor
|
||||
- __call__
|
||||
|
||||
[[autodoc]] WhisperTimeStampLogitsProcessor
|
||||
- __call__
|
||||
|
||||
[[autodoc]] WatermarkLogitsProcessor
|
||||
- __call__
|
||||
|
||||
## StoppingCriteria
|
||||
|
||||
A [`StoppingCriteria`] can be used to change when to stop generation (other than EOS token). Please note that this is exclusively available to our PyTorch implementations.
|
||||
|
||||
[[autodoc]] StoppingCriteria
|
||||
- __call__
|
||||
|
||||
[[autodoc]] StoppingCriteriaList
|
||||
- __call__
|
||||
|
||||
[[autodoc]] MaxLengthCriteria
|
||||
- __call__
|
||||
|
||||
[[autodoc]] MaxTimeCriteria
|
||||
- __call__
|
||||
|
||||
[[autodoc]] StopStringCriteria
|
||||
- __call__
|
||||
|
||||
[[autodoc]] EosTokenCriteria
|
||||
- __call__
|
||||
|
||||
## Streamers
|
||||
|
||||
[[autodoc]] TextStreamer
|
||||
|
||||
[[autodoc]] TextIteratorStreamer
|
||||
|
||||
[[autodoc]] AsyncTextIteratorStreamer
|
||||
|
||||
[[autodoc]] TextDiffusionStreamer
|
||||
|
||||
## Caches
|
||||
|
||||
[[autodoc]] CacheLayerMixin
|
||||
- update
|
||||
- get_seq_length
|
||||
- get_mask_sizes
|
||||
- get_max_length
|
||||
- reset
|
||||
- reorder_cache
|
||||
- lazy_initialization
|
||||
|
||||
[[autodoc]] DynamicLayer
|
||||
- update
|
||||
- lazy_initialization
|
||||
- crop
|
||||
- batch_repeat_interleave
|
||||
- batch_select_indices
|
||||
|
||||
[[autodoc]] StaticLayer
|
||||
- update
|
||||
- lazy_initialization
|
||||
|
||||
[[autodoc]] StaticSlidingWindowLayer
|
||||
- update
|
||||
- lazy_initialization
|
||||
|
||||
[[autodoc]] QuantoQuantizedLayer
|
||||
- update
|
||||
- lazy_initialization
|
||||
|
||||
[[autodoc]] HQQQuantizedLayer
|
||||
- update
|
||||
- lazy_initialization
|
||||
|
||||
[[autodoc]] Cache
|
||||
- update
|
||||
- early_initialization
|
||||
- get_seq_length
|
||||
- get_mask_sizes
|
||||
- get_max_length
|
||||
- reset
|
||||
- reorder_cache
|
||||
- crop
|
||||
- batch_repeat_interleave
|
||||
- batch_select_indices
|
||||
|
||||
[[autodoc]] DynamicCache
|
||||
|
||||
[[autodoc]] StaticCache
|
||||
|
||||
[[autodoc]] QuantizedCache
|
||||
|
||||
[[autodoc]] EncoderDecoderCache
|
||||
|
||||
## Watermark Utils
|
||||
|
||||
[[autodoc]] WatermarkingConfig
|
||||
- __call__
|
||||
|
||||
[[autodoc]] WatermarkDetector
|
||||
- __call__
|
||||
|
||||
[[autodoc]] BayesianDetectorConfig
|
||||
|
||||
[[autodoc]] BayesianDetectorModel
|
||||
- forward
|
||||
|
||||
[[autodoc]] SynthIDTextWatermarkingConfig
|
||||
|
||||
[[autodoc]] SynthIDTextWatermarkDetector
|
||||
- __call__
|
||||
|
||||
## Compile Utils
|
||||
|
||||
[[autodoc]] CompileConfig
|
||||
- __call__
|
||||
@@ -0,0 +1,48 @@
|
||||
<!--Copyright 2022 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Utilities for Image Processors
|
||||
|
||||
This page lists all the utility functions used by the image processors, mainly the functional
|
||||
transformations used to process the images.
|
||||
|
||||
Most of those are only useful if you are studying the code of the image processors in the library.
|
||||
|
||||
## Image Transformations
|
||||
|
||||
[[autodoc]] image_transforms.center_crop
|
||||
|
||||
[[autodoc]] image_transforms.center_to_corners_format
|
||||
|
||||
[[autodoc]] image_transforms.corners_to_center_format
|
||||
|
||||
[[autodoc]] image_transforms.id_to_rgb
|
||||
|
||||
[[autodoc]] image_transforms.normalize
|
||||
|
||||
[[autodoc]] image_transforms.pad
|
||||
|
||||
[[autodoc]] image_transforms.rgb_to_id
|
||||
|
||||
[[autodoc]] image_transforms.rescale
|
||||
|
||||
[[autodoc]] image_transforms.resize
|
||||
|
||||
[[autodoc]] image_transforms.to_pil_image
|
||||
|
||||
## ImageProcessingMixin
|
||||
|
||||
[[autodoc]] image_processing_utils.ImageProcessingMixin
|
||||
@@ -0,0 +1,101 @@
|
||||
<!--Copyright 2025 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Import Utilities
|
||||
|
||||
This page goes through the transformers utilities to enable lazy and fast object import.
|
||||
While we strive for minimal dependencies, some models have specific dependencies requirements that cannot be
|
||||
worked around. We don't want for all users of `transformers` to have to install those dependencies to use other models,
|
||||
we therefore mark those as soft dependencies rather than hard dependencies.
|
||||
|
||||
The transformers toolkit is not made to error-out on import of a model that has a specific dependency; instead, an
|
||||
object for which you are lacking a dependency will error-out when calling any method on it. As an example, if
|
||||
`torchvision` isn't installed, the fast image processors will not be available.
|
||||
|
||||
This object is still importable:
|
||||
|
||||
```python
|
||||
>>> from transformers import DetrImageProcessor
|
||||
>>> print(DetrImageProcessor)
|
||||
<class 'DetrImageProcessor'>
|
||||
```
|
||||
|
||||
However, no method can be called on that object:
|
||||
|
||||
```python
|
||||
>>> DetrImageProcessor.from_pretrained()
|
||||
ImportError:
|
||||
DetrImageProcessor requires the Torchvision library but it was not found in your environment. Check out the instructions on the
|
||||
installation page: https://pytorch.org/get-started/locally/ and follow the ones that match your environment.
|
||||
Please note that you may need to restart your runtime after installation.
|
||||
```
|
||||
|
||||
Let's see how to specify specific object dependencies.
|
||||
|
||||
## Specifying Object Dependencies
|
||||
|
||||
### Filename-based
|
||||
|
||||
All objects under a given filename have an automatic dependency to the tool linked to the filename
|
||||
|
||||
**PyTorch**: All files starting with `modeling_` have an automatic PyTorch dependency
|
||||
|
||||
**Tokenizers**: All files starting with `tokenization_` and ending with `_fast` have an automatic `tokenizers` dependency
|
||||
|
||||
**Vision**: All files starting with `image_processing_` have an automatic dependency to the `vision` dependency group;
|
||||
at the time of writing, this only contains the `pillow` dependency.
|
||||
|
||||
**Vision + Torch + Torchvision**: All files starting with `image_processing_` and ending with `_fast` have an automatic
|
||||
dependency to `vision`, `torch`, and `torchvision`.
|
||||
|
||||
All of these automatic dependencies are added on top of the explicit dependencies that are detailed below.
|
||||
|
||||
### Explicit Object Dependencies
|
||||
|
||||
We add a method called `requires` that is used to explicitly specify the dependencies of a given object. As an
|
||||
example, the `Trainer` class has two hard dependencies: `torch` and `accelerate`. Here is how we specify these
|
||||
required dependencies:
|
||||
|
||||
```python
|
||||
from .utils.import_utils import requires
|
||||
|
||||
@requires(backends=("torch", "accelerate"))
|
||||
class Trainer:
|
||||
...
|
||||
```
|
||||
|
||||
Backends that can be added here are all the backends that are available in the `import_utils.py` module.
|
||||
|
||||
Additionally, specific versions can be specified in each backend. For example, this is how you would specify
|
||||
a requirement on torch>=2.6 on the `Trainer` class:
|
||||
|
||||
```python
|
||||
from .utils.import_utils import requires
|
||||
|
||||
@requires(backends=("torch>=2.6", "accelerate"))
|
||||
class Trainer:
|
||||
...
|
||||
```
|
||||
|
||||
You can specify the following operators: `==`, `>`, `>=`, `<`, `<=`, `!=`.
|
||||
|
||||
## Methods
|
||||
|
||||
[[autodoc]] utils.import_utils.define_import_structure
|
||||
|
||||
[[autodoc]] utils.import_utils.requires
|
||||
|
||||
[[autodoc]] utils.import_utils.requires_backends
|
||||
@@ -0,0 +1,439 @@
|
||||
<!--Copyright 2025 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Model debugging toolboxes
|
||||
|
||||
This page lists all the debugging and model adding tools used by the library, as well as the utility functions it
|
||||
provides for it.
|
||||
|
||||
Most of those are only useful if you are adding new models in the library.
|
||||
|
||||
## Model addition debuggers
|
||||
|
||||
### Model addition debugger - context manager for model adders
|
||||
|
||||
This context manager is a power user tool intended for model adders. It tracks all forward calls within a model forward
|
||||
and logs a slice of each input and output on a nested JSON. To note, this context manager enforces `torch.no_grad()`.
|
||||
|
||||
### Rationale
|
||||
|
||||
When porting models to transformers, even from python to python, model adders often have to do a lot of manual
|
||||
operations, involving saving and loading tensors, comparing dtypes, etc. This small tool can hopefully shave off some
|
||||
time.
|
||||
|
||||
### Usage
|
||||
|
||||
Add this context manager as follows to debug a model:
|
||||
|
||||
```python
|
||||
import torch
|
||||
from PIL import Image
|
||||
import requests
|
||||
from transformers import LlavaProcessor, LlavaForConditionalGeneration
|
||||
from transformers.model_debugging_utils import model_addition_debugger_context
|
||||
torch.random.manual_seed(673)
|
||||
|
||||
# load pretrained model and processor
|
||||
model_id = "llava-hf/llava-1.5-7b-hf"
|
||||
processor = LlavaProcessor.from_pretrained(model_id)
|
||||
model = LlavaForConditionalGeneration.from_pretrained(model_id)
|
||||
|
||||
# create random image input
|
||||
random_image = Image.fromarray(torch.randint(0, 256, (224, 224, 3), dtype=torch.uint8).numpy())
|
||||
|
||||
# prompt
|
||||
prompt = "<image>Describe this image."
|
||||
|
||||
# process inputs
|
||||
inputs = processor(text=prompt, images=random_image, return_tensors="pt")
|
||||
|
||||
# call forward method (not .generate!)
|
||||
with model_addition_debugger_context(
|
||||
model,
|
||||
debug_path="optional_path_to_your_directory",
|
||||
do_prune_layers=False # This will output ALL the layers of a model.
|
||||
):
|
||||
output = model.forward(**inputs)
|
||||
|
||||
```
|
||||
|
||||
### Reading results
|
||||
|
||||
The debugger generates two files from the forward call, both with the same base name, but ending either with
|
||||
`_SUMMARY.json` or with `_FULL_TENSORS.json`.
|
||||
|
||||
The first one will contain a summary of each module's _input_ and _output_ tensor values and shapes.
|
||||
|
||||
```json
|
||||
{
|
||||
"module_path": "MolmoForConditionalGeneration",
|
||||
"inputs": {
|
||||
"args": [],
|
||||
"kwargs": {
|
||||
"input_ids": {
|
||||
"shape": "torch.Size([1, 589])",
|
||||
"dtype": "torch.int64"
|
||||
},
|
||||
"attention_mask": {
|
||||
"shape": "torch.Size([1, 589])",
|
||||
"dtype": "torch.int64"
|
||||
},
|
||||
"pixel_values": {
|
||||
"shape": "torch.Size([1, 5, 576, 588])",
|
||||
"dtype": "torch.float32",
|
||||
"mean": "tensor(-8.9514e-01, device='cuda:0')",
|
||||
"std": "tensor(9.2586e-01, device='cuda:0')",
|
||||
"min": "tensor(-1.7923e+00, device='cuda:0')",
|
||||
"max": "tensor(1.8899e+00, device='cuda:0')"
|
||||
}
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"module_path": "MolmoForConditionalGeneration.language_model.model.embed_tokens",
|
||||
"inputs": {
|
||||
"args": [
|
||||
{
|
||||
"shape": "torch.Size([1, 589])",
|
||||
"dtype": "torch.int64"
|
||||
}
|
||||
]
|
||||
},
|
||||
"outputs": {
|
||||
"shape": "torch.Size([1, 589, 3584])",
|
||||
"dtype": "torch.float32",
|
||||
"mean": "tensor(6.5460e-06, device='cuda:0')",
|
||||
"std": "tensor(2.3807e-02, device='cuda:0')",
|
||||
"min": "tensor(-3.3398e-01, device='cuda:0')",
|
||||
"max": "tensor(3.9453e-01, device='cuda:0')"
|
||||
}
|
||||
},
|
||||
{
|
||||
"module_path": "MolmoForConditionalGeneration.vision_tower",
|
||||
"inputs": {
|
||||
"args": [
|
||||
{
|
||||
"shape": "torch.Size([5, 1, 576, 588])",
|
||||
"dtype": "torch.float32",
|
||||
"mean": "tensor(-8.9514e-01, device='cuda:0')",
|
||||
"std": "tensor(9.2586e-01, device='cuda:0')",
|
||||
"min": "tensor(-1.7923e+00, device='cuda:0')",
|
||||
"max": "tensor(1.8899e+00, device='cuda:0')"
|
||||
}
|
||||
],
|
||||
"kwargs": {
|
||||
"output_hidden_states": "True"
|
||||
}
|
||||
},
|
||||
"children": [
|
||||
{ ... and so on
|
||||
```
|
||||
|
||||
The `_FULL_TENSORS.json` file will display a full view of all tensors, which is useful for comparing two files.
|
||||
|
||||
```json
|
||||
"pixel_values": {
|
||||
"shape": "torch.Size([1, 5, 576, 588])",
|
||||
"dtype": "torch.float32",
|
||||
"value": [
|
||||
"tensor([[[[-1.7923e+00, -1.7521e+00, -1.4802e+00, ..., -1.7923e+00, -1.7521e+00, -1.4802e+00],",
|
||||
" [-1.7923e+00, -1.7521e+00, -1.4802e+00, ..., -1.7923e+00, -1.7521e+00, -1.4802e+00],",
|
||||
" [-1.7923e+00, -1.7521e+00, -1.4802e+00, ..., -1.7923e+00, -1.7521e+00, -1.4802e+00],",
|
||||
" ...,",
|
||||
" [-1.7923e+00, -1.7521e+00, -1.4802e+00, ..., -1.7923e+00, -1.7521e+00, -1.4802e+00],",
|
||||
" [-1.7923e+00, -1.7521e+00, -1.4802e+00, ..., -1.7923e+00, -1.7521e+00, -1.4802e+00],",
|
||||
" [-1.7923e+00, -1.7521e+00, -1.4802e+00, ..., -1.7923e+00, -1.7521e+00, -1.4802e+00]],",
|
||||
"",
|
||||
" [[-1.7923e+00, -1.7521e+00, -1.4802e+00, ..., -1.7923e+00, -1.7521e+00, -1.4802e+00],",
|
||||
" [-1.7923e+00, -1.7521e+00, -1.4802e+00, ..., -1.7923e+00, -1.7521e+00, -1.4802e+00],",
|
||||
" [-1.7923e+00, -1.7521e+00, -1.4802e+00, ..., -1.7923e+00, -1.7521e+00, -1.4802e+00],",
|
||||
" ...,",
|
||||
" [-1.4857e+00, -1.4820e+00, -1.2100e+00, ..., -6.0979e-01, -5.9650e-01, -3.8527e-01],",
|
||||
" [-1.6755e+00, -1.7221e+00, -1.4518e+00, ..., -7.5577e-01, -7.4658e-01, -5.5592e-01],",
|
||||
" [-7.9957e-01, -8.2162e-01, -5.7014e-01, ..., -1.3689e+00, -1.3169e+00, -1.0678e+00]],",
|
||||
"",
|
||||
" [[-1.7923e+00, -1.7521e+00, -1.4802e+00, ..., -1.7923e+00, -1.7521e+00, -1.4802e+00],",
|
||||
" [-1.7923e+00, -1.7521e+00, -1.4802e+00, ..., -1.7923e+00, -1.7521e+00, -1.4802e+00],",
|
||||
" [-1.7923e+00, -1.7521e+00, -1.4802e+00, ..., -1.7923e+00, -1.7521e+00, -1.4802e+00],",
|
||||
" ...,",
|
||||
" [-3.0322e-01, -5.0645e-01, -5.8436e-01, ..., -6.2439e-01, -7.9160e-01, -8.1188e-01],",
|
||||
" [-4.4921e-01, -6.5653e-01, -7.2656e-01, ..., -3.4702e-01, -5.2146e-01, -5.1326e-01],",
|
||||
" [-3.4702e-01, -5.3647e-01, -5.4170e-01, ..., -1.0915e+00, -1.1968e+00, -1.0252e+00]],",
|
||||
"",
|
||||
" [[-1.1207e+00, -1.2718e+00, -1.0678e+00, ..., 1.2013e-01, -1.3126e-01, -1.7197e-01],",
|
||||
" [-6.9738e-01, -9.1166e-01, -8.5454e-01, ..., -5.5050e-02, -2.8134e-01, -4.2793e-01],",
|
||||
" [-3.4702e-01, -5.5148e-01, -5.8436e-01, ..., 1.9312e-01, -8.6235e-02, -2.1463e-01],",
|
||||
" ...,",
|
||||
" [-1.7923e+00, -1.7521e+00, -1.4802e+00, ..., -1.7923e+00, -1.7521e+00, -1.4802e+00],",
|
||||
" [-1.7923e+00, -1.7521e+00, -1.4802e+00, ..., -1.7923e+00, -1.7521e+00, -1.4802e+00],",
|
||||
" [-1.7923e+00, -1.7521e+00, -1.4802e+00, ..., -1.7923e+00, -1.7521e+00, -1.4802e+00]],",
|
||||
"",
|
||||
" [[-1.0039e+00, -9.5669e-01, -6.5546e-01, ..., -1.4711e+00, -1.4219e+00, -1.1389e+00],",
|
||||
" [-1.0039e+00, -9.5669e-01, -6.5546e-01, ..., -1.7193e+00, -1.6771e+00, -1.4091e+00],",
|
||||
" [-1.6317e+00, -1.6020e+00, -1.2669e+00, ..., -1.2667e+00, -1.2268e+00, -8.9720e-01],",
|
||||
" ...,",
|
||||
" [-1.7923e+00, -1.7521e+00, -1.4802e+00, ..., -1.7923e+00, -1.7521e+00, -1.4802e+00],",
|
||||
" [-1.7923e+00, -1.7521e+00, -1.4802e+00, ..., -1.7923e+00, -1.7521e+00, -1.4802e+00],",
|
||||
" [-1.7923e+00, -1.7521e+00, -1.4802e+00, ..., -1.7923e+00, -1.7521e+00, -1.4802e+00]]]], device='cuda:0')"
|
||||
],
|
||||
"mean": "tensor(-8.9514e-01, device='cuda:0')",
|
||||
"std": "tensor(9.2586e-01, device='cuda:0')",
|
||||
"min": "tensor(-1.7923e+00, device='cuda:0')",
|
||||
"max": "tensor(1.8899e+00, device='cuda:0')"
|
||||
},
|
||||
```
|
||||
|
||||
#### Saving tensors to disk
|
||||
|
||||
Some model adders may benefit from logging full tensor values to disk to support, for example, numerical analysis
|
||||
across implementations.
|
||||
|
||||
Set `use_repr=False` to write tensors to disk using [SafeTensors](https://huggingface.co/docs/safetensors/en/index).
|
||||
|
||||
```python
|
||||
with model_addition_debugger_context(
|
||||
model,
|
||||
debug_path="optional_path_to_your_directory",
|
||||
do_prune_layers=False,
|
||||
use_repr=False, # Defaults to True
|
||||
):
|
||||
output = model.forward(**inputs)
|
||||
```
|
||||
|
||||
When using `use_repr=False`, tensors are written to the same disk location as the `_SUMMARY.json` and
|
||||
`_FULL_TENSORS.json` files. The `value` property of entries in the `_FULL_TENSORS.json` file will contain a relative
|
||||
path reference to the associated `.safetensors` file. Each tensor is written to its own file as the `data` property of
|
||||
the state dictionary. File names are constructed using the `module_path` as a prefix with a few possible postfixes that
|
||||
are built recursively.
|
||||
|
||||
* Module inputs are denoted with the `_inputs` and outputs by `_outputs`.
|
||||
* `list` and `tuple` instances, such as `args` or function return values, will be postfixed with `_{index}`.
|
||||
* `dict` instances will be postfixed with `_{key}`.
|
||||
|
||||
### Comparing between implementations
|
||||
|
||||
Once the forward passes of two models have been traced by the debugger, one can compare the `json` output files. See
|
||||
below: we can see slight differences between these two implementations' key projection layer. Inputs are mostly
|
||||
identical, but not quite. Looking through the file differences makes it easier to pinpoint which layer is wrong.
|
||||
|
||||

|
||||
|
||||
### Limitations and scope
|
||||
|
||||
This feature will only work for torch-based models. Models relying heavily on external kernel calls may work, but trace will
|
||||
probably miss some things. Regardless, any python implementation that aims at mimicking another implementation can be
|
||||
traced once instead of reran N times with breakpoints.
|
||||
|
||||
If you pass `do_prune_layers=False` to your model debugger, ALL the layers will be outputted to `json`. Else, only the
|
||||
first and last layer will be shown. This is useful when some layers (typically cross-attention) appear only after N
|
||||
layers.
|
||||
|
||||
[[autodoc]] model_addition_debugger_context
|
||||
|
||||
## Analyzer of skipped tests
|
||||
|
||||
### Scan skipped tests - for model adders and maintainers
|
||||
|
||||
This small util is a power user tool intended for model adders and maintainers. It lists all test methods
|
||||
existing in `test_modeling_common.py`, inherited by all model tester classes, and scans the repository to measure
|
||||
how many tests are being skipped and for which models.
|
||||
|
||||
### Rationale
|
||||
|
||||
When porting models to transformers, tests fail as they should, and sometimes `test_modeling_common` feels irreconcilable with the peculiarities of our brand new model. But how can we be sure we're not breaking everything by adding a seemingly innocent skip?
|
||||
|
||||
This utility:
|
||||
|
||||
- scans all test_modeling_common methods
|
||||
- looks for times where a method is skipped
|
||||
- returns a summary json you can load as a DataFrame/inspect
|
||||
|
||||
**For instance test_inputs_embeds is skipped in a whooping 39% proportion at the time of writing this util.**
|
||||
|
||||

|
||||
|
||||
### Usage
|
||||
|
||||
You can run the skipped test analyzer in two ways:
|
||||
|
||||
#### Full scan (default)
|
||||
|
||||
From the root of `transformers` repo, scans all common test methods and outputs the results to a JSON file (default: `all_tests_scan_result.json`).
|
||||
|
||||
```bash
|
||||
python utils/scan_skipped_tests.py --output_dir path/to/output
|
||||
```
|
||||
|
||||
- `--output_dir` (optional): Directory where the JSON results will be saved. Defaults to the current directory.
|
||||
|
||||
**Example output:**
|
||||
|
||||
```text
|
||||
🔬 Parsing 331 model test files once each...
|
||||
📝 Aggregating 224 tests...
|
||||
(224/224) test_update_candidate_strategy_with_matches_1es_3d_is_nonecodet_schedule_fa_kwargs
|
||||
✅ Scan complete.
|
||||
|
||||
📄 JSON saved to /home/pablo/git/transformers/all_tests_scan_result.json
|
||||
|
||||
```
|
||||
|
||||
And it will generate `all_tests_scan_result.json` file that you can inspect. The JSON is indexed by method name, and each entry follows this schema, indicating the origin as well (from `common`or `GenerationMixin`.)
|
||||
|
||||
```json
|
||||
{
|
||||
"<method_name>": {
|
||||
"origin": "<test suite>"
|
||||
"models_ran": ["<model_name>", ...],
|
||||
"models_skipped": ["<model_name>", ...],
|
||||
"skipped_proportion": <float>,
|
||||
"reasons_skipped": ["<model_name>: <reason>",
|
||||
...
|
||||
]
|
||||
},
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Which you can visualise as above with e.g. `pandas`
|
||||
|
||||
```python
|
||||
df = pd.read_json('all_tests_scan_result.json').T
|
||||
df.sort_values(by=['skipped_proportion'], ascending=False)
|
||||
|
||||
```
|
||||
|
||||
### Scan a single test method
|
||||
|
||||
You can focus on a specific test method using `--test_method_name`:
|
||||
|
||||
```bash
|
||||
python utils/scan_skipped_tests.py --test_method_name test_inputs_embeds --output_dir path/to/output
|
||||
```
|
||||
|
||||
- `--test_method_name`: Name of the test method to scan (e.g., `test_inputs_embeds`).
|
||||
- `--output_dir` (optional): Directory where the JSON result will be saved.
|
||||
|
||||
**Example output:**
|
||||
|
||||
```bash
|
||||
$ python utils/scan_skipped_tests.py --test_method_name test_inputs_embeds
|
||||
|
||||
🔬 Parsing 331 model test files once each...
|
||||
|
||||
== test_inputs_embeds ==
|
||||
|
||||
Ran : 199/323
|
||||
Skipped : 124/323 (38.4%)
|
||||
- aimv2: Aimv2 does not use inputs_embeds
|
||||
- align: Inputs_embeds is tested in individual model tests
|
||||
- altclip: Inputs_embeds is tested in individual model tests
|
||||
- audio_spectrogram_transformer: AST does not use inputs_embeds
|
||||
- beit: BEiT does not use inputs_embeds
|
||||
- bit: Bit does not use inputs_embeds
|
||||
- blip: Blip does not use inputs_embeds
|
||||
- blip_2: Inputs_embeds is tested in individual model tests
|
||||
- bridgetower:
|
||||
- canine: CANINE does not have a get_input_embeddings() method.
|
||||
- ...
|
||||
|
||||
📄 JSON saved to /home/pablo/git/transformers/scan_test_inputs_embeds.json
|
||||
|
||||
```
|
||||
|
||||
## Modular model detector
|
||||
|
||||
### Code similarity analyzer - for model adders
|
||||
|
||||
This utility analyzes code similarities between model implementations to identify opportunities for modularization. It compares a new or existing modeling file against all models in the library using embedding-based and token-based similarity metrics.
|
||||
|
||||
### Rationale
|
||||
|
||||
When adding a new model to transformers, many components (attention layers, MLPs, outputs, etc.) may already exist in similar form in other models. Instead of implementing everything from scratch, model adders can identify which existing classes are similar and potentially reusable through modularization.
|
||||
|
||||
The tool computes two similarity scores:
|
||||
|
||||
- **Embedding score**: Uses semantic code embeddings (via `Qwen/Qwen3-Embedding-4B`) to detect functionally similar code even with different naming
|
||||
- **Jaccard score**: Measures token set overlap to identify structurally similar code patterns
|
||||
|
||||
A score of 1.00 means the code is identical.
|
||||
|
||||
### Usage
|
||||
|
||||
From the root of the `transformers` repository:
|
||||
|
||||
```bash
|
||||
python utils/modular_model_detector.py --modeling-file path/to/modeling_file.py
|
||||
```
|
||||
|
||||
The tool will automatically download the pre-built index from the Hub (requires RAM/VRAM for the embedding model).
|
||||
|
||||
**Example output:**
|
||||
|
||||
```text
|
||||
Loading checkpoint shards: 100%|████████████████████| 2/2 [00:00<00:00, 33.62it/s]
|
||||
encoding 21 query definitions with Qwen/Qwen3-Embedding-4B (device=cuda, batch=16, max_length=4096)
|
||||
|
||||
stuff.py::Beit3ImageTextMatchingOutput:
|
||||
embedding:
|
||||
blip_2::Blip2ImageTextMatchingModelOutput (0.9994)
|
||||
chinese_clip::ChineseCLIPOutput (0.9818)
|
||||
owlvit::OwlViTOutput (0.9818)
|
||||
jaccard:
|
||||
owlv2::Owlv2Output (0.9667)
|
||||
metaclip_2::MetaClip2Output (0.9667)
|
||||
altclip::AltCLIPOutput (0.9667)
|
||||
intersection:
|
||||
blip::BlipOutput
|
||||
owlvit::OwlViTOutput
|
||||
|
||||
stuff.py::Beit3MLP:
|
||||
embedding:
|
||||
efficientloftr::EfficientLoFTRMLP (0.9718)
|
||||
seggpt::SegGptMlp (0.9650)
|
||||
jaccard:
|
||||
chinese_clip::ChineseCLIPTextSelfOutput (0.5294)
|
||||
bert::BertSelfOutput (0.5294)
|
||||
intersection:
|
||||
```
|
||||
|
||||
The `intersection` field shows classes that appear in both top-5 results, indicating high confidence for modularization candidates.
|
||||
|
||||
### Building a custom index
|
||||
|
||||
To rebuild the index from your local codebase (useful after adding new models or using a different embedding model):
|
||||
|
||||
```bash
|
||||
python utils/modular_model_detector.py --build
|
||||
```
|
||||
|
||||
To push the rebuilt index to a Hub dataset:
|
||||
|
||||
```bash
|
||||
python utils/modular_model_detector.py --build --push-new-index --hub-dataset your-org/your-dataset
|
||||
```
|
||||
|
||||
### Options
|
||||
|
||||
- `--modeling-file`: Path to the modeling file to analyze
|
||||
- `--build`: Build the code similarity index from all modeling files in `src/transformers/models/`
|
||||
- `--push-new-index`: After building, push the index to a Hub dataset (requires `--build`)
|
||||
- `--hub-dataset`: Hub dataset repository ID to pull/push the index (default: `hf-internal-testing/transformers_code_embeddings`)
|
||||
|
||||
### Limitations
|
||||
|
||||
This tool requires GPU/CPU resources to run the embedding model (`Qwen/Qwen3-Embedding-4B`). The pre-built index is downloaded from the Hub by default, which requires an internet connection on first use.
|
||||
|
||||
Results are suggestions based on code similarity and should be manually reviewed before modularization. High similarity scores don't guarantee perfect compatibility.
|
||||
@@ -0,0 +1,75 @@
|
||||
<!--Copyright 2020 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Custom Layers and Utilities
|
||||
|
||||
This page lists all the custom layers used by the library, as well as the utility functions and classes it provides for modeling.
|
||||
|
||||
Most of those are only useful if you are studying the code of the models in the library.
|
||||
|
||||
## WeightRenaming
|
||||
|
||||
[[autodoc]] GroupWeightRename
|
||||
|
||||
## WeightConverter
|
||||
|
||||
[[autodoc]] WeightConverter
|
||||
|
||||
### Conversion operations
|
||||
|
||||
[[autodoc]] ConversionOps
|
||||
|
||||
[[autodoc]] Chunk
|
||||
|
||||
[[autodoc]] Concatenate
|
||||
|
||||
[[autodoc]] MergeModulelist
|
||||
|
||||
[[autodoc]] SplitModulelist
|
||||
|
||||
[[autodoc]] PermuteForRope
|
||||
|
||||
[[autodoc]] VisionFuseAndPermuteForRope
|
||||
|
||||
[[autodoc]] VisionUnfuseAndPermuteForRope
|
||||
|
||||
## Layers
|
||||
|
||||
[[autodoc]] GradientCheckpointingLayer
|
||||
|
||||
## Attention Functions
|
||||
|
||||
[[autodoc]] AttentionInterface
|
||||
- register
|
||||
|
||||
## Attention Mask Functions
|
||||
|
||||
[[autodoc]] AttentionMaskInterface
|
||||
- register
|
||||
|
||||
## Rotary Position Embedding Functions
|
||||
|
||||
[[autodoc]] dynamic_rope_update
|
||||
|
||||
## Pytorch custom modules
|
||||
|
||||
[[autodoc]] pytorch_utils.Conv1D
|
||||
|
||||
## PyTorch Helper Functions
|
||||
|
||||
[[autodoc]] pytorch_utils.apply_chunking_to_forward
|
||||
|
||||
[[autodoc]] pytorch_utils.prune_linear_layer
|
||||
@@ -0,0 +1,41 @@
|
||||
<!--Copyright 2020 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Utilities for pipelines
|
||||
|
||||
This page lists all the utility functions the library provides for pipelines.
|
||||
|
||||
Most of those are only useful if you are studying the code of the models in the library.
|
||||
|
||||
## Argument handling
|
||||
|
||||
[[autodoc]] pipelines.ArgumentHandler
|
||||
|
||||
[[autodoc]] pipelines.ZeroShotClassificationArgumentHandler
|
||||
|
||||
## Data format
|
||||
|
||||
[[autodoc]] pipelines.PipelineDataFormat
|
||||
|
||||
[[autodoc]] pipelines.CsvPipelineDataFormat
|
||||
|
||||
[[autodoc]] pipelines.JsonPipelineDataFormat
|
||||
|
||||
[[autodoc]] pipelines.PipedPipelineDataFormat
|
||||
|
||||
## Utilities
|
||||
|
||||
[[autodoc]] pipelines.PipelineException
|
||||
@@ -0,0 +1,83 @@
|
||||
<!--Copyright 2020 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Utilities for Rotary Embedding
|
||||
|
||||
This page explains how the Rotary Embedding is computed and applied in Transformers and what types of RoPE are supported.
|
||||
|
||||
## Overview
|
||||
|
||||
Rotary Position Embeddings are a technique used to inject positional information into attention mechanisms without relying on explicit position encodings.
|
||||
Instead of adding position vectors to token embeddings, RoPE rotates query and key vectors in the complex plane according to their positions enabling relative positional awareness and better extrapolation to unseen sequence lengths.
|
||||
|
||||
The Transformers library provides a flexible and extensible implementation of various RoPE types defined in `[`~modeling_rope_utils.ROPE_VALIDATION_FUNCTIONS`]`, including both the default and scaled variants:
|
||||
|
||||
| Rope Type | Description |
|
||||
|------------|-------------|
|
||||
| `"default"` | Standard rotary embedding as in LLaMA. |
|
||||
| `"linear"` | Linear-scaled RoPE which allows longer context windows. |
|
||||
| `"dynamic"` | NTK-aware scaling computed by rescaling frequency base (`θ`) for longer context. |
|
||||
| `"yarn"` | YaRN scaling variant providing smoother extrapolation and stability. |
|
||||
| `"longrope"` | [LongRoPE](https://github.com/microsoft/LongRoPE) scaling as in Phi-2 model series. |
|
||||
| `"llama3"` | RoPE scaling as in Llama3.1. |
|
||||
|
||||
## Configuration in Model Configs
|
||||
|
||||
To enable and customize rotary embeddings, add a `rope_parameters` field to your model’s configuration file (`config.json`). This field controls the RoPE behavior across model layers. Note that each RoPE variant defines its own set of expected keys and missing keys will raise an error. See the example below which creates a llama config with default RoPE parameters:
|
||||
|
||||
```python
|
||||
from transformers import LlamaConfig
|
||||
|
||||
config = LlamaConfig()
|
||||
config.rope_parameters = {
|
||||
"rope_type": "default", # type of RoPE to use
|
||||
# rope_theta is optional — omitting it uses the model’s default_theta (typically 10000.0)
|
||||
}
|
||||
|
||||
# If we want to apply a scaled RoPE type, we need to pass extra parameters
|
||||
config.rope_parameters = {
|
||||
"rope_type": "linear",
|
||||
"rope_theta": 10000.0, # can be omitted to fall back to default_theta
|
||||
"factor": 8.0 # scale factor for context extension
|
||||
}
|
||||
```
|
||||
|
||||
## Per-Layer-Type RoPE Configuration
|
||||
|
||||
Some models such as Gemma-3 use different layer types with different attention mechanisms, i.e. "full attention" in some blocks and "sliding-window attention" in others. Transformers supports specifying distinct RoPE parameters per layer type for these models. In this case, `rope_parameters` should be a nested dictionary, where top-level keys correspond to `config.layer_types` and values are per-type RoPE parameters. During model initialization, each decoder layer will automatically look up the matching RoPE configuration based on its declared layer type.
|
||||
|
||||
```python
|
||||
from transformers import Gemma3Config
|
||||
|
||||
config = Gemma3Config()
|
||||
config.rope_parameters = {
|
||||
"full_attention": {
|
||||
"rope_type": "dynamic",
|
||||
"rope_theta": 1000000.0,
|
||||
"factor": 8.0,
|
||||
"original_max_position_embeddings": 8096,
|
||||
},
|
||||
"sliding_attention": {
|
||||
"rope_type": "default",
|
||||
"rope_theta": 10000.0,
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Utilities
|
||||
|
||||
[[autodoc]] RopeParameters
|
||||
- __call__
|
||||
@@ -0,0 +1,29 @@
|
||||
<!--Copyright 2023 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Time Series Utilities
|
||||
|
||||
This page lists all the utility functions and classes that can be used for Time Series based models.
|
||||
|
||||
Most of those are only useful if you are studying the code of the time series models or you wish to add to the collection of distributional output classes.
|
||||
|
||||
## Distributional Output
|
||||
|
||||
[[autodoc]] time_series_utils.NormalOutput
|
||||
|
||||
[[autodoc]] time_series_utils.StudentTOutput
|
||||
|
||||
[[autodoc]] time_series_utils.NegativeBinomialOutput
|
||||
@@ -0,0 +1,37 @@
|
||||
<!--Copyright 2020 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Utilities for Tokenizers
|
||||
|
||||
This page lists all the utility functions used by the tokenizers, mainly the class
|
||||
[`~tokenization_utils_base.PreTrainedTokenizerBase`] that implements the common methods between
|
||||
[`PreTrainedTokenizer`] and [`PreTrainedTokenizerFast`].
|
||||
|
||||
Most of those are only useful if you are studying the code of the tokenizers in the library.
|
||||
|
||||
## PreTrainedTokenizerBase
|
||||
|
||||
[[autodoc]] tokenization_utils_base.PreTrainedTokenizerBase
|
||||
- __call__
|
||||
- all
|
||||
|
||||
## Enums and namedtuples
|
||||
|
||||
[[autodoc]] tokenization_utils_base.TruncationStrategy
|
||||
|
||||
[[autodoc]] tokenization_utils_base.CharSpan
|
||||
|
||||
[[autodoc]] tokenization_utils_base.TokenSpan
|
||||
@@ -0,0 +1,45 @@
|
||||
<!--Copyright 2020 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Utilities for Trainer
|
||||
|
||||
This page lists all the utility functions used by [`Trainer`].
|
||||
|
||||
Most of those are only useful if you are studying the code of the Trainer in the library.
|
||||
|
||||
## Utilities
|
||||
|
||||
[[autodoc]] EvalPrediction
|
||||
|
||||
[[autodoc]] IntervalStrategy
|
||||
|
||||
[[autodoc]] enable_full_determinism
|
||||
|
||||
[[autodoc]] set_seed
|
||||
|
||||
[[autodoc]] torch_distributed_zero_first
|
||||
|
||||
## Callbacks internals
|
||||
|
||||
[[autodoc]] trainer_callback.CallbackHandler
|
||||
|
||||
## Trainer Argument Parser
|
||||
|
||||
[[autodoc]] HfArgumentParser
|
||||
|
||||
## Debug Utilities
|
||||
|
||||
[[autodoc]] debug_utils.DebugUnderflowOverflow
|
||||
@@ -0,0 +1,295 @@
|
||||
<!--Copyright 2026 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Loading kernels
|
||||
|
||||
A kernel works as a drop-in replacement for standard PyTorch operations. It swaps the `forward` method with the optimized kernel implementation without breaking model code.
|
||||
|
||||
This guide shows how to load kernels to accelerate inference.
|
||||
|
||||
Install the kernels package. We recommend the latest version which provides the best performance and bug fixes.
|
||||
|
||||
> [!NOTE]
|
||||
> kernels >=0.11.0 is the minimum required version for working with Transformers.
|
||||
|
||||
```bash
|
||||
pip install -U kernels
|
||||
```
|
||||
|
||||
Set `use_kernels=True` in [`~PreTrainedModel.from_pretrained`] to load the most performant kernels available on the Hub for your device. This replaces supported PyTorch operations with the kernel implementation.
|
||||
|
||||
```py
|
||||
from transformers import AutoModelForCausalLM
|
||||
|
||||
model = AutoModelForCausalLM.from_pretrained(
|
||||
"Qwen/Qwen3-0.6B",
|
||||
use_kernels=True,
|
||||
device_map="cuda"
|
||||
)
|
||||
```
|
||||
|
||||
The default kernels differ by device type. The table below lists the Hub repository that supplies each operation's default kernel. When no default kernel is registered, the operation falls back to standard PyTorch.
|
||||
|
||||
| Operation | NVIDIA (CUDA) | AMD (ROCm) | Intel (XPU) |
|
||||
|---|---|---|---|
|
||||
| RMSNorm | `kernels-community/liger-kernels` | `kernels-community/liger-kernels` | `kernels-community/rmsnorm` |
|
||||
| MoE MLP | `kernels-community/megablocks` | `kernels-community/megablocks` | `kernels-community/megablocks` |
|
||||
| MLP (SwiGLU, GeGLU) | `kernels-community/liger-kernels` | — | — |
|
||||
| Linear | `kernels-community/liger-kernels` | — | — |
|
||||
| Activations (GELU variants, SiLU) | `kernels-community/activation` | — | — |
|
||||
| Rotary embeddings | `kernels-community/rotary` | `kernels-community/aiter-rope` | `kernels-community/rotary` |
|
||||
| Causal LM loss | `kernels-community/liger-kernels` | — | — |
|
||||
| Deformable attention | `kernels-community/deformable-detr` | — | — |
|
||||
|
||||
> [!NOTE]
|
||||
> AMD GPUs report their device type as `cuda` in PyTorch. Transformers detects ROCm at runtime and routes supported operations to the AMD kernels above, including [AITER](https://github.com/ROCm/aiter) builds such as `kernels-community/aiter-rope`. You don't need to set the device type yourself.
|
||||
|
||||
Browse available kernels in the [kernels-community](https://huggingface.co/kernels-community) organization.
|
||||
|
||||
## Attention kernels
|
||||
|
||||
Load attention kernels from the Hub with the `attn_implementation` argument.
|
||||
|
||||
```py
|
||||
from transformers import AutoModelForCausalLM
|
||||
|
||||
model = AutoModelForCausalLM.from_pretrained(
|
||||
"Qwen/Qwen3-0.6B",
|
||||
attn_implementation="kernels-community/flash-attn2",
|
||||
device_map="cuda"
|
||||
)
|
||||
```
|
||||
|
||||
Note that for attention kernels, anything that is not part of the `kernels-community` repository (which is trusted - we may add more trusted repositories in the future) will require an additional `allow_all_kernels=True` kwarg to be used (similar to the `trust_remote_code=True` kwarg for non-HF models). This is because loading a kernel can lead to arbitrary code execution on the host machine, and we cannot verify every repo, so you need to explicitly allow it.
|
||||
|
||||
```py
|
||||
from transformers import AutoModelForCausalLM
|
||||
|
||||
model = AutoModelForCausalLM.from_pretrained(
|
||||
"Qwen/Qwen3-0.6B",
|
||||
attn_implementation="random-repo/random-attention",
|
||||
allow_all_kernels=True,
|
||||
device_map="cuda"
|
||||
)
|
||||
```
|
||||
|
||||
Specific kernels, like attention, accept several formats.
|
||||
|
||||
- `@v2.1.0` pins to a specific tag or branch.
|
||||
- `@>=2.0,<3.0` sets semantic versioning constraints.
|
||||
|
||||
```py
|
||||
from transformers import AutoModelForCausalLM
|
||||
|
||||
# pin to a specific version
|
||||
model = AutoModelForCausalLM.from_pretrained(
|
||||
"Qwen/Qwen3-0.6B",
|
||||
attn_implementation="kernels-community/flash-attn2@v2.1.0",
|
||||
device_map="cuda"
|
||||
)
|
||||
# use semantic versioning constraints
|
||||
model = AutoModelForCausalLM.from_pretrained(
|
||||
"Qwen/Qwen3-0.6B",
|
||||
attn_implementation="kernels-community/flash-attn2@>=2.0,<3.0",
|
||||
device_map="cuda"
|
||||
)
|
||||
```
|
||||
|
||||
## Mode-awareness
|
||||
|
||||
Kernels automatically adapt to [training](https://docs.pytorch.org/docs/stable/generated/torch.nn.Module.html#torch.nn.Module.train) and [inference](https://docs.pytorch.org/docs/stable/generated/torch.nn.Module.html#torch.nn.Module.eval) modes based on PyTorch's `model.training` state.
|
||||
|
||||
```py
|
||||
import torch
|
||||
from transformers import AutoModelForCausalLM
|
||||
|
||||
model = AutoModelForCausalLM.from_pretrained(
|
||||
"Qwen/Qwen3-0.6B",
|
||||
use_kernels=True,
|
||||
device_map="cuda"
|
||||
)
|
||||
|
||||
# Switch to inference mode - uses inference-optimized kernels
|
||||
model.eval()
|
||||
with torch.no_grad():
|
||||
output = model.generate(input_ids, max_new_tokens=50)
|
||||
|
||||
# Switch to training mode - uses training-optimized kernels with gradient support
|
||||
model.train()
|
||||
loss = model(input_ids, labels=labels).loss
|
||||
loss.backward()
|
||||
```
|
||||
|
||||
Explicitly enable training and inference modes with the `mode` argument in the [`~transformers.kernelize`] function. Training mode also supports an additional torch.compile mode.
|
||||
|
||||
```py
|
||||
from kernels import Mode
|
||||
from transformers import kernelize
|
||||
|
||||
# inference optimized kernels
|
||||
kernelize(model, mode=Mode.INFERENCE)
|
||||
|
||||
# training optimized kernels
|
||||
kernelize(model, mode=Mode.TRAINING)
|
||||
|
||||
# training and torch-compile friendly kernels
|
||||
kernelize(model, mode=Mode.TRAINING | Mode.TORCH_COMPILE)
|
||||
```
|
||||
|
||||
## KernelConfig
|
||||
|
||||
[`KernelConfig`] customizes which kernels are used in a model.
|
||||
|
||||
The `:` separator names a specific kernel entry inside the repository and maps it to a layer.
|
||||
|
||||
```py
|
||||
from transformers import AutoModelForCausalLM, KernelConfig
|
||||
|
||||
kernel_config = KernelConfig(
|
||||
kernel_mapping={
|
||||
"RMSNorm": "kernels-community/liger_kernels:LigerRMSNorm",
|
||||
}
|
||||
)
|
||||
model = AutoModelForCausalLM.from_pretrained(
|
||||
"Qwen/Qwen3-0.6B",
|
||||
attn_implementation="kernels-community/flash-attn2:FlashAttention2",
|
||||
use_kernels=True,
|
||||
kernel_config=kernel_config,
|
||||
device_map="cuda"
|
||||
)
|
||||
```
|
||||
|
||||
Specify different kernel implementations for each device type.
|
||||
|
||||
```py
|
||||
from transformers import KernelConfig
|
||||
|
||||
kernel_config = KernelConfig(
|
||||
kernel_mapping={
|
||||
"RMSNorm": {
|
||||
"cuda": "kernels-community/liger_kernels:LigerRMSNorm",
|
||||
"rocm": "kernels-community/rocm-kernels:RocmRMSNorm",
|
||||
"metal": "kernels-community/metal-kernels:MetalRMSNorm",
|
||||
"xpu": "kernels-community/xpu-kernels:XpuRMSNorm"
|
||||
}
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
## Module fusion
|
||||
|
||||
Fuse adjacent modules into a single kernel by passing a tuple of `(class_name, path_pattern)` pairs as the key in [`KernelConfig`]. All patterns must share the same parent module. `*` matches any single path segment.
|
||||
|
||||
```python
|
||||
from transformers import AutoModelForCausalLM, KernelConfig
|
||||
|
||||
kernel_config = KernelConfig(
|
||||
{
|
||||
(
|
||||
("RMSNorm", "model.layers.*.post_attention_layernorm"),
|
||||
("MLP", "model.layers.*.mlp"),
|
||||
): "owner/fused-rmsnorm-mlp:RMSNormMLP",
|
||||
}
|
||||
)
|
||||
model = AutoModelForCausalLM.from_pretrained(
|
||||
"Qwen/Qwen3-0.6B",
|
||||
use_kernels=True,
|
||||
kernel_config=kernel_config,
|
||||
device_map="cuda",
|
||||
)
|
||||
```
|
||||
|
||||
Fusion requires the kernel repo to provide a companion `KernelNameLayout` class alongside the `KernelName` class. See the [Writing kernels](./writing_kernels) guide for how to implement one.
|
||||
|
||||
## Local kernels
|
||||
|
||||
Load kernels from local file paths with `use_local_kernel=True` in [`KernelConfig`]. This loads from a local filesystem path instead of a Hub repository.
|
||||
|
||||
Local kernels use `/abs/path:layer_name` instead of the Hub format `org/repo:layer_name`.
|
||||
|
||||
```py
|
||||
from transformers import KernelConfig, AutoModelForCausalLM
|
||||
|
||||
kernel_mapping = {
|
||||
"RMSNorm": "/path/to/liger_kernels:LigerRMSNorm",
|
||||
}
|
||||
kernel_config = KernelConfig(kernel_mapping, use_local_kernel=True)
|
||||
|
||||
model = AutoModelForCausalLM.from_pretrained(
|
||||
"Qwen/Qwen3-0.6B",
|
||||
dtype="auto",
|
||||
device_map="auto",
|
||||
use_kernels=True,
|
||||
kernel_config=kernel_config
|
||||
)
|
||||
```
|
||||
|
||||
## Disabling kernels
|
||||
|
||||
Disable kernels for specific layers with an empty kernel mapping in [`KernelConfig`].
|
||||
|
||||
```py
|
||||
from transformers import AutoModelForCausalLM, KernelConfig
|
||||
|
||||
kernel_config = KernelConfig(
|
||||
kernel_mapping={
|
||||
"RMSNorm": "",
|
||||
}
|
||||
)
|
||||
|
||||
model = AutoModelForCausalLM.from_pretrained(
|
||||
"Qwen/Qwen3-0.6B",
|
||||
use_kernels=True,
|
||||
kernel_config=kernel_config,
|
||||
device_map="cuda"
|
||||
)
|
||||
```
|
||||
|
||||
Set the environment variable to disable kernels globally.
|
||||
|
||||
```bash
|
||||
export USE_HUB_KERNELS=0 # or OFF or NO
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
Kernel integration depends on hardware, drivers, and package versions working together. The following sections cover common failures.
|
||||
|
||||
### Installation issues
|
||||
|
||||
Import errors indicate the kernels library isn't installed.
|
||||
|
||||
```bash
|
||||
pip install -U kernels
|
||||
```
|
||||
|
||||
### Kernel loading failures
|
||||
|
||||
If specific kernels fail to load, try the following.
|
||||
|
||||
- Check your hardware compatibility with the kernel requirements.
|
||||
- Verify your CUDA/ROCm/Metal drivers are up to date.
|
||||
- Consult the kernel repository documentation for known issues.
|
||||
|
||||
### Device compatibility
|
||||
|
||||
Not all kernels support all devices. The library falls back to standard PyTorch operations if a kernel is unavailable for your hardware. Check kernel repository documentation for device-specific support.
|
||||
|
||||
## Resources
|
||||
|
||||
- [Kernels](https://github.com/huggingface/kernels) repository
|
||||
- [Enhance Your Models in 5 Minutes with the Hugging Face Kernel Hub](https://huggingface.co/blog/hello-hf-kernels) blog post
|
||||
- Discover kernels in the [kernels-community](https://huggingface.co/kernels-community) org
|
||||
@@ -0,0 +1,48 @@
|
||||
<!--Copyright 2026 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Kernels
|
||||
|
||||
PyTorch operations are general-purpose. Hardware vendors and the community create specialized implementations that run faster on specific platforms. Installing these optimized kernels is a challenge because it requires matching compiler versions, CUDA toolkits, and platform-specific builds.
|
||||
|
||||
| platform | supported devices |
|
||||
| :--- | :--- |
|
||||
| NVIDIA GPUs (CUDA) | Modern architectures with compute capability 7.0+ (Volta, Turing, Ampere, Hopper, Blackwell) |
|
||||
| AMD GPUs (ROCm) | Compatible with ROCm-supported devices |
|
||||
| Apple Silicon (Metal) | M-series chips (M1, M2, M3, M4 and newer) |
|
||||
| Intel GPUs (XPU) | Intel Data Center GPU Max Series and compatible devices |
|
||||
|
||||
[Kernels](https://huggingface.co/docs/kernels/index) solves this by distributing precompiled binaries through the [Hub](https://huggingface.co/kernels-community). It detects your platform at runtime and loads the right binary automatically.
|
||||
|
||||
When `use_kernels=True`, Transformers identifies layers with available optimized kernel implementations. It downloads and [caches](../installation#cache-directory) kernels from the Hub only when needed to reduce startup time. Kernels accelerate compute-intensive operations such as attention, normalization, and fused operations.
|
||||
|
||||
Not all operations have kernel implementations. The library falls back to standard PyTorch when no kernel is available.
|
||||
|
||||
## Determinism
|
||||
|
||||
Some kernels produce slightly different results than PyTorch due to operation reordering or accumulation strategies. These differences are functionally equivalent but affect reproducibility.
|
||||
|
||||
For deterministic behavior, try the following.
|
||||
|
||||
- Check kernel repository documentation for determinism guarantees. For example, the SDPA kernel in [gpt-oss-metal-kernels](https://huggingface.co/kernels-community/gpt-oss-metal-kernels#4-scaled-dot-product-attention-sdpa) matches the PyTorch implementation 97% of the time.
|
||||
- Disable specific kernels that affect your use case.
|
||||
- Set random seeds and PyTorch deterministic flags.
|
||||
|
||||
## Resources
|
||||
|
||||
- [Loading kernels](./loading_kernels) guide to get started
|
||||
- [Kernels](https://github.com/huggingface/kernels) GitHub repository
|
||||
- [Enhance Your Models in 5 Minutes with the Hugging Face Kernel Hub](https://huggingface.co/blog/hello-hf-kernels) blog post
|
||||
@@ -0,0 +1,168 @@
|
||||
<!--Copyright 2026 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Writing kernels
|
||||
|
||||
This guide explains how to write kernels that go beyond a stateless `forward` replacement. It covers two capabilities the extended `KernelConfig` API supports:
|
||||
|
||||
1. Parameter transformation: the kernel expects weights in a different layout than the original model (for example, renamed or merged parameters).
|
||||
2. Module fusion: the kernel replaces multiple adjacent modules with a single fused implementation.
|
||||
|
||||
For basic kernels (stateless `forward` replacements with no parameter changes), see the [kernels](https://github.com/huggingface/kernels) library documentation.
|
||||
|
||||
## Two-class pattern
|
||||
|
||||
Any kernel that carries its own parameters follows a two-class pattern.
|
||||
|
||||
- `KernelName`: contains only the `forward` pass. The `kernels` library uses this class to kernelize the model because it does not allow stateful kernel classes.
|
||||
- `KernelNameLayout`: an `nn.Module` that holds the parameters and monkey-patches the original module before the checkpoint is loaded. At runtime, `kernelize` replaces its `forward` with the `forward` from `KernelName`'. You do not need to define `forward`. Transformers injects one automatically with the same signature as `KernelName.forward`.
|
||||
|
||||
> [!IMPORTANT]
|
||||
|
||||
The naming convention is strict. The layout class must be named `{KernelName}Layout` and defined in the same module as `KernelName`.
|
||||
|
||||
## Parameter transformation
|
||||
|
||||
Use this pattern when the kernel expects weights under different names or in a different shape than the original model checkpoint.
|
||||
|
||||
The `KernelNameLayout` class has the same `__init__` signature as the module it replaces and declares a `conversion_mapping` class attribute that tells Transformers how to remap checkpoint keys to the new parameter names (see [Dynamic weight loading](../weightconverter) for more details).
|
||||
|
||||
```python
|
||||
import torch
|
||||
import torch.nn as nn
|
||||
|
||||
class CustomRMSNormLayout(nn.Module):
|
||||
conversion_mapping = [...] # rules that remap checkpoint keys to the new parameter names
|
||||
|
||||
def __init__(self, hidden_size: int, eps: float = 1e-6):
|
||||
super().__init__()
|
||||
self.scale = nn.Parameter(torch.ones(hidden_size))
|
||||
self.variance_epsilon = eps
|
||||
|
||||
|
||||
class CustomRMSNorm(nn.Module):
|
||||
def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
|
||||
input_dtype = hidden_states.dtype
|
||||
hidden_states = hidden_states.to(torch.float32)
|
||||
variance = hidden_states.pow(2).mean(-1, keepdim=True)
|
||||
hidden_states = hidden_states * torch.rsqrt(variance + self.variance_epsilon)
|
||||
return self.scale * hidden_states.to(input_dtype)
|
||||
|
||||
|
||||
class layers:
|
||||
CustomRMSNorm = CustomRMSNorm
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> The `layers` class is required by the `kernels` library to expose the kernel entry point.
|
||||
|
||||
Load this kernel by passing the repo and class name to [`KernelConfig`]. The key is the original module class name from the model. The value points to the `KernelName` class (not the `Layout`) in the repo.
|
||||
|
||||
```python
|
||||
from transformers import AutoModelForCausalLM, KernelConfig
|
||||
|
||||
kernel_config = KernelConfig({"RMSNorm": "owner/my-kernel:CustomRMSNorm"})
|
||||
model = AutoModelForCausalLM.from_pretrained(
|
||||
"Qwen/Qwen3-0.6B",
|
||||
use_kernels=True,
|
||||
kernel_config=kernel_config,
|
||||
device_map="cuda",
|
||||
)
|
||||
```
|
||||
|
||||
When the model loads, Transformers:
|
||||
1. Loads `CustomRMSNorm` from the repo and looks for `CustomRMSNormLayout` in the same module.
|
||||
2. Monkey-patches every `RMSNorm` in the model with `CustomRMSNormLayout`.
|
||||
3. Remaps checkpoint weights using `conversion_mapping` so they load into the new parameter names.
|
||||
4. Calls `kernelize`, which replaces `CustomRMSNormLayout.forward` with `CustomRMSNorm.forward`.
|
||||
|
||||
## Module fusion
|
||||
|
||||
Use this pattern when a kernel replaces multiple adjacent modules with a single fused implementation. Because the fused module combines parameters from several original modules, the `KernelNameLayout.__init__` receives the instantiated child modules rather than their constructor arguments.
|
||||
|
||||
```python
|
||||
import torch
|
||||
import torch.nn as nn
|
||||
|
||||
class RMSNormMLPLayout(nn.Module):
|
||||
conversion_mapping = [...] # rules that remap checkpoint keys to the fused parameter names
|
||||
|
||||
def __init__(self, norm, mlp):
|
||||
super().__init__()
|
||||
self.variance_epsilon = norm.variance_epsilon
|
||||
self.scale = nn.Parameter(torch.empty_like(norm.weight))
|
||||
self.gate_up_proj = nn.Linear(
|
||||
mlp.gate_proj.in_features,
|
||||
mlp.gate_proj.out_features + mlp.up_proj.out_features,
|
||||
bias=mlp.gate_proj.bias is not None,
|
||||
device=mlp.gate_proj.weight.device,
|
||||
dtype=mlp.gate_proj.weight.dtype,
|
||||
)
|
||||
self.down_proj = nn.Linear(
|
||||
mlp.down_proj.in_features,
|
||||
mlp.down_proj.out_features,
|
||||
bias=mlp.down_proj.bias is not None,
|
||||
device=mlp.down_proj.weight.device,
|
||||
dtype=mlp.down_proj.weight.dtype,
|
||||
)
|
||||
self.act_fn = mlp.act_fn
|
||||
|
||||
|
||||
class RMSNormMLP(nn.Module):
|
||||
def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
|
||||
input_dtype = hidden_states.dtype
|
||||
hidden_states = hidden_states.to(torch.float32)
|
||||
variance = hidden_states.pow(2).mean(-1, keepdim=True)
|
||||
hidden_states = hidden_states * torch.rsqrt(variance + self.variance_epsilon)
|
||||
hidden_states = self.scale * hidden_states.to(input_dtype)
|
||||
gate, up = self.gate_up_proj(hidden_states).chunk(2, dim=-1)
|
||||
return self.down_proj(self.act_fn(gate) * up)
|
||||
|
||||
|
||||
class layers:
|
||||
RMSNormMLP = RMSNormMLP
|
||||
```
|
||||
|
||||
To fuse modules, pass a tuple of `(class_name, path_pattern)` pairs as the key in `KernelConfig` instead of a plain string. All patterns must share the same parent module (Transformers fuses the children in that parent). The `*` wildcard matches any single path segment.
|
||||
|
||||
```python
|
||||
from transformers import AutoModelForCausalLM, KernelConfig
|
||||
|
||||
kernel_config = KernelConfig(
|
||||
{
|
||||
(
|
||||
("RMSNorm", "model.layers.*.post_attention_layernorm"),
|
||||
("MLP", "model.layers.*.mlp"),
|
||||
): "owner/my-kernel:RMSNormMLP",
|
||||
}
|
||||
)
|
||||
model = AutoModelForCausalLM.from_pretrained(
|
||||
"Qwen/Qwen3-0.6B",
|
||||
use_kernels=True,
|
||||
kernel_config=kernel_config,
|
||||
device_map="cuda",
|
||||
)
|
||||
```
|
||||
|
||||
When the model loads, Transformers:
|
||||
1. Loads `RMSNormMLP` from the repo and finds `RMSNormMLPLayout` in the same module.
|
||||
2. Matches every decoder layer at `model.layers.*` and builds a fused parent class whose `__init__` calls `RMSNormMLPLayout(post_attention_layernorm, mlp)`.
|
||||
3. Replaces the remaining child (`mlp`) with `nn.Identity()` to preserve the parent module's interface.
|
||||
4. Remaps checkpoint weights using `conversion_mapping`.
|
||||
5. Calls `kernelize`, which replaces `RMSNormMLPLayout.forward` with `RMSNormMLP.forward`.
|
||||
|
||||
> [!TIP]
|
||||
> The order of pairs in the fusion tuple determines the argument order passed to `KernelNameLayout.__init__`.
|
||||
@@ -0,0 +1,82 @@
|
||||
<!---Copyright 2026 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
-->
|
||||
|
||||
|
||||
# Kernels
|
||||
|
||||
Custom kernels target specific ops like matrix multiplications, attention, and normalization to run them faster. Fusing multiple ops into a single kernel reduces memory bandwidth usage by reading and writing GPU memory fewer times, and cuts per-op launch overhead.
|
||||
|
||||
## Hub kernels
|
||||
|
||||
The [Hub](https://huggingface.co/kernels-community) hosts community kernels you can load with [`KernelConfig`]. Pass the config to `kernel_config` in [`~AutoModelForCausalLM.from_pretrained`]. Once the kernel is loaded, it's active for training. Read the [Loading kernels](./kernel_doc/loading_kernels#kernelconfig) guide for all available options.
|
||||
|
||||
```py
|
||||
from transformers import AutoModelForCausalLM, KernelConfig
|
||||
|
||||
kernel_config = KernelConfig(
|
||||
kernel_mapping={
|
||||
"RMSNorm": "kernels-community/rmsnorm",
|
||||
}
|
||||
)
|
||||
model = AutoModelForCausalLM.from_pretrained(
|
||||
"Qwen/Qwen3-0.6B",
|
||||
use_kernels=True,
|
||||
kernel_config=kernel_config,
|
||||
)
|
||||
```
|
||||
|
||||
## Liger
|
||||
|
||||
[Liger Kernel](https://github.com/linkedin/Liger-Kernel) fuses layers like RMSNorm, RoPE, SwiGLU, CrossEntropy, and FusedLinearCrossEntropy into single Triton kernels. It's compatible with FlashAttention, FSDP, and DeepSpeed, and improves multi-GPU training throughput while reducing memory usage, making larger vocabularies, batch sizes, and context lengths more feasible.
|
||||
|
||||
```bash
|
||||
pip install liger-kernel
|
||||
```
|
||||
|
||||
Set `use_liger_kernel=True` in [`TrainingArguments`] to patch the corresponding model layers with Liger's kernels.
|
||||
|
||||
> [!TIP]
|
||||
> See the [patching](https://github.com/linkedin/Liger-Kernel#patching) page for a complete list of supported models.
|
||||
|
||||
```py
|
||||
from transformers import TrainingArguments
|
||||
|
||||
training_args = TrainingArguments(
|
||||
...,
|
||||
use_liger_kernel=True
|
||||
)
|
||||
```
|
||||
|
||||
To control which layers are patched, pass `liger_kernel_config` as a dict. Available options vary by model and include: `rope`, `swiglu`, `cross_entropy`, `fused_linear_cross_entropy`, `rms_norm`, etc.
|
||||
|
||||
```py
|
||||
from transformers import TrainingArguments
|
||||
|
||||
training_args = TrainingArguments(
|
||||
...,
|
||||
use_liger_kernel=True,
|
||||
liger_kernel_config={
|
||||
"rope": True,
|
||||
"cross_entropy": True,
|
||||
"rms_norm": False,
|
||||
"swiglu": True,
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
## Next steps
|
||||
|
||||
- See the [Attention backends](./attention_interface) guide for details on kernels like FlashAttention that reduce memory usage.
|
||||
- See the [torch.compile](./torch_compile) guide to learn how to compile the forward and backward pass for your entire training step.
|
||||
@@ -0,0 +1,300 @@
|
||||
<!--Copyright 2024 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Cache strategies
|
||||
|
||||
The key-value (KV) vectors are used to calculate attention scores. For autoregressive models, KV scores are calculated *every* time because the model predicts one token at a time. Each prediction depends on the previous tokens, which means the model performs the same computations each time.
|
||||
|
||||
A KV *cache* stores these calculations so they can be reused without recomputing them. Efficient caching is crucial for optimizing model performance because it reduces computation time and improves response rates. Refer to the [Caching](./cache_explanation) doc for a more detailed explanation about how a cache works.
|
||||
|
||||
Transformers offers several [`Cache`] classes that implement different caching mechanisms. Some of these [`Cache`] classes are optimized to save memory while others are designed to maximize generation speed. Refer to the table below to compare cache types and use it to help you select the best cache for your use case.
|
||||
|
||||
| Cache Type | Supports sliding layers | Supports offloading | Supports torch.compile() | Expected memory usage |
|
||||
|------------------------|--------------------------|---------------------|--------------------------|-----------------------|
|
||||
| Dynamic Cache | Yes | Yes | No | Medium |
|
||||
| Static Cache | Yes | Yes | Yes | High |
|
||||
| Quantized Cache | No | No | No | Low |
|
||||
|
||||
This guide introduces you to the different [`Cache`] classes and shows you how to use them for generation.
|
||||
|
||||
## Default cache
|
||||
|
||||
The [`DynamicCache`] is the default cache class for all models. It allows the cache size to grow dynamically in order to store an increasing number of keys and values as generation progresses.
|
||||
|
||||
Note that for models using sliding window attention (Mistral, Gemma2,...) or chunked attention (Llama4), the cache will stop growing when the layers using these types of attention have reached their maximum size (the sliding window or chunk size).
|
||||
|
||||
Disable the cache by configuring `use_cache=False` in [`~GenerationMixin.generate`].
|
||||
|
||||
```py
|
||||
import torch
|
||||
from transformers import AutoTokenizer, AutoModelForCausalLM
|
||||
|
||||
tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-2-7b-chat-hf")
|
||||
model = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-2-7b-chat-hf", dtype=torch.float16, device_map="auto")
|
||||
inputs = tokenizer("I like rock music because", return_tensors="pt").to(model.device)
|
||||
|
||||
model.generate(**inputs, do_sample=False, max_new_tokens=20, use_cache=False)
|
||||
```
|
||||
|
||||
Cache classes can also be initialized first before calling and passing it to the models [`~generation.GenerateDecoderOnlyOutput#past_key_values`] parameter. This can be useful for more fine-grained control, or more advanced usage such as context caching.
|
||||
|
||||
In most cases, it's easier to define the cache strategy in the [`~GenerationConfig#cache_implementation`] parameter.
|
||||
|
||||
```py
|
||||
import torch
|
||||
from transformers import AutoTokenizer, AutoModelForCausalLM, DynamicCache
|
||||
|
||||
tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-2-7b-chat-hf")
|
||||
model = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-2-7b-chat-hf", dtype=torch.float16, device_map="auto")
|
||||
inputs = tokenizer("I like rock music because", return_tensors="pt").to(model.device)
|
||||
|
||||
past_key_values = DynamicCache(config=model.config)
|
||||
out = model.generate(**inputs, do_sample=False, max_new_tokens=20, past_key_values=past_key_values)
|
||||
```
|
||||
|
||||
## Fixed-size cache
|
||||
|
||||
The default [`DynamicCache`] prevents you from taking advantage of most just-in-time (JIT) optimizations because the cache size isn't fixed. JIT optimizations enable you to minimize latency at the expense of memory usage. All of the following cache types are compatible with JIT optimizations like [torch.compile](./perf_torch_compile) to accelerate generation.
|
||||
|
||||
A fixed-size cache ([`StaticCache`]) pre-allocates a specific maximum cache size for the kv pairs. You can generate up to the maximum cache size without needing to modify it. However, having a fixed (usually large) size for the key/value states means that while generating, a lot of tokens will actually be masked as they should not take part in the attention. So this trick allows to easily `compile` the decoding stage, but it incurs a waste of tokens in the attention computation. As all things, it's then a trade-off which should be very good if you generate with several sequence of more or less the same lengths, but may be sub-optimal if you have for example 1 very large sequence, and then only short sequences (as the fix cache size would be large, a lot would be wasted for the short sequences). Make sure you understand the impact if you use it!
|
||||
|
||||
As for [`DynamicCache`], note that for models using sliding window attention (Mistral, Gemma2,...) or chunked attention (Llama4), the cache will never be larger than the sliding window/chunk size on layers using these types of attention, even if the maximum length specified is larger.
|
||||
|
||||
You can enable [`StaticCache`] by configuring `cache_implementation="static"` in [`~GenerationMixin.generate`]. This will also turn on automatic `compilation` of the decoding stage for greedy and sample decoding strategies.
|
||||
|
||||
```py
|
||||
import torch
|
||||
from transformers import AutoTokenizer, AutoModelForCausalLM
|
||||
|
||||
tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-2-7b-chat-hf")
|
||||
model = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-2-7b-chat-hf", dtype=torch.float16, device_map="auto")
|
||||
inputs = tokenizer("Hello, my name is", return_tensors="pt").to(model.device)
|
||||
|
||||
out = model.generate(**inputs, do_sample=False, max_new_tokens=20, cache_implementation="static")
|
||||
tokenizer.batch_decode(out, skip_special_tokens=True)[0]
|
||||
"Hello, my name is [Your Name], and I am a [Your Profession] with [Number of Years] of"
|
||||
```
|
||||
|
||||
## Keep generation tensors on CPU
|
||||
|
||||
Compiler backends like Neuron and TPU trace your model into a fixed computation graph. The generation loop maintains tensors (output sequence, `attention_mask`, `position_ids`) that grow by one token each step. The compiler retraces the graph whenever these tensors change shape on the accelerator, which slows generation.
|
||||
|
||||
[`~GenerationMixin.generate`] moves only the tensors that `forward` consumes onto the model device, right before each `forward` call. The output is moved back to match the device of the input. Pass your inputs on CPU to keep the loop's growing tensor bookkeeping off the accelerator. The compiled graph stays stable, and because the output follows the input device, the generated output stays on CPU.
|
||||
|
||||
```py
|
||||
import torch
|
||||
from transformers import AutoTokenizer, AutoModelForCausalLM
|
||||
|
||||
tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen3-0.6B")
|
||||
model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen3-0.6B", device_map="auto")
|
||||
|
||||
# leave the inputs on CPU instead of calling .to(model.device).
|
||||
inputs = tokenizer("The French Bread Law states", return_tensors="pt")
|
||||
|
||||
# generate runs forward on the model device but returns the output on the input_ids device.
|
||||
output = model.generate(**inputs, do_sample=False, max_new_tokens=20)
|
||||
print(output.device)
|
||||
cpu
|
||||
```
|
||||
|
||||
## Cache offloading
|
||||
|
||||
The KV cache can occupy a significant portion of memory and become a [bottleneck](https://hf.co/blog/llama31#inference-memory-requirements) for long-context generation. Memory efficient caches focus on trading off speed for reduced memory usage. This is especially important for large language models (LLMs) and if your hardware is memory constrained.
|
||||
|
||||
Offloading the cache saves GPU memory by moving the KV cache for model layers except one to the CPU. Only the current layer cache is maintained on the GPU during a models `forward` iteration over the layers. It will asynchronously prefetch the next layer's cache, and send back the current layer's cache back to the CPU after attention computation.
|
||||
|
||||
You may want to consider offloading if you have a small GPU and you're getting out-of-memory (OOM) errors.
|
||||
|
||||
> [!WARNING]
|
||||
> You may notice a small degradation in generation throughput compared to a full on-device cache, depending on your model and generation choices (context size, number of generated tokens, number of beams, etc.). This is because moving the key/value states back and forth requires some work.
|
||||
|
||||
Offloading is available for both [`DynamicCache`] and [`StaticCache`]. You can enable it by configuring `cache_implementation="offloaded"` for the dynamic version, or `cache_implementation="offloaded_static"` for the static version, in either [`GenerationConfig`] or [`~GenerationMixin.generate`].
|
||||
Additionally, you can also instantiate your own [`DynamicCache`] or [`StaticCache`] with the `offloading=True` option, and pass this cache in `generate` or your model's `forward` (for example, `past_key_values=DynamicCache(config=model.config, offloading=True)` for a dynamic cache).
|
||||
|
||||
Note that the 2 [`Cache`] classes mentioned above have an additional option when instantiating them directly, `offload_only_non_sliding`.
|
||||
This additional argument decides if the layers using sliding window/chunk attention (if any), will be offloaded as well. Since
|
||||
these layers are usually short anyway, it may be better to avoid offloading them, as offloading may incur a speed penalty. By default, this option is `False` for [`DynamicCache`], and `True` for [`StaticCache`].
|
||||
|
||||
```py
|
||||
import torch
|
||||
from transformers import AutoTokenizer, AutoModelForCausalLM
|
||||
|
||||
ckpt = "microsoft/Phi-3-mini-4k-instruct"
|
||||
tokenizer = AutoTokenizer.from_pretrained(ckpt)
|
||||
model = AutoModelForCausalLM.from_pretrained(ckpt, dtype=torch.float16, device_map="auto")
|
||||
inputs = tokenizer("Fun fact: The shortest", return_tensors="pt").to(model.device)
|
||||
|
||||
out = model.generate(**inputs, do_sample=False, max_new_tokens=23, cache_implementation="offloaded")
|
||||
print(tokenizer.batch_decode(out, skip_special_tokens=True)[0])
|
||||
Fun fact: The shortest war in history was between Britain and Zanzibar on August 27, 1896.
|
||||
```
|
||||
|
||||
The example below shows how you can fallback to an offloaded cache if you run out of memory:
|
||||
|
||||
```py
|
||||
import torch
|
||||
from transformers import AutoTokenizer, AutoModelForCausalLM
|
||||
from accelerate import Accelerator
|
||||
|
||||
def resilient_generate(model, *args, **kwargs):
|
||||
oom = False
|
||||
device = Accelerator().device
|
||||
torch_device_module = getattr(torch, device, torch.cuda)
|
||||
try:
|
||||
return model.generate(*args, **kwargs)
|
||||
except torch.OutOfMemoryError as e:
|
||||
print(e)
|
||||
print("retrying with cache_implementation='offloaded'")
|
||||
oom = True
|
||||
if oom:
|
||||
torch_device_module.empty_cache()
|
||||
kwargs["cache_implementation"] = "offloaded"
|
||||
return model.generate(*args, **kwargs)
|
||||
|
||||
ckpt = "microsoft/Phi-3-mini-4k-instruct"
|
||||
tokenizer = AutoTokenizer.from_pretrained(ckpt)
|
||||
model = AutoModelForCausalLM.from_pretrained(ckpt, dtype=torch.float16, device_map="auto")
|
||||
prompt = ["okay "*1000 + "Fun fact: The most"]
|
||||
inputs = tokenizer(prompt, return_tensors="pt").to(model.device)
|
||||
beams = { "num_beams": 40, "num_return_sequences": 20, "max_new_tokens": 23, "early_stopping": True, }
|
||||
out = resilient_generate(model, **inputs, **beams)
|
||||
responses = tokenizer.batch_decode(out[:,-28:], skip_special_tokens=True)
|
||||
```
|
||||
|
||||
## Quantized cache
|
||||
|
||||
The [`QuantizedCache`] reduces memory requirements by quantizing the KV values to a lower precision. [`QuantizedCache`] currently supports two quantization backends:
|
||||
|
||||
- `hqq` supports int2, int4, and int8 datatypes.
|
||||
- `quanto` supports int2 and int4 datatypes. This is the default quantization backend.
|
||||
|
||||
> [!WARNING]
|
||||
> Quantizing the cache can harm latency if the context length is short and there is enough GPU memory available for generation without enabling cache quantization. Try to find a balance between memory efficiency and latency.
|
||||
|
||||
Enable [`QuantizedCache`] by configuring `cache_implementation="quantized"` in [`GenerationConfig`], and the quantization backend, as well as any additional quantization related parameters should also be passed either as a dict. You should use the default values for these additional parameters unless you're running out-of-memory. In that case, consider decreasing the residual length.
|
||||
|
||||
<hfoptions id="quantized-cache">
|
||||
|
||||
For the `hqq` backend, we recommend setting the `axis-key` and `axis-value` parameters to `1`.
|
||||
|
||||
```py
|
||||
import torch
|
||||
from transformers import AutoTokenizer, AutoModelForCausalLM, QuantizedCache
|
||||
|
||||
tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-2-7b-chat-hf")
|
||||
model = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-2-7b-chat-hf", dtype=torch.float16, device_map="auto")
|
||||
inputs = tokenizer("I like rock music because", return_tensors="pt").to(model.device)
|
||||
|
||||
out = model.generate(**inputs, do_sample=False, max_new_tokens=20, cache_implementation="quantized", cache_config={"backend": "hqq"})
|
||||
print(tokenizer.batch_decode(out, skip_special_tokens=True)[0])
|
||||
I like rock music because it's loud and energetic. It's a great way to express myself and rel
|
||||
```
|
||||
|
||||
For `quanto` backend, we recommend setting the `axis-key` and `axis-value` parameters to `0`.
|
||||
|
||||
```py
|
||||
import torch
|
||||
from transformers import AutoTokenizer, AutoModelForCausalLM
|
||||
|
||||
tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-2-7b-chat-hf")
|
||||
model = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-2-7b-chat-hf", dtype=torch.float16, device_map="auto")
|
||||
inputs = tokenizer("I like rock music because", return_tensors="pt").to(model.device)
|
||||
|
||||
out = model.generate(**inputs, do_sample=False, max_new_tokens=20, cache_implementation="quantized", cache_config={"nbits": 4, "backend": "quanto"})
|
||||
print(tokenizer.batch_decode(out, skip_special_tokens=True)[0])
|
||||
I like rock music because it's loud and energetic. It's a great way to express myself and rel
|
||||
```
|
||||
|
||||
## Encoder-decoder cache
|
||||
|
||||
[`EncoderDecoderCache`] is designed for encoder-decoder models. It manages both the self-attention and cross-attention caches to ensure storage and retrieval of previous kv pairs. It is possible to individually set a different cache type for the encoder and decoder.
|
||||
|
||||
This cache type doesn't require any setup. It is a simple wrapper around 2 [`Cache`]s as described above, that will be used independently directly by the model.
|
||||
|
||||
## Model-specific caches
|
||||
|
||||
Some models have a unique way of storing past kv pairs or states that is not compatible with any other cache classes.
|
||||
|
||||
Mamba models, such as [Mamba](./model_doc/mamba), require a specific cache because the model doesn't have an attention mechanism or kv states. Thus, they are not compatible with the above [`Cache`] classes.
|
||||
|
||||
## Iterative generation
|
||||
|
||||
A cache can also work in iterative generation settings where there is back-and-forth interaction with a model (chatbots). Like regular generation, iterative generation with a cache allows a model to efficiently handle ongoing conversations without recomputing the entire context at each step.
|
||||
|
||||
For iterative generation with a cache, start by initializing an empty cache class and then you can feed in your new prompts. Keep track of dialogue history with a [chat template](./chat_templating).
|
||||
|
||||
The following example demonstrates [Llama-2-7b-chat-hf](https://huggingface.co/meta-llama/Llama-2-7b-chat-hf). If you're using a different chat-style model, [`~PreTrainedTokenizer.apply_chat_template`] may process messages differently. It might cut out important tokens depending on how the Jinja template is written. For multimodal chat models, see the [iterative chatting with cache](./tasks/image_text_to_text.md#iterative-chatting-with-cache) guide for how to process images or audio.
|
||||
|
||||
For example, some models use special `<think> ... </think>` tokens during reasoning. These could get lost during re-encoding, causing indexing issues. You might need to manually remove or adjust extra tokens from the completions to keep things stable.
|
||||
|
||||
```py
|
||||
import torch
|
||||
from transformers import AutoTokenizer,AutoModelForCausalLM, DynamicCache, StaticCache
|
||||
|
||||
model_id = "meta-llama/Llama-2-7b-chat-hf"
|
||||
model = AutoModelForCausalLM.from_pretrained(model_id, dtype=torch.bfloat16, device_map='auto')
|
||||
tokenizer = AutoTokenizer.from_pretrained(model_id)
|
||||
|
||||
user_prompts = ["Hello, what's your name?", "Btw, yesterday I was on a rock concert."]
|
||||
|
||||
past_key_values = DynamicCache(config=model.config)
|
||||
|
||||
messages = []
|
||||
for prompt in user_prompts:
|
||||
messages.append({"role": "user", "content": prompt})
|
||||
inputs = tokenizer.apply_chat_template(messages, add_generation_prompt=True, return_tensors="pt", return_dict=True).to(model.device)
|
||||
input_length = inputs["input_ids"].shape[1]
|
||||
outputs = model.generate(**inputs, do_sample=False, max_new_tokens=256, past_key_values=past_key_values)
|
||||
completion = tokenizer.decode(outputs[0, input_length: ], skip_special_tokens=True)
|
||||
messages.append({"role": "assistant", "content": completion})
|
||||
```
|
||||
|
||||
## Prefill a cache (prefix caching)
|
||||
|
||||
In some situations, you may want to fill a [`Cache`] with kv pairs for a certain prefix prompt and reuse it to generate different sequences.
|
||||
|
||||
The example below initializes a [`StaticCache`], and then caches an initial prompt. Now you can generate several sequences from the prefilled prompt.
|
||||
|
||||
```py
|
||||
import copy
|
||||
import torch
|
||||
from transformers import AutoModelForCausalLM, AutoTokenizer, DynamicCache, StaticCache
|
||||
|
||||
model_id = "meta-llama/Llama-2-7b-chat-hf"
|
||||
model = AutoModelForCausalLM.from_pretrained(model_id, dtype=torch.bfloat16, device_map={"": 0})
|
||||
tokenizer = AutoTokenizer.from_pretrained(model_id)
|
||||
|
||||
# Init StaticCache with big enough max-length (1024 tokens for the below example)
|
||||
# You can also init a DynamicCache, if that suits you better
|
||||
prompt_cache = StaticCache(config=model.config, max_cache_len=1024)
|
||||
|
||||
INITIAL_PROMPT = "You are a helpful assistant. "
|
||||
inputs_initial_prompt = tokenizer(INITIAL_PROMPT, return_tensors="pt").to(model.device.type)
|
||||
# This is the common prompt cached, we need to run forward without grad to be able to copy
|
||||
with torch.no_grad():
|
||||
prompt_cache = model(**inputs_initial_prompt, past_key_values = prompt_cache).past_key_values
|
||||
|
||||
prompts = ["Help me to write a blogpost about travelling.", "What is the capital of France?"]
|
||||
responses = []
|
||||
for prompt in prompts:
|
||||
new_inputs = tokenizer(INITIAL_PROMPT + prompt, return_tensors="pt").to(model.device.type)
|
||||
past_key_values = copy.deepcopy(prompt_cache)
|
||||
outputs = model.generate(**new_inputs, past_key_values=past_key_values,max_new_tokens=20)
|
||||
response = tokenizer.batch_decode(outputs)[0]
|
||||
responses.append(response)
|
||||
|
||||
print(responses)
|
||||
```
|
||||
@@ -0,0 +1,312 @@
|
||||
<!--Copyright 2024 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Text generation
|
||||
|
||||
[[open-in-colab]]
|
||||
|
||||
Text generation is the most popular application for large language models (LLMs). A LLM is trained to generate the next word (token) given some initial text (prompt) along with its own generated outputs up to a predefined length or when it reaches an end-of-sequence (`EOS`) token.
|
||||
|
||||
In Transformers, the [`~GenerationMixin.generate`] API handles text generation, and it is available for all models with generative capabilities. This guide will show you the basics of text generation with [`~GenerationMixin.generate`] and some common pitfalls to avoid.
|
||||
|
||||
> [!TIP]
|
||||
> For the following commands, please make sure [`transformers serve` is running](https://huggingface.co/docs/transformers/main/en/serving).
|
||||
>
|
||||
> ```shell
|
||||
> transformers chat Qwen/Qwen2.5-0.5B-Instruct
|
||||
> ```
|
||||
|
||||
## Default generate
|
||||
|
||||
Before you begin, it's helpful to install [bitsandbytes](https://hf.co/docs/bitsandbytes/index) to quantize really large models to reduce their memory usage.
|
||||
|
||||
```bash
|
||||
!pip install -U transformers bitsandbytes
|
||||
```
|
||||
|
||||
Bitsandbytes supports multiple backends in addition to CUDA-based GPUs. Refer to the multi-backend installation [guide](https://huggingface.co/docs/bitsandbytes/main/en/installation#multi-backend) to learn more.
|
||||
|
||||
Load a LLM with [`~PreTrainedModel.from_pretrained`] and add the following two parameters to reduce the memory requirements.
|
||||
|
||||
- `device_map="auto"` enables Accelerates' [Big Model Inference](./models#big-model-inference) feature for automatically initiating the model skeleton and loading and dispatching the model weights across all available devices, starting with the fastest device (GPU).
|
||||
- `quantization_config` is a configuration object that defines the quantization settings. This examples uses bitsandbytes as the quantization backend (see the [Quantization](./quantization/overview) section for more available backends) and it loads the model in [4-bits](./quantization/bitsandbytes).
|
||||
|
||||
```py
|
||||
from transformers import AutoTokenizer, AutoModelForCausalLM, BitsAndBytesConfig
|
||||
|
||||
quantization_config = BitsAndBytesConfig(load_in_4bit=True)
|
||||
model = AutoModelForCausalLM.from_pretrained("mistralai/Mistral-7B-v0.1", device_map="auto", quantization_config=quantization_config)
|
||||
```
|
||||
|
||||
Tokenize your input, and set the [`~PreTrainedTokenizer.padding_side`] parameter to `"left"` because a LLM is not trained to continue generation from padding tokens. The tokenizer returns the input ids and attention mask.
|
||||
|
||||
> [!TIP]
|
||||
> Process more than one prompt at a time by passing a list of strings to the tokenizer. Batch the inputs to improve throughput at a small cost to latency and memory.
|
||||
|
||||
```py
|
||||
tokenizer = AutoTokenizer.from_pretrained("mistralai/Mistral-7B-v0.1", padding_side="left")
|
||||
model_inputs = tokenizer(["A list of colors: red, blue"], return_tensors="pt").to(model.device)
|
||||
```
|
||||
|
||||
Pass the inputs to [`~GenerationMixin.generate`] to generate tokens, and [`~PreTrainedTokenizer.batch_decode`] the generated tokens back to text.
|
||||
|
||||
```py
|
||||
generated_ids = model.generate(**model_inputs)
|
||||
tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]
|
||||
"A list of colors: red, blue, green, yellow, orange, purple, pink,"
|
||||
```
|
||||
|
||||
## Generation configuration
|
||||
|
||||
All generation settings are contained in [`GenerationConfig`]. In the example above, the generation settings are derived from the `generation_config.json` file of [mistralai/Mistral-7B-v0.1](https://huggingface.co/mistralai/Mistral-7B-v0.1). A default decoding strategy is used when no configuration is saved with a model.
|
||||
|
||||
Inspect the configuration through the `generation_config` attribute. It only shows values that are different from the default configuration, in this case, the `bos_token_id` and `eos_token_id`.
|
||||
|
||||
```py
|
||||
from transformers import AutoModelForCausalLM
|
||||
|
||||
model = AutoModelForCausalLM.from_pretrained("mistralai/Mistral-7B-v0.1", device_map="auto")
|
||||
model.generation_config
|
||||
GenerationConfig {
|
||||
"bos_token_id": 1,
|
||||
"eos_token_id": 2
|
||||
}
|
||||
```
|
||||
|
||||
You can customize [`~GenerationMixin.generate`] by overriding the parameters and values in [`GenerationConfig`]. See [this section below](#common-options) for commonly adjusted parameters.
|
||||
|
||||
```py
|
||||
# enable beam search sampling strategy
|
||||
model.generate(**inputs, num_beams=4, do_sample=True)
|
||||
```
|
||||
|
||||
[`~GenerationMixin.generate`] can also be extended with external libraries or custom code:
|
||||
|
||||
1. the `logits_processor` parameter accepts custom [`LogitsProcessor`] instances for manipulating the next token probability distribution;
|
||||
2. the `stopping_criteria` parameters supports custom [`StoppingCriteria`] to stop text generation;
|
||||
3. other custom generation methods can be loaded through the `custom_generate` flag ([docs](generation_strategies.md/#custom-decoding-methods)).
|
||||
|
||||
Refer to the [Generation strategies](./generation_strategies) guide to learn more about search, sampling, and decoding strategies.
|
||||
|
||||
### Saving
|
||||
|
||||
Create an instance of [`GenerationConfig`] and specify the decoding parameters you want.
|
||||
|
||||
```py
|
||||
from transformers import AutoModelForCausalLM, GenerationConfig
|
||||
|
||||
model = AutoModelForCausalLM.from_pretrained("my_account/my_model")
|
||||
generation_config = GenerationConfig(
|
||||
max_new_tokens=50, do_sample=True, top_k=50, eos_token_id=model.config.eos_token_id
|
||||
)
|
||||
```
|
||||
|
||||
Use [`~GenerationConfig.save_pretrained`] to save a specific generation configuration and set the `push_to_hub` parameter to `True` to upload it to the Hub.
|
||||
|
||||
```py
|
||||
generation_config.save_pretrained("my_account/my_model", push_to_hub=True)
|
||||
```
|
||||
|
||||
Leave the `config_file_name` parameter empty. This parameter should be used when storing multiple generation configurations in a single directory. It gives you a way to specify which generation configuration to load. You can create different configurations for different generative tasks (creative text generation with sampling, summarization with beam search) for use with a single model.
|
||||
|
||||
```py
|
||||
from transformers import AutoModelForSeq2SeqLM, AutoTokenizer, GenerationConfig
|
||||
|
||||
tokenizer = AutoTokenizer.from_pretrained("google-t5/t5-small")
|
||||
model = AutoModelForSeq2SeqLM.from_pretrained("google-t5/t5-small")
|
||||
|
||||
translation_generation_config = GenerationConfig(
|
||||
num_beams=4,
|
||||
early_stopping=True,
|
||||
decoder_start_token_id=0,
|
||||
eos_token_id=model.config.eos_token_id,
|
||||
pad_token=model.config.pad_token_id,
|
||||
)
|
||||
|
||||
translation_generation_config.save_pretrained("/tmp", config_file_name="translation_generation_config.json", push_to_hub=True)
|
||||
|
||||
generation_config = GenerationConfig.from_pretrained("/tmp", config_file_name="translation_generation_config.json")
|
||||
inputs = tokenizer("translate English to French: Configuration files are easy to use!", return_tensors="pt")
|
||||
outputs = model.generate(**inputs, generation_config=generation_config)
|
||||
print(tokenizer.batch_decode(outputs, skip_special_tokens=True))
|
||||
```
|
||||
|
||||
## Common Options
|
||||
|
||||
[`~GenerationMixin.generate`] is a powerful tool that can be heavily customized. This can be daunting for a new users. This section contains a list of popular generation options that you can define in most text generation tools in Transformers: [`~GenerationMixin.generate`], [`GenerationConfig`], `pipelines`, the `chat` CLI, ...
|
||||
|
||||
| Option name | Type | Simplified description |
|
||||
|---|---|---|
|
||||
| `max_new_tokens` | `int` | Controls the maximum generation length. Be sure to define it, as it usually defaults to a small value. |
|
||||
| `do_sample` | `bool` | Defines whether generation will sample the next token (`True`), or is greedy instead (`False`). Most use cases should set this flag to `True`. Check [this guide](./generation_strategies) for more information. |
|
||||
| `temperature` | `float` | How unpredictable the next selected token will be. High values (`>0.8`) are good for creative tasks, low values (e.g. `<0.4`) for tasks that require "thinking". Requires `do_sample=True`. |
|
||||
| `num_beams` | `int` | When set to `>1`, activates the beam search algorithm. Beam search is good on input-grounded tasks. Check [this guide](./generation_strategies) for more information. |
|
||||
| `repetition_penalty` | `float` | Set it to `>1.0` if you're seeing the model repeat itself often. Larger values apply a larger penalty. |
|
||||
| `eos_token_id` | `list[int]` | The token(s) that will cause generation to stop. The default value is usually good, but you can specify a different token. |
|
||||
|
||||
## Pitfalls
|
||||
|
||||
The section below covers some common issues you may encounter during text generation and how to solve them.
|
||||
|
||||
### Output length
|
||||
|
||||
[`~GenerationMixin.generate`] returns up to 20 tokens by default unless otherwise specified in a models [`GenerationConfig`]. It is highly recommended to manually set the number of generated tokens with the [`max_new_tokens`] parameter to control the output length. [Decoder-only](https://hf.co/learn/nlp-course/chapter1/6?fw=pt) models returns the initial prompt along with the generated tokens.
|
||||
|
||||
```py
|
||||
model_inputs = tokenizer(["A sequence of numbers: 1, 2"], return_tensors="pt").to(model.device)
|
||||
```
|
||||
|
||||
<hfoptions id="output-length">
|
||||
<hfoption id="default length">
|
||||
|
||||
```py
|
||||
generated_ids = model.generate(**model_inputs)
|
||||
tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]
|
||||
'A sequence of numbers: 1, 2, 3, 4, 5'
|
||||
```
|
||||
|
||||
</hfoption>
|
||||
<hfoption id="max_new_tokens">
|
||||
|
||||
```py
|
||||
generated_ids = model.generate(**model_inputs, max_new_tokens=50)
|
||||
tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]
|
||||
'A sequence of numbers: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,'
|
||||
```
|
||||
|
||||
</hfoption>
|
||||
</hfoptions>
|
||||
|
||||
### Decoding strategy
|
||||
|
||||
The default decoding strategy in [`~GenerationMixin.generate`] is *greedy search*, which selects the next most likely token, unless otherwise specified in a models [`GenerationConfig`]. While this decoding strategy works well for input-grounded tasks (transcription, translation), it is not optimal for more creative use cases (story writing, chat applications).
|
||||
|
||||
For example, enable a [multinomial sampling](./generation_strategies#multinomial-sampling) strategy to generate more diverse outputs. Refer to the [Generation strategy](./generation_strategies) guide for more decoding strategies.
|
||||
|
||||
```py
|
||||
model_inputs = tokenizer(["I am a cat."], return_tensors="pt").to(model.device)
|
||||
```
|
||||
|
||||
<hfoptions id="decoding">
|
||||
<hfoption id="greedy search">
|
||||
|
||||
```py
|
||||
generated_ids = model.generate(**model_inputs)
|
||||
tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]
|
||||
```
|
||||
|
||||
</hfoption>
|
||||
<hfoption id="multinomial sampling">
|
||||
|
||||
```py
|
||||
generated_ids = model.generate(**model_inputs, do_sample=True)
|
||||
tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]
|
||||
```
|
||||
|
||||
</hfoption>
|
||||
</hfoptions>
|
||||
|
||||
### Padding side
|
||||
|
||||
Inputs need to be padded if they don't have the same length. But LLMs aren't trained to continue generation from padding tokens, which means the [`~PreTrainedTokenizer.padding_side`] parameter needs to be set to the left of the input.
|
||||
|
||||
<hfoptions id="padding">
|
||||
<hfoption id="right pad">
|
||||
|
||||
```py
|
||||
model_inputs = tokenizer(
|
||||
["1, 2, 3", "A, B, C, D, E"], padding=True, return_tensors="pt"
|
||||
).to(model.device)
|
||||
generated_ids = model.generate(**model_inputs)
|
||||
tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]
|
||||
'1, 2, 33333333333'
|
||||
```
|
||||
|
||||
</hfoption>
|
||||
<hfoption id="left pad">
|
||||
|
||||
```py
|
||||
tokenizer = AutoTokenizer.from_pretrained("mistralai/Mistral-7B-v0.1", padding_side="left")
|
||||
tokenizer.pad_token = tokenizer.eos_token
|
||||
model_inputs = tokenizer(
|
||||
["1, 2, 3", "A, B, C, D, E"], padding=True, return_tensors="pt"
|
||||
).to(model.device)
|
||||
generated_ids = model.generate(**model_inputs)
|
||||
tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]
|
||||
'1, 2, 3, 4, 5, 6,'
|
||||
```
|
||||
|
||||
</hfoption>
|
||||
</hfoptions>
|
||||
|
||||
### Prompt format
|
||||
|
||||
Some models and tasks expect a certain input prompt format, and if the format is incorrect, the model returns a suboptimal output. You can learn more about prompting in the [prompt engineering](./tasks/prompting) guide.
|
||||
|
||||
For example, a chat model expects the input as a [chat template](./chat_templating). Your prompt should include a `role` and `content` to indicate who is participating in the conversation. If you try to pass your prompt as a single string, the model doesn't always return the expected output.
|
||||
|
||||
```py
|
||||
from transformers import AutoTokenizer, AutoModelForCausalLM, BitsAndBytesConfig
|
||||
|
||||
tokenizer = AutoTokenizer.from_pretrained("HuggingFaceH4/zephyr-7b-alpha")
|
||||
model = AutoModelForCausalLM.from_pretrained(
|
||||
"HuggingFaceH4/zephyr-7b-alpha", device_map="auto", quantization_config=BitsAndBytesConfig(load_in_4bit=True)
|
||||
)
|
||||
```
|
||||
|
||||
<hfoptions id="format">
|
||||
<hfoption id="no format">
|
||||
|
||||
```py
|
||||
prompt = """How many cats does it take to change a light bulb? Reply as a pirate."""
|
||||
model_inputs = tokenizer([prompt], return_tensors="pt").to(model.device)
|
||||
input_length = model_inputs.input_ids.shape[1]
|
||||
generated_ids = model.generate(**model_inputs, max_new_tokens=50)
|
||||
print(tokenizer.batch_decode(generated_ids[:, input_length:], skip_special_tokens=True)[0])
|
||||
"Aye, matey! 'Tis a simple task for a cat with a keen eye and nimble paws. First, the cat will climb up the ladder, carefully avoiding the rickety rungs. Then, with"
|
||||
```
|
||||
|
||||
</hfoption>
|
||||
<hfoption id="chat template">
|
||||
|
||||
```py
|
||||
messages = [
|
||||
{
|
||||
"role": "system",
|
||||
"content": "You are a friendly chatbot who always responds in the style of a pirate",
|
||||
},
|
||||
{"role": "user", "content": "How many cats does it take to change a light bulb?"},
|
||||
]
|
||||
model_inputs = tokenizer.apply_chat_template(messages, add_generation_prompt=True, return_tensors="pt").to(model.device)
|
||||
input_length = model_inputs.shape[1]
|
||||
generated_ids = model.generate(model_inputs, do_sample=True, max_new_tokens=50)
|
||||
print(tokenizer.batch_decode(generated_ids[:, input_length:], skip_special_tokens=True)[0])
|
||||
"Arr, matey! According to me beliefs, 'twas always one cat to hold the ladder and another to climb up it an’ change the light bulb, but if yer looking to save some catnip, maybe yer can
|
||||
```
|
||||
|
||||
</hfoption>
|
||||
</hfoptions>
|
||||
|
||||
## Resources
|
||||
|
||||
Take a look below for some more specific and specialized text generation libraries.
|
||||
|
||||
- [Optimum](https://github.com/huggingface/optimum): an extension of Transformers focused on optimizing training and inference on specific hardware devices
|
||||
- [Outlines](https://github.com/dottxt-ai/outlines): a library for constrained text generation (generate JSON files for example).
|
||||
- [SynCode](https://github.com/uiuc-focal-lab/syncode): a library for context-free grammar guided generation (JSON, SQL, Python).
|
||||
- [Text Generation Inference](https://github.com/huggingface/text-generation-inference): a production-ready server for LLMs.
|
||||
- [Text generation web UI](https://github.com/oobabooga/text-generation-webui): a Gradio web UI for text generation.
|
||||
- [logits-processor-zoo](https://github.com/NVIDIA/logits-processor-zoo): additional logits processors for controlling text generation.
|
||||
@@ -0,0 +1,640 @@
|
||||
<!--Copyright 2023 The HuggingFace Team. All rights reserved.
|
||||
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.
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
-->
|
||||
|
||||
# Optimizing LLMs for Speed and Memory
|
||||
|
||||
[[open-in-colab]]
|
||||
|
||||
Large Language Models (LLMs) such as GPT3/4, [Falcon](https://huggingface.co/tiiuae/falcon-40b), and [Llama](https://huggingface.co/meta-llama/Llama-2-70b-hf) are rapidly advancing in their ability to tackle human-centric tasks, establishing themselves as essential tools in modern knowledge-based industries.
|
||||
Deploying these models in real-world tasks remains challenging, however:
|
||||
|
||||
- To exhibit near-human text understanding and generation capabilities, LLMs currently require to be composed of billions of parameters (see [Kaplan et al](https://huggingface.co/papers/2001.08361), [Wei et. al](https://huggingface.co/papers/2206.07682)). This consequently amplifies the memory demands for inference.
|
||||
- In many real-world tasks, LLMs need to be given extensive contextual information. This necessitates the model's capability to manage very long input sequences during inference.
|
||||
|
||||
The crux of these challenges lies in augmenting the computational and memory capabilities of LLMs, especially when handling expansive input sequences.
|
||||
|
||||
In this guide, we will go over the effective techniques for efficient LLM deployment:
|
||||
|
||||
1. **Lower Precision:** Research has shown that operating at reduced numerical precision, namely [8-bit and 4-bit](./main_classes/quantization) can achieve computational advantages without a considerable decline in model performance.
|
||||
|
||||
2. **Flash Attention:** Flash Attention is a variation of the attention algorithm that not only provides a more memory-efficient approach but also realizes increased efficiency due to optimized GPU memory utilization.
|
||||
|
||||
3. **Architectural Innovations:** Considering that LLMs are always deployed in the same way during inference, namely autoregressive text generation with a long input context, specialized model architectures have been proposed that allow for more efficient inference. The most important advancement in model architectures hereby are [Alibi](https://huggingface.co/papers/2108.12409), [Rotary embeddings](https://huggingface.co/papers/2104.09864), [Multi-Query Attention (MQA)](https://huggingface.co/papers/1911.02150) and [Grouped-Query-Attention (GQA)](https://huggingface.co/papers/2305.13245).
|
||||
|
||||
Throughout this guide, we will offer an analysis of auto-regressive generation from a tensor's perspective. We delve into the pros and cons of adopting lower precision, provide a comprehensive exploration of the latest attention algorithms, and discuss improved LLM architectures. While doing so, we run practical examples showcasing each of the feature improvements.
|
||||
|
||||
## 1. Lower Precision
|
||||
|
||||
Memory requirements of LLMs can be best understood by seeing the LLM as a set of weight matrices and vectors and the text inputs as a sequence of vectors. In the following, the definition *weights* will be used to signify all model weight matrices and vectors.
|
||||
|
||||
At the time of writing this guide, LLMs consist of at least a couple billion parameters. Each parameter thereby is made of a decimal number, e.g. `4.5689` which is usually stored in either [float32](https://en.wikipedia.org/wiki/Single-precision_floating-point_format), [bfloat16](https://en.wikipedia.org/wiki/Bfloat16_floating-point_format), or [float16](https://en.wikipedia.org/wiki/Half-precision_floating-point_format) format. This allows us to easily compute the memory requirement to load the LLM into memory:
|
||||
|
||||
> *Loading the weights of a model having X billion parameters requires roughly 4 \* X GB of VRAM in float32 precision*
|
||||
|
||||
Nowadays, models are however rarely trained in full float32 precision, but usually in bfloat16 precision or less frequently in float16 precision. Therefore the rule of thumb becomes:
|
||||
|
||||
> *Loading the weights of a model having X billion parameters requires roughly 2 \* X GB of VRAM in bfloat16/float16 precision*
|
||||
|
||||
For shorter text inputs (less than 1024 tokens), the memory requirement for inference is very much dominated by the memory requirement to load the weights. Therefore, for now, let's assume that the memory requirement for inference is equal to the memory requirement to load the model into the GPU VRAM.
|
||||
|
||||
To give some examples of how much VRAM it roughly takes to load a model in bfloat16:
|
||||
|
||||
- **GPT3** requires 2 \* 175 GB = **350 GB** VRAM
|
||||
- [**Bloom**](https://huggingface.co/bigscience/bloom) requires 2 \* 176 GB = **352 GB** VRAM
|
||||
- [**Llama-2-70b**](https://huggingface.co/meta-llama/Llama-2-70b-hf) requires 2 \* 70 GB = **140 GB** VRAM
|
||||
- [**Falcon-40b**](https://huggingface.co/tiiuae/falcon-40b) requires 2 \* 40 GB = **80 GB** VRAM
|
||||
- [**MPT-30b**](https://huggingface.co/mosaicml/mpt-30b) requires 2 \* 30 GB = **60 GB** VRAM
|
||||
- [**bigcode/starcoder**](https://huggingface.co/bigcode/starcoder) requires 2 \* 15.5 = **31 GB** VRAM
|
||||
|
||||
As of writing this document, the largest GPU chip on the market is the A100 & H100 offering 80GB of VRAM. Most of the models listed before require more than 80GB just to be loaded and therefore necessarily require [tensor parallelism](https://huggingface.co/docs/transformers/perf_train_gpu_many#tensor-parallelism) and/or [pipeline parallelism](https://huggingface.co/docs/transformers/perf_train_gpu_many#naive-model-parallelism-vertical-and-pipeline-parallelism).
|
||||
|
||||
🤗 Transformers now supports tensor parallelism for supported models having `base_tp_plan` in their respective config classes. Learn more about Tensor Parallelism [here](perf_train_gpu_many#tensor-parallelism). Furthermore, if you're interested in writing models in a tensor-parallelism-friendly way, feel free to have a look at [the text-generation-inference library](https://github.com/huggingface/text-generation-inference/tree/main/server/text_generation_server/models/custom_modeling).
|
||||
|
||||
Naive pipeline parallelism is supported out of the box. For this, simply load the model with `device="auto"` which will automatically place the different layers on the available GPUs as explained [here](https://huggingface.co/docs/accelerate/v0.22.0/en/concept_guides/big_model_inference).
|
||||
Note, however that while very effective, this naive pipeline parallelism does not tackle the issues of GPU idling. For this more advanced pipeline parallelism is required as explained [here](https://huggingface.co/docs/transformers/en/perf_train_gpu_many#naive-model-parallelism-vertical-and-pipeline-parallelism).
|
||||
|
||||
If you have access to an 8 x 80GB A100 node, you could load BLOOM as follows
|
||||
|
||||
```bash
|
||||
!pip install transformers accelerate bitsandbytes optimum
|
||||
```
|
||||
|
||||
```python
|
||||
from transformers import AutoModelForCausalLM
|
||||
|
||||
model = AutoModelForCausalLM.from_pretrained("bigscience/bloom", device_map="auto", pad_token_id=0)
|
||||
```
|
||||
|
||||
By using `device_map="auto"` the attention layers would be equally distributed over all available GPUs.
|
||||
|
||||
In this guide, we will use [bigcode/octocoder](https://huggingface.co/bigcode/octocoder) as it can be run on a single 40 GB A100 GPU device chip. Note that all memory and speed optimizations that we will apply going forward, are equally applicable to models that require model or tensor parallelism.
|
||||
|
||||
Since the model is loaded in bfloat16 precision, using our rule of thumb above, we would expect the memory requirement to run inference with `bigcode/octocoder` to be around 31 GB VRAM. Let's give it a try.
|
||||
|
||||
We first load the model and tokenizer and then pass both to Transformers' [pipeline](https://huggingface.co/docs/transformers/main_classes/pipelines) object.
|
||||
|
||||
```python
|
||||
from transformers import AutoModelForCausalLM, AutoTokenizer, pipeline
|
||||
import torch
|
||||
|
||||
model = AutoModelForCausalLM.from_pretrained("bigcode/octocoder", dtype=torch.bfloat16, device_map="auto", pad_token_id=0)
|
||||
tokenizer = AutoTokenizer.from_pretrained("bigcode/octocoder")
|
||||
|
||||
pipe = pipeline("text-generation", model=model, tokenizer=tokenizer)
|
||||
```
|
||||
|
||||
```python
|
||||
prompt = "Question: Please write a function in Python that transforms bytes to Giga bytes.\n\nAnswer:"
|
||||
|
||||
result = pipe(prompt, max_new_tokens=60)[0]["generated_text"][len(prompt):]
|
||||
result
|
||||
```
|
||||
|
||||
**Output**:
|
||||
|
||||
```text
|
||||
Here is a Python function that transforms bytes to Giga bytes:\n\n```python\ndef bytes_to_giga_bytes(bytes):\n return bytes / 1024 / 1024 / 1024\n```\n\nThis function takes a single
|
||||
```
|
||||
|
||||
Nice, we can now directly use the result to convert bytes into Gigabytes.
|
||||
|
||||
```python
|
||||
def bytes_to_giga_bytes(bytes):
|
||||
return bytes / 1024 / 1024 / 1024
|
||||
```
|
||||
|
||||
Let's call [`torch.cuda.memory.max_memory_allocated`](https://docs.pytorch.org/docs/stable/generated/torch.cuda.memory.max_memory_allocated.html) to measure the peak GPU memory allocation.
|
||||
|
||||
```python
|
||||
bytes_to_giga_bytes(torch.cuda.max_memory_allocated())
|
||||
```
|
||||
|
||||
**Output**:
|
||||
|
||||
```text
|
||||
29.0260648727417
|
||||
```
|
||||
|
||||
Close enough to our back-of-the-envelope computation! We can see the number is not exactly correct as going from bytes to kilobytes requires a multiplication of 1024 instead of 1000. Therefore the back-of-the-envelope formula can also be understood as an "at most X GB" computation.
|
||||
Note that if we had tried to run the model in full float32 precision, a whopping 64 GB of VRAM would have been required.
|
||||
|
||||
> Almost all models are trained in bfloat16 nowadays, there is no reason to run the model in full float32 precision if [your GPU supports bfloat16](https://discuss.pytorch.org/t/bfloat16-native-support/117155/5). Float32 won't give better inference results than the precision that was used to train the model.
|
||||
|
||||
If you are unsure in which format the model weights are stored on the Hub, you can always look into the checkpoint's config under `"dtype"`, *e.g.* [here](https://huggingface.co/meta-llama/Llama-2-7b-hf/blob/6fdf2e60f86ff2481f2241aaee459f85b5b0bbb9/config.json#L21). It is recommended to set the model to the same precision type as written in the config when loading with `from_pretrained(..., dtype=...)` except when the original type is float32 in which case one can use both `float16` or `bfloat16` for inference.
|
||||
|
||||
Let's define a `flush(...)` function to free all allocated memory so that we can accurately measure the peak allocated GPU memory.
|
||||
|
||||
```python
|
||||
del pipe
|
||||
del model
|
||||
|
||||
import gc
|
||||
import torch
|
||||
|
||||
def flush():
|
||||
gc.collect()
|
||||
torch.cuda.empty_cache()
|
||||
torch.cuda.reset_peak_memory_stats()
|
||||
```
|
||||
|
||||
Let's call it now for the next experiment.
|
||||
|
||||
```python
|
||||
flush()
|
||||
```
|
||||
|
||||
From the Accelerate library, you can also use a device-agnostic utility method called [release_memory](https://github.com/huggingface/accelerate/blob/29be4788629b772a3b722076e433b5b3b5c85da3/src/accelerate/utils/memory.py#L63), which takes various hardware backends like XPU, MLU, NPU, MPS, and more into account.
|
||||
|
||||
```python
|
||||
from accelerate.utils import release_memory
|
||||
# ...
|
||||
|
||||
release_memory(model)
|
||||
```
|
||||
|
||||
Now what if your GPU does not have 32 GB of VRAM? It has been found that model weights can be quantized to 8-bit or 4-bits without a significant loss in performance (see [Dettmers et al.](https://huggingface.co/papers/2208.07339)).
|
||||
Model can be quantized to even 3 or 2 bits with an acceptable loss in performance as shown in the recent [GPTQ paper](https://huggingface.co/papers/2210.17323) 🤯.
|
||||
|
||||
Without going into too many details, quantization schemes aim at reducing the precision of weights while trying to keep the model's inference results as accurate as possible (*a.k.a* as close as possible to bfloat16).
|
||||
Note that quantization works especially well for text generation since all we care about is choosing the *set of most likely next tokens* and don't really care about the exact values of the next token *logit* distribution.
|
||||
All that matters is that the next token *logit* distribution stays roughly the same so that an `argmax` or `topk` operation gives the same results.
|
||||
|
||||
There are various quantization techniques, which we won't discuss in detail here, but in general, all quantization techniques work as follows:
|
||||
|
||||
- 1. Quantize all weights to the target precision
|
||||
- 2. Load the quantized weights, and pass the input sequence of vectors in bfloat16 precision
|
||||
- 3. Dynamically dequantize weights to bfloat16 to perform the computation with their input vectors in bfloat16 precision
|
||||
|
||||
In a nutshell, this means that *inputs-weight matrix* multiplications, with $X$ being the *inputs*, $W$ being a weight matrix and $Y$ being the output:
|
||||
|
||||
$$ Y = X * W $$
|
||||
|
||||
are changed to
|
||||
|
||||
$$ Y = X * \text{dequantize}(W) $$
|
||||
|
||||
for every matrix multiplication. Dequantization and re-quantization is performed sequentially for all weight matrices as the inputs run through the network graph.
|
||||
|
||||
Therefore, inference time is often **not** reduced when using quantized weights, but rather increases.
|
||||
Enough theory, let's give it a try! To quantize the weights with Transformers, you need to make sure that
|
||||
the [`bitsandbytes`](https://github.com/bitsandbytes-foundation/bitsandbytes) library is installed.
|
||||
|
||||
```bash
|
||||
!pip install bitsandbytes
|
||||
```
|
||||
|
||||
We can then load models in 8-bit quantization by simply adding a `load_in_8bit=True` flag to `from_pretrained`.
|
||||
|
||||
```python
|
||||
model = AutoModelForCausalLM.from_pretrained("bigcode/octocoder", quantization_config=BitsAndBytesConfig(load_in_8bit=True), pad_token_id=0)
|
||||
```
|
||||
|
||||
Now, let's run our example again and measure the memory usage.
|
||||
|
||||
```python
|
||||
pipe = pipeline("text-generation", model=model, tokenizer=tokenizer)
|
||||
|
||||
result = pipe(prompt, max_new_tokens=60)[0]["generated_text"][len(prompt):]
|
||||
result
|
||||
```
|
||||
|
||||
**Output**:
|
||||
|
||||
```text
|
||||
Here is a Python function that transforms bytes to Giga bytes:\n\n```python\ndef bytes_to_giga_bytes(bytes):\n return bytes / 1024 / 1024 / 1024\n```\n\nThis function takes a single
|
||||
```
|
||||
|
||||
Nice, we're getting the same result as before, so no loss in accuracy! Let's look at how much memory was used this time.
|
||||
|
||||
```python
|
||||
bytes_to_giga_bytes(torch.cuda.max_memory_allocated())
|
||||
```
|
||||
|
||||
**Output**:
|
||||
|
||||
```text
|
||||
15.219234466552734
|
||||
```
|
||||
|
||||
Significantly less! We're down to just a bit over 15 GBs and could therefore run this model on consumer GPUs like the 4090.
|
||||
We're seeing a very nice gain in memory efficiency and more or less no degradation to the model's output. However, we can also notice a slight slow-down during inference.
|
||||
|
||||
We delete the models and flush the memory again.
|
||||
|
||||
```python
|
||||
del model
|
||||
del pipe
|
||||
```
|
||||
|
||||
```python
|
||||
flush()
|
||||
```
|
||||
|
||||
Let's see what peak GPU memory consumption 4-bit quantization gives. Quantizing the model to 4-bit can be done with the same API as before - this time by passing `load_in_4bit=True` instead of `load_in_8bit=True`.
|
||||
|
||||
```python
|
||||
model = AutoModelForCausalLM.from_pretrained("bigcode/octocoder", quantization_config=BitsAndBytesConfig(load_in_4bit=True), pad_token_id=0)
|
||||
|
||||
pipe = pipeline("text-generation", model=model, tokenizer=tokenizer)
|
||||
|
||||
result = pipe(prompt, max_new_tokens=60)[0]["generated_text"][len(prompt):]
|
||||
result
|
||||
```
|
||||
|
||||
**Output**:
|
||||
|
||||
```text
|
||||
Here is a Python function that transforms bytes to Giga bytes:\n\n```\ndef bytes_to_gigabytes(bytes):\n return bytes / 1024 / 1024 / 1024\n```\n\nThis function takes a single argument
|
||||
```
|
||||
|
||||
We're almost seeing the same output text as before - just the `python` is missing just before the code snippet. Let's see how much memory was required.
|
||||
|
||||
```python
|
||||
bytes_to_giga_bytes(torch.cuda.max_memory_allocated())
|
||||
```
|
||||
|
||||
**Output**:
|
||||
|
||||
```text
|
||||
9.543574333190918
|
||||
```
|
||||
|
||||
Just 9.5GB! That's really not a lot for a >15 billion parameter model.
|
||||
|
||||
While we see very little degradation in accuracy for our model here, 4-bit quantization can in practice often lead to different results compared to 8-bit quantization or full `bfloat16` inference. It is up to the user to try it out.
|
||||
|
||||
Also note that inference here was again a bit slower compared to 8-bit quantization which is due to the more aggressive quantization method used for 4-bit quantization leading to $\text{quantize}$ and $\text{dequantize}$ taking longer during inference.
|
||||
|
||||
```python
|
||||
del model
|
||||
del pipe
|
||||
```
|
||||
|
||||
```python
|
||||
flush()
|
||||
```
|
||||
|
||||
Overall, we saw that running OctoCoder in 8-bit precision reduced the required GPU VRAM from 32G GPU VRAM to only 15GB and running the model in 4-bit precision further reduces the required GPU VRAM to just a bit over 9GB.
|
||||
|
||||
4-bit quantization allows the model to be run on GPUs such as RTX3090, V100, and T4 which are quite accessible for most people.
|
||||
|
||||
For more information on quantization and to see how one can quantize models to require even less GPU VRAM memory than 4-bit, we recommend looking into the [`GPT-QModel`](https://huggingface.co/docs/transformers/main/en/main_classes/quantization#gptqmodel) implementation.
|
||||
|
||||
> As a conclusion, it is important to remember that model quantization trades improved memory efficiency against accuracy and in some cases inference time.
|
||||
|
||||
If GPU memory is not a constraint for your use case, there is often no need to look into quantization. However many GPUs simply can't run LLMs without quantization methods and in this case, 4-bit and 8-bit quantization schemes are extremely useful tools.
|
||||
|
||||
For more in-detail usage information, we strongly recommend taking a look at the [Transformers Quantization Docs](https://huggingface.co/docs/transformers/main_classes/quantization#general-usage).
|
||||
Next, let's look into how we can improve computational and memory efficiency by using better algorithms and an improved model architecture.
|
||||
|
||||
## 2. Flash Attention
|
||||
|
||||
Today's top-performing LLMs share more or less the same fundamental architecture that consists of feed-forward layers, activation layers, layer normalization layers, and most crucially, self-attention layers.
|
||||
|
||||
Self-attention layers are central to Large Language Models (LLMs) in that they enable the model to understand the contextual relationships between input tokens.
|
||||
However, the peak GPU memory consumption for self-attention layers grows *quadratically* both in compute and memory complexity with number of input tokens (also called *sequence length*) that we denote in the following by $N$ .
|
||||
While this is not really noticeable for shorter input sequences (of up to 1000 input tokens), it becomes a serious problem for longer input sequences (at around 16000 input tokens).
|
||||
|
||||
Let's take a closer look. The formula to compute the output $\mathbf{O}$ of a self-attention layer for an input $\mathbf{X}$ of length $N$ is:
|
||||
|
||||
$$ \textbf{O} = \text{Attn}(\mathbf{X}) = \mathbf{V} \times \text{Softmax}(\mathbf{QK}^T) \text{ with } \mathbf{Q} = \mathbf{W}_q \mathbf{X}, \mathbf{V} = \mathbf{W}_v \mathbf{X}, \mathbf{K} = \mathbf{W}_k \mathbf{X} $$
|
||||
|
||||
$\mathbf{X} = (\mathbf{x}_1, ... \mathbf{x}_{N})$ is thereby the input sequence to the attention layer. The projections $\mathbf{Q}$ and $\mathbf{K}$ will each consist of $N$ vectors resulting in the $\mathbf{QK}^T$ being of size $N^2$ .
|
||||
|
||||
LLMs usually have multiple attention heads, thus doing multiple self-attention computations in parallel.
|
||||
Assuming, the LLM has 40 attention heads and runs in bfloat16 precision, we can calculate the memory requirement to store the $\mathbf{QK^T}$ matrices to be $40 * 2 * N^2$ bytes. For $N=1000$ only around 50 MB of VRAM are needed, however, for $N=16000$ we would need 19 GB of VRAM, and for $N=100,000$ we would need almost 1TB just to store the $\mathbf{QK}^T$ matrices.
|
||||
|
||||
Long story short, the default self-attention algorithm quickly becomes prohibitively memory-expensive for large input contexts.
|
||||
|
||||
As LLMs improve in text comprehension and generation, they are applied to increasingly complex tasks. While models once handled the translation or summarization of a few sentences, they now manage entire pages, demanding the capability to process extensive input lengths.
|
||||
|
||||
How can we get rid of the exorbitant memory requirements for large input lengths? We need a new way to compute the self-attention mechanism that gets rid of the $\mathbf{QK}^T$ matrix. [Tri Dao et al.](https://huggingface.co/papers/2205.14135) developed exactly such a new algorithm and called it **Flash Attention**.
|
||||
|
||||
In a nutshell, Flash Attention breaks the $\mathbf{V} \times \text{Softmax}(\mathbf{QK}^T)$ computation apart and instead computes smaller chunks of the output by iterating over multiple softmax computation steps:
|
||||
|
||||
$$ \textbf{O}_i \leftarrow s^a_{ij} * \textbf{O}_i + s^b_{ij} * \mathbf{V}_{j} \times \text{Softmax}(\mathbf{QK}^T_{i,j}) \text{ for multiple } i, j \text{ iterations} $$
|
||||
|
||||
with $s^a_{ij}$ and $s^b_{ij}$ being some softmax normalization statistics that need to be recomputed for every $i$ and $j$ .
|
||||
|
||||
Please note that the whole Flash Attention is a bit more complex and is greatly simplified here as going in too much depth is out of scope for this guide. The reader is invited to take a look at the well-written [Flash Attention paper](https://huggingface.co/papers/2205.14135) for more details.
|
||||
|
||||
The main takeaway here is:
|
||||
|
||||
> By keeping track of softmax normalization statistics and by using some smart mathematics, Flash Attention gives **numerical identical** outputs compared to the default self-attention layer at a memory cost that only increases linearly with $N$ .
|
||||
|
||||
Looking at the formula, one would intuitively say that Flash Attention must be much slower compared to the default self-attention formula as more computation needs to be done. Indeed Flash Attention requires more FLOPs compared to normal attention as the softmax normalization statistics have to constantly be recomputed (see [paper](https://huggingface.co/papers/2205.14135) for more details if interested)
|
||||
|
||||
> However, Flash Attention is much faster in inference compared to default attention which comes from its ability to significantly reduce the demands on the slower, high-bandwidth memory of the GPU (VRAM), focusing instead on the faster on-chip memory (SRAM).
|
||||
|
||||
Essentially, Flash Attention makes sure that all intermediate write and read operations can be done using the fast *on-chip* SRAM memory instead of having to access the slower VRAM memory to compute the output vector $\mathbf{O}$ .
|
||||
|
||||
In practice, there is currently absolutely no reason to **not** use Flash Attention if available. The algorithm gives mathematically the same outputs, and is both faster and more memory-efficient.
|
||||
|
||||
## 3. Architectural Innovations
|
||||
|
||||
So far we have looked into improving computational and memory efficiency by:
|
||||
|
||||
- Casting the weights to a lower precision format
|
||||
- Replacing the self-attention algorithm with a more memory- and compute efficient version
|
||||
|
||||
Let's now look into how we can change the architecture of an LLM so that it is most effective and efficient for tasks that require long text inputs, *e.g.*:
|
||||
|
||||
- Retrieval augmented Questions Answering,
|
||||
- Summarization,
|
||||
- Chat
|
||||
|
||||
Note that *chat* not only requires the LLM to handle long text inputs, but it also necessitates that the LLM is able to efficiently handle the back-and-forth dialogue between user and assistant (such as ChatGPT).
|
||||
|
||||
Once trained, the fundamental LLM architecture is difficult to change, so it is important to make considerations about the LLM's tasks beforehand and accordingly optimize the model's architecture.
|
||||
There are two important components of the model architecture that quickly become memory and/or performance bottlenecks for large input sequences.
|
||||
|
||||
- The positional embeddings
|
||||
- The key-value cache
|
||||
|
||||
Let's go over each component in more detail
|
||||
|
||||
### 3.1 Improving positional embeddings of LLMs
|
||||
|
||||
Self-attention puts each token in relation to each other's tokens.
|
||||
As an example, the $\text{Softmax}(\mathbf{QK}^T)$ matrix of the text input sequence *"Hello", "I", "love", "you"* could look as follows:
|
||||
|
||||

|
||||
|
||||
Each word token is given a probability mass at which it attends all other word tokens and, therefore is put into relation with all other word tokens. E.g. the word *"love"* attends to the word *"Hello"* with 5%, to *"I"* with 30%, and to itself with 65%.
|
||||
|
||||
A LLM based on self-attention, but without position embeddings would have great difficulties in understanding the positions of the text inputs to each other.
|
||||
This is because the probability score computed by $\mathbf{QK}^T$ relates each word token to each other word token in $O(1)$ computations regardless of their relative positional distance to each other.
|
||||
Therefore, for the LLM without position embeddings each token appears to have the same distance to all other tokens, *e.g.* differentiating between *"Hello I love you"* and *"You love I hello"* would be very challenging.
|
||||
|
||||
For the LLM to understand sentence order, an additional *cue* is needed and is usually applied in the form of *positional encodings* (or also called *positional embeddings*).
|
||||
Positional encodings, encode the position of each token into a numerical presentation that the LLM can leverage to better understand sentence order.
|
||||
|
||||
The authors of the [*Attention Is All You Need*](https://huggingface.co/papers/1706.03762) paper introduced sinusoidal positional embeddings $\mathbf{P} = \mathbf{p}_1, \ldots, \mathbf{p}_N$ .
|
||||
where each vector $\mathbf{p}_i$ is computed as a sinusoidal function of its position $i$ .
|
||||
The positional encodings are then simply added to the input sequence vectors $\mathbf{\hat{X}} = \mathbf{\hat{x}}_1, \ldots, \mathbf{\hat{x}}_N$ = $\mathbf{x}_1 + \mathbf{p}_1, \ldots, \mathbf{x}_N + \mathbf{p}_N$ thereby cueing the model to better learn sentence order.
|
||||
|
||||
Instead of using fixed position embeddings, others (such as [Devlin et al.](https://huggingface.co/papers/1810.04805)) used learned positional encodings for which the positional embeddings
|
||||
$\mathbf{P}$ are learned during training.
|
||||
|
||||
Sinusoidal and learned position embeddings used to be the predominant methods to encode sentence order into LLMs, but a couple of problems related to these positional encodings were found:
|
||||
|
||||
1. Sinusoidal and learned position embeddings are both absolute positional embeddings, *i.e.* encoding a unique embedding for each position id: $0, \ldots, N$ . As shown by [Huang et al.](https://huggingface.co/papers/2009.13658) and [Su et al.](https://huggingface.co/papers/2104.09864), absolute positional embeddings lead to poor LLM performance for long text inputs. For long text inputs, it is advantageous if the model learns the relative positional distance input tokens have to each other instead of their absolute position.
|
||||
2. When using learned position embeddings, the LLM has to be trained on a fixed input length $N$, which makes it difficult to extrapolate to an input length longer than what it was trained on.
|
||||
|
||||
Recently, relative positional embeddings that can tackle the above mentioned problems have become more popular, most notably:
|
||||
|
||||
- [Rotary Position Embedding (RoPE)](https://huggingface.co/papers/2104.09864)
|
||||
- [ALiBi](https://huggingface.co/papers/2108.12409)
|
||||
|
||||
Both *RoPE* and *ALiBi* argue that it's best to cue the LLM about sentence order directly in the self-attention algorithm as it's there that word tokens are put into relation with each other. More specifically, sentence order should be cued by modifying the $\mathbf{QK}^T$ computation.
|
||||
|
||||
Without going into too many details, *RoPE* notes that positional information can be encoded into query-key pairs, *e.g.* $\mathbf{q}_i$ and $\mathbf{x}_j$ by rotating each vector by an angle $\theta * i$ and $\theta * j$ respectively with $i, j$ describing each vectors sentence position:
|
||||
|
||||
$$ \mathbf{\hat{q}}_i^T \mathbf{\hat{x}}_j = \mathbf{{q}}_i^T \mathbf{R}_{\theta, i -j} \mathbf{{x}}_j. $$
|
||||
|
||||
$\mathbf{R}_{\theta, i - j}$ thereby represents a rotational matrix. $\theta$ is *not* learned during training, but instead set to a pre-defined value that depends on the maximum input sequence length during training.
|
||||
|
||||
> By doing so, the probability score between $\mathbf{q}_i$ and $\mathbf{q}_j$ is only affected if $i \ne j$ and solely depends on the relative distance $i - j$ regardless of each vector's specific positions $i$ and $j$ .
|
||||
|
||||
*RoPE* is used in multiple of today's most important LLMs, such as:
|
||||
|
||||
- [**Falcon**](https://huggingface.co/tiiuae/falcon-40b)
|
||||
- [**Llama**](https://huggingface.co/papers/2302.13971)
|
||||
- [**PaLM**](https://huggingface.co/papers/2204.02311)
|
||||
|
||||
As an alternative, *ALiBi* proposes a much simpler relative position encoding scheme. The relative distance that input tokens have to each other is added as a negative integer scaled by a pre-defined value `m` to each query-key entry of the $\mathbf{QK}^T$ matrix right before the softmax computation.
|
||||
|
||||

|
||||
|
||||
As shown in the [ALiBi](https://huggingface.co/papers/2108.12409) paper, this simple relative positional encoding allows the model to retain a high performance even at very long text input sequences.
|
||||
|
||||
*ALiBi* is used in multiple of today's most important LLMs, such as:
|
||||
|
||||
- [**MPT**](https://huggingface.co/mosaicml/mpt-30b)
|
||||
- [**BLOOM**](https://huggingface.co/bigscience/bloom)
|
||||
|
||||
Both *RoPE* and *ALiBi* position encodings can extrapolate to input lengths not seen during training whereas it has been shown that extrapolation works much better out-of-the-box for *ALiBi* as compared to *RoPE*.
|
||||
For ALiBi, one simply increases the values of the lower triangular position matrix to match the length of the input sequence.
|
||||
For *RoPE*, keeping the same $\theta$ that was used during training leads to poor results when passing text inputs much longer than those seen during training, *c.f* [Press et al.](https://huggingface.co/papers/2108.12409). However, the community has found a couple of effective tricks that adapt $\theta$, thereby allowing *RoPE* position embeddings to work well for extrapolated text input sequences (see [here](https://github.com/huggingface/transformers/pull/24653)).
|
||||
|
||||
> Both RoPE and ALiBi are relative positional embeddings that are *not* learned during training, but instead are based on the following intuitions:
|
||||
|
||||
- Positional cues about the text inputs should be given directly to the $\mathbf{QK}^T$ matrix of the self-attention layer.
|
||||
- The LLM should be incentivized to learn a constant *relative* distance positional encoding.
|
||||
- The further text input tokens are from each other, the lower the probability of their query-value probability. Both RoPE and ALiBi lower the query-key probability of tokens far away from each other. RoPE lowers by decreasing their vector product by increasing the angle between the query-key vectors. ALiBi lowers by adding large negative numbers to the vector product.
|
||||
|
||||
In conclusion, LLMs that are intended to be deployed in tasks that require handling large text inputs are better trained with relative positional embeddings, such as RoPE and ALiBi. Also note that even if an LLM with RoPE and ALiBi has been trained only on a fixed length of say $N_1 = 2048$ it can still be used in practice with text inputs much larger than $N_1$, like $N_2 = 8192 > N_1$ by extrapolating the positional embeddings.
|
||||
|
||||
### 3.2 The key-value cache
|
||||
|
||||
Auto-regressive text generation with LLMs works by iteratively putting in an input sequence, sampling the next token, appending the next token to the input sequence, and continuing to do so until the LLM produces a token that signifies that the generation has finished.
|
||||
|
||||
Please have a look at [Transformer's Generate Text Tutorial](https://huggingface.co/docs/transformers/llm_tutorial#generate-text) to get a more visual explanation of how auto-regressive generation works.
|
||||
|
||||
Let's run a quick code snippet to show how auto-regressive works in practice. We will simply take the most likely next token via `torch.argmax`.
|
||||
|
||||
```python
|
||||
input_ids = tokenizer(prompt, return_tensors="pt")["input_ids"].to("cuda")
|
||||
|
||||
for _ in range(5):
|
||||
next_logits = model(input_ids)["logits"][:, -1:]
|
||||
next_token_id = torch.argmax(next_logits,dim=-1)
|
||||
|
||||
input_ids = torch.cat([input_ids, next_token_id], dim=-1)
|
||||
print("shape of input_ids", input_ids.shape)
|
||||
|
||||
generated_text = tokenizer.batch_decode(input_ids[:, -5:])
|
||||
generated_text
|
||||
```
|
||||
|
||||
**Output**:
|
||||
|
||||
```text
|
||||
shape of input_ids torch.Size([1, 21])
|
||||
shape of input_ids torch.Size([1, 22])
|
||||
shape of input_ids torch.Size([1, 23])
|
||||
shape of input_ids torch.Size([1, 24])
|
||||
shape of input_ids torch.Size([1, 25])
|
||||
[' Here is a Python function']
|
||||
```
|
||||
|
||||
As we can see every time we increase the text input tokens by the just sampled token.
|
||||
|
||||
With very few exceptions, LLMs are trained using the [causal language modeling objective](https://huggingface.co/docs/transformers/tasks/language_modeling#causal-language-modeling) and therefore mask the upper triangle matrix of the attention score - this is why in the two diagrams above the attention scores are left blank (*a.k.a* have 0 probability). For a quick recap on causal language modeling you can refer to the [*Illustrated Self Attention blog*](https://jalammar.github.io/illustrated-gpt2/#part-2-illustrated-self-attention).
|
||||
|
||||
As a consequence, tokens *never* depend on later tokens, more specifically the $\mathbf{q}_i$ vector is never put in relation with any key, values vectors $\mathbf{k}_j, \mathbf{v}_j$ if $j > i$ . Instead $\mathbf{q}_i$ only attends to previous key-value vectors $\mathbf{k}_{m < i}, \mathbf{v}_{m < i} \text{ , for } m \in \{0, \ldots i - 1\}$. In order to reduce unnecessary computation, one can therefore cache each layer's key-value vectors for all previous timesteps.
|
||||
|
||||
In the following, we will tell the LLM to make use of the key-value cache by retrieving and forwarding it for each forward pass.
|
||||
In Transformers, we can retrieve the key-value cache by passing the `use_cache` flag to the `forward` call and can then pass it with the current token.
|
||||
|
||||
```python
|
||||
past_key_values = None # past_key_values is the key-value cache
|
||||
generated_tokens = []
|
||||
next_token_id = tokenizer(prompt, return_tensors="pt")["input_ids"].to("cuda")
|
||||
|
||||
for _ in range(5):
|
||||
next_logits, past_key_values = model(next_token_id, past_key_values=past_key_values, use_cache=True).to_tuple()
|
||||
next_logits = next_logits[:, -1:]
|
||||
next_token_id = torch.argmax(next_logits, dim=-1)
|
||||
|
||||
print("shape of input_ids", next_token_id.shape)
|
||||
print("length of key-value cache", past_key_values.get_seq_length()) # past_key_values are of shape [num_layers, 0 for k, 1 for v, batch_size, length, hidden_dim]
|
||||
generated_tokens.append(next_token_id.item())
|
||||
|
||||
generated_text = tokenizer.batch_decode(generated_tokens)
|
||||
generated_text
|
||||
```
|
||||
|
||||
**Output**:
|
||||
|
||||
```text
|
||||
shape of input_ids torch.Size([1, 1])
|
||||
length of key-value cache 20
|
||||
shape of input_ids torch.Size([1, 1])
|
||||
length of key-value cache 21
|
||||
shape of input_ids torch.Size([1, 1])
|
||||
length of key-value cache 22
|
||||
shape of input_ids torch.Size([1, 1])
|
||||
length of key-value cache 23
|
||||
shape of input_ids torch.Size([1, 1])
|
||||
length of key-value cache 24
|
||||
[' Here', ' is', ' a', ' Python', ' function']
|
||||
```
|
||||
|
||||
As one can see, when using the key-value cache the text input tokens are *not* increased in length, but remain a single input vector. The length of the key-value cache on the other hand is increased by one at every decoding step.
|
||||
|
||||
> Making use of the key-value cache means that the $\mathbf{QK}^T$ is essentially reduced to $\mathbf{q}_c\mathbf{K}^T$ with $\mathbf{q}_c$ being the query projection of the currently passed input token which is *always* just a single vector.
|
||||
|
||||
Using the key-value cache has two advantages:
|
||||
|
||||
- Significant increase in computational efficiency as less computations are performed compared to computing the full $\mathbf{QK}^T$ matrix. This leads to an increase in inference speed
|
||||
- The maximum required memory is not increased quadratically with the number of generated tokens, but only increases linearly.
|
||||
|
||||
> One should *always* make use of the key-value cache as it leads to identical results and a significant speed-up for longer input sequences. Transformers has the key-value cache enabled by default when making use of the text pipeline or the [`generate` method](https://huggingface.co/docs/transformers/main_classes/text_generation). We have an entire guide dedicated to caches [here](./kv_cache).
|
||||
|
||||
<Tip warning={true}>
|
||||
|
||||
Note that, despite our advice to use key-value caches, your LLM output may be slightly different when you use them. This is a property of the matrix multiplication kernels themselves -- you can read more about it [here](https://github.com/huggingface/transformers/issues/25420#issuecomment-1775317535).
|
||||
|
||||
</Tip>
|
||||
|
||||
#### 3.2.1 Multi-round conversation
|
||||
|
||||
The key-value cache is especially useful for applications such as chat where multiple passes of auto-regressive decoding are required. Let's look at an example.
|
||||
|
||||
```text
|
||||
User: How many people live in France?
|
||||
Assistant: Roughly 75 million people live in France
|
||||
User: And how many are in Germany?
|
||||
Assistant: Germany has ca. 81 million inhabitants
|
||||
```
|
||||
|
||||
In this chat, the LLM runs auto-regressive decoding twice:
|
||||
|
||||
1. The first time, the key-value cache is empty and the input prompt is `"User: How many people live in France?"` and the model auto-regressively generates the text `"Roughly 75 million people live in France"` while increasing the key-value cache at every decoding step.
|
||||
2. The second time the input prompt is `"User: How many people live in France? \n Assistant: Roughly 75 million people live in France \n User: And how many in Germany?"`. Thanks to the cache, all key-value vectors for the first two sentences are already computed. Therefore the input prompt only consists of `"User: And how many in Germany?"`. While processing the shortened input prompt, its computed key-value vectors are concatenated to the key-value cache of the first decoding. The second Assistant's answer `"Germany has ca. 81 million inhabitants"` is then auto-regressively generated with the key-value cache consisting of encoded key-value vectors of `"User: How many people live in France? \n Assistant: Roughly 75 million people live in France \n User: And how many are in Germany?"`.
|
||||
|
||||
Two things should be noted here:
|
||||
|
||||
1. Keeping all the context is crucial for LLMs deployed in chat so that the LLM understands all the previous context of the conversation. E.g. for the example above the LLM needs to understand that the user refers to the population when asking `"And how many are in Germany"`.
|
||||
2. The key-value cache is extremely useful for chat as it allows us to continuously grow the encoded chat history instead of having to re-encode the chat history again from scratch (as e.g. would be the case when using an encoder-decoder architecture).
|
||||
|
||||
In `transformers`, a `generate` call will return `past_key_values` when `return_dict_in_generate=True` is passed, in addition to the default `use_cache=True`. Note that it is not yet available through the `pipeline` interface.
|
||||
|
||||
```python
|
||||
# Generation as usual
|
||||
prompt = system_prompt + "Question: Please write a function in Python that transforms bytes to Giga bytes.\n\nAnswer: Here"
|
||||
model_inputs = tokenizer(prompt, return_tensors='pt')
|
||||
generation_output = model.generate(**model_inputs, max_new_tokens=60, return_dict_in_generate=True)
|
||||
decoded_output = tokenizer.batch_decode(generation_output.sequences)[0]
|
||||
|
||||
# Piping the returned `past_key_values` to speed up the next conversation round
|
||||
prompt = decoded_output + "\nQuestion: How can I modify the function above to return Mega bytes instead?\n\nAnswer: Here"
|
||||
model_inputs = tokenizer(prompt, return_tensors='pt')
|
||||
generation_output = model.generate(
|
||||
**model_inputs,
|
||||
past_key_values=generation_output.past_key_values,
|
||||
max_new_tokens=60,
|
||||
return_dict_in_generate=True
|
||||
)
|
||||
tokenizer.batch_decode(generation_output.sequences)[0][len(prompt):]
|
||||
```
|
||||
|
||||
**Output**:
|
||||
|
||||
```text
|
||||
is a modified version of the function that returns Mega bytes instead.
|
||||
|
||||
def bytes_to_megabytes(bytes):
|
||||
return bytes / 1024 / 1024
|
||||
|
||||
Answer: The function takes a number of bytes as input and returns the number of
|
||||
```
|
||||
|
||||
Great, no additional time is spent recomputing the same key and values for the attention layer! There is however one catch. While the required peak memory for the $\mathbf{QK}^T$ matrix is significantly reduced, holding the key-value cache in memory can become very memory expensive for long input sequences or multi-turn chat. Remember that the key-value cache needs to store the key-value vectors for all previous input vectors $\mathbf{x}_i \text{, for } i \in \{1, \ldots, c - 1\}$ for all self-attention layers and for all attention heads.
|
||||
|
||||
Let's compute the number of float values that need to be stored in the key-value cache for the LLM `bigcode/octocoder` that we used before.
|
||||
The number of float values amounts to two times the sequence length times the number of attention heads times the attention head dimension and times the number of layers.
|
||||
Computing this for our LLM at a hypothetical input sequence length of 16000 gives:
|
||||
|
||||
```python
|
||||
config = model.config
|
||||
2 * 16_000 * config.n_layer * config.n_head * config.n_embd // config.n_head
|
||||
```
|
||||
|
||||
**Output**:
|
||||
|
||||
```text
|
||||
7864320000
|
||||
```
|
||||
|
||||
Roughly 8 billion float values! Storing 8 billion float values in `float16` precision requires around 15 GB of RAM which is circa half as much as the model weights themselves!
|
||||
Researchers have proposed two methods that allow to significantly reduce the memory cost of storing the key-value cache, which are explored in the next subsections.
|
||||
|
||||
#### 3.2.2 Multi-Query-Attention (MQA)
|
||||
|
||||
[Multi-Query-Attention](https://huggingface.co/papers/1911.02150) was proposed in Noam Shazeer's *Fast Transformer Decoding: One Write-Head is All You Need* paper. As the title says, Noam found out that instead of using `n_head` key-value projections weights, one can use a single head-value projection weight pair that is shared across all attention heads without that the model's performance significantly degrades.
|
||||
|
||||
> By using a single head-value projection weight pair, the key value vectors $\mathbf{k}_i, \mathbf{v}_i$ have to be identical across all attention heads which in turn means that we only need to store 1 key-value projection pair in the cache instead of `n_head` ones.
|
||||
|
||||
As most LLMs use between 20 and 100 attention heads, MQA significantly reduces the memory consumption of the key-value cache. For the LLM used in this notebook we could therefore reduce the required memory consumption from 15 GB to less than 400 MB at an input sequence length of 16000.
|
||||
|
||||
In addition to memory savings, MQA also leads to improved computational efficiency as explained in the following.
|
||||
In auto-regressive decoding, large key-value vectors need to be reloaded, concatenated with the current key-value vector pair to be then fed into the $\mathbf{q}_c\mathbf{K}^T$ computation at every step. For auto-regressive decoding, the required memory bandwidth for the constant reloading can become a serious time bottleneck. By reducing the size of the key-value vectors less memory needs to be accessed, thus reducing the memory bandwidth bottleneck. For more detail, please have a look at [Noam's paper](https://huggingface.co/papers/1911.02150).
|
||||
|
||||
The important part to understand here is that reducing the number of key-value attention heads to 1 only makes sense if a key-value cache is used. The peak memory consumption of the model for a single forward pass without key-value cache stays unchanged as every attention head still has a unique query vector so that each attention head still has a different $\mathbf{QK}^T$ matrix.
|
||||
|
||||
MQA has seen wide adoption by the community and is now used by many of the most popular LLMs:
|
||||
|
||||
- [**Falcon**](https://huggingface.co/tiiuae/falcon-40b)
|
||||
- [**PaLM**](https://huggingface.co/papers/2204.02311)
|
||||
- [**MPT**](https://huggingface.co/mosaicml/mpt-30b)
|
||||
- [**BLOOM**](https://huggingface.co/bigscience/bloom)
|
||||
|
||||
Also, the checkpoint used in this notebook - `bigcode/octocoder` - makes use of MQA.
|
||||
|
||||
#### 3.2.3 Grouped-Query-Attention (GQA)
|
||||
|
||||
[Grouped-Query-Attention](https://huggingface.co/papers/2305.13245), as proposed by Ainslie et al. from Google, found that using MQA can often lead to quality degradation compared to using vanilla multi-key-value head projections. The paper argues that more model performance can be kept by less drastically reducing the number of query head projection weights. Instead of using just a single key-value projection weight, `n < n_head` key-value projection weights should be used. By choosing `n` to a significantly smaller value than `n_head`, such as 2,4 or 8 almost all of the memory and speed gains from MQA can be kept while sacrificing less model capacity and thus arguably less performance.
|
||||
|
||||
Moreover, the authors of GQA found out that existing model checkpoints can be *uptrained* to have a GQA architecture with as little as 5% of the original pre-training compute. While 5% of the original pre-training compute can still be a massive amount, GQA *uptraining* allows existing checkpoints to be useful for longer input sequences.
|
||||
|
||||
GQA was only recently proposed which is why there is less adoption at the time of writing this notebook.
|
||||
The most notable application of GQA is [Llama-v2](https://huggingface.co/meta-llama/Llama-2-70b-hf).
|
||||
|
||||
> As a conclusion, it is strongly recommended to make use of either GQA or MQA if the LLM is deployed with auto-regressive decoding and is required to handle large input sequences as is the case for example for chat.
|
||||
|
||||
## Conclusion
|
||||
|
||||
The research community is constantly coming up with new, nifty ways to speed up inference time for ever-larger LLMs. As an example, one such promising research direction is [speculative decoding](https://huggingface.co/papers/2211.17192) where "easy tokens" are generated by smaller, faster language models and only "hard tokens" are generated by the LLM itself. Going into more detail is out of the scope of this notebook, but can be read upon in this [nice blog post](https://huggingface.co/blog/assisted-generation).
|
||||
|
||||
The reason massive LLMs such as GPT3/4, Llama-2-70b, Claude, PaLM can run so quickly in chat-interfaces such as [Hugging Face Chat](https://huggingface.co/chat/) or ChatGPT is to a big part thanks to the above-mentioned improvements in precision, algorithms, and architecture.
|
||||
Going forward, accelerators such as GPUs, TPUs, etc... will only get faster and allow for more memory, but one should nevertheless always make sure to use the best available algorithms and architectures to get the most bang for your buck 🤗
|
||||
@@ -0,0 +1,60 @@
|
||||
<!--Copyright 2023 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Backbone
|
||||
|
||||
A backbone is a model used for feature extraction for higher level computer vision tasks such as object detection and image classification. Transformers provides an [`AutoBackbone`] class for initializing a Transformers backbone from pretrained model weights, and two utility classes:
|
||||
|
||||
* [`~backbone_utils.BackboneMixin`] enables initializing a backbone from Transformers or [timm](https://hf.co/docs/timm/index) and includes functions for returning the output features and indices.
|
||||
* [`~backbone_utils.BackboneConfigMixin`] sets the output features and indices of the backbone configuration.
|
||||
|
||||
[timm](https://hf.co/docs/timm/index) models are loaded with the [`TimmBackbone`] and [`TimmBackboneConfig`] classes.
|
||||
|
||||
Backbones are supported for the following models:
|
||||
|
||||
* [BEiT](../model_doc/beit)
|
||||
* [BiT](../model_doc/bit)
|
||||
* [ConvNext](../model_doc/convnext)
|
||||
* [ConvNextV2](../model_doc/convnextv2)
|
||||
* [DiNAT](../model_doc/dinat)
|
||||
* [DINOV2](../model_doc/dinov2)
|
||||
* [FocalNet](../model_doc/focalnet)
|
||||
* [MaskFormer](../model_doc/maskformer)
|
||||
* [NAT](../model_doc/nat)
|
||||
* [ResNet](../model_doc/resnet)
|
||||
* [Swin Transformer](../model_doc/swin)
|
||||
* [Swin Transformer v2](../model_doc/swinv2)
|
||||
* [ViTDet](../model_doc/vitdet)
|
||||
|
||||
## AutoBackbone
|
||||
|
||||
[[autodoc]] AutoBackbone
|
||||
|
||||
## BackboneMixin
|
||||
|
||||
[[autodoc]] backbone_utils.BackboneMixin
|
||||
|
||||
## BackboneConfigMixin
|
||||
|
||||
[[autodoc]] backbone_utils.BackboneConfigMixin
|
||||
|
||||
## TimmBackbone
|
||||
|
||||
[[autodoc]] models.timm_backbone.TimmBackbone
|
||||
|
||||
## TimmBackboneConfig
|
||||
|
||||
[[autodoc]] models.timm_backbone.TimmBackboneConfig
|
||||
@@ -0,0 +1,116 @@
|
||||
<!--Copyright 2020 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Callbacks
|
||||
|
||||
Callbacks are objects that can customize the behavior of the training loop in the PyTorch
|
||||
[`Trainer`] that can inspect the training loop state (for progress reporting, logging on TensorBoard or other ML
|
||||
platforms...) and take decisions (like early stopping).
|
||||
|
||||
Callbacks are "read only" pieces of code, apart from the [`TrainerControl`] object they return, they
|
||||
cannot change anything in the training loop. For customizations that require changes in the training loop, you should
|
||||
subclass [`Trainer`] and override the methods you need (see [trainer](trainer) for examples).
|
||||
|
||||
By default, `TrainingArguments.report_to` is set to `"none"`.
|
||||
|
||||
The main class that implements callbacks is [`TrainerCallback`]. It gets the
|
||||
[`TrainingArguments`] used to instantiate the [`Trainer`], can access that
|
||||
Trainer's internal state via [`TrainerState`], and can take some actions on the training loop via
|
||||
[`TrainerControl`].
|
||||
|
||||
## Available Callbacks
|
||||
|
||||
Here is the list of the available [`TrainerCallback`] in the library:
|
||||
|
||||
[[autodoc]] integrations.CometCallback
|
||||
- setup
|
||||
|
||||
[[autodoc]] DefaultFlowCallback
|
||||
|
||||
[[autodoc]] PrinterCallback
|
||||
|
||||
[[autodoc]] ProgressCallback
|
||||
|
||||
[[autodoc]] EarlyStoppingCallback
|
||||
|
||||
[[autodoc]] integrations.TensorBoardCallback
|
||||
|
||||
[[autodoc]] integrations.TrackioCallback
|
||||
- setup
|
||||
|
||||
[[autodoc]] integrations.WandbCallback
|
||||
- setup
|
||||
|
||||
[[autodoc]] integrations.MLflowCallback
|
||||
- setup
|
||||
|
||||
[[autodoc]] integrations.AzureMLCallback
|
||||
|
||||
[[autodoc]] integrations.CodeCarbonCallback
|
||||
|
||||
[[autodoc]] integrations.ClearMLCallback
|
||||
|
||||
[[autodoc]] integrations.DagsHubCallback
|
||||
|
||||
[[autodoc]] integrations.FlyteCallback
|
||||
|
||||
[[autodoc]] integrations.KubeflowCallback
|
||||
|
||||
[[autodoc]] integrations.DVCLiveCallback
|
||||
- setup
|
||||
|
||||
[[autodoc]] integrations.SwanLabCallback
|
||||
- setup
|
||||
|
||||
## TrainerCallback
|
||||
|
||||
[[autodoc]] TrainerCallback
|
||||
|
||||
Here is an example of how to register a custom callback with the PyTorch [`Trainer`]:
|
||||
|
||||
```python
|
||||
class MyCallback(TrainerCallback):
|
||||
"A callback that prints a message at the beginning of training"
|
||||
|
||||
def on_train_begin(self, args, state, control, **kwargs):
|
||||
print("Starting training")
|
||||
|
||||
|
||||
trainer = Trainer(
|
||||
model,
|
||||
args,
|
||||
train_dataset=train_dataset,
|
||||
eval_dataset=eval_dataset,
|
||||
callbacks=[MyCallback], # We can either pass the callback class this way or an instance of it (MyCallback())
|
||||
)
|
||||
```
|
||||
|
||||
Another way to register a callback is to call `trainer.add_callback()` as follows:
|
||||
|
||||
```python
|
||||
trainer = Trainer(...)
|
||||
trainer.add_callback(MyCallback)
|
||||
# Alternatively, we can pass an instance of the callback class
|
||||
trainer.add_callback(MyCallback())
|
||||
```
|
||||
|
||||
## TrainerState
|
||||
|
||||
[[autodoc]] TrainerState
|
||||
|
||||
## TrainerControl
|
||||
|
||||
[[autodoc]] TrainerControl
|
||||
@@ -0,0 +1,31 @@
|
||||
<!--Copyright 2020 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Configuration
|
||||
|
||||
The base class [`PreTrainedConfig`] implements the common methods for loading/saving a configuration
|
||||
either from a local file or directory, or from a pretrained model configuration provided by the library (downloaded
|
||||
from HuggingFace's AWS S3 repository).
|
||||
|
||||
Each derived config class implements model specific attributes. Common attributes present in all config classes are:
|
||||
`hidden_size`, `num_attention_heads`, and `num_hidden_layers`. Text models further implement:
|
||||
`vocab_size`.
|
||||
|
||||
## PreTrainedConfig
|
||||
|
||||
[[autodoc]] PreTrainedConfig
|
||||
- push_to_hub
|
||||
- all
|
||||
@@ -0,0 +1,33 @@
|
||||
<!--Copyright 2026 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Continuous batching
|
||||
|
||||
This page documents the classes behind continuous batching inference: submitting prompts, configuring scheduling and memory limits, and retrieving results.
|
||||
|
||||
For usage examples, see the [Continuous batching](../continuous_batching) guide and for how scheduling and memory interact, see the [Continuous batching architecture](../continuous_batching_architecture) doc.
|
||||
|
||||
## ContinuousMixin.generate_batch
|
||||
|
||||
[[autodoc]] ContinuousMixin.generate_batch
|
||||
|
||||
## ContinuousBatchingManager
|
||||
|
||||
[[autodoc]] ContinuousBatchingManager
|
||||
|
||||
## Continuous batching config
|
||||
|
||||
[[autodoc]] ContinuousBatchingConfig
|
||||
@@ -0,0 +1,72 @@
|
||||
<!--Copyright 2020 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Data Collator
|
||||
|
||||
Data collators are objects that will form a batch by using a list of dataset elements as input. These elements are of
|
||||
the same type as the elements of `train_dataset` or `eval_dataset`.
|
||||
|
||||
To be able to build batches, data collators may apply some processing (like padding). Some of them (like
|
||||
[`DataCollatorForLanguageModeling`]) also apply some random data augmentation (like random masking)
|
||||
on the formed batch.
|
||||
|
||||
Examples of use can be found in the [example scripts](../examples) or [example notebooks](../notebooks).
|
||||
|
||||
## Default data collator
|
||||
|
||||
[[autodoc]] data.data_collator.default_data_collator
|
||||
|
||||
## DefaultDataCollator
|
||||
|
||||
[[autodoc]] data.data_collator.DefaultDataCollator
|
||||
|
||||
## DataCollatorWithPadding
|
||||
|
||||
[[autodoc]] data.data_collator.DataCollatorWithPadding
|
||||
|
||||
## DataCollatorForTokenClassification
|
||||
|
||||
[[autodoc]] data.data_collator.DataCollatorForTokenClassification
|
||||
|
||||
## DataCollatorForSeq2Seq
|
||||
|
||||
[[autodoc]] data.data_collator.DataCollatorForSeq2Seq
|
||||
|
||||
## DataCollatorForLanguageModeling
|
||||
|
||||
[[autodoc]] data.data_collator.DataCollatorForLanguageModeling
|
||||
- numpy_mask_tokens
|
||||
- torch_mask_tokens
|
||||
|
||||
## DataCollatorForWholeWordMask
|
||||
|
||||
[[autodoc]] data.data_collator.DataCollatorForWholeWordMask
|
||||
- numpy_mask_tokens
|
||||
- torch_mask_tokens
|
||||
|
||||
## DataCollatorForPermutationLanguageModeling
|
||||
|
||||
[[autodoc]] data.data_collator.DataCollatorForPermutationLanguageModeling
|
||||
- numpy_mask_tokens
|
||||
- torch_mask_tokens
|
||||
|
||||
## DataCollatorWithFlattening
|
||||
|
||||
[[autodoc]] data.data_collator.DataCollatorWithFlattening
|
||||
|
||||
## DataCollatorForMultipleChoice
|
||||
|
||||
[[autodoc]] data.data_collator.DataCollatorForMultipleChoice
|
||||
@@ -0,0 +1,32 @@
|
||||
<!--Copyright 2020 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# DeepSpeed
|
||||
|
||||
[DeepSpeed](https://github.com/deepspeedai/DeepSpeed), powered by Zero Redundancy Optimizer (ZeRO), is an optimization library for training and fitting very large models onto a GPU. It is available in several ZeRO stages, where each stage progressively saves more GPU memory by partitioning the optimizer state, gradients, parameters, and enabling offloading to a CPU or NVMe. DeepSpeed is integrated with the [`Trainer`] class and most of the setup is automatically taken care of for you.
|
||||
|
||||
However, if you want to use DeepSpeed without the [`Trainer`], Transformers provides a [`HfDeepSpeedConfig`] class.
|
||||
|
||||
<Tip>
|
||||
|
||||
Learn more about using DeepSpeed with [`Trainer`] in the [DeepSpeed](../deepspeed) guide.
|
||||
|
||||
</Tip>
|
||||
|
||||
## HfDeepSpeedConfig
|
||||
|
||||
[[autodoc]] integrations.HfDeepSpeedConfig
|
||||
- all
|
||||
@@ -0,0 +1,31 @@
|
||||
<!--Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# ExecuTorch
|
||||
|
||||
[`ExecuTorch`](https://github.com/pytorch/executorch) is an end-to-end solution for enabling on-device inference capabilities across mobile and edge devices including wearables, embedded devices and microcontrollers. It is part of the PyTorch ecosystem and supports the deployment of PyTorch models with a focus on portability, productivity, and performance.
|
||||
|
||||
ExecuTorch introduces well defined entry points to perform model, device, and/or use-case specific optimizations such as backend delegation, user-defined compiler transformations, memory planning, and more. The first step in preparing a PyTorch model for execution on an edge device using ExecuTorch is to export the model. This is achieved through the use of a PyTorch API called [`torch.export`](https://pytorch.org/docs/stable/export.html).
|
||||
|
||||
## ExecuTorch Integration
|
||||
|
||||
An integration point is being developed to ensure that 🤗 Transformers can be exported using `torch.export`. The goal of this integration is not only to enable export but also to ensure that the exported artifact can be further lowered and optimized to run efficiently in `ExecuTorch`, particularly for mobile and edge use cases.
|
||||
|
||||
[[autodoc]] TorchExportableModuleWithStaticCache
|
||||
- forward
|
||||
|
||||
[[autodoc]] convert_and_export_with_cache
|
||||
@@ -0,0 +1,49 @@
|
||||
<!--Copyright 2026 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Exporters
|
||||
|
||||
New export backends can be added to Transformers by subclassing [`HfExporter`].
|
||||
|
||||
<Tip>
|
||||
|
||||
Learn how to use the built-in exporters in the [Exporters](../exporters) guide.
|
||||
|
||||
</Tip>
|
||||
|
||||
## AutoHfExporter
|
||||
|
||||
[[autodoc]] exporters.auto.AutoHfExporter
|
||||
|
||||
## AutoExportConfig
|
||||
|
||||
[[autodoc]] exporters.auto.AutoExportConfig
|
||||
|
||||
## HfExporter
|
||||
|
||||
[[autodoc]] exporters.base.HfExporter
|
||||
|
||||
## DynamoConfig
|
||||
|
||||
[[autodoc]] exporters.configs.DynamoConfig
|
||||
|
||||
## OnnxConfig
|
||||
|
||||
[[autodoc]] exporters.configs.OnnxConfig
|
||||
|
||||
## ExecutorchConfig
|
||||
|
||||
[[autodoc]] exporters.configs.ExecutorchConfig
|
||||
@@ -0,0 +1,38 @@
|
||||
<!--Copyright 2021 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Feature Extractor
|
||||
|
||||
A feature extractor is in charge of preparing input features for audio models. This includes feature extraction from sequences, e.g., pre-processing audio files to generate Log-Mel Spectrogram features, and conversion to NumPy and PyTorch tensors.
|
||||
|
||||
## FeatureExtractionMixin
|
||||
|
||||
[[autodoc]] feature_extraction_utils.FeatureExtractionMixin
|
||||
- from_pretrained
|
||||
- save_pretrained
|
||||
|
||||
## SequenceFeatureExtractor
|
||||
|
||||
[[autodoc]] SequenceFeatureExtractor
|
||||
- pad
|
||||
|
||||
## BatchFeature
|
||||
|
||||
[[autodoc]] BatchFeature
|
||||
|
||||
## ImageFeatureExtractionMixin
|
||||
|
||||
[[autodoc]] image_utils.ImageFeatureExtractionMixin
|
||||
@@ -0,0 +1,93 @@
|
||||
<!--Copyright 2022 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Image Processor
|
||||
|
||||
An image processor is in charge of loading images (optionally), preparing input features for vision models and post processing their outputs. This includes transformations such as resizing, normalization, and conversion to PyTorch and Numpy tensors. It may also include model specific post-processing such as converting logits to segmentation masks.
|
||||
|
||||
Image processors use a backend-based architecture. The class hierarchy is:
|
||||
|
||||
- [`BaseImageProcessor`] — abstract base class (for backward compatibility only; do not instantiate directly)
|
||||
- [`TorchvisionBackend`] — the **default** [torchvision-backed](https://pytorch.org/vision/stable/index.html) backend. GPU-accelerated and significantly faster than the PIL backend. All models expose a `<Model>ImageProcessor` class that inherits from it.
|
||||
- [`PilBackend`] — the PIL/NumPy alternative backend. Portable, CPU-only. Only available for older models via a `<Model>ImageProcessorPil` class; useful when exact numerical parity with the original implementation is required.
|
||||
|
||||
Both backends expose the same API. Use the `backend` attribute to inspect which backend a loaded processor uses (e.g. `processor.backend == "torchvision"`).
|
||||
|
||||
Pass `backend` to [`AutoImageProcessor.from_pretrained`] to select a backend. When `backend` is omitted (the default), torchvision is picked if it's installed, otherwise PIL is used. A few models that use Lanczos interpolation (Chameleon, Flava, Idefics3, SmolVLM) are an exception, and they default to PIL when torchvision < 0.27. Forcing `backend="torchvision"` for these models on torchvision < 0.27 falls back to BICUBIC interpolation, since torchvision supports Lanczos for tensors only from 0.27 onward.
|
||||
|
||||
```python
|
||||
from transformers import AutoImageProcessor
|
||||
|
||||
# Default: picks torchvision if available, otherwise pil
|
||||
processor = AutoImageProcessor.from_pretrained("facebook/detr-resnet-50")
|
||||
|
||||
# Explicitly request torchvision
|
||||
processor = AutoImageProcessor.from_pretrained("facebook/detr-resnet-50", backend="torchvision")
|
||||
|
||||
# Explicitly request PIL
|
||||
processor = AutoImageProcessor.from_pretrained("facebook/detr-resnet-50", backend="pil")
|
||||
```
|
||||
|
||||
When using the torchvision backend, you can set the `device` argument to specify the device on which the processing should be done. By default, the processing is done on the same device as the inputs if the inputs are tensors, or on the CPU otherwise.
|
||||
|
||||
```python
|
||||
from torchvision.io import read_image
|
||||
from transformers import DetrImageProcessor
|
||||
|
||||
images = read_image("image.jpg")
|
||||
processor = DetrImageProcessor.from_pretrained("facebook/detr-resnet-50")
|
||||
images_processed = processor(images, return_tensors="pt", device="cuda")
|
||||
```
|
||||
|
||||
Here are some speed comparisons between the torchvision and PIL backends for the `DETR` and `RT-DETR` models, and how they impact overall inference time:
|
||||
|
||||
<div class="flex">
|
||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/benchmark_results_full_pipeline_detr_fast_padded.png" />
|
||||
</div>
|
||||
<div class="flex">
|
||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/benchmark_results_full_pipeline_detr_fast_batched_compiled.png" />
|
||||
</div>
|
||||
|
||||
<div class="flex">
|
||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/benchmark_results_full_pipeline_rt_detr_fast_single.png" />
|
||||
</div>
|
||||
<div class="flex">
|
||||
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/benchmark_results_full_pipeline_rt_detr_fast_batched.png" />
|
||||
</div>
|
||||
|
||||
These benchmarks were run on an [AWS EC2 g5.2xlarge instance](https://aws.amazon.com/ec2/instance-types/g5/), utilizing an NVIDIA A10G Tensor Core GPU.
|
||||
|
||||
## ImageProcessingMixin
|
||||
|
||||
[[autodoc]] image_processing_utils.ImageProcessingMixin
|
||||
- from_pretrained
|
||||
- save_pretrained
|
||||
|
||||
## BatchFeature
|
||||
|
||||
[[autodoc]] BatchFeature
|
||||
|
||||
## BaseImageProcessor
|
||||
|
||||
[[autodoc]] image_processing_utils.BaseImageProcessor
|
||||
|
||||
## TorchvisionBackend
|
||||
|
||||
[[autodoc]] image_processing_backends.TorchvisionBackend
|
||||
|
||||
## PilBackend
|
||||
|
||||
[[autodoc]] image_processing_backends.PilBackend
|
||||
@@ -0,0 +1,11 @@
|
||||
## Kernels
|
||||
|
||||
This page documents the kernels configuration utilities.
|
||||
|
||||
### kernelize
|
||||
|
||||
[[autodoc]] kernelize
|
||||
|
||||
### KernelConfig
|
||||
|
||||
[[autodoc]] KernelConfig
|
||||
@@ -0,0 +1,119 @@
|
||||
<!--Copyright 2020 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Logging
|
||||
|
||||
🤗 Transformers has a centralized logging system, so that you can setup the verbosity of the library easily.
|
||||
|
||||
Currently the default verbosity of the library is `WARNING`.
|
||||
|
||||
To change the level of verbosity, just use one of the direct setters. For instance, here is how to change the verbosity
|
||||
to the INFO level.
|
||||
|
||||
```python
|
||||
import transformers
|
||||
|
||||
transformers.logging.set_verbosity_info()
|
||||
```
|
||||
|
||||
You can also use the environment variable `TRANSFORMERS_VERBOSITY` to override the default verbosity. You can set it
|
||||
to one of the following: `debug`, `info`, `warning`, `error`, `critical`, `fatal`. For example:
|
||||
|
||||
```bash
|
||||
TRANSFORMERS_VERBOSITY=error ./myprogram.py
|
||||
```
|
||||
|
||||
Additionally, some `warnings` can be disabled by setting the environment variable
|
||||
`TRANSFORMERS_NO_ADVISORY_WARNINGS` to a true value, like *1*. This will disable any warning that is logged using
|
||||
[`logger.warning_advice`]. For example:
|
||||
|
||||
```bash
|
||||
TRANSFORMERS_NO_ADVISORY_WARNINGS=1 ./myprogram.py
|
||||
```
|
||||
|
||||
Here is an example of how to use the same logger as the library in your own module or script:
|
||||
|
||||
```python
|
||||
from transformers.utils import logging
|
||||
|
||||
logging.set_verbosity_info()
|
||||
logger = logging.get_logger("transformers")
|
||||
logger.info("INFO")
|
||||
logger.warning("WARN")
|
||||
```
|
||||
|
||||
All the methods of this logging module are documented below, the main ones are
|
||||
[`logging.get_verbosity`] to get the current level of verbosity in the logger and
|
||||
[`logging.set_verbosity`] to set the verbosity to the level of your choice. In order (from the least
|
||||
verbose to the most verbose), those levels (with their corresponding int values in parenthesis) are:
|
||||
|
||||
- `transformers.logging.CRITICAL` or `transformers.logging.FATAL` (int value, 50): only report the most
|
||||
critical errors.
|
||||
- `transformers.logging.ERROR` (int value, 40): only report errors.
|
||||
- `transformers.logging.WARNING` or `transformers.logging.WARN` (int value, 30): only reports error and
|
||||
warnings. This is the default level used by the library.
|
||||
- `transformers.logging.INFO` (int value, 20): reports error, warnings and basic information.
|
||||
- `transformers.logging.DEBUG` (int value, 10): report all information.
|
||||
|
||||
By default, `tqdm` progress bars will be displayed during model download. [`logging.disable_progress_bar`] and [`logging.enable_progress_bar`] can be used to suppress or unsuppress this behavior.
|
||||
|
||||
## `logging` vs `warnings`
|
||||
|
||||
Python has two logging systems that are often used in conjunction: `logging`, which is explained above, and `warnings`,
|
||||
which allows further classification of warnings in specific buckets, e.g., `FutureWarning` for a feature or path
|
||||
that has already been deprecated and `DeprecationWarning` to indicate an upcoming deprecation.
|
||||
|
||||
We use both in the `transformers` library. We leverage and adapt `logging`'s `captureWarnings` method to allow
|
||||
management of these warning messages by the verbosity setters above.
|
||||
|
||||
What does that mean for developers of the library? We should respect the following heuristics:
|
||||
|
||||
- `warnings` should be favored for developers of the library and libraries dependent on `transformers`
|
||||
- `logging` should be used for end-users of the library using it in every-day projects
|
||||
|
||||
See reference of the `captureWarnings` method below.
|
||||
|
||||
[[autodoc]] logging.captureWarnings
|
||||
|
||||
## Base setters
|
||||
|
||||
[[autodoc]] logging.set_verbosity_error
|
||||
|
||||
[[autodoc]] logging.set_verbosity_warning
|
||||
|
||||
[[autodoc]] logging.set_verbosity_info
|
||||
|
||||
[[autodoc]] logging.set_verbosity_debug
|
||||
|
||||
## Other functions
|
||||
|
||||
[[autodoc]] logging.get_verbosity
|
||||
|
||||
[[autodoc]] logging.set_verbosity
|
||||
|
||||
[[autodoc]] logging.get_logger
|
||||
|
||||
[[autodoc]] logging.enable_default_handler
|
||||
|
||||
[[autodoc]] logging.disable_default_handler
|
||||
|
||||
[[autodoc]] logging.enable_explicit_format
|
||||
|
||||
[[autodoc]] logging.reset_format
|
||||
|
||||
[[autodoc]] logging.enable_progress_bar
|
||||
|
||||
[[autodoc]] logging.disable_progress_bar
|
||||
@@ -0,0 +1,44 @@
|
||||
<!--Copyright 2020 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Models
|
||||
|
||||
The base class [`PreTrainedModel`] implements the common methods for loading/saving a model either from a local
|
||||
file or directory, or from a pretrained model configuration provided by the library (downloaded from HuggingFace's Hub).
|
||||
|
||||
[`PreTrainedModel`] also implements a few methods which are common among all the models to:
|
||||
|
||||
- resize the input token embeddings when new tokens are added to the vocabulary
|
||||
|
||||
The other methods that are common to each model are defined in [`~modeling_utils.ModuleUtilsMixin`] and [`~generation.GenerationMixin`].
|
||||
|
||||
## PreTrainedModel
|
||||
|
||||
[[autodoc]] PreTrainedModel
|
||||
- push_to_hub
|
||||
- all
|
||||
|
||||
Custom models should also include a `_supports_assign_param_buffer`, which determines if superfast init can apply
|
||||
on the particular model. Signs that your model needs this are if `test_save_and_load_from_pretrained` fails. If so,
|
||||
set this to `False`.
|
||||
|
||||
## ModuleUtilsMixin
|
||||
|
||||
[[autodoc]] modeling_utils.ModuleUtilsMixin
|
||||
|
||||
## Pushing to the Hub
|
||||
|
||||
[[autodoc]] utils.PushToHubMixin
|
||||
@@ -0,0 +1,97 @@
|
||||
<!--Copyright 2020 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Optimization
|
||||
|
||||
The `.optimization` module provides:
|
||||
|
||||
- an optimizer with weight decay fixed that can be used to fine-tuned models, and
|
||||
- several schedules in the form of schedule objects that inherit from `_LRSchedule`:
|
||||
- a gradient accumulation class to accumulate the gradients of multiple batches
|
||||
|
||||
## AdaFactor
|
||||
|
||||
[[autodoc]] Adafactor
|
||||
|
||||
## Schedules
|
||||
|
||||
### SchedulerType
|
||||
|
||||
[[autodoc]] SchedulerType
|
||||
|
||||
### get_scheduler
|
||||
|
||||
[[autodoc]] get_scheduler
|
||||
|
||||
### get_constant_schedule
|
||||
|
||||
[[autodoc]] get_constant_schedule
|
||||
|
||||
### get_constant_schedule_with_warmup
|
||||
|
||||
[[autodoc]] get_constant_schedule_with_warmup
|
||||
|
||||
<img alt="" src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/warmup_constant_schedule.png"/>
|
||||
|
||||
### get_cosine_schedule_with_warmup
|
||||
|
||||
[[autodoc]] get_cosine_schedule_with_warmup
|
||||
|
||||
<img alt="" src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/warmup_cosine_schedule.png"/>
|
||||
|
||||
### get_cosine_with_hard_restarts_schedule_with_warmup
|
||||
|
||||
[[autodoc]] get_cosine_with_hard_restarts_schedule_with_warmup
|
||||
|
||||
### get_cosine_with_min_lr_schedule_with_warmup
|
||||
|
||||
[[autodoc]] get_cosine_with_min_lr_schedule_with_warmup
|
||||
|
||||
### get_cosine_with_min_lr_schedule_with_warmup_lr_rate
|
||||
|
||||
[[autodoc]] get_cosine_with_min_lr_schedule_with_warmup_lr_rate
|
||||
|
||||
<img alt="" src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/warmup_cosine_hard_restarts_schedule.png"/>
|
||||
|
||||
### GreedyLR
|
||||
|
||||
[[autodoc]] GreedyLR
|
||||
|
||||
### get_greedy_schedule
|
||||
|
||||
[[autodoc]] get_greedy_schedule
|
||||
|
||||
### get_linear_schedule_with_warmup
|
||||
|
||||
[[autodoc]] get_linear_schedule_with_warmup
|
||||
|
||||
<img alt="" src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/warmup_linear_schedule.png"/>
|
||||
|
||||
### get_polynomial_decay_schedule_with_warmup
|
||||
|
||||
[[autodoc]] get_polynomial_decay_schedule_with_warmup
|
||||
|
||||
### get_inverse_sqrt_schedule
|
||||
|
||||
[[autodoc]] get_inverse_sqrt_schedule
|
||||
|
||||
### get_reduce_on_plateau_schedule
|
||||
|
||||
[[autodoc]] get_reduce_on_plateau_schedule
|
||||
|
||||
### get_wsd_schedule
|
||||
|
||||
[[autodoc]] get_wsd_schedule
|
||||
@@ -0,0 +1,188 @@
|
||||
<!--Copyright 2020 The HuggingFace Team. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
|
||||
rendered properly in your Markdown viewer.
|
||||
|
||||
-->
|
||||
|
||||
# Model outputs
|
||||
|
||||
All models have outputs that are instances of subclasses of [`~utils.ModelOutput`]. Those are
|
||||
data structures containing all the information returned by the model, but that can also be used as tuples or
|
||||
dictionaries.
|
||||
|
||||
Let's see how this looks in an example:
|
||||
|
||||
```python
|
||||
from transformers import BertTokenizer, BertForSequenceClassification
|
||||
import torch
|
||||
|
||||
tokenizer = BertTokenizer.from_pretrained("google-bert/bert-base-uncased")
|
||||
model = BertForSequenceClassification.from_pretrained("google-bert/bert-base-uncased")
|
||||
|
||||
inputs = tokenizer("Hello, my dog is cute", return_tensors="pt")
|
||||
labels = torch.tensor([1]).unsqueeze(0) # Batch size 1
|
||||
outputs = model(**inputs, labels=labels)
|
||||
```
|
||||
|
||||
The `outputs` object is a [`~modeling_outputs.SequenceClassifierOutput`], as we can see in the
|
||||
documentation of that class below, it means it has an optional `loss`, a `logits`, an optional `hidden_states` and
|
||||
an optional `attentions` attribute. Here we have the `loss` since we passed along `labels`, but we don't have
|
||||
`hidden_states` and `attentions` because we didn't pass `output_hidden_states=True` or
|
||||
`output_attentions=True`.
|
||||
|
||||
<Tip>
|
||||
|
||||
When passing `output_hidden_states=True` you may expect the `outputs.hidden_states[-1]` to match `outputs.last_hidden_state` exactly.
|
||||
However, this is not always the case. Some models apply normalization or subsequent process to the last hidden state when it's returned.
|
||||
|
||||
</Tip>
|
||||
|
||||
You can access each attribute as you would usually do, and if that attribute has not been returned by the model, you
|
||||
will get `None`. Here for instance `outputs.loss` is the loss computed by the model, and `outputs.attentions` is
|
||||
`None`.
|
||||
|
||||
When considering our `outputs` object as tuple, it only considers the attributes that don't have `None` values.
|
||||
Here for instance, it has two elements, `loss` then `logits`, so
|
||||
|
||||
```python
|
||||
outputs[:2]
|
||||
```
|
||||
|
||||
will return the tuple `(outputs.loss, outputs.logits)` for instance.
|
||||
|
||||
When considering our `outputs` object as dictionary, it only considers the attributes that don't have `None`
|
||||
values. Here for instance, it has two keys that are `loss` and `logits`.
|
||||
|
||||
We document here the generic model outputs that are used by more than one model type. Specific output types are
|
||||
documented on their corresponding model page.
|
||||
|
||||
## ModelOutput
|
||||
|
||||
[[autodoc]] utils.ModelOutput
|
||||
- to_tuple
|
||||
|
||||
## BaseModelOutput
|
||||
|
||||
[[autodoc]] modeling_outputs.BaseModelOutput
|
||||
|
||||
## BaseModelOutputWithPooling
|
||||
|
||||
[[autodoc]] modeling_outputs.BaseModelOutputWithPooling
|
||||
|
||||
## BaseModelOutputWithCrossAttentions
|
||||
|
||||
[[autodoc]] modeling_outputs.BaseModelOutputWithCrossAttentions
|
||||
|
||||
## BaseModelOutputWithPoolingAndCrossAttentions
|
||||
|
||||
[[autodoc]] modeling_outputs.BaseModelOutputWithPoolingAndCrossAttentions
|
||||
|
||||
## BaseModelOutputWithPast
|
||||
|
||||
[[autodoc]] modeling_outputs.BaseModelOutputWithPast
|
||||
|
||||
## BaseModelOutputWithPastAndCrossAttentions
|
||||
|
||||
[[autodoc]] modeling_outputs.BaseModelOutputWithPastAndCrossAttentions
|
||||
|
||||
## Seq2SeqModelOutput
|
||||
|
||||
[[autodoc]] modeling_outputs.Seq2SeqModelOutput
|
||||
|
||||
## CausalLMOutput
|
||||
|
||||
[[autodoc]] modeling_outputs.CausalLMOutput
|
||||
|
||||
## CausalLMOutputWithCrossAttentions
|
||||
|
||||
[[autodoc]] modeling_outputs.CausalLMOutputWithCrossAttentions
|
||||
|
||||
## CausalLMOutputWithPast
|
||||
|
||||
[[autodoc]] modeling_outputs.CausalLMOutputWithPast
|
||||
|
||||
## MaskedLMOutput
|
||||
|
||||
[[autodoc]] modeling_outputs.MaskedLMOutput
|
||||
|
||||
## Seq2SeqLMOutput
|
||||
|
||||
[[autodoc]] modeling_outputs.Seq2SeqLMOutput
|
||||
|
||||
## NextSentencePredictorOutput
|
||||
|
||||
[[autodoc]] modeling_outputs.NextSentencePredictorOutput
|
||||
|
||||
## SequenceClassifierOutput
|
||||
|
||||
[[autodoc]] modeling_outputs.SequenceClassifierOutput
|
||||
|
||||
## Seq2SeqSequenceClassifierOutput
|
||||
|
||||
[[autodoc]] modeling_outputs.Seq2SeqSequenceClassifierOutput
|
||||
|
||||
## MultipleChoiceModelOutput
|
||||
|
||||
[[autodoc]] modeling_outputs.MultipleChoiceModelOutput
|
||||
|
||||
## TokenClassifierOutput
|
||||
|
||||
[[autodoc]] modeling_outputs.TokenClassifierOutput
|
||||
|
||||
## QuestionAnsweringModelOutput
|
||||
|
||||
[[autodoc]] modeling_outputs.QuestionAnsweringModelOutput
|
||||
|
||||
## Seq2SeqQuestionAnsweringModelOutput
|
||||
|
||||
[[autodoc]] modeling_outputs.Seq2SeqQuestionAnsweringModelOutput
|
||||
|
||||
## Seq2SeqSpectrogramOutput
|
||||
|
||||
[[autodoc]] modeling_outputs.Seq2SeqSpectrogramOutput
|
||||
|
||||
## SemanticSegmenterOutput
|
||||
|
||||
[[autodoc]] modeling_outputs.SemanticSegmenterOutput
|
||||
|
||||
## ImageClassifierOutput
|
||||
|
||||
[[autodoc]] modeling_outputs.ImageClassifierOutput
|
||||
|
||||
## ImageClassifierOutputWithNoAttention
|
||||
|
||||
[[autodoc]] modeling_outputs.ImageClassifierOutputWithNoAttention
|
||||
|
||||
## DepthEstimatorOutput
|
||||
|
||||
[[autodoc]] modeling_outputs.DepthEstimatorOutput
|
||||
|
||||
## Wav2Vec2BaseModelOutput
|
||||
|
||||
[[autodoc]] modeling_outputs.Wav2Vec2BaseModelOutput
|
||||
|
||||
## XVectorOutput
|
||||
|
||||
[[autodoc]] modeling_outputs.XVectorOutput
|
||||
|
||||
## Seq2SeqTSModelOutput
|
||||
|
||||
[[autodoc]] modeling_outputs.Seq2SeqTSModelOutput
|
||||
|
||||
## Seq2SeqTSPredictionOutput
|
||||
|
||||
[[autodoc]] modeling_outputs.Seq2SeqTSPredictionOutput
|
||||
|
||||
## SampleTSPredictionOutput
|
||||
|
||||
[[autodoc]] modeling_outputs.SampleTSPredictionOutput
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user