개요

개요

Transformers는 모델을 빠르고 저렴하며 접근 가능하게 만들기 위한 여러 추론 최적화 기법을 제공합니다. 옵션에는 메모리 트래픽을 줄이는 대체 어텐션 메커니즘, 더 빠른 실행을 위한 코드 컴파일, 처리량을 위한 최적화된 커널이 포함됩니다. 최대 성능을 위해 이 기법들을 조합할 수 있습니다.

출처: 문서

본문

Transformers는 모델을 빠르고 저렴하며 접근 가능하게 만들기 위한 여러 추론 최적화 기법을 제공합니다. 옵션에는 메모리 트래픽을 줄이는 대체 어텐션 메커니즘, 더 빠른 실행을 위한 코드 컴파일, 처리량을 위한 최적화된 커널이 포함됩니다. 최대 성능을 위해 이 기법들을 조합하세요.

[!NOTE] 메모리와 속도는 밀접하게 관련되어 있지만 동일하지는 않습니다. 메모리 사용 공간을 줄이면 이동할 데이터가 적어지므로 모델이 "빨라집니다". 순수 속도 최적화는 항상 메모리를 줄이는 것은 아니며 때로는 사용량을 늘리기도 합니다. 사용 사례와 하드웨어에 따라 적절한 최적화를 선택하세요.

아래 표를 사용해 최적화 기법을 선택하세요.

기법 속도 메모리
컴파일 ✅
Attention 백엔드 ✅ ✅
커널 ✅ ✅
양자화 ✅ ✅
캐싱 ✅ ✅
병렬화 ✅
Continuous batching ✅

이 가이드는 Transformers 최적화에 대한 빠른 시작을 제공합니다.

컴파일

torch.compile은 Python 오버헤드를 줄이고, 연산을 퓨전하며, 사용자의 형태와 하드웨어에 맞게 조정된 커널을 생성합니다. 첫 실행이 워밍업 역할을 하고 이후 실행은 더 빠른 컴파일된 경로를 사용합니다.

generate()에 고정 크기 캐시를 전달하면 torch.compile을 자동으로 트리거합니다.

import torch
from transformers import AutoTokenizer, AutoModelForCausalLM

tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen3-0.6B")
model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen3-0.6B", dtype=torch.float16, device_map="auto")
input = tokenizer("The French Bread Law states", return_tensors="pt").to(model.device)

output = model.generate(**input, do_sample=False, max_new_tokens=20, cache_implementation="static")
tokenizer.batch_decode(output, skip_special_tokens=True)[0]

[!WARNING] 모델이 매 스텝마다 재컴파일되는 것을 막으려면 generate() 밖에서 torch.compile(model)을 호출하지 마세요.

Attention 백엔드

대체 attention 백엔드는 메모리 트래픽을 낮춥니다. 예를 들어 FlashAttention은 어텐션 계산을 타일링하고 큰 중간 텐서를 피해 메모리 사용 공간을 줄입니다.

from_pretrained()에서 attn_implementation을 설정해 최적화된 어텐션 백엔드를 로드합니다.

from transformers import AutoModelForCausalLM

model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen3-0.6B", attn_implementation="flash_attention_2")

커널

커널은 연산을 퓨전하여 처리량을 높이고 메모리 사용을 줄입니다. Kernels 라이브러리는 Hub에서 최적화된 계산 커널을 유연하고 버전에 안전한 방식으로 로드합니다.

아래 예시는 패키지를 설치하지 않고 최적화된 FlashAttention-2 커널을 로드합니다.

import torch
from transformers import AutoModelForCausalLM

model = AutoModelForCausalLM.from_pretrained(
    "Qwen/Qwen3-0.6B", attn_implementation="kernels-community/flash-attn2"
)

양자화

양자화는 모든 파라미터의 크기를 줄여 메모리 사용 공간을 낮추고, 더 많은 연산을 처리할 수 있으므로 속도를 높입니다.

from_pretrained()의 quantization_config 인자에 양자화 config를 전달합니다. 각 양자화 백엔드는 서로 다른 인자를 가진 서로 다른 config를 가집니다. 아래 예시는 모델을 4비트로 양자화하고 bitsandbytes 백엔드로 computation dtype을 구성합니다.

import torch
from transformers import AutoModelForCausalLM, BitsAndBytesConfig

bnb_config = BitsAndBytesConfig(load_in_4bit=True, bnb_4bit_compute_dtype=torch.bfloat16)

model = AutoModelForCausalLM.from_pretrained(
    "allenai/Olmo-3-7B-Think", quantization_config=bnb_config
)

캐싱

캐싱은 모든 토큰에 대해 과거 키와 값을 다시 계산하는 대신 재사용하여 생성을 가속화합니다. 과거 키와 값을 저장하는 메모리 비용을 상쇄하고 줄이기 위해, Transformers는 캐시를 CPU로 오프로딩하는 것을 지원합니다. 현재 레이어만 GPU에 남습니다.

generate()에서 cache_implementation 인자를 사용해 캐시 전략을 설정합니다.

import torch
from transformers import AutoTokenizer, AutoModelForCausalLM

tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen3-0.6B")
model = AutoModelForCausalLM.from_pretrained(
    "Qwen/Qwen3-0.6B", attn_implementation="kernels-community/flash-attn2"
)
inputs = tokenizer("The Le Décret Pain states that a baguette must,", return_tensors="pt")
outputs = model.generate(**inputs, do_sample=False, max_new_tokens=50, cache_implementation="offloaded")

병렬화

병렬화는 모델을 여러 장치에 분산하여 한 장치에 너무 큰 모델도 빠르게 실행되게 합니다. 이 방식은 샤딩 오버헤드와 결과 동기화를 위한 통신 때문에 더 많은 메모리를 사용합니다.

텐서 병렬화는 모델 레이어를 여러 장치로 분할합니다. DistributedConfig(tp_size=N)으로 장치 수를 설정하고 이를 from_pretrained()에 전달하여 활성화합니다.

from transformers import AutoModelForCausalLM, DistributedConfig

distributed_config = DistributedConfig(tp_size=4)
model = AutoModelForCausalLM.from_pretrained(
    "meta-llama/Meta-Llama-3-8B-Instruct",
    distributed_config=distributed_config,
)
print(model._tp_plan)

Continuous batching

Continuous batching은 동적 스케줄링과 chunked prefill로 GPU를 계속 바쁘게 유지하여 처리량을 극대화합니다. 서빙 애플리케이션은 이를 사용해 여러 수신 요청을 동시에 처리합니다.

generate_batch()를 사용해 continuous batching을 활성화합니다.

import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
from transformers.generation import ContinuousBatchingConfig, GenerationConfig

model = AutoModelForCausalLM.from_pretrained(
    "Qwen/Qwen3-0.6B",
    attn_implementation="paged|sdpa",
    device_map="auto",
    torch_dtype=torch.bfloat16,
)
tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen3-0.6B")

prompts = [
    "The Le Décret Pain states that a baguette must",
    "Explain gravity in one sentence.",
    "Name the capital of France.",
]
inputs = [tokenizer.encode(p) for p in prompts]

generation_config = GenerationConfig(
    max_new_tokens=32,
    eos_token_id=tokenizer.eos_token_id,
    pad_token_id=tokenizer.pad_token_id,
    do_sample=False,
)
continuous_batching_config = ContinuousBatchingConfig(max_batch_tokens=512)

outputs = model.generate_batch(
    inputs=inputs,
    generation_config=generation_config,
    continuous_batching_config=continuous_batching_config,
)

for request_id, output in outputs.items():
    text = tokenizer.decode(output.generated_tokens, skip_special_tokens=True)
    print(f"[{request_id}] {text}")

더 알아보기 (Learn more)