개념
추론(inference)은 이미 학습이 끝난 모델에 입력을 넣어 출력을 얻는 과정을 말한다. 학습이 가중치를 바꿔 가며 모델을 만드는 단계라면, 추론은 그렇게 만들어진 가중치를 그대로 두고 계산만 수행하는 단계다. 우리가 챗봇에 질문을 던지고 답을 받는 모든 순간이 추론이다.
LLM의 추론은 두 국면으로 나뉜다. 먼저 입력 프롬프트 전체를 한꺼번에 읽어 내부 상태를 만드는 단계가 있고, 그다음 토큰을 하나씩 순서대로 생성하는 단계가 이어진다. 앞 단계는 병렬로 처리되어 비교적 빠르지만, 뒤 단계는 이전 토큰이 정해져야 다음 토큰을 계산할 수 있어 본질적으로 순차적이다. 긴 답변일수록 시간이 길어지는 이유가 여기에 있다.
이 순차 생성 때문에 추론 속도는 계산량보다 메모리 대역폭에 좌우되는 경우가 많다. 토큰 하나를 만들 때마다 거대한 가중치를 메모리에서 읽어 와야 하기 때문이다. 이미 계산한 중간 상태를 다시 쓰는 캐시, 양자화로 가중치 크기를 줄이는 방법, 여러 요청을 묶어 한 번에 처리하는 배치가 모두 이 병목을 겨냥한 기법이다.
배치가 특히 중요한 이유가 여기에 있다. 가중치를 한 번 읽어 오는 김에 여러 요청의 토큰을 함께 계산하면, 요청 하나당 드는 메모리 접근 비용이 나뉘어 전체 처리량이 크게 올라간다. 다만 요청을 모으는 동안 대기가 생기므로, 처리량과 개별 응답 속도 사이의 균형을 어디에 둘지가 운영에서의 판단 지점이 된다.
쓰임새
서비스 운영의 관점에서 추론은 곧 비용이다. 모델을 한 번 학습시키는 비용은 크지만 한 번으로 끝나는 반면, 추론 비용은 사용자가 늘어나는 만큼 계속 늘어난다. API 요금이 입력 토큰과 출력 토큰으로 나뉘어 매겨지는 것도 두 국면의 계산 비용이 다르기 때문이다.
체감 품질을 좌우하는 지표도 여기서 나온다. 첫 글자가 나오기까지 걸리는 시간과 이후 초당 생성되는 토큰 수가 대표적이며, 스트리밍으로 생성되는 대로 화면에 흘려보내는 방식이 널리 쓰이는 것도 앞쪽 지표를 개선하기 위해서다.
같은 프롬프트 앞부분이 반복되는 서비스라면 캐시가 큰 도움이 된다. 긴 지시문이나 문서가 매 요청마다 똑같이 들어간다면 그 부분의 계산 결과를 재사용해 읽어 들이는 단계를 건너뛸 수 있다. 프롬프트를 설계할 때 고정된 내용을 앞에, 매번 달라지는 내용을 뒤에 두라는 조언은 이 구조에서 나온 것이다.
자주 하는 오해
추론할 때 모델이 배우는 것 아닌가?
추론 중에 가중치는 전혀 바뀌지 않는다. 대화에서 알려 준 내용이 모델에 남는 것처럼 보인다면, 그것은 학습이 아니라 다음 호출의 프롬프트에 그 내용을 다시 넣어 주는 시스템 덕분이다. 같은 모델을 쓰는 다른 사용자에게 그 내용이 옮겨 가지도 않는다.
입력이 길어도 답이 짧으면 빠르지 않나?
긴 프롬프트는 읽어 들이는 단계에서 그만큼의 계산과 비용을 발생시킨다. 컨텍스트 윈도우를 가득 채운 요청은 답이 한 줄이어도 결코 저렴하지 않다.
GPU가 좋으면 추론이 빨라지지 않나?
순차 생성 구간에서는 연산 성능보다 메모리 대역폭과 용량이 병목인 경우가 많다. 연산 능력만 높은 장비를 붙여도 기대만큼 빨라지지 않으며, 모델이 메모리에 다 올라가지 않으면 오히려 크게 느려진다.