제5부 추론 최적화와 서빙
5.8 TensorRT-LLM II — 인플라이트 배칭·페이지드 KV
5.8.1 이 장에서 배우는 것 / 선수 지식
5.7에서 KV 캐시가 LLM 추론 메모리·처리량의 핵심이고, 인플라이트 배칭·페이지드 KV가 그것을 푸는 레버라는 원리를 세웠다. 이 장은 그 둘을 운영 수준으로 판다 — 요청들이 제각각 끝나는 batch를 어떻게 매 스텝 다시 채워 GPU를 유휴 상태로 두지 않는지(인플라이트/연속 배칭), KV를 작은 블록으로 분할해 단편화를 없애 동시성을 끌어올리는 페이지드 KV, 그리고 KV가 모자랄 때의 스케줄링·preemption까지.
이것은 5.1의 "배치=마스터 노브"와 "decode는 메모리 바운드"가 실제 처리량으로 바뀌는 지점이다. 정적 배칭으로는 GPU가 약 절반 유휴 상태이고, 인플라이트 배칭+페이지드 KV로 그 빈자리를 메워 같은 GPU에서 처리량을 몇 배로 끌어올린다.
배우는 것:
- 정적 배칭의 두 낭비 — 길이 패딩(compute·memory)과 종료 대기(GPU 유휴 버블) — 와 그것이 처리량을 어떻게 낮추는지.
- 인플라이트(연속) 배칭 — 매 디코딩 스텝(iteration) 단위로 끝난 요청을 빼고 새 요청을 넣는 메커니즘. Triton 동적 배칭(5.13)과의 차이.
- prefill/decode 혼합 스케줄링·청크 prefill — 긴 프롬프트가 decode를 막지 않게 하는 법.
- 페이지드 KV — 블록 단위 할당·블록 매니저·free 풀, 단편화 제거, prefix 공유(KV 재사용).
- KV 고갈 시 스케줄링 — admission(수용)·preemption(축출/재계산)·우선순위.
- 빌드·런타임에서 켜고 튜닝하는 법, 정적 대비 처리량 벤치마크(실습).
선수 지식: 5.7(KV 캐시·페이지드 KV 도입·trtllm-build·KV 예산), 5.1(prefill/decode·배치·goodput·메모리 바운드), 3.6~3.7(어텐션), 2.13(Nsight로 활용률·버블 보기), 5.11/5.13(Triton 서빙·동적 배칭 — 구분). 환경은 5.7.
정직: 인플라이트 배칭·페이지드 KV의 설정 인자명·스케줄러 정책·기본값은 TRT-LLM 버전마다 다르다(
max_num_tokens·kv_cache_free_gpu_mem_fraction·scheduler policy 등). 이 장은 메커니즘과 튜닝 사고를 중심에 두고 인자는 한 시점의 형태를 예시 — 정확한 이름·범위는 그 버전 문서로 확인. 페이지드 어텐션은 vLLM이 대중화한 공통 기법이다(엔비디아 전용 아님). 모든 수치는 환경 의존 개략값, 실측.
5.8.2 정적 배칭의 두 낭비
5.1의 배치는 "여러 요청을 한 번에"였다. 가장 단순한 구현 — 정적(static) 배칭 — 은 batch를 한 번 묶어 모두 끝날 때까지 함께 처리한다. 여기엔 LLM 특유의 두 낭비가 있다.
정적 배칭(4요청). 출력 길이가 제각각이다:
파랑은 실제로 토큰을 만드는 활성 구간, 점선 회색은 비어 버린 슬롯이다. B는 2스텝에 끝났지만 정적 batch는 가장 긴 C(12스텝)가 끝날 때까지 유지된다 — 먼저 끝난 B·D·A가 비운 자리는 '패딩'으로 계산되거나 GPU가 유휴가 되어(버블) 활용률을 낮춘다.
낭비 ① 종료 대기(GPU 유휴 버블). 요청마다 EOS(종료) 시점이 다른데, 정적 batch는 가장 긴 요청이 끝날 때까지 batch를 유지한다. 먼저 끝난 요청의 슬롯은 빈자리(패딩)로 계산되거나 GPU가 유휴 상태가 되어 활용률이 떨어진다.
낭비 ② 길이 패딩. 프롬프트 길이도 제각각인데 한 batch로 묶으려면 최대 길이에 패딩한다 → 패딩 토큰에 쓸데없는 compute·KV 메모리. (prefill에서 특히.)
결과: 정적 배칭은 GPU를 약 절반 유휴 상태로 만든다. decode가 메모리 바운드라 배치로 채워야 처리량이 나오는데(5.1.4), 빈 슬롯이 그 채움을 깨뜨린다. 인플라이트 배칭이 이 빈자리를 새 요청으로 메운다.
5.8.3 인플라이트(연속) 배칭 — 메커니즘
핵심 아이디어: batch를 "요청 단위"가 아니라 "스텝(iteration) 단위"로 관리한다. 매 디코딩 스텝마다:
인플라이트 배칭(같은 4요청 + 대기 E·F·G):
파랑은 진행 중인 요청, 주황은 빈 슬롯에 새로 투입된 요청이다. A가 끝나자마자 E, B(2토큰)가 끝나자마자 F, D가 끝나자마자 G가 즉시 합류한다.
정적 vs 인플라이트:
| 정적 배칭 | 인플라이트(연속) 배칭 | |
|---|---|---|
| 단위 | 요청 batch 전체 | 스텝(iteration) |
| 종료 처리 | 가장 긴 요청까지 대기 | 끝난 즉시 제거·교체 |
| GPU 활용 | 버블 많음 | 항상 채움(높음) |
| 처리량 | 낮음 | 높음(몇 배 가능, 개략) |
| 지연 | 큐 대기 길 수 있음 | 빈 슬롯 즉시 수용 → 대기↓ |
Triton 동적 배칭(5.13)과 혼동 금지. Triton 동적 배칭은 요청 단위로 들어오는 요청을 잠깐 모아 한 batch로 묶는다(단발 추론·전체 모델 1회용에 적합). 인플라이트 배칭은 자기회귀 디코딩의 스텝 단위로 batch를 재구성한다(LLM 전용). LLM은 TRT-LLM의 인플라이트 배칭을 쓰고, Triton은 그 위에서 요청을 라우팅·스트리밍한다(5.11 TRT-LLM 백엔드).
5.8.4 prefill과 decode를 한 batch에 — 청크 prefill
새 요청이 합류하려면 먼저 prefill(프롬프트 처리, 컴퓨트 바운드)을 해야 한다. 그런데 prefill은 부하가 크다(긴 프롬프트는 더). 진행 중인 다른 요청들의 decode(메모리 바운드)와 한 스텝에 섞을 때 문제가 생긴다:
청크 prefill(chunked prefill). 긴 prefill을 여러 청크로 분할해 여러 스텝에 나눠 처리한다. 그러면 한 스텝이 prefill로 독점되지 않고, decode와 prefill 청크를 섞어 진행 중 요청의 TPOT 스파이크를 완화한다.
청크 prefill은 긴 prefill을 여러 스텝에 분산해 decode 흐름을 유지한다(TTFT는 약간↑, TPOT 안정).
트레이드오프: 청크 prefill은 새 요청의 TTFT를 약간 늘리는 대신(prefill이 여러 스텝에 분산) 진행 중 요청의 TPOT 안정성을 얻는다. 스케줄러 정책(처리량 우선 vs 지연 우선)으로 균형을 맞춘다(버전 의존).
5.8.5 페이지드 KV — 블록 관리로 단편화 제거
5.7에서 본 페이지드 KV를 운영 관점으로. 문제는 연속 KV 할당의 단편화다:
연속 KV(naive)는 요청마다 max_seq_len만큼 연속 블록을 예약한다:
파랑은 실제로 쓰는 KV, 회색은 예약했으나 안 쓰는 빈 공간이다.
페이지드 KV: KV를 고정 크기 블록(페이지) 으로 분할하고, 요청이 자라는 만큼 필요할 때 블록을 할당한다(OS 가상메모리와 동형).
페이지드 KV는 KV를 블록 풀(블록 = 예: 16토큰 분량)로 관리한다:
파랑은 req A, 주황은 req B가 점유한 블록, 회색은 free 풀에 남은 블록이다. 물리적으로 흩어져 있어도 논리적으로는 연속으로 매핑된다.
블록 매니저가 하는 일:
- 할당: 요청이 토큰을 더 만들면 새 블록을 free 풀에서 가져옴. 풀이 비면 그 요청은 더 못 자람 → 스케줄러가 개입(5.8.6).
- 반납: 요청 종료 시 블록을 free 풀로 → 즉시 다른 요청에 재사용(인플라이트 배칭과 짝).
- 블록 크기 트레이드오프: 작으면 단편화↓·관리 오버헤드↑, 크면 반대. 보통 토큰 수십 단위(버전 의존).
prefix 공유(KV 재사용). 여러 요청이 같은 프롬프트 접두(prefix) 를 가지면(시스템 프롬프트·공통 문맥·few-shot 예시) 그 prefix의 KV 블록을 공유할 수 있다 — 한 번만 계산·저장하고 여러 요청이 가리킨다(copy-on-write). 효과:
- prefill 절감: 공통 prefix를 매 요청 재계산하지 않음 → TTFT↓·compute↓.
- 메모리 절감: 같은 KV를 공유 → 동시성↑.
- 예: 챗봇의 긴 시스템 프롬프트, RAG의 공통 문서, 동일 few-shot. (기능명·가용성 버전 의존: prefix caching / KV reuse.)
5.8.6 KV 고갈과 스케줄링 — admission·preemption
페이지드 KV로도 블록 풀은 유한하다. 동시 요청이 많거나 시퀀스가 길어지면 KV가 고갈된다. 스케줄러의 결정:
preemption의 두 방식(버전·구현 의존):
- recompute(재계산): 축출된 요청의 KV를 버리고, 재개 시 prefill을 다시 계산. 메모리 회수는 간결하나 compute 낭비.
- swap(스왑): 축출된 요청의 KV를 CPU 메모리로 내림, 재개 시 다시 적재함. compute는 아끼나 PCIe 전송 비용(2.5).
함정: KV 여유가 적은데 동시 요청을 무리하게 받으면 preemption thrashing(축출↔재개 반복)으로 처리량이 오히려 무너진다. admission을 보수적으로(KV 여유를 보고 수용) 두는 것이 안정적 — 처리량과 지연 안정성의 균형을 스케줄러 정책으로 맞춘다.
5.8.7 워크스루 — 켜고 튜닝하고 측정
빌드·런타임에서 인플라이트 배칭·페이지드 KV를 켜고 정적과 비교한다(인자명 버전 의존, 문서 확인).
# 1) 빌드: 페이지드 KV·인플라이트 배칭 지원으로(대개 기본 권장)
trtllm-build --checkpoint_dir ./ckpt --output_dir ./engine \
--gemm_plugin auto \
--paged_kv_cache enable \
--remove_input_padding enable \
--max_batch_size 64 \
--max_num_tokens 8192 \
--max_seq_len 4096
# remove_input_padding=패딩 제거(길이 낭비↓) · ★max_num_tokens=한 스텝 처리 토큰 총량 상한(인플라이트 배칭의 핵심)
런타임/서빙 핵심 손잡이(개념):
| 손잡이 | 의미 | 튜닝 |
|---|---|---|
| max_num_tokens | 한 iteration에 처리하는 토큰 총합 상한(prefill+decode) | 너무 작으면 처리량↓, 크면 지연 스파이크·메모리↑ |
| KV free mem fraction | KV 캐시에 줄 GPU 메모리 비율 | 크게=동시성↑(다른 버퍼와 균형) |
| scheduler policy | 처리량 우선 vs 지연 보장(max_utilization vs guaranteed_no_evict 류) | 워크로드·SLA에 맞춤 |
| chunked prefill | 긴 prefill 청크 분할 | 긴 프롬프트 많으면 켜서 TPOT 안정 |
| enable_kv_reuse | prefix KV 공유 | 공통 prefix(시스템 프롬프트·RAG) 많으면 |
# 2) 처리량 비교: 정적 vs 인플라이트(벤치 스크립트는 버전별)
# 동일 부하(동시성·시퀀스 분포)로 tokens/s·p99 TTFT/TPOT·GPU util 측정
# 인플라이트+페이지드가 정적 대비 tokens/s가 크게(개략 수배) 높고 util↑가 정상
python benchmark.py --engine ./engine --mode inflight --concurrency 64
python benchmark.py --engine ./engine --mode static --concurrency 64
3) Nsight Systems(2.13)로 타임라인 확인:
| 모드 | Nsight 타임라인에서 보이는 것 |
|---|---|
| 정적 | decode 사이 빈 구간(버블), GPU util 낮음 |
| 인플라이트 | GPU가 빽빽이 채워짐, util 높음 |
prefill 스파이크가 decode를 막으면 chunked prefill을 검토한다.
실무: TRT-LLM 인플라이트 배칭은 대개 Triton TRT-LLM 백엔드(5.11)로 서빙한다 — 요청 큐·스트리밍·메트릭을 Triton이, 인플라이트 디코딩을 TRT-LLM Executor가 맡는 조합. 직접 Executor를 호출할 수도 있다(버전별 API).
5.8.8 중간 점검 (체크포인트)
- [ ] 정적 배칭의 두 낭비(종료 대기 버블·길이 패딩)와 그것이 처리량을 낮추는 이유를 설명한다.
- [ ] 인플라이트 배칭이 스텝 단위로 끝난 요청을 빼고 새 요청을 넣어 GPU를 채우는 메커니즘을, Triton 동적 배칭과 구분해 말한다.
- [ ] 청크 prefill이 진행 중 요청의 TPOT 스파이크를 왜·어떻게 완화하는지 안다.
- [ ] 페이지드 KV의 블록 관리(할당·반납·블록 크기)가 단편화를 없애 동시성을 높이는 원리와, prefix 공유의 이득을 설명한다.
- [ ] KV 고갈 시 admission·preemption(recompute/swap) 결정과 thrashing 위험을 안다.
- [ ] 빌드·런타임에서 켜고(
paged_kv_cache·max_num_tokens등) 정적 대비 처리량·활용률을 측정한다.
증상→의심: GPU 활용률 낮고 처리량 안 나옴 → 정적 배칭·인플라이트 미사용 → 켜기. tokens/s가 어느 지점부터 안 오름 → max_num_tokens·KV 메모리 한계 → 늘리거나 병렬(5.9). 진행 요청 TPOT가 가끔 튐 → 긴 prefill이 decode 방해 → chunked prefill. 처리량이 출렁이며 떨어짐 → preemption thrashing(KV 고갈) → admission 보수적·KV 메모리↑·동시성↓. 공통 시스템 프롬프트인데 TTFT 높음 → prefix KV 재사용 미사용 → enable_kv_reuse.
5.8.9 트레이드오프·대안
처리량 우선 vs 지연 보장. 스케줄러 정책의 핵심 갈래.
| 정책 | 누구에게 | 비고 |
|---|---|---|
| 처리량 최대(공격적 수용) | 배치 처리·비용 최소·느슨한 SLA | 동시성·tokens/s↑, p99 꼬리·preemption 위험↑ |
| 지연 보장(보수적 수용·no-evict) | 대화형·엄격한 p99 | 안정적 TPOT, 처리량은 다소↓ |
| 청크 prefill on | 긴 프롬프트 섞임 | TPOT 안정(진행 요청), 새 TTFT 약간↑ |
| prefix 재사용 on | 공통 prefix 많음 | TTFT·메모리↓, 캐시 관리 오버헤드 |
견해: 대화형 서비스는 지연 보장 쪽 + 청크 prefill, 오프라인 대량 생성은 처리량 최대로 가는 것이 자연스럽다. 둘 다 필요하면 운영점을 분리(요청 클래스별 정책·풀). 핵심은 admission을 KV 여유에 맞춰 보수적으로 두어 thrashing을 피하는 것 — 무리한 동시성은 처리량을 오히려 낮춘다. 모든 정책은 부하 생성기로 p99·goodput 곡선을 그려 운영점을 실측으로 정한다(5.1).
비엔비디아 정직: 페이지드 어텐션·연속 배칭은 vLLM이 대중화한 공통 기법이고 SGLang 등도 제공한다(SGLang은 RadixAttention 등 prefix 공유를 강조). TRT-LLM의 차별점은 엔비디아 커널·FP8/FP4·트랜스포머 엔진·NVLink 병렬·Triton 통합이다. 처리량·지연 우열은 모델·하드웨어·시점마다 다르니 당신 워크로드로 vLLM/SGLang과 실측 비교(5.15).
5.8.10 흔한 함정
- 정적 배칭을 인플라이트로 착각. 인플라이트 배칭을 안 켜면(또는 정적 모드) GPU가 유휴 상태이고 처리량이 안 난다. paged KV·인플라이트 활성화 확인.
- Triton 동적 배칭과 혼동. 동적 배칭(요청 단위, 5.13)은 단발 추론용. LLM 자기회귀는 인플라이트 배칭(스텝 단위) — 둘은 다른 계층.
- max_num_tokens 과소. 한 스텝 토큰 상한이 작으면 batch를 못 채워 처리량↓. 메모리·지연과 균형 맞춰 충분히.
- KV 무리 수용 → preemption thrashing. 동시 요청을 KV 여유 이상으로 받으면 축출↔재개 반복으로 처리량 붕괴. admission 보수적.
- 긴 prefill로 decode 정체. 청크 prefill 없이 긴 프롬프트가 들어오면 진행 요청 TPOT가 튐. chunked prefill.
- prefix 재사용 미활용. 공통 시스템 프롬프트·RAG 문맥을 매 요청 재계산하면 TTFT·메모리 낭비. KV reuse(가용 시).
- max_seq_len·max_batch를 부하 분포 무시하고 설정. KV 예산이 어긋나 OOM이나 저활용. 실제 분포로(5.7).
- 인자명을 버전 불문 복붙. 스케줄러 정책·인자가 릴리스마다 변함 — 그 버전 문서.
5.8.11 연습문제
연습 1 (정적의 낭비). 출력 길이가 [3,3,3,300] 토큰인 4요청을 정적 배칭으로 실행한다. (a) GPU가 낭비되는 지점을 설명하고, (b) 인플라이트 배칭이 이를 어떻게 바꾸나, (c) 처리량 개선의 대략적 크기는?
정답
(a) 정적은 가장 긴 요청(300토큰)이 끝날 때까지 batch 유지 → 짧은 3개는 3스텝에 끝났는데 297스텝 동안 그 슬롯이 빈자리(패딩/유휴). 4개 중 3개 슬롯이 사실상 유휴여서 GPU 활용률·처리량 급락. (b) 인플라이트는 3토큰 요청이 끝나는 즉시 슬롯을 반납하고 대기 큐의 새 요청을 투입 → 빈 슬롯이 계속 새 작업으로 채워짐. (c) 이 극단 예에서 정적은 사실상 1요청(300토큰)분 처리량인데, 인플라이트는 빈 3슬롯을 계속 실행해 이론상 수배 처리량(부하·KV 여유에 따라). 실제 크기는 시퀀스 분포·동시성·KV로 결정 → 실측.
연습 2 (인플라이트 vs 동적 배칭). 동료가 "Triton 동적 배칭을 켰으니 LLM 처리량이 최적"이라 한다. 무엇이 잘못된 이해이고, 올바른 구성은?
정답
잘못: Triton 동적 배칭(요청 단위) 은 단발 추론(전체 모델 1회 forward, 예: 분류)을 잠깐 모아 묶는 것으로, 자기회귀 디코딩의 스텝 단위 동역학을 다루지 않는다. LLM은 토큰을 수백 번 생성하며 요청이 제각각 끝나므로, 인플라이트(연속) 배칭(스텝 단위) 이 필요하다 — 이것은 TRT-LLM Executor가 한다. 올바른 구성: TRT-LLM 엔진(paged KV·인플라이트 배칭) + Triton TRT-LLM 백엔드(5.11) — Triton은 요청 큐·스트리밍·메트릭을, 인플라이트 디코딩은 TRT-LLM이. 동적 배칭 토글이 아니라 인플라이트 배칭이 핵심.
연습 3 (페이지드 KV). 연속 KV 할당에서 단편화가 왜 생기고 동시성을 어떻게 낮추는지, 페이지드 KV가 이를 어떻게 푸는지 블록 관점에서 설명하라. prefix 공유가 추가로 주는 이득은?
정답
연속 할당: 요청마다 최대 길이만큼 연속 공간을 예약하지만 실제 길이는 짧고 제각각이라 예약했으나 안 쓰는 빈틈이 흩어진다(단편화) → 합치면 새 요청 하나가 들어갈 메모리인데 연속 공간이 없어 못 받음 → 동시성↓. 페이지드 KV: KV를 고정 블록으로 분할해 요청이 자라는 만큼 free 풀에서 블록을 할당, 종료 시 반납 → 빈틈 없이 채우고 재사용(논리적으로만 연속, 물리적으로 흩어져도 됨) → 같은 HBM으로 동시 요청↑. prefix 공유: 공통 프롬프트 접두의 KV 블록을 여러 요청이 공유(copy-on-write) → 공통 prefill 재계산 제거(TTFT↓)·메모리 절감(동시성↑).
연습 4 (preemption). 처리량을 높이려 admission을 공격적으로 키웠더니 처리량이 오히려 출렁이며 떨어졌다. 무슨 일이며, recompute와 swap 중 어떤 preemption이 쓰였을지와 각 비용, 해결책은?
정답
무슨 일: KV 여유보다 많은 요청을 받아 KV 고갈 → preemption(축출) 이 빈발, 축출된 요청을 재개하느라 자원을 쓰고 다시 축출되는 thrashing → 유효 처리량 붕괴·출렁임. preemption 비용: recompute(KV 버리고 재개 시 prefill 재계산) = compute 낭비, swap(KV를 CPU로 내보냄/적재함) = PCIe 전송 비용(2.5). 어느 쪽이든 thrashing이면 손해. 해결: admission을 보수적으로(KV 여유를 보고 수용), max_batch/동시성↓, KV 메모리 비율↑, 긴 시퀀스 분리. 처리량은 "무리한 동시성"이 아니라 thrashing 없는 안정 운영점에서 최대 — p99·goodput 곡선으로 그 점을 찾는다.
연습 5 (정책 선택). (a) 엄격한 p99 TPOT의 대화형 코드 어시스턴트, (b) 야간 대량 문서 요약(지연 느슨, 비용 최소), (c) 긴 시스템 프롬프트를 모든 요청이 공유하는 챗봇. 각각에 스케줄러·기능 설정을 제안하라.
정답
(a) 지연 보장 정책(보수적 admission/no-evict) + 청크 prefill — TPOT 안정이 최우선, preemption·prefill 간섭 회피. 동시성은 SLA 한도까지. (b) 처리량 최대 정책(공격적 수용) — 느슨한 SLA라 GPU를 빽빽이 채워 tokens/s·$/토큰 최적, preemption 약간 감수. max_num_tokens·KV 메모리 크게. (c) prefix KV 재사용(enable_kv_reuse) on — 공통 시스템 프롬프트의 KV를 공유해 매 요청 prefill·메모리 절감(TTFT↓·동시성↑) + (대화형이면) 지연 보장·청크 prefill 병행. 모든 경우 부하 생성기로 p99·goodput·util을 측정해 운영점 확정.
5.8.12 요약 · 다음 장
- 정적 배칭은 종료 대기 버블과 길이 패딩으로 GPU를 유휴 상태로 만든다. 인플라이트(연속) 배칭은 batch를 스텝 단위로 관리해 끝난 요청을 즉시 빼고 새 요청을 넣어 GPU를 채운다 → 처리량 몇 배(개략). Triton 동적 배칭(요청 단위)과는 다른 계층.
- 청크 prefill은 긴 prefill을 분할해 진행 중 요청의 TPOT 스파이크를 완화한다(새 TTFT 약간↑ 대가).
- 페이지드 KV는 KV를 블록으로 관리해 단편화를 없애 동시성↑, prefix 공유로 공통 prefill·메모리를 아낀다.
- KV 고갈 시 admission·preemption(recompute/swap) 으로 스케줄 — 무리한 수용은 thrashing으로 처리량을 낮추니 보수적 admission이 안정적. 정책(처리량 vs 지연)을 워크로드에 맞춘다.
- 빌드·런타임에서
paged_kv_cache·max_num_tokens·스케줄러 정책으로 켜고 튜닝하며, 대개 Triton TRT-LLM 백엔드로 서빙. 정직: 인자·정책은 버전 의존, 페이지드/연속 배칭은 공통 기법, 모든 수치 실측.
다음 장: 5.9 TensorRT-LLM III — 양자화·병렬(TP·PP). 한 GPU에 안 들어가는 큰 모델을 텐서 병렬(TP)·파이프라인 병렬(PP) 로 여러 GPU에 나누는 법(4.13~4.14의 NCCL·매핑과 연결)과, LLM 특화 양자화(FP8·가중치 INT4 AWQ/GPTQ 등) 가 추론 메모리·처리량을 어떻게 더 미는지를 본다.