FAISS Index
FAISS는 Facebook AI Simillarity Search의 약자로, 페이스북에서 개발한 벡터 기반 유사도 검색 라이브러리이다.
I. FAISS chapter 1 - Flat, IVFFlat, IVFPQ
인덱싱
FAISS는 수십억개 규모의 밀집 벡터들을 효율적으로 검색하기 위해 강력한 인덱싱 기능을 제공한다. 인덱싱이란 비슷한 의미를 지닌 벡터들끼리 사전 분류작업을 하는것으로, 도서관에서 도서의 장르별로 배치를 분류하는 작업이라고 볼 수 있다.
FAISS에서 제공하는 주된 인덱싱 방법은 세가지가 있다.
- IndexFlatL2: 무차별 대입(brute force) 방식으로 하나의 벡터와 다른 모든 벡터들간의 유클리드 거리(L2)를 비교하여 가장 가까운 벡터를 찾아낸다.
- IndexIVFFlat: 전체 공간에 여러개의 중심점(Centeroid) 을 생성하고 각 벡터들은 가장 가까운 중심점을 찾아 군집화한다. 검색시에는 쿼리 벡터와 가까운 몇개의 중심점들을 찾고 그에 속한 벡터들만 검색하여 검색 시간을 단축시킨다. 이때 필요한 사전 작업을 클러스터링(Clustering) 이라고 한다.
- IndexIVFPQ: IVF 방식에 제품 양자화(Product Quantization) 과정을 추가한 인덱싱 방법이다. 벡터를 매우 작은 크기로 압축함으로서 정확성을 약간 포기한 대신 메모리 사용량을 극적으로 줄이고 속도를 높였다.
데이터셋의 규모가 거대해질수록 IndexFlatL2 -> IndexIVFFlat -> IndexIVFPQ 순으로 높은 효율을 보인다.
IndexFlatIP는? L2는 유클리디안 거리를 측정하지만 IP(Inner Product)는 벡터 내적으로 거리를 계산한다.
IndexFlatL2 시각화

IndexIVF 시각화

검색 시간 비교

IndexFlatL2 예제
IndexFlatL2 검색 결과
- 쿼리 문장: 'someone sprints with a football'
- 검색 시간: 0.001566499937325716
클러스터링
인접한 벡터들끼리 클러스터를 형성하여, 검색시 모든 벡터들이 아닌 특정 클러스터 내의 벡터들만 검색하기에 검색 효율이 증가한다. 데이터셋의 규모가 클수록 그 효율은 증가한다. 다만 벡터의 물리적 거리가 가까워도 클러스터가 다르다는 이유로 검색 결과에서 제외되는 경우가 종종 있을 수 있기에 정확도는 L2보다는 낮다.
FAISS의 클러스터링 과정의 핵심은 전체 벡터 공간에서 여러개의 중심점을 구하고 각 벡터들은 가장 가까이 있는 중심점이 속해있는 클러스터로 분류된다는 점이다. 이는 보로노이 다이어그램 알고리즘과 유사하다.
쿼리가 발생했을 때 가장 가까운 중심점을 구한 뒤 그 클러스터에 속한 벡터들만 검색하게 된다.
IndexIVFFlat 예제
IndexIVFFlat 검색 결과
- 쿼리 문장: 'someone sprints with a football'
- 검색 시간: 0.00019400008022785187
검색 시간이 상당히 단축된것을 볼 수 있다. 예제용 데이터셋이 그렇게 크지 않아 검색 결과는 같지만, 데이터셋 구모가 증가하고 검색 결과로 요청한 문장 수가 많을수록 정확도는 낮아질 수 있다.
제품 양자화(Product Quantization, PQ)
PQ는 벡터의 크기를 줄이기 위한 손실 압축 과정이다. PQ는 다음 세 단계를 거친다. 숫자는 예시를 들었다.
- 원본 벡터(768차원)를 여러개의 하위 벡터(96차원 * 8개)로 쪼갠다.
- 쪼개진 하위 벡터들에 대한 클러스터링을 수행한다. 이때 생성되는 클러스터들은 내부 클러스터, 즉 하위 벡터들의 유사도를 근사하는 클러스터로 IVF 과정에서 생성되는 외부 클러스터와는 다르다.
- 클러스터링이 끝나면 하위 벡터들이 속한 중심점의 ID값(0 ~ 255)으로 원본 벡터를 다시 만든다.
이 과정이 끝나면 4바이트 부동소수점으로 이루어진 768차원이었던 원본 벡터가 1바이트 정수로 이루어진 8차원 벡터가 된다. 이는 메모리 사용량을 극적으로 줄이는 획기적인 알고리즘이며, IVF와 결합된 IndexIVFPQ는 대규모의 데이터셋을 운용하는 프로젝트에서 가장 많이 사용하는 인덱스 유형이다.
IVF는 인접한 벡터끼리 묶어 검색 범위를 줄이는 방식으로 최적화했다면, PQ는 벡터 자체를 쪼개 근사하여 압축하는 것이다. 의미적으로 유사한 하위 벡터들이 가장 가까운 하나의 중심점 ID로 대체되는 과정에서 손실이 발생한다.

IndexIVFQP 예제
IndexIVFQP 검색 결과
- 쿼리 문장: 'someone sprints with a football'
- 검색 시간: 0.0001501000951975584
테스트 결과 정확도는 IVFFlat에 비해 감소한 모습을 보이나 유사도 검색으로서의 기능에는 큰 결함이 없는것으로 보인다. 또한 검색 결과로 출력된 거리 배열(D)의 내용들이, 개별 벡터에 대한 거리가 아닌 PQ에 의해 결정된 중심점과의 거리로 대체되었기 때문에 공통된 수치로 나타나는것을 볼 수 있다.
데이터셋 규모의 증가에 따른 검색 시간은 다음과 같은 증가세를 보인다.

II. FAISS chapter 2 - LSH, HNSW
IVF만으로도 훌륭한 성능 최적화 결과를 보이지만 데이터 다양성과 수가 증가함에 따라 클러스터, 벡터들과 무차별적인 순회를 처음부터 피한다면 최적의 이웃을 찾아가기 위한 시간 소모를 급격히 줄일 수 있다. 가장 먼저, 파이썬의 딕셔너리처럼 해시 컨테이너 기반의 자료구조를 떠올려볼 수 있다.
LSH(Locally Sensitive Hashing)
파이썬의 딕셔너리와 같이 일반적인 해싱 컨테이너는 데이터를 담을 버킷(Bucket) 의 충돌을 최소화하려고 한다. 반면 LSH는 일반적인 해싱 함수와 달리 유사한 키(Key)끼리의 충돌을 극대화하도록 설계된 해싱 함수이다.
LSH는 유사한 키값끼리 최대한 같은 버킷 주소가 산출되도록 한다. 그로인해 마치 IVF처럼, 유사한 벡터끼리 그룹화할 수 있게 한다.

IndexLSH 예제
IndexLSH를 생성할 때 nbits라는 매개변수가 필요한데, 이는 해시값의 해상도를 의미한다. 해상도가 높다는 것은 많은 버킷을 생성할 수 있다는 의미이다.
nbits가 클수록 높은 재현율(recall)을 보이는데, 재현율이란 LSH가 Flat과 비교했을떄 검색 결과가 얼마나 정확한지를 백분율로 나타낸것이다. 즉 nbits값이 높을수록 정확도가 증가한다.
LSH의 치명적인 단점은 벡터의 차원이 클수록 nbits가 기하급수적으로 증가해 성능이 큰 폭으로 하락한다는 것이다. 성능 하락이 심해지면 Flat보다도 높은 검색 시간이 발생한다. 따라서 낮은 차원의 데이터셋을 운용할 때 높은 효율을 보이는 인덱스라고 할 수 있다.
HNSW(Hierarchical Navigable Small World Graphs)
'계층적 작은 세계 그래프'
페이스북이 개발한 차세대 인덱스이다. 최단 경로 알고리즘으로 개별 벡터들을 하나의 노드로 만들어 가장 인접한 이웃들끼리 연결한다.
이때 연결을 계층적으로 연결하는것이 특징인데, 듬성듬성 떨어진 먼 노드들끼리의 긴 연결부터 시작하여 하위 계층으로 갈수록 짧고 조밀한 연결을 이루게 된다. 하위 레이어에서는 이전 레이어에서 연결되어있던 이웃 노드들을 제외하고 탐색한다.
매개변수 M은 이웃노드 수, 즉 그래프 구축 시 각 노드가 얼마나 많은 이웃노드들과 연결될 것인지를 결정하는 변수이다. M값의 증가에 따라 재현율이 증가한다.
다만 메모리 사용량 역시 선형적으로 증가하므로 이를 염두에 두고 결정해야 한다.

인덱스 생성 후에 정의하는 속성으로 ef_construction과 ef_search가 있는데, 이들이 가지는 정확한 의미는 다음과 같다.
- efConstruction: 인덱스 구축 또는 새 데이터를 추가할 때, 새로운 노드와 연결할 이웃 노드들을 얼마나 깊게 탐색할 지 결정하는 수치이다.
- efSearch: 인덱스에서 검색할 때, 최적의 이웃 노드를 얼마나 깊게 탐색할 지 결정하는 수치이다.
두 속성 모두 높을수록 검색 시 정확한 결과를 반환하지만 시간에 영향을 미친다.
| efConstruction | efSearch |
|---|---|
| 데이터를 삽입할 때 사용 | 검색할 때 사용 |
| 구축 시간에 영향 | 검색 시간에 영향 |
HNSW의 가장 큰 장점은 바로 검색할 때 efSearch값을 조절하여 빠른 시간을 포기하는 대신 더 정확한 결과를 얻는 등 상충되는 두 요구사항을 필요에 맞게 조절할 수 있다는 점이다.

