[논문 리뷰] Vectorizing the Trie: Efficient Constrained Decoding for LLM-based Generative Retrieval on Accelerators

Generative retrieval has emerged as a powerful paradigm for LLM-based recommendation. However, industrial recommender systems often benefit from restricting the output space to a constrained subset of...

[논문 리뷰] Vectorizing the Trie: Efficient Constrained Decoding for LLM-based Generative Retrieval on Accelerators

[논문 리뷰] Vectorizing the Trie: 가속기에서 LLM 제약 디코딩을 효율적으로 수행하는 방법

TL;DR

대규모 언어 모델(LLM)을 활용한 생성형 검색은 추천 시스템의 새로운 패러다임입니다. 하지만 LLM이 유효한 항목 ID만 생성하도록 제약하는 것은 실시간 서비스에서 큰 병목이었습니다. **STATIC (Sparse Transition Matrix-Accelerated Trie Index for Constrained Decoding)**은 이 문제를 해결하기 위해 제안된 기술입니다. 핵심 아이디어는 유효한 ID 집합을 나타내는 접두사 트리(Trie)를 희소 행렬(Sparse Matrix)로 변환하는 것입니다. 이를 통해 불규칙한 메모리 접근을 유발하는 트리 탐색을 GPU/TPU에 최적화된 병렬 행렬 연산으로 대체합니다. 그 결과, CPU 기반 트라이 구현 대비 최대 948배, 기존 가속기 기반 검색 방식 대비 최대 1033배의 속도 향상을 달성했으며, YouTube와 같은 대규모 플랫폼에서 실시간 제약 디코딩을 가능하게 했습니다.

연구 배경 및 동기

LLM이 추천 및 검색 시스템에 통합되면서, 사용자의 복잡한 의도를 이해하고 개인화된 결과를 생성하는 능력이 비약적으로 발전했습니다. 기존의 검색 시스템이 사용자의 질의를 임베딩 벡터로 변환하여 유사한 항목을 찾는 방식이었다면, 생성형 검색은 LLM이 항목의 고유 식별자(ID)를 토큰 시퀀스로 직접 생성합니다. 이는 훨씬 더 유연하고 문맥에 맞는 추천을 가능하게 합니다.

하지만 여기에는 치명적인 문제가 있습니다. LLM이 존재하지 않는 상품 ID나 유효하지 않은 비디오 링크를 생성할 수 있다는 것입니다. 이를 방지하기 위해 '제약 디코딩(Constrained Decoding)' 기술이 필요합니다. 즉, LLM이 다음 토큰을 생성할 때마다, 현재까지 생성된 시퀀스가 유효한 ID의 접두사인지 확인하고, 가능한 토큰들만 후보로 남겨두는 것입니다. 기존의 트라이(Trie) 자료구조를 이용한 방식은 정확하지만, 순차적인 탐색 방식으로 인해 GPU/TPU와 같은 병렬 처리 장치에서 성능이 저하되어 실제 서비스에 적용하기 어려웠습니다. 이 연구는 바로 이 병목을 해결하고자 시작되었습니다.

관련 연구

생성형 검색과 제약 디코딩은 최근 활발히 연구되는 분야입니다.

연구 분야 장점 단점 STATIC의 차별점
BERT 기반 검색 깊은 문맥 이해 가능 제약 조건 적용이 어렵고, 생성형이 아님 생성 모델에 직접 제약 디코딩 적용
Transformer 기반 추천 대용량 데이터의 빠른 처리 생성된 결과의 유효성 보장 어려움 각 생성 단계에서 유효성 실시간 보장
트라이(Trie) 기반 디코딩 제약 조건 적용 용이, 정확성 보장 순차적 탐색으로 인한 속도 저하 (GPU 비친화적) 트라이를 희소 행렬로 변환하여 병렬화
희소 행렬 연산 대규모 데이터의 효율적 처리 제약 디코딩 문제에 직접 적용된 사례 부족 트라이 구조를 희소 행렬 연산으로 모델링
GPU/TPU 가속화 뛰어난 병렬 처리 성능 동적 분기(Dynamic Branching)로 인한 성능 저하 조건 분기를 제거한 브랜치 없는 알고리즘 설계

핵심 기여

  1. STATIC 방법론 제안: 접두사 트리를 상태 전이(State Transition)를 나타내는 희소 행렬로 변환하여, GPU/TPU에서의 병렬 처리 효율을 극대화했습니다.
  2. 브랜치 없는(Branch-less) 알고리즘: GPU 스레드들의 실행 경로를 갈라지게 하는 if-else와 같은 조건 분기를 제거했습니다. 동적 슬라이싱과 마스크 연산을 활용하여 모든 스레드가 동일한 명령어를 수행하도록 만들어 하드웨어 효율을 최고로 끌어올렸습니다.
  3. 대규모 실제 서비스 적용: YouTube 추천 시스템에 STATIC을 성공적으로 적용하여, 실시간으로 엄격한 제약 조건(예: 최근 몇 분 내 업로드된 비디오만 추천)을 적용할 수 있음을 입증했습니다.
  4. 압도적인 성능 향상: CPU 기반 트라이 구현 대비 948배, 하드웨어 가속 이진 검색 대비 최대 1033배 빠른 속도를 달성했습니다.
  5. 콜드 스타트 문제 완화: 새로운 항목이 추가되었을 때, 이를 즉시 추천 후보에 포함할 수 있어 콜드 스타트 문제를 효과적으로 해결할 수 있습니다.

제안 방법론: STATIC

STATIC의 핵심은 관점의 전환입니다. 기존의 '한 노드씩 포인터를 따라가는' 트리 탐색 방식을, '현재 상태(state)에서 특정 토큰을 입력받았을 때 다음 상태가 무엇인지 미리 계산된 행렬을 통해 한 번에 찾는' 상태 머신(State Machine) 관점으로 바꾼 것입니다.

1. 왜 기존 트라이는 가속기에서 느린가?

트라이 탐색은 본질적으로 포인터 체이싱(pointer chasing)입니다. 현재 노드에서 다음 토큰에 해당하는 자식 노드의 메모리 주소를 찾아 이동하는 과정의 연속입니다. 이러한 불규칙한 메모리 접근 패턴은 GPU의 SIMD(Single Instruction, Multiple Data) 아키텍처에 치명적입니다. 수천 개의 스레드가 동시에 각기 다른 메모리 주소에 접근하려고 하면 메모리 대역폭 병목이 발생하고, 캐시 효율도 급격히 떨어집니다.

2. 트라이를 희소 행렬로 변환하기

STATIC은 이 문제를 해결하기 위해 트라이를 **상태 전이 행렬 T\mathbf{T}**로 변환합니다.

  • 상태(State): 트라이의 각 노드는 고유한 상태 ID를 가집니다. (루트 노드 = 상태 0)
  • 전이(Transition): 상태 sis_i (현재 노드)에서 토큰 vv (간선)를 따라가면 상태 sjs_j (자식 노드)에 도달하는 관계를 행렬에 표현합니다. 즉, T[si,v]=sj\mathbf{T}[s_i, v] = s_j 입니다.

유효한 ID가 [1, 3], [1, 4, 2], [2, 5] 세 가지라고 가정해봅시다. 이를 트라이로 만들고 행렬로 변환하는 과정은 다음과 같습니다.

  • Trie: (0)에서 1을 따라가면 (1)로, 다시 3을 따라가면 (2)로 갑니다.
  • Transition Matrix T\mathbf{T}: 이 관계를 행렬로 표현합니다. 예를 들어, T[0, 1] = 1은 상태 0(루트)에서 토큰 1을 받으면 상태 1로 전이함을 의미합니다. 대부분의 칸이 0이므로 이는 희소 행렬이 됩니다. STATIC은 이를 메모리 효율적인 CSR(Compressed Sparse Row) 형식으로 저장합니다.

3. 벡터화된 병렬 디코딩

이제 디코딩 과정은 간단한 행렬 조회 연산이 됩니다. 배치(batch) 내의 모든 생성 시퀀스에 대해 다음 상태를 찾는 과정은 다음과 같이 병렬로 처리됩니다.

# 기존 Trie 방식 (순차적, GPU 비친화적)
def get_next_valid_tokens_trie(node):
  return list(node.children.keys())

# STATIC 방식 (병렬적, GPU 친화적)
# B: 배치 크기, V: 어휘 크기
# current_states: (B,) 크기 벡터. 각 시퀀스의 현재 상태(노드 ID)
# transition_matrix: (S, V) 크기 희소 행렬. S는 총 상태(노드) 수
def get_next_states_static(current_states, next_tokens, transition_matrix):
  # 각 시퀀스에 대해 다음 상태를 병렬로 조회
  # 이 연산이 SpMV(희소 행렬-벡터 곱)와 유사하게 구현됨
  next_states = transition_matrix[current_states, next_tokens]
  return next_states

각 디코딩 단계 tt에서, 모델이 예측한 로짓(logits)에 마스크를 적용하여 유효한 다음 토큰만 남깁니다. 현재 상태가 st1s_{t-1}일 때, 토큰 vv가 유효한지 여부는 단순히 T[s_{t-1}, v]가 0이 아닌지만 확인하면 됩니다. 이 마스킹 과정 역시 거대한 행렬 연산으로 병렬 처리됩니다.

4. 핵심 수식

제약 디코딩의 목표는 각 디코딩 단계 tt에서 어휘 집합 V\mathcal{V} 중 다음 토큰 ytVy_t \in \mathcal{V}를 선택할 때, 생성된 시퀀스 (y1,,yt)(y_1, \dots, y_t)가 유효한 접두사가 되도록 하는 것입니다. 이를 제약 함수 FtF_t로 표현할 수 있습니다.

Ft(y1,,yt)={1if (y1,,yt) is a valid prefix0otherwiseF_t(y_1, \dots, y_t) = \begin{cases} 1 & \text{if } (y_1, \dots, y_t) \text{ is a valid prefix} \\ 0 & \text{otherwise} \end{cases}

STATIC은 이 FtF_t 함수를 희소 전이 행렬 T\mathbf{T}를 이용한 상태 전이로 효율적으로 구현합니다. 현재 상태를 나타내는 원핫 벡터가 st1\mathbf{s}_{t-1}이고 다음 토큰이 vv일 때, 다음 상태 st\mathbf{s}_t는 행렬-벡터 곱으로 계산될 수 있습니다. 실제 구현에서는 인덱싱으로 더 효율적으로 처리됩니다.

next_state st=T[st1,v]\text{next\_state } s_t = \mathbf{T}[s_{t-1}, v]

이 모든 과정은 벡터화된 노드 전이 커널(Vectorized Node Transition Kernel) 내에서 배치 단위로 동시에 처리되어 가속기 효율을 극대화합니다.

실험 설정

실험은 YouTube의 대규모 비디오 추천 플랫폼에서 수행되었으며, 실제 서비스 환경의 데이터셋을 사용하여 STATIC의 성능을 검증했습니다.

  • 데이터셋: YouTube 비디오 ID 데이터셋 (수백만 개), Amazon 상품 리뷰 데이터셋
  • 평가 지표: 지연 시간(Latency), 처리량(Throughput), 그리고 추천 성능 지표인 클릭률(CTR), Recall@1 등
  • 베이스라인:
    1. CPU Trie: C++로 최적화된 표준 트라이 구현
    2. Binary Search on GPU: 정렬된 유효 ID 리스트를 GPU에서 이진 검색하는 방식
  • 하이퍼파라미터:
하이퍼파라미터
배치 크기 128
학습률 0.001
최대 시퀀스 길이 256
희소 행렬 형식 CSR

실험 결과 분석

STATIC은 모든 베이스라인을 압도하는 성능을 보여주었습니다.

비교 대상 성능 향상 (속도) 비고
CPU 기반 Trie 구현 948배 빠름 전통적인 방식 대비 압도적인 성능
하드웨어 가속 이진 검색 47 ~ 1033배 빠름 기존 가속 방식보다 월등한 효율성 입증
  • 확장성: 제약 집합의 크기(수백만 개)나 ID 어휘의 크기가 증가해도 STATIC은 매우 낮은 지연 시간을 일관되게 유지했습니다. 반면 베이스라인들은 크기가 커질수록 성능이 급격히 저하되었습니다.
  • 메모리 효율성: CSR 희소 행렬 형식을 사용하여 메모리 사용량을 효율적으로 관리하며, 대규모 시스템에서도 실용적임을 입증했습니다.

이러한 성능 향상은 단순히 속도 개선을 넘어, 이전에는 불가능했던 실시간 제약 조건(e.g., 사용자의 실시간 위치 기반 추천, 수 분 내 업로드된 최신 비디오만 추천)을 대규모 서비스에 적용할 수 있게 되었음을 의미합니다.

비판적 평가

STATIC은 LLM 기반 생성형 검색 시스템이 가진 '속도'와 '정확성'이라는 두 마리 토끼를 모두 잡는 실용적인 해법을 제시합니다.

강점

  1. 혁신적인 아이디어: 트라이를 희소 행렬로 변환한다는 아이디어는 GPU 아키텍처의 강점을 극대화하는 매우 효과적인 접근법입니다.
  2. 압도적인 성능 및 확장성: 실험 결과가 증명하듯, 기존 방식들과 비교할 수 없는 성능을 보여주며 대규모 제약 집합에서도 강건합니다.
  3. 실용성: YouTube라는 세계 최대 규모의 플랫폼에서 성공적으로 적용되어 그 실용성과 효과를 입증했습니다.

한계점과 개선 방향

  1. 정적(Static) 제약 조건: 이름에서 알 수 있듯, STATIC은 디코딩 세션이 시작되기 전에 제약 조건(유효 ID 집합)이 고정되어 있어야 합니다. 실시간으로 제약 집합이 매우 동적으로 변하는 환경에서는 트라이와 행렬을 다시 빌드하는 오버헤드가 발생할 수 있습니다.
  2. 초기 빌드 복잡성 및 비용: 수백만 개의 항목으로 트라이를 구축하고 이를 희소 행렬로 변환하는 과정은 상당한 시간과 컴퓨팅 자원을 필요로 합니다. 이 파이프라인을 효율적으로 구축하고 관리하는 엔지니어링 노력이 필요합니다.
  3. 특정 환경 의존성: GPU/TPU와 같은 특정 하드웨어 가속기에 고도로 최적화되어 있어, 범용 CPU 환경에서는 그 이점이 줄어들 수 있습니다.

향후 연구 방향

STATIC의 아이디어는 추천 시스템을 넘어 다양한 LLM 응용 분야로 확장될 잠재력이 큽니다.

  • 구조화된 데이터 생성: JSON 스키마, SQL 쿼리, 프로그래밍 코드 등 정해진 문법을 따라야 하는 텍스트 생성에 적용할 수 있습니다.
  • Tool-using LLM: LLM이 사용할 수 있는 API 함수나 도구의 집합을 제약 조건으로 걸어, 허용된 함수 호출만 생성하도록 강제할 수 있습니다.
  • 동적 STATIC: 제약 집합의 변경을 효율적으로 행렬에 반영할 수 있는 동적 업데이트 메커니즘에 대한 연구도 흥미로운 방향이 될 것입니다.

결론

STATIC은 접두사 트리를 희소 행렬로 변환하고 하드웨어 가속을 활용하는 독창적인 아이디어를 통해, 대규모 생성형 검색 시스템에서 실시간 제약 디코딩을 현실로 만들었습니다. 이 연구는 LLM 기반 시스템이 단순히 그럴듯한 결과를 생성하는 것을 넘어, 복잡한 비즈니스 규칙을 준수하는 정확하고 신뢰도 높은 결과를 제공할 수 있는 길을 열었습니다. 이는 개인화된 e-커머스, 뉴스 추천, 콘텐츠 플랫폼 등 다양한 분야에 큰 영향을 미칠 중요한 기술적 진전입니다.

참고 자료