Transformers documentation
Attention 백엔드
Attention 백엔드
모든 attention 구현은 동일한 계산을 수행합니다. 모든 토큰이 다른 모든 토큰과 비교됩니다. 차이는 어떤 방식으로 계산을 수행하느냐에 있습니다. 기본 attention은 메모리에 전체 attention matrix를 materialize하기 때문에 확장성이 낮으며, 추론을 늦추는 병목 현상을 유발합니다. 최적화된 구현은 수식을 재배열하여 메모리 트래픽을 줄이고, 더 빠르고 비용 효율적인 추론을 가능하게 합니다.
AttentionInterface는 최적화된 attention 구현을 제공합니다. attention 구현을 모델 구현과 분리하여 다양한 함수에 대한 실험을 단순화합니다. 이 일관된 인터페이스를 사용하면 새로운 backends를 쉽게 추가할 수 있습니다.
| Attention 백엔드 | 설명 |
|---|---|
"flash_attention_3" | FlashAttention-2를 개선하여 연산 오버랩을 수행하고 포워드와 백워드 패스를 더 긴밀하게 융합합니다 |
"flash_attention_2" | tiles 컴퓨테이션을 더 작은 블록으로 나누고 빠른 온칩 메모리를 사용합니다 |
"flex_attention" | framework for specifying custom attention patterns (sparse, block-local, sliding window) without writing low-level kernels by hand |
"sdpa" | 스케일된 도트 프로덕트 어텐션의 내장 PyTorch 구현 |
"paged|flash_attention_3" | FlashAttention-3의 Paged 버전 |
"paged|flash_attention_2" | FlashAttention-2의 Paged 버전 |
"paged|sdpa" | SDPA의 페이지드 버전 |
"paged|eager" | eager의 Paged 버전 |
어텐션 백엔드 설정
attn_implementation 인수를 from_pretrained()에 전달하여 특정 attention 함수를 사용하는 모델을 생성합니다.
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 라이브러리를 사용하면 런타임에 컴파일된 compute kernel을 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의 scaled dot product attention(SDPA)은 CUDA 백엔드에 대해 가장 빠른 attention 함수를 자동으로 선택합니다. 다른 백엔드의 경우 기본값으로 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에서 특정 backbones을 제외하면 기본 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"
)빈 키를 사용하여 attention 함수를 전역으로 설정합니다.
model = AutoModelForImageTextToText.from_pretrained(
"facebook/chameleon-7b", attn_implementation={"": "eager"}
)새로운 attention 함수 만들기
AttentionInterface.register()를 사용하여 attention 레지스트리에 attention 함수를 추가하여 attention 함수를 사용자 지정하거나 새로 만들 수 있습니다. 모델은 attn_implementation 인수를 통해 이러한 함수를 사용합니다.
커스텀 어텐션 함수를 등록할 때 매칭되는 어텐션 마스크 함수도 함께 등록하세요. 커스텀
attn_implementation이름이 AttentionMaskInterface에 등록되어 있지 않으면, Transformers는 마스크 생성을 건너뛰고 어텐션 레이어에attention_mask=None을 전달합니다. 이 경우 어텐션 함수가 causal, padding, packing 또는 sliding-window 제약 조건을 스스로 처리해야 하며, 그렇지 않으면 해당 제약 조건이 조용히 무시될 수 있습니다.
이 예제는 각 레이어마다 문구를 출력하도록 attention 함수를 커스터마이징합니다. masking_utils.sdpa_mask를 attention mask 함수로 등록하여 원래 구현의 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))attention 함수에 새로운 인수를 추가할 수도 있습니다. AttentionInterface를 지원하는 모델은 kwargs를 attention 레이어와 attention 함수로 전달합니다. 모델의 forward 함수에서 인수를 kwargs로 전달하세요. 사용자 정의 attention 함수는 이 시그니처와 반환 형식을 따르야 합니다.
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 function에 어떤 arguments와 kwargs를 전달하는지 확인하세요.
AttentionMaskInterface
AttentionMaskInterface는 create_*_mask 함수들이 마스크를 활성 어텐션 백엔드가 기대하는 형식으로 변환하기 위해 참조하는 레지스트리입니다. FlexAttention은 BlockMask를, SDPA는 4D 텐서를, FlashAttention은 기본 2D 패딩 마스크를 필요로 합니다. 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에 대해 등록된 formatter가 없으면 mask 생성이 건너뛰어지고 attention_mask=None이 attention 레이어로 전달됩니다.
등록된 함수는 이 시그니처와 일치해야 합니다.
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)를 받아 해당 위치가 어텐션 계산에 기여하는지 여부를 나타내는 불리언 값을 반환합니다. 이는 Build an attention mask에서 or_mask_function와 and_mask_function에 사용되는 것과 동일한 기본 형태입니다.
mask_function이 마스크를 생성하지 못하는 경우 torch.export에 이 우회 방법을 사용하세요.
Attention mask 만들기
transformers.masking_utils의 create_*_mask 함수를 사용하여 attention mask를 생성합니다. 각 함수는 모델 config에서 활성 attention backend를 읽고, AttentionMaskInterface에서 해당 backend의 mask formatter를 조회한 뒤, 해당 backend가 기대하는 형식으로 반환합니다. mask를 직접 반전, 확장 또는 캐스팅할 필요가 없습니다.
어텐션 패턴과 일치하는 함수를 선택하세요.
| 함수 | 사용 사례 |
|---|---|
create_causal_mask | 각 토큰이 자신과 이전 토큰에만 주의를 기울이는 decoder-only 모델 |
create_bidirectional_mask | 인코더 모델, 또는 디코더에서 인코더 상태로 향하는 크로스 어텐션 |
create_sliding_window_causal_mask | 슬라이딩 윈도우 어텐션 패턴을 사용하는 decoder 모델 |
create_chunked_causal_mask | 고정 크기 블록으로 시퀀스를 분할하는 decoder 모델 |
create_bidirectional_sliding_window_mask | 슬라이딩 윈도우 어텐션 패턴을 사용하는 인코더 모델 |
레거시 callable mask 헬퍼 -
get_extended_attention_mask,create_extended_attention_mask_for_decoder,invert_attention_mask- 은 비권장(deprecation) 경고를 출력하며 향후 릴리스에서 제거될 예정입니다. 대신create_*_mask함수를 사용하세요.
디코더의 forward pass 안에서 create_causal_mask를 호출합니다. config, 입력 임베딩, 사용자가 제공한 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,
)인코더 셀프 어텐션에 create_bidirectional_mask를 호출합니다. 인코더는 캐시를 사용하지 않으므로 past_key_values를 제거합니다.
from transformers.masking_utils import create_bidirectional_mask
attention_mask = create_bidirectional_mask(
config=self.config,
inputs_embeds=embedding_output,
attention_mask=attention_mask,
)크로스 어텐션의 경우, encoder_hidden_states로 인코더 상태를 전달하면 마스크가 디코더의 쿼리 길이가 아닌 인코더의 키와 값 길이를 사용합니다.
encoder_attention_mask = create_bidirectional_mask(
config=self.config,
inputs_embeds=embedding_output,
attention_mask=encoder_attention_mask,
encoder_hidden_states=encoder_hidden_states,
)or_mask_function 및 and_mask_function 인수를 사용하여 기본 마스크 위에 추가 제약 조건을 적용합니다. or_mask_function는 추가 위치가 attend하도록 허용하고, and_mask_function는 기본 패턴을 더 제한하는 데 사용됩니다. 두 함수 모두 AttentionMaskInterface에 설명된 4인덱스 mask_function 시그니처를 따릅니다. (batch_idx, head_idx, q_idx, kv_idx)를 인수로 받아 boolean을 반환합니다.
or_mask_function과and_mask_function은 임의의 어텐션 패턴을 표현할 수 있지만, 내장된 패턴보다 느리며 ExecuTorch와 호환되지 않습니다. 오버헤드는 작은 모델(~200M 파라미터)에서 가장 두드러지며, 이 경우 마스크 생성이 포워드 패스 시간에 차지하는 비중이 커집니다. 표준create_*_mask함수로 필요한 내용을 표현할 수 없는 경우에만 이 함수들을 사용하세요.
예를 들어, 모든 위치에서 True를 반환하는 함수를 causal mask에 오버레이하여 완전히 양방향(bidirectional) mask로 변환할 수 있습니다. causal 패턴과의 합집합을 통해 모든 토큰이 다른 모든 토큰을 attend할 수 있게 됩니다.
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_*_mask로 분기하는 create_masks_for_generate를 통해 마스크를 생성합니다. 생성을 위한 사용자 정의 마스킹 전략을 적용하려면 모델 클래스에서 이 메서드를 오버라이드하세요.
사용자 정의 4D attention mask를 전달
create_*_mask 함수로 표현할 수 없는 어텐션 패턴이 필요할 때 직접 4D 마스크를 전달하세요. 4D 마스크의 형태는 (batch_size, 1, query_length, kv_length)이며, 여기서 1은 모든 어텐션 헤드에 동일한 마스크가 브로드캐스트됨을 의미합니다. Transformers는 해당 마스크를 감지하여 그대로 사용하며, create_*_mask를 건너뜁니다.
4D 마스크는 두 가지 값 규약 중 하나를 사용합니다.
| dtype | 참석 | 마스크 처리 |
|---|---|---|
| boolean | True | False |
| float | 0.0 | -inf |
float 규약은 softmax 전에 마스크를 attention score에 더합니다. 점수에 0.0을 더하면 값이 변하지 않으므로 해당 위치가 기여합니다. 점수에 -inf을 더하면 softmax 이후에 0이 되므로 해당 위치가 제외됩니다.
수용되는 규약은 attention backend에 따라 다릅니다.
sdpa는 boolean 또는 float mask를 받습니다.eager는 mask를 scores에 더하므로 float mask만 받습니다.flash_attention_2와flex_attention는 자체 형식(2D padding mask와 BlockMask)을 사용하며, 원본 4D mask는 받지 않습니다.
흔한 실수는 2D 패딩 마스크의 1/0 규약을 float 4D 마스크에 재사용하는 것입니다. 마스크가 점수에 더해지므로, 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 모델은 기본적으로 인과적(단방향) attention을 사용하며, 각 토큰은 자신과 이전 토큰에만 attention을 기울입니다. is_causal=False로 설정하면 모든 토큰이 다른 모든 토큰에 attention을 기울이는 양방향 attention으로 전환됩니다. 이를 통해 Decoder-only 모델을 텍스트 인코더로 사용할 수 있으며, 예를 들어 임베딩을 생성하는 데 활용할 수 있습니다.
이 기능은 causal(decoder) 모델에서만 작동합니다. encoder 모델을 decoder 모델로 변환하지는 않습니다.
모든 forward pass에서 양방향 attention을 기본으로 하려면 모델 config에서 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)모델을 두 번 로드하지 않고 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)