KV 캐시 블록 추정 트러블슈팅¶
kvcache_num_blocks를 지정하지 않으면 RBLN Optimum은 컴파일 완료 후 paged attention KV 캐시 크기를 자동으로 결정합니다. 이때 NPU에 들어가는 가장 큰 블록 pool을 사용하되, 배치의 모든 항목이 max_seq_len 길이의 시퀀스를 담을 수 있는 크기를 넘지 않습니다. 이 가이드에서는 Qwen3-8B Model Zoo 예제를 통해 memory_budget 옵션으로 이 자동 할당 크기를 제한하는 방법을 설명합니다. memory_budget은 추정이 가정할 수 있는 NPU당 DRAM 양으로, 사용 가능한 DRAM의 비율(0.5), 백분율("50%"), 바이트 수("8GB")로 지정합니다. 이 값에는 KV cache뿐 아니라 가중치와 작업 공간도 포함되며, KV cache는 그 나머지를 사용합니다(Step 1). 이 옵션은 KV cache가 시퀀스보다 작은 블록으로 나뉘는 경우, 즉 RBLN Optimum에서는 flash attention(attn_impl="flash_attn" 또는 kvcache_partition_len 지정)일 때만 적용됩니다. eager attention에서는 시퀀스마다 max_seq_len 크기의 블록 하나를 쓰므로 블록 수를 지정하지 않으면 batch_size가 되고, 추정할 것이 없습니다.
전제 조건
아래 측정값은 Qwen3-8B를 max_seq_len=40_960, kvcache_partition_len=8_192로 컴파일해 제품별로 측정한 결과이며, 장비와 설정은 아래 탭과 같습니다. 블록 수는 모델, 컴파일 설정, NPU에 따라 달라지므로 이 값은 그대로 쓰기보다 트레이드오프 경향을 파악하는 참고 자료로 활용하는 것을 권합니다.
rbln-smi로 호스트의 NPU를 확인하고, 하드웨어에 맞게 num_devices를 조정해야 합니다.
Rebel100™(RBLN-CR13) 1장, num_devices=1, batch_size=8.
ATOM™-Max(RBLN-CA25) 4장, num_devices=4, batch_size=8.
요약¶
| 증상 | 근본 원인 | 해결 |
|---|---|---|
| 컴파일된 모델이 NPU 전체를 점유해 다른 모델을 올릴 여유가 없음 | 자동 블록 추정이 최대 블록 수 범위 안에서 사용 가능한 DRAM을 모두 KV 캐시에 할당함 | Step 1 |
memory_budget을 지정한 뒤 Insufficient memory for the required KV cache | memory_budget이 낮아 추정치가 그 설정에 필요한 최소 블록 수 아래로 내려감 | Step 2 |
memory_budget ... exceeds the target NPU's available DRAM | 지정한 값이 NPU가 내주는 DRAM 용량보다 큼 | Step 3 |
memory_budget and an explicit kvcache_num_blocks are mutually exclusive | 두 값을 함께 지정했으나 추정은 블록 수가 비어 있을 때만 동작함 | Step 3 |
Step 1: 자동 KV 캐시 추정 제한하기¶
증상¶
모델 하나만 사용할 때는 컴파일과 추론 모두 정상적으로 동작하지만, 컴파일된 모델이 NPU 메모리 전체를 차지할 수 있습니다. 이 경우 같은 NPU에 두 번째 모델이나 같은 파이프라인의 다른 submodule을 로드할 수 없고, 이후 batch 크기를 늘릴 여유 공간도 남지 않습니다.
근본 원인¶
kvcache_num_blocks의 기본값은 0이며, 이는 KV 캐시 크기를 컴파일 후에 자동으로 결정한다는 의미입니다. 이때 RBLN Optimum은 NPU DRAM에서 컴파일된 모델 자체가 사용하는 메모리를 뺀 나머지에 최대 블록 수(num_full_blocks, Step 2 참고)가 들어가는지 먼저 확인합니다. 들어가면 최대 블록 수를 그대로 쓰고, 들어가지 않으면 들어가는 가장 큰 블록 pool을 탐색합니다. 최대 블록 수를 넘지는 않지만, 어느 경우든 KV 캐시가 남은 DRAM을 쓸 수 있는 만큼 사용하고 다른 용도의 여유 공간은 따로 남기지 않습니다.
기준 설정에서는 최대 블록 수인 40블록이 그대로 들어가며, NPU에 45 GiB의 KV 캐시를 예약합니다.
기준 설정에서는 최대 블록 수인 40블록이 그대로 들어가며, NPU 4장 각각에 11.25 GB의 KV 캐시를 예약합니다.
해결¶
KV 캐시 크기를 자동으로 결정할 때 사용할 DRAM 용량을 memory_budget으로 제한합니다. memory_budget은 NPU 1장 단위로 적용되며, 그 NPU가 실제로 내주는 DRAM 용량을 기준으로 해석됩니다.
Rebel100™(RBLN-CR13)는 시스템 예약분을 제외하고 150,323,855,360 바이트(140 GiB)를 내주며, rbln-smi가 보고하는 전체 메모리 값이 바로 이 용량입니다.
ATOM™-Max(RBLN-CA25)는 시스템 예약분을 제외하고 16,877,879,296 바이트(15.72 GB)를 내주며, rbln-smi가 보고하는 전체 메모리 값이 바로 이 용량입니다.
memory_budget은 세 가지 형태를 받습니다.
| 형태 | 예 | 의미 |
|---|---|---|
| 비율 | 0.5 | NPU가 내주는 DRAM의 절반. (0, 1] 범위의 float이며 권장하는 형태입니다. |
| 퍼센트 문자열 | "50%" | 0.5와 동일합니다. 값이 커맨드라인을 거쳐 전달될 때 편리합니다. |
| 바이트 수 | "8GB", "512MB", 8 * 2**30 | 용량을 직접 지정합니다. 단위는 이진(KB = 1024 바이트이며 TB까지)이고 대소문자를 구분하지 않으며, 단순 int는 바이트 수입니다. |
memory_budget은 KV 캐시에만 적용되는 값이 아니라 컴파일된 모델이 NPU에 올리는 모든 것에 적용됩니다. 가중치와 workspace를 먼저 차감하고 남은 공간을 KV 캐시가 차지하기 때문에, KV 캐시의 블록 수는 memory_budget보다 더 가파르게 줄어듭니다.
위 예제에서 memory_budget만 바꿔 보면 다음과 같습니다.
memory_budget | 추정된 kvcache_num_blocks | NPU의 KV 캐시 |
|---|---|---|
| 미지정 | 40 | 45.00 GiB |
0.9 … 0.5, "64GB" | 40 | 45.00 GiB |
0.45 | 39 | 43.88 GiB |
0.4 | 33 | 37.13 GiB |
0.35 | 27 | 30.38 GiB |
"48GB" | 26 | 29.25 GiB |
0.3 | 21 | 23.63 GiB |
"40GB" | 19 | 21.38 GiB |
"36GB" | 15 | 16.88 GiB |
0.25 | 14 | 15.75 GiB |
0.22 | 11 | 12.38 GiB |
0.5까지는 NPU DRAM에 최대 블록 수가 그대로 들어가고, 그보다 낮추면 추정치가 하한인 9블록(Step 2)을 향해 줄어듭니다.
확정된 블록 수는 저장된 산출물에서 확인합니다.
위 예제에서 memory_budget만 바꿔 보면 다음과 같습니다.
memory_budget | 추정된 kvcache_num_blocks | NPU당 KV 캐시 |
|---|---|---|
| 미지정 | 40 | 11.25 GB |
0.9 | 37 | 10.41 GB |
0.8 | 31 | 8.72 GB |
"12GB" | 29 | 8.16 GB |
0.7 | 25 | 7.03 GB |
0.6 | 20 | 5.62 GB |
"8GB" | 15 | 4.22 GB |
0.5 | 14 | 3.94 GB |
0.4 | 9 | 2.53 GB |
확정된 블록 수는 저장된 산출물에서 확인합니다.
컴파일된 산출물에는 0이 기록되지 않습니다. kvcache_num_blocks를 명시했다면 그 값이, 자동 추정을 했다면 추정된 값이 저장됩니다. eager attention에서 블록 수를 지정하지 않았다면 memory_budget과 관계없이 최대 블록 수가 저장됩니다.
같은 옵션을 컴파일 CLI에서도 쓸 수 있으며, 세 가지 형태가 모두 동작합니다.
Step 2: memory_budget을 최소 블록 수 위로 유지하기¶
근본 원인¶
블록 pool이 일정 크기 아래로 내려가면 시퀀스 하나를 온전히 담을 수 없고 batch의 각 항목에 블록을 하나씩 나눠 줄 수도 없습니다. 따라서 RBLN Optimum은 더 작은 pool로 물러서지 않고 추정 결과를 거부합니다. flash attention에서 하한과 최대 블록 수는 다음 식으로 정해집니다.
+ 1은 시퀀스가 계속 길어지는 동안 블록 테이블의 빈 슬롯을 채우기 위한 여분 블록으로, 두 항 중 어느 쪽이 하한이 되든 항상 필요합니다.
기준 설정에서는 다음과 같습니다.
여기서 kvcache_block_size는 kvcache_partition_len과 같습니다. 기준 설정의 시퀀스 항은 5블록인데 batch_size=8이 이를 8블록으로 끌어올리므로 하한은 9블록이고, 최대 블록 수는 40블록입니다. 0.22는 11블록으로 하한 바로 위에 있고, 0.2는 8블록으로 추정되어 위 에러로 거부됩니다.
여기서 kvcache_block_size는 kvcache_partition_len과 같습니다. 기준 설정의 시퀀스 항은 5블록인데 batch_size=8이 이를 8블록으로 끌어올리므로 하한은 9블록이고, 최대 블록 수는 40블록입니다. 0.4는 9블록으로 하한과 정확히 같고, 0.3은 3블록으로 추정되어 위 에러로 거부됩니다.
memory_budget을 낮출 수 있는 폭은 이 두 값의 간격에서 나오고, 그 간격은 batch_size가 벌립니다. batch 항목이 하나 늘 때마다 최대 블록 수는 시퀀스 하나 분량만큼 커지는데, 하한은 두 항 중 큰 쪽만 따라가기 때문입니다. 같은 설정에서 batch_size=1이면 최대 블록 수와 하한이 모두 5블록으로 같아지므로, 최대 블록 수에 못 미치는 값은 어느 것도 통과하지 못합니다.
해결¶
추정치가 하한을 넘길 때까지 memory_budget을 올린 뒤, Step 1처럼 확정된 블록 수를 확인합니다. 하한 때문에 memory_budget을 더 낮출 수 없다면 max_seq_len을 줄여야 합니다. max_seq_len을 낮추면 하한도 함께 내려가므로 시퀀스 하나가 예약하는 양 자체가 줄어듭니다.
| 변경 | memory_budget 조정 폭에 미치는 영향 |
|---|---|
batch_size 상향 | 하한과 최대 블록 수의 간격이 넓어져 조정 폭이 커집니다 |
max_seq_len 하향 | 하한과 최대 블록 수가 함께 내려가 같은 DRAM으로도 시퀀스를 담을 수 있습니다 |
kvcache_partition_len 하향 | 하한의 시퀀스 항은 올라가지만 블록 하나의 크기가 작아집니다 |
Step 3: memory_budget 설정 오류 해결하기¶
근본 원인¶
바이트로 지정한 값이 대상 NPU가 내주는 DRAM 용량을 넘으면 첫 번째 에러가 발생합니다. 그 용량은 Step 1에서 본 것처럼 Rebel100™에서 150,323,855,360 바이트(140 GiB), ATOM™-Max에서 16,877,879,296 바이트(15.72 GB)입니다. 이보다 큰 값은 장치에 없는 용량을 요구하는 셈이므로 조용히 잘라내지 않고 거부합니다.
두 번째 에러는 자동 추정이 무력화되는 조합을 막습니다. memory_budget은 자동 추정이 쓰는 값이고, 자동 추정은 kvcache_num_blocks가 비어 있을 때만 동작합니다. 두 값을 함께 지정하면 추정을 건너뛰면서 memory_budget이 조용히 무시되므로, 설정 시점에 조합 자체를 거부합니다.
해결¶
산출물을 여러 환경에서 쓸 예정이라면 바이트 수보다 비율로 지정하는 것을 권장합니다. 비율은 컴파일 대상 NPU에 맞춰 해석됩니다. 바이트로 지정한다면 대상 NPU가 내주는 DRAM 용량 아래로 유지해야 합니다.
두 제어 수단 중 하나만 선택합니다.
| 목적 | 지정할 값 |
|---|---|
| 메모리 상한 안에서 블록 수를 추정에 맡김 | memory_budget |
| 블록 수를 정확히 고정 | kvcache_num_blocks |
Note
memory_budget은 컴파일 시점 입력이라 rbln_config.json에 기록되지 않습니다. 산출물에는 확정된 kvcache_num_blocks만 남으며 추론은 그 값을 읽습니다. memory_budget을 바꾸려면 다시 컴파일해야 합니다.