Transformers documentation

アテンションのバックエンド

You are viewing main version, which requires installation from source. If you'd like regular pip install, checkout the latest stable version (v5.22.1).
Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

アテンションのバックエンド

すべてのアテンション実装は同じ計算を実行します。各トークンは他のすべてのトークンと比較されます。違いは、計算がどのように実行されるかという点です。基本的なアテンションは、メモリ上に完全なアテンション行列をマテリアライズするため、スケーリングが不良であり、推論を遅くするボトルネックを生み出します。最適化された実装は、計算を再構成してメモリトラフィックを削減し、より高速で低コストな推論を実現します。

AttentionInterface は、最適化されたアテンションの実装を提供します。アテンションの実装とモデルの実装を分離することで、異なる関数を用いた実験を簡素化します。この一貫したインターフェースにより、新しいバックエンドを簡単に追加できます。

アテンションバックエンド説明
"flash_attention_3"FlashAttention-2を改善し、操作のオーバーラップに加え、フォワードパスとバックワードパスをより密接に融合します
"flash_attention_2"計算をより小さなブロックに分割し、高速なオンチップメモリを使用します
"flex_attention"低レベルのカーネルを手作業で書くことなく、カスタムのアテンションパターン(スパース、ブロックローカル、スライディングウィンドウ)を指定するためのフレームワーク
"sdpa"PyTorchの組み込み実装であるスケーリングドットプロダクトアテンション
"paged|flash_attention_3"FlashAttention-3のページド版
"paged|flash_attention_2"FlashAttention-2のページド版
"paged|sdpa"SDPAのページング版
"paged|eager"Eagerのページング版

アテンションバックエンドを設定する

attn_implementation 引数を from_pretrained() に渡すことで、特定の注意機構関数を用いたモデルをインスタンス化できます。

import torch
from transformers import AutoModelForCausalLM

model = AutoModelForCausalLM.from_pretrained(
    "meta-llama/Llama-3.2-1B", attn_implementation="flash_attention_2"
)

モデルを再読み込みせずに、set_attn_implementation() を使用してランタイムでアテンションのバックエンドを切り替えます。

model.set_attn_implementation("sdpa")

カーネル

Kernels ライブラリを使用すると、実行時にコンパイル済みの計算カーネルを Hub から直接ダウンロードして読み込むことができます。これにより、PyTorch や CUDA のバージョン不一致によるパッケージングの問題を回避できます。

Kernels は検出時に自動的に AttentionInterface に登録されます。FlashAttention パッケージを明示的にインストールする必要はありません。FlashAttention を名前でリクエストした場合も Hub kernel にフォールバックします。FlashAttention fallback を参照してください。

import torch
from transformers import AutoModelForCausalLM

model = AutoModelForCausalLM.from_pretrained(
    "meta-llama/Llama-3.2-1B", attn_implementation="kernels-community/flash-attn2"
)

SDPAコンテキストマネージャー

PyTorchのスケーリングドットプロダクトアテンション(SDPA)は、CUDAバックエンドに対して最速のアテンション関数を自動的に選択します。その他のバックエンドでは、デフォルトでPyTorchのC++実装を使用します。

torch.nn.attention.sdpa_kernel コンテキストマネージャーを使用して、SDPAに特定の実装を使用させることができます。

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)

バックボーン固有の注意

マルチモーダルモデルでは、各モダリティごとに異なるバックボーンを使用します。各バックボーンに特定の注意機構を割り当てることで、パフォーマンスを最適化できます。例えば、一部のビジョンバックボーンはfp32でより良いパフォーマンスを発揮しますが、FlashAttentionはこれをサポートしていません。

dict を使用してビジョンのバックボーンを異なるアテンション関数にマッピングし、テキストのバックボーンは引き続き FlashAttention を使用します。アテンション実装のキーは、サブ設定の名前と一致する必要があります。

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
)

dictから特定のbackboneを省略すると、デフォルトのattention関数(SDPA)が使用されます。

model = AutoModelForImageTextToText.from_pretrained(
    "facebook/chameleon-7b", attn_implementation={"text_config": "flash_attention_2"}
)

単一の文字列で、すべてのバックボーンに同じアテンション関数を設定します。

model = AutoModelForImageTextToText.from_pretrained(
    "facebook/chameleon-7b", attn_implementation="eager"
)

空のキーでアテンション関数をグローバルに設定します。

model = AutoModelForImageTextToText.from_pretrained(
    "facebook/chameleon-7b", attn_implementation={"": "eager"}
)

新しいアテンション関数を作成する

AttentionInterface.register() を使用してアテンションレジストリに追加することで、アテンション関数をカスタマイズしたり、新しいアテンション関数を作成したりできます。モデルは attn_implementation 引数を通じてこれらの関数を使用します。

カスタムアテンション関数を登録する際は、対応するアテンションマスク関数も登録してください。カスタムのattn_implementation名がAttentionMaskInterfaceに登録されていない場合、Transformersはマスクの作成をスキップし、アテンションレイヤーにattention_mask=Noneを渡します。そのため、アテンション関数内で因果性、パディング、パッキング、またはスライディングウィンドウの制約を自分で処理する必要があります。そうしないと、これらの制約が黙って無視されてしまいます。

この例では、アテンション関数をカスタマイズして、各レイヤーごとにステートメントを出力します。元の実装のマスクを保持するために、masking_utils.sdpa_maskをアテンションマスク関数として登録しています。

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))

アテンション関数に新しい引数を追加することもできます。AttentionInterfaceをサポートするモデルは、kwargsをアテンション層およびアテンション関数に伝播します。モデルのforward関数で引数をkwargsとして渡します。カスタムアテンション関数は、このシグネチャと返却形式に従う必要があります。

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=...)

モデルのmodeling codeを確認し、attention関数に渡される引数とkwargsを特定してください。

AttentionMaskInterface

AttentionMaskInterface は、create_*_mask 関数が参照して、マスクをアクティブなアテンションバックエンドが期待する形式に変換するためのレジストリです。FlexAttention には BlockMask が必要で、SDPA には 4 次元テンソル、FlashAttention にはベースとなる 2 次元パディングマスクが必要です。AttentionMaskInterface.register() を使用して、カスタムバックエンドを登録したり、既存のバックエンドのフォーマッターをオーバーライドしたりできます。

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)

アクティブなattn_implementationに対応するフォーマッタが登録されていない場合、マスクの作成はスキップされ、attention_mask=Noneがアテンション層に渡されます。

登録された関数は、このシグネチャと一致する必要があります。

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]:

mask_function 引数は、PyTorch の mask_mod 関数を模した Callable です。4 つのインデックス (batch_idx, head_idx, q_idx, kv_idx) を受け取り、その位置がアテンション計算に寄与するかどうかを示すブール値を返します。これは、アテンションマスクの構築 で or_mask_function および and_mask_function に使用されているのと同じ基本形です。

mask_functionがマスクの作成に失敗する場合、torch.exportにはこのワークアラウンドを使用してください。

アテンションマスクの構築

transformers.masking_utils の create_*_mask 関数を使用してアテンションマスクを構築します。各関数はモデル設定からアクティブなアテンションバックエンドを読み取り、AttentionMaskInterface でそのバックエンドのマスクフォーマッタを検索し、バックエンドが期待する形式を返します。マスクの反転、拡張、キャストを自分で行う必要はありません。

アテンションパターンに一致する関数を選択します。

関数ユースケース
create_causal_mask各トークンが自分自身とそれ以前のトークンにアテンションを向けるdecoder-onlyモデル
create_bidirectional_maskエンコーダーモデル、またはデコーダーからエンコーダー状態へのクロスアテンション
create_sliding_window_causal_maskスライディングウィンドウアテンションパターンを持つデコーダーモデル
create_chunked_causal_maskシーケンスを固定サイズのブロックに分割するデコーダーモデル
create_bidirectional_sliding_window_maskスライディングウィンドウアテンションパターンを持つエンコーダーモデル

レガシーの呼び出し可能なマスクヘルパー - get_extended_attention_mask、create_extended_attention_mask_for_decoder、invert_attention_mask - は非推奨の警告を出力し、将来のリリースで削除されます。代わりにcreate_*_mask関数を使用してください。

causal attention
エンコーダー自己アテンション
クロスアテンション

デコーダーのフォワードパス内でcreate_causal_maskを呼び出します。設定、入力埋め込み、ユーザーが指定した2次元のattention_mask、およびキャッシュを引数として渡します。この関数は、埋め込みからバッチサイズ、クエリ長、dtype、デバイスを読み取り、キャッシュからキー長を計算します。

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,
)

or_mask_function と and_mask_function 引数を使用して、ベースマスクの上に追加の制約を付けます。or_mask_function を使用すると追加の位置がアテンションできるようになり、and_mask_function を使用するとベースパターンをさらに制限できます。どちらも、AttentionMaskInterface で説明されている4インデックスの mask_function シグネチャに従います。(batch_idx, head_idx, q_idx, kv_idx) を受け取り、ブール値を返します。

or_mask_function と and_mask_function は任意の注意パターンを表現できますが、組み込みパターンよりも遅く、ExecuTorch と互換性がありません。オーバーヘッドは、マスク生成がフォワードパスの時間に占める割合が大きくなる小型モデル(約 2 億パラメータ)で特に顕著です。標準的な create_*_mask 関数では必要な表現ができない場合のみ、これらを使用してください。

例えば、どこでもTrueを返す関数をオーバーレイして因果マスクを完全に双方向なものに変換できます。因果パターンとの和集合により、すべてのトークンが他のすべてのトークンに注意を払うようになります。

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)

生成時、generate() は create_masks_for_generate を介してマスクを構築します。この関数は、モデルの構成に基づいて適切な create_*_mask にディスパッチします。モデルクラスでこれをオーバーライドすることで、生成用のカスタムなマスキング戦略を適用できます。

カスタムの4Dアテンションマスクを渡す

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.

4Dマスクは、2つの値の慣用法のいずれかを使用します。

dtypeattendマスクアウト
booleanTrueFalse
float0.0-inf

float 規約では、softmax の前にマスクをアテンションスコアに加算します。スコアに 0.0 を加えても値は変化しないため、その位置は貢献します。一方、スコアに -inf を加えると softmax 後にゼロになるため、その位置は除外されます。

受け入れられる規約はアテンションバックエンドによって異なります。sdpaはブール値または浮動小数点マスクを受け取ります。eagerはマスクをスコアに追加するため、浮動小数点マスクのみを受け取ります。flash_attention_2とflex_attentionは独自の形式(2次元パディングマスクとBlockMask)を使用し、生の4次元マスクは受け入れません。

よくある間違いとして、2次元のpaddingマスクで使われる1/0の慣習を、float型の4次元マスクにそのまま適用してしまうことです。マスクはスコアに足し算されるため、0.0は位置を保持し、1.0はわずかなバイアスを加えるだけです。

以下の例では、誤ったマスクと正しいマスクを比較しています。どちらも同じ1/0の因果パターンから始まります。

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]

0.0がマスクに使用される値であるため、誤ったマスクでは何も除外されず、すべての位置が保持されます。

        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

双方向アテンション

Decoder-onlyモデルはデフォルトでcausal(単方向)アテンションを使用し、各トークンは自分自身とそれ以前のトークンのみにアテンションを向けます。is_causal=Falseを設定すると、すべてのトークンが他のすべてのトークンにアテンションを向ける双方向アテンションに切り替わります。これにより、Decoder-onlyモデルをテキストエンコーダーとして使用できるようになり、例えば埋め込みの生成が可能になります。

これは因果的(デコーダー)モデルでのみ機能します。エンコーダーモデルをデコーダーモデルに変換するものではありません。

モデル設定でis_causal=Falseを設定すると、すべてのフォワードパスで双方向アテンションがデフォルトになります。

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)

モデルを2回読み込むことなく、causal attentionとbidirectional attentionの切り替えを行うには、モデルのconfigではなく、forward呼び出しでis_causalを渡します。このkwargはconfigを一時的に上書きし、呼び出し後に元の状態に復元されます。

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)
Update on GitHub