1차 공개일 · 8월 20일1차 강의가 모두 공개됩니다
TECH 으로 돌아가기
TECH HACKER NEWS 오늘 8분 읽기 26 READS

페이스북 FAISS보다 빠른 벡터 검색, 러스트 라이브러리 Turbovec가 던진 질문

페이스북 FAISS보다 빠른 벡터 검색, 러스트 라이브러리 Turbovec가 던진 질문
SOURCE IMAGE · HACKER NEWS

검색 증강 생성(RAG) 시스템이 늘어나면서 임베딩 벡터를 얼마나 작고 빠르게 다루느냐가 실무의 병목으로 떠오르고 있다. 1천만 건 규모의 문서 코퍼스를 float32로 그대로 메모리에 올리면 약 31GB가 필요하다. 오픈소스 프로젝트 Turbovec는 이를 4GB에 담으면서도 널리 쓰이는 FAISS보다 빠른 검색을 낸다고 주장한다. Turbovec는 러스트로 작성되고 파이썬 바인딩을 제공하는 벡터 인덱스로, 구글 리서치가 제안한 TurboQuant 양자화 알고리즘을 구현 기반으로 삼는다. TurboQuant는 입력 데이터의 분포에 의존하지 않는(data-oblivious) 양자화 방식이며, 별도의 학습(training) 단계가 필요 없다는 점이 특징이다.

학습 없는 양자화가 가능한 이유

핵심 아이디어는 의외로 단순하다. 먼저 각 벡터에서 길이(norm)를 떼어내 별도의 float 값으로 저장하면, 남는 것은 고차원 초구면 위의 단위 방향 벡터가 된다. 여기에 모든 벡터를 동일한 무작위 직교 행렬로 회전시키면, 회전 후 각 좌표는 입력이 무엇이든 알려진 분포를 따르게 된다. 구체적으로는 베타 분포를 따르며 고차원에서는 평균 0, 분산 1/d인 정규분포로 수렴한다. 분포를 미리 안다는 것은 곧 최적의 버킷 경계를 데이터가 아니라 수학으로 미리 계산할 수 있다는 뜻이다. Lloyd-Max 스칼라 양자화로 2비트면 4개, 4비트면 16개의 버킷을 평균제곱오차가 최소가 되도록 나눈다. 그 결과 1536차원 벡터는 FP32 기준 6,144바이트에서 2비트 기준 384바이트로, 즉 16배 압축된다.

다만 베타 분포로의 수렴은 어디까지나 점근적 성질이라, 차원이 낮거나 저비트일 때는 개별 좌표가 이상적인 형태에서 벗어난다. Turbovec는 이를 보정하기 위해 TQ+라는 좌표별 캘리브레이션을 둔다. 좌표마다 이동값과 스케일값 두 개의 스칼라를 맞춰 경험적 분위수를 코드북의 최외곽 중심점에 대응시키는 방식이다. 사용자는 대표성 있는 표본 약 1,024행으로 index.calibrate(sample)를 한 번 호출하기만 하면 된다. 저자에 따르면 이 표본 크기면 전체 코퍼스로 맞추는 것과 사실상 동일한 결과가 나오며, 이후 캘리브레이션은 그대로 고정되어 모든 add에 재사용된다. 재학습이나 재구축이 없다는 점에서 기존 학습형 양자화와 성격이 다르다.

FAISS 대비 벤치마크를 어떻게 읽을 것인가

저자는 FAISS의 IndexPQ(LUT256, nbits=8)를 비교 기준으로 삼았다. 이는 대다수 사용자가 실제로 프로덕션에서 먼저 손대는 구성이며, TurboQuant 논문이 쓴 커스텀 u8-LUT PQ보다 오히려 강한 상대다. 100K 벡터, 1K 쿼리, k=64 조건에서 OpenAI d=1536과 d=3072 임베딩의 경우 캘리브레이션된 TQ+가 네 개 셀 중 세 개에서 R@1 기준으로 FAISS를 0.9~2.9포인트 앞섰고, 한 셀(d=1536, 4비트)만 0.7포인트 뒤졌다. 반면 차원이 낮은 GloVe d=200은 베타 가정이 가장 느슨해지는 영역이라 결과가 갈린다. TQ+는 두 비트 폭 모두에서 R@1 기준으로 앞서지만, 2비트에서는 k가 8 부근을 넘어가면 FAISS가 근소한 우위를 유지한다. 속도 측면에서는 ARM에서 4비트 평균 3.5배, x86에서 4비트 평균 3.4배 빠르다고 보고되며, 2비트대에서는 격차가 20~26% 수준으로 좁혀진다.

특히 눈에 띄는 것은 삽입과 삭제 성능이다. 단일 add()는 셀에 따라 6.3~19.7µs로 FAISS 단일 add보다 7.6~13.9배 빠르고, 삭제는 더 극적이다. Turbovec의 IdMapIndex.remove(id)는 O(1) swap-and-pop 방식이라 0.44~1.37µs에 끝나는 반면, IndexPQFastScan 위 IndexIDMap에 대한 FAISS의 remove_ids는 호출마다 저장된 코드를 재패킹하느라 100K 규모에서 건당 0.19~1.02초가 걸린다. 삭제 차트가 로그 스케일 축을 쓰는 이유가 여기에 있다. 잦은 갱신과 삭제가 발생하는 임베딩 스토어라면 이 차이는 결코 사소하지 않다.

실무에서 챙겨야 할 지점과 한계

실무 관점에서 유용한 세부 기능도 있다. 후보 집합 필터링이 SIMD 커널 내부 32-벡터 블록 단위로 이뤄져, 허용 슬롯이 하나도 없는 블록은 LUT 조회 이전에 건너뛴다. 즉 SQL이나 BM25, 접근제어(ACL), 시간 창으로 좁힌 소수 후보만 검색할 때 SIMD 비용 대부분을 아낄 수 있다. 또한 결과 길이는 min(k, 허용 벡터 수)로 정확히 맞춰져 의미 없는 패딩이 섞이지 않는다. 데이터 타입에 엄격하다는 점도 기억할 만하다. 입력은 (n, dim) 형태의 float32 배열이어야 하며 다른 dtype은 조용히 변환되지 않고 거부되므로 np.asarray로 미리 캐스팅해야 한다. 저장은 단일 .tv 파일에 fsync와 원자적 rename으로 이뤄지고, 여러 RAG 프레임워크의 참조 벡터·문서 스토어를 임포트만 바꿔 교체할 수 있게 설계됐다고 한다.

동시에 경계할 지점도 분명하다. 벤치마크는 모두 100K 벡터, 5회 중앙값이라는 고정 조건에서 나온 수치이므로, 서두의 1천만 건 4GB 사례처럼 규모가 커졌을 때의 검색 지연이나 정확도가 동일하게 유지되는지는 이 자료만으로 단정할 수 없다. TurboQuant 자체가 근사 검색(quantization)에 기반한 방식인 만큼, 낮은 차원이나 저비트 구성에서 재현율 손실이 존재한다는 점도 저자가 인정하는 부분이다. Lloyd-Max 코드북의 왜곡은 정보이론적 하한의 2.7배 이내라고 밝히고 있어, 무손실이 아니라 손실을 수학적으로 통제한 압축임을 이해하고 도입해야 한다. 결국 Turbovec가 제시하는 것은 만능 해법이 아니라, 프라이버시·메모리·지연이 함께 걸린 RAG 환경에서 학습 단계 없이 메모리를 대폭 줄이면서 갱신 비용을 낮추는 하나의 설계 선택지다. 자신의 임베딩 차원과 비트 폭이 어느 구간에 놓이는지를 먼저 확인한 뒤, 공개된 벤치마크 스크립트로 직접 재현해 보는 것이 합리적인 접근이다.

SOURCE · HACKER NEWS
원문 전체 보기 → https://github.com/RyanCodrai/turbovec
SHARE
NEXT · CHOOSE

변화를 읽었다면,
내가 만들 수익 구조를 고릅니다.

정보를 더 모으는 데서 멈추지 않고, 광고·외주·판매·중개·구독 중 내 상황에 맞는 출발점을 정해보세요.

21가지 수익 구조 살펴보기
처리 중...