Transformers documentation

Paged attention

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

and get access to the augmented documentation experience

to get started

Paged attention

이 페이지는 continuous batching에서 사용되는 paged attention forward 함수를 문서화합니다.

Varlen 경로

flash_attn_varlen_func 커널은 가변 길이 배치(batch)를 처리합니다. prefill 단계에서 요청 수가 많은 배치의 경우 이 경로를 사용하는 것이 권장됩니다.

캐시 동작

이 커널은 paged cache와 직접 상호작용하는 메커니즘이 없으므로, ~PagedAttentionCache.update 메서드를 사용하여 캐시를 수동으로 읽고 씁니다. 시퀀스 길이가 커지면 이것이 병목 현상이 될 수 있습니다.

인덱싱 메커니즘

커널은 각 시퀀스에 대한 attention을 계산하기 위해 최대 시퀀스 길이(max_length_q, max_length_k)와 누적 시퀀스 길이(cu_seq_lens_q, cu_seq_lens_k)를 사용합니다.

예시

쿼리 길이가 [10, 3, 1]이고 키 길이가 [0, 1, 7]인 3개의 시퀀스로 이루어진 배치에 대해 생각해 보겠습니다:

cu_seq_lens_q = [0, 10, 13, 14]
cu_seq_lens_k = [0, 0, 1, 8]
max_length_q = 10
max_length_k = 7

입력 형상:

Q:      [1, 10+3+1, num_heads, head_dim] = [1, 14, num_heads, head_dim]
K or V: [1, 0+1+7, num_kv_heads, head_dim] = [1, 8, num_kv_heads, head_dim]

커널은 누적 시퀀스 길이를 사용하여 각 쿼리 및 키/밸류 토큰을 시퀀스에 할당합니다:

Q request index: [r0, r0, r0, r0, r0, r0, r0, r0, r0, r0, r1, r1, r1, r2]
cu_seq_lens_q:   0____________________________________10__________13__14

K request index: [r1, r2, r2, r2, r2, r2, r2, r2]  (r0 has 0 K tokens)
cu_seq_lens_k: 0,0_1_______________________8

디코딩 경로

flash_attn_with_kvcache 커널은 각 시퀀스가 정확히 하나의 query 토큰을 가지는 decode 전용 배치만 처리합니다. varlen 경로보다 효율적이지만, prefilling 요청이 포함된 배치는 처리할 수 없습니다.

캐시 동작

이 커널은 block_table을 사용하여 paged cache에 접근하고, 이를 인덱싱한 뒤 인플레이스로 업데이트합니다. 블록 테이블의 shape은 (batch_size, max_blocks_per_seq)이며, 각 행에는 해당 요청의 KV cache 텐서 내 캐시 블록의 물리적 위치가 포함됩니다.

인덱싱 메커니즘

커널은 cache_seqlens를 사용하여 각 시퀀스의 캐시 길이를 가져옵니다. 각 쿼리 토큰이 서로 다른 시퀀스에 속한다고 가정합니다(시퀀스당 1개 토큰).

예시

쿼리 길이가 [1, 1, 1], 키 길이가 [30, 32, 70]인 3개의 시퀀스로 구성된 배치라고 가정해 보겠습니다. 캐시 블록 크기는 32이고, 시퀀스당 최대 블록 수는 4입니다.

캐시 시퀀스 길이는 단순히 키 길이입니다:

cache_seqlens = [30, 32, 70]

블록 테이블의 모양은 (3, 4)입니다. 예시 주소를 사용하여:

block_table = [[2, -1, -1, -1],
               [0,  1, -1, -1],
               [3,  5,  6, -1]]

-1 값은 할당되지 않은 블록을 나타냅니다.

  • Sequence 0(캐시된 토큰 30개): KV_cache[2]에 캐시됨. 새 토큰이 들어갈 수 있음(30 + 1 = 31 < 32).
  • Sequence 1(캐시된 토큰 32개): KV_cache[0]와 KV_cache[1]에 캐시됩니다. 32 + 1 > 32이므로 두 번째 블록이 필요합니다.
  • Sequence 2 (캐시된 토큰 70개): KV_cache[3], KV_cache[5], KV_cache[6]에 캐시됨. 블록이 반드시 연속적이지 않을 수 있으며, 이것이 paged cache의 핵심 장점입니다. 새로운 토큰은 세 번째 블록에 들어갑니다.
Update on GitHub