AI Sparkup

복잡한 AI 세상을 읽는 힘 ⚡

AI 추론 비용 90% 절약하는 3단계 최적화 전략

GPU 자원을 한계까지 활용하고 메모리 병목을 제거하며 세부 비용까지 잡아내는 체계적 접근법으로 LLM 운영 비용을 10-15배 줄일 수 있습니다.

AI 추론 비용 폭탄의 현실

AI 업계가 ‘추론 스케일링(Inference Scaling)’ 시대로 접어들고 있습니다. 엔비디아 CEO 젠슨 황은 “테스트 타임 스케일링이 급증할 것”이라고 예측했습니다. 모델 학습의 한계에 부딪힌 AI 기업들이 추론 단계에서 더 많은 연산을 투입해 성능을 끌어올리는 방식으로 전환하고 있기 때문입니다.

문제는 비용입니다. 추론 요청이 늘어날수록 GPU 사용료가 기하급수적으로 증가합니다. 특히 긴 문맥을 다루는 작업에서는 메모리 사용량이 폭발적으로 늘어납니다. 3만 2천 토큰 길이의 문맥을 처리하는 경우, KV 캐시만으로도 레이어당 8GB가 필요합니다. 40개 레이어를 가진 모델이라면 320GB의 메모리가 순식간에 사라집니다.

이런 상황에서 AI 개발팀들은 어떻게 비용을 통제할 수 있을까요? 이 글은 AI Made Simple에서 제시한 검증된 최적화 기법들을 바탕으로, 실제 현업에서 적용 가능한 3단계 체계적 접근법을 소개합니다.

중요한 경고: 이런 기법들이 간단해 보일 수 있지만 실제로는 그렇지 않습니다. 배칭, 병렬 추론, 하이퍼파라미터 조정 등 ML 엔지니어링의 복잡한 문제들과 씨름해야 합니다. 이런 도전을 감당할 수 없다면 OpenAI나 Google API를 그대로 사용하는 게 낫습니다.

AI 업계의 추론 스케일링 트렌드 (출처: Cerebras)

1단계: GPU를 한계까지 활용하라

첫 번째 단계는 GPU 자원 활용률을 극대화하는 것입니다. 비싼 GPU를 샀다면 모든 코어가 쉬지 않고 일하도록 만들어야 합니다.

배칭으로 GPU 포화 상태 만들기

LLM 추론은 크게 두 단계로 나뉩니다. 프리필(Prefill) 단계는 입력 프롬프트 전체를 한 번에 처리하는 과정으로, GPU가 가장 좋아하는 행렬 연산이 주를 이룹니다. 디코드(Decode) 단계는 토큰을 하나씩 생성하는 과정으로, 메모리 읽기/쓰기가 주를 이룹니다.

여기서 핵심은 연속 배칭(Continuous Batching)입니다. 기존 방식은 배치 내 모든 시퀀스가 완료될 때까지 기다려야 했습니다. 하지만 연속 배칭은 토큰 생성 단계마다 완료된 시퀀스를 즉시 제거하고 새로운 요청을 추가합니다. 이를 통해 GPU가 항상 포화 상태를 유지할 수 있습니다.

Anthropic의 Claude 3는 연속 배칭을 통해 처리량을 초당 50토큰에서 450토큰으로 9배 향상시켰습니다. Anyscale은 23배의 처리량 개선을 보고했습니다.

배칭 최적화 과정
LLM 추론 배칭 최적화 과정 (출처: AI Made Simple)

길이 인식 버킷팅(Length-aware Bucketing)도 중요합니다. 배치 내 시퀀스들의 길이가 다르면 짧은 시퀀스에 패딩 토큰을 추가해야 합니다. GPU는 이 무의미한 패딩 토큰까지 연산하느라 자원을 낭비합니다. 비슷한 길이의 요청들을 묶어서 처리하면 패딩을 최소화할 수 있습니다.

커널 융합으로 메모리 트래픽 줄이기

PyTorch나 TensorFlow로 LLM을 실행하면 하나의 forward pass에 수천 개의 GPU 커널이 호출됩니다. 각 커널은 작은 작업을 수행한 후 결과를 글로벌 GPU 메모리에 저장합니다. 다음 커널이 이를 다시 읽어오는 과정이 반복되면서 엄청난 메모리 트래픽이 발생합니다.

커널 융합(Kernel Fusion)은 여러 연산을 하나의 커널로 합쳐서 중간 결과가 레지스터나 공유 메모리에 머물도록 합니다. 예를 들어 LayerNorm, QKV 프로젝션, bias 추가를 별도 커널로 실행하는 대신 하나로 융합하면 메모리 트래픽을 크게 줄일 수 있습니다.

CUDA 그래프(CUDA Graphs)는 디코딩 과정에서 반복되는 커널 시퀀스를 미리 기록해 두고 재사용하는 기법입니다. CPU를 거치지 않고 GPU에서 직접 실행할 수 있어 오버헤드를 제거합니다. 긴 시퀀스에서는 토큰당 수백 마이크로초를 절약할 수 있습니다.

FlashAttention으로 어텐션 최적화

표준 어텐션은 N×N 크기의 점수 행렬을 메모리에 저장해야 합니다. 4천 토큰 시퀀스라면 1600만 개의 항목이 생깁니다. 이 행렬을 저장하고 읽어오는 과정에서 기가바이트급 메모리 트래픽이 발생합니다.

FlashAttention은 이 문제를 타일링으로 해결합니다. 전체 행렬을 한 번에 만드는 대신, 작은 블록들로 나누어 온칩 SRAM에서 처리합니다. 중간 결과는 버리고 최종 컨텍스트 벡터만 저장합니다. 메모리 대역폭을 3-5배 줄이면서도 수학적으로 정확한 결과를 얻을 수 있습니다.

FlashAttention 동작 원리
FlashAttention의 메모리 최적화 원리 (출처: AI Made Simple)

양자화로 메모리 사용량 반토막

모델 가중치를 16비트나 32비트 부동소수점으로 저장할 필요가 없습니다. 가중치 전용 양자화(Weight-only Quantization)를 통해 8비트나 4비트 정수로 저장하고, 연산 시에만 스케일링해서 사용할 수 있습니다.

Hopper GPU에서는 FP8 연산이 가능합니다. 16비트 대신 8비트 부동소수점을 직접 사용해 메모리 사용량을 절반으로 줄이면서도 정확도 손실을 최소화할 수 있습니다.

양자화는 공짜가 아닙니다. 잘못 조정하면 모델 성능이 급격히 떨어집니다. 하지만 제대로 적용하면 성능 저하 없이 메모리 사용량을 크게 줄일 수 있습니다.

1단계 완료 기준

다음 조건을 만족해야 2단계로 넘어갈 수 있습니다.

프리필과 디코드가 분리되어 각각 75% 이상의 GPU 활용률을 보여야 합니다. 디코드 루프가 CUDA 그래프로 실행되어야 합니다. 양자화된 모델이 평가 셋에서 1% 미만의 성능 저하를 보여야 합니다.

2단계: 메모리 병목을 뚫어라

1단계에서 GPU를 바쁘게 만들었다면, 2단계는 GPU가 하는 일의 비용을 줄이는 단계입니다. 메모리 대역폭과 제곱 복잡도 어텐션이 주요 적입니다.

KV 캐시 최적화

트랜스포머는 각 토큰에 대해 키(K)와 값(V) 벡터를 저장해야 합니다. 이것이 바로 KV 캐시입니다. 캐시가 없으면 매번 모든 토큰을 다시 계산해야 하지만, 캐시가 있으면 메모리를 엄청나게 잡아먹습니다.

앞서 계산한 예시처럼 3만 2천 토큰 문맥에서는 레이어당 8GB, 40개 레이어에서는 총 320GB가 필요합니다. 새로운 토큰을 생성할 때마다 이 전체 캐시를 읽어야 하므로 메모리 대역폭이 병목이 됩니다.

페이지 KV 캐시(Paged KV)는 캐시를 고정 크기 페이지로 나누어 관리합니다. 가상 메모리처럼 공통 프리픽스를 재사용할 수 있고 메모리 단편화를 방지합니다.

프리픽스 캐싱(Prefix Caching)은 채팅 시스템에서 반복되는 시스템 프롬프트를 한 번만 캐시하고 재사용하는 기법입니다. 다만 타임스탬프나 ID 같은 작은 차이로도 캐시 히트를 놓칠 수 있으므로 정규화가 중요합니다.

다중 쿼리 어텐션(MQA)이나 그룹 쿼리 어텐션(GQA)은 모든 헤드가 각자 K/V를 갖는 대신 공유하도록 만듭니다. 32개 헤드가 하나의 K/V를 공유하면 캐시 크기를 8분의 1로 줄일 수 있습니다.

희소성으로 복잡도 깨기

일반적인 트랜스포머는 밀집 구조입니다. 모든 파라미터가 모든 토큰에 대해 실행되고, 모든 토큰이 다른 모든 토큰에 어텐션을 합니다. 이는 작은 규모에서는 괜찮지만 큰 규모에서는 치명적입니다.

희소성(Sparsity)은 이 연결을 끊는 방법입니다. 두 가지 직교하는 접근법이 있습니다.

Mixture-of-Experts(MoE)는 파라미터 희소성을 구현합니다. 여러 전문가 네트워크 중에서 각 토큰마다 일부만 활성화합니다. 조 단위 파라미터를 가진 모델도 토큰당 연산량은 훨씬 적게 만들 수 있습니다.

하지만 MoE는 까다롭습니다. 전문가 간 통신이 빨라야 하고, 로드 밸런싱 문제와 라우터 불안정성을 해결해야 합니다. 실제로 Meta의 Llama 4도 MoE 구현에 상당한 어려움을 겪었습니다. 충분한 자금과 인재, 그리고 주요 오픈 LLM에서 MoE 경험이 있었음에도 불구하고 말입니다. 기능할 때는 놀랍지만 자주 불안정하고, 많은 통신이 필요합니다.

희소 어텐션(Sparse Attention)은 활성화 희소성을 구현합니다. 모든 토큰 쌍에 어텐션하는 대신 패턴을 제한합니다. 슬라이딩 윈도우는 최근 토큰들만 보고, 로컬+글로벌 패턴은 일부 토큰을 글로벌 앵커로 지정합니다.

희소 어텐션 패턴
다양한 희소 어텐션 패턴 비교 (출처: AI Made Simple)

추측적 디코딩으로 속도 2배 향상

LLM은 본질적으로 토큰을 하나씩 순서대로 생성합니다. 다음 토큰을 예측하려면 이전 모든 토큰을 알아야 하기 때문입니다. 이 순차적 의존성이 지연 시간을 만듭니다.

추측적 디코딩(Speculative Decoding)은 이 문제를 우아하게 해결합니다. 작고 빠른 초안 모델이 여러 토큰을 미리 예측하고, 큰 타겟 모델이 한 번의 forward pass로 이를 검증합니다. 맞는 예측은 채택하고 틀린 예측은 타겟 모델의 출력으로 교체합니다.

핵심은 초안 모델의 상당 부분이 맞다는 가정입니다. k번의 타겟 모델 패스 대신 1번의 타겟 모델 패스와 k번의 (훨씬 저렴한) 초안 모델 패스로 대체할 수 있습니다.

구글의 원래 논문에서는 번역과 요약 작업에서 2-3배 개선을 보고했습니다. 이후 여러 구글 제품에서 활용되고 있습니다.

MedusaLookahead Decoding은 별도 초안 모델 없이 추측적 디코딩을 구현하는 발전된 기법들입니다. Medusa는 타겟 모델에 가벼운 디코딩 헤드들을 추가하고, Lookahead Decoding은 Jacobi 반복과 유사한 수학적 기법을 사용합니다.

2단계 완료 기준

다음을 만족해야 3단계로 넘어갈 수 있습니다.

KV 캐시 대역폭이 통제되고 프리픽스 재사용이 로그에 나타나야 합니다. 추측적 디코딩이 종단간 2배 이상 속도 향상을 보여야 합니다. 희소 방법들이 장거리 작업에서 성능 저하 없이 실제 처리량 향상을 보여야 합니다. 3만 2천 토큰 이상의 문맥이 안정적으로 실행되어야 합니다.

3단계: 세부 비용까지 잡아라

3단계는 규모에서 시스템을 조금씩 잡아먹는 한계 비용들을 해결하는 단계입니다. FLOPs나 메모리 대역폭 같은 명백한 병목이 아니라, 천 번의 작은 상처로 죽음에 이르게 하는 요소들입니다.

제약 디코딩으로 무효 출력 제거

무효한 토큰 하나도 실제 비용입니다. 잘못된 JSON 브래킷을 생성하더라도 수만 개 로짓에 대한 소프트맥스 연산, KV 캐시 확장, 디코딩 루프 패스가 필요합니다.

제약 디코딩(Constrained Decoding)은 생성 시점에 불가능한 토큰을 마스킹합니다. JSON 스키마 강제, 정규식 마스크, 트라이 기반 어휘 제한 등을 통해 유효한 출력만 생성하도록 합니다.

이는 정확성과 효율성을 동시에 향상시킵니다. 무효 출력률이 0에 가까워지고, 재시도가 줄어들며, 출력 길이가 짧아집니다. 기업 채팅 워크로드에서는 생성 길이를 15-20% 줄일 수 있습니다.

증류와 가지치기로 모델 압축

2단계 트릭을 써도 비대한 모델은 여전히 돈을 태웁니다. 13B 밀집 모델은 7B 모델의 두 배 VRAM을 소모합니다. 배치 크기가 절반이 되고 토큰당 비용이 두 배가 됩니다.

증류(Distillation)는 작은 학생 모델이 큰 교사 모델을 모방하도록 훈련시킵니다. 로짓 증류가 가장 효과적입니다. 학생이 교사의 확률 분포를 따라하도록 만드는 방식입니다.

구글의 Gemini 2.5 Flash가 완벽한 예입니다. 현재 시장 최고 성능의 모델인 2.5 Pro를 증류해서 놀라운 가성비를 달성했습니다. 증류 예산의 80% 이상을 로짓 증류에 투입하는 것이 가장 효과적입니다.

가지치기(Pruning)는 중요하지 않은 가중치를 제거합니다. 크기 기반 가지치기는 가장 작은 가중치들을 버립니다. 구조적 가지치기는 전체 채널이나 뉴런을 제거합니다. N:M 희소성은 “4개 가중치 중 2개만 0이 아님” 같은 패턴을 강제해서 하드웨어가 이를 활용할 수 있게 합니다.

2:4 희소성을 지원하는 GPU에서는 처음부터 재훈련 없이도 1.5-2배 처리량 향상을 얻을 수 있습니다.

검증기로 똑똑한 조기 종료

추론 비용이 폭발하는 이유는 모든 토큰이 모델의 전체 깊이를 통과하기 때문입니다. 조기 종료와 추측적 디코딩이 더 적은 작업으로 해결하려 하지만, 언제 “적게”가 충분한지는 누가 결정할까요?

검증기(Verifiers)가 그 답입니다. 보상 모델이나 점수 모델이 불완전한 생성을 보고 결정을 내립니다. 충분히 좋으면 종료하고, 나쁘면 대안을 탐색하고, 수정이 필요하면 경로를 조정합니다.

이는 도메인별 검증기가 필요하다는 뜻입니다. 순수 디코딩에서 검증기 구축과 실행으로 자본을 이동시키는 것입니다. 하지만 검증기는 조합 가능하고, 플러그 앤 플레이가 가능하며, 에이전트 시스템과 규제 영역에 자연스럽게 맞습니다.

토폴로지와 정책 튜닝

최고로 최적화된 모델도 시스템 안에 살아갑니다. GPU, CPU, 메모리, 네트워크의 배치가 지연 시간과 처리량을 결정합니다. 잘못된 배치는 성능을 조용히 망가뜨립니다.

모델과 데이터를 같은 랙에 배치하세요. 랙 간 홉은 요청마다 밀리초를 추가해서 꼬리 지연시간을 늘립니다. NUMA 인식도 중요합니다. 멀티소켓 호스트에서 메모리는 CPU에 속합니다. GPU 워커가 잘못된 소켓에 고정되면 모든 전송이 NUMA 레인을 거쳐야 합니다.

응답 캐싱은 프롬프트가 도착하는 곳 가까이에 완성된 응답을 캐시합니다. 기업 채팅에서는 프롬프트가 정규화되면 30-50%의 요청이 캐시에 히트할 수 있습니다.

샘플링 정책 튜닝도 중요합니다. temperature, top-k, 페널티 조정은 스타일만 바꾸는 게 아닙니다. 시퀀스 길이를 바꿉니다. 잘못 조정된 샘플러는 출력당 10-20% 더 많은 토큰을 추가할 수 있습니다.

3단계 완료 기준

구조화된 작업에서 무효 출력률이 0.1% 미만이어야 합니다. 증류/가지치기된 모델이 교사 모델보다 토큰당 최소 30-50% 저렴해야 합니다. 프로덕션에서 응답 캐시 히트율이 25% 이상이어야 합니다. 토폴로지 조정 후 꼬리 지연시간(P99)이 안정되어야 합니다. 디코딩 정책 튜닝 후 출력당 평균 토큰 수가 감소해야 합니다.

스케일링 시대를 현명하게 항해하기

이 3단계 최적화 전략은 AI Made Simple에서 실제 검증된 기법들을 바탕으로 구성했습니다. 각 단계별로 명확한 완료 기준을 제시한 이유는 과도한 최적화를 방지하기 위해서입니다. 기술적 완벽함보다는 실용적 가치에 초점을 맞춰야 합니다.

하지만 더 큰 질문이 남아있습니다. 스케일링은 과연 누구를 위한 것일까요?

하이퍼스케일러들과 인프라 거대 기업들은 끝없는 스케일링으로 수익을 냅니다. 토큰 하나하나가 그들의 락인을 강화합니다. 개발자들에게는 더 저렴한 추론과 더 넓은 접근성을 제공하지만, 동시에 중앙화를 강화하는 위험도 있습니다.

역사를 보면 두 가지가 동시에 일어납니다. 개인의 권한과 자율성이 증가해서 더 많은 일을 할 수 있게 되지만, 동시에 엘리트의 권력도 불균형적으로 증가해서 불평등이 심화됩니다. 현대인은 중세 농민보다 훨씬 많은 일을 할 수 있지만, 동시에 사회에 더 깊이 얽매여 있고 진정한 탈출은 불가능합니다.

그렇다면 우리는 어떻게 스케일링의 이점을 누리면서도, 그것이 우리를 더 큰 의존으로 이끄는 족쇄가 되지 않도록 할 수 있을까요? 현재 시스템 안에서 번영하면서도, 권력을 집중시키는 대신 분산시키는 대안적 미래를 상상할 수 있을까요?


참고자료:


AI Sparkup 구독하기

최신 게시물 요약과 더 심층적인 정보를 이메일로 받아 보세요! (무료)

Comments