Field Log · Entry
Embedding 압축과 ANN 서빙: Dimension부터 Re-index까지 (12/14)
이번 글의 결론
- Production 품질은 encoder 하나가 아니라
representation × dimension × dtype/code × index × search parameter의 조합입니다.- 차원 절단은 MRL로 학습됐는지 확인해야 합니다. 임의의 embedding 뒷부분을 자르는 것은 일반적인 압축법이 아닙니다.
- Quantization loss와 ANN loss를 한 번에 측정하지 않습니다.
fp32 exact → compressed exact → compressed ANN순서로 원인을 분해합니다.- HNSW의
M·efConstruction·efSearch, IVF의nlist·nprobe, PQ code 크기는 품질·memory·latency를 바꾸는 실험 변수입니다.- Model 또는 dimension이 바뀌면 기존 vector와 섞지 말고 shadow index를 만들며, dual-read·canary·rollback이 가능한 version contract를 둡니다.
앞 글에서 model quality를 공정하게 읽는 법을 배웠습니다. 이제 exact matrix에 있던 vector를 실제 traffic과 corpus 규모에 맞춥니다.
1. 먼저 용량을 계산한다
Dense vector의 raw storage는 단순합니다.
raw bytes = number_of_vectors × dimension × bytes_per_element
1억 개, 1,024차원이라면:
| 표현 | 원소당 byte | Raw vector만의 크기 |
|---|---|---|
| float32 | 4 | 약 409.6 GB |
| float16 | 2 | 약 204.8 GB |
| int8 | 1 | 약 102.4 GB |
| binary | 1 bit | 약 12.8 GB |
여기에 ID, metadata, graph edge, posting list, allocator overhead, replica가 더해집니다. HNSW index가 raw vector size와 같다고 가정하면 capacity plan이 틀립니다.
2. 다섯 층을 분리한다
encoder weights
→ full embedding z ∈ R^d
→ dimension policy d'
→ numeric representation / code
→ ANN index structure
→ search-time parameters
각 층의 질문:
| 층 | 품질 질문 | 운영 질문 |
|---|---|---|
| Model | relevant item을 가깝게 두는가 | encode throughput·memory |
| Dimension | 정보가 prefix에 보존되는가 | vector bytes·dot-product cost |
| Quantization | score ordering을 얼마나 보존하는가 | memory bandwidth·SIMD |
| Index | exact neighbor를 얼마나 찾는가 | build time·RAM·disk |
| Search | target recall을 어떤 비용으로 달성하는가 | p95·p99·QPS |
한 번에 모두 바꾸면 regression 원인을 찾을 수 없습니다.
3. Matryoshka Representation Learning, MRL
MRL은 큰 vector의 앞쪽 prefix도 유용한 representation이 되도록 여러 차원에서 loss를 겁니다.
z = [z1, z2, ..., z1024]
loss = w128 L(z[:128])
+ w256 L(z[:256])
+ w512 L(z[:512])
+ w1024 L(z[:1024])
이렇게 학습된 model은 같은 checkpoint에서 128·256·512·1,024차원을 선택하는 quality–cost knob를 제공합니다.
중요한 제한
MRL을 적용하지 않은 model의 앞 256차원이 특별히 중요하다는 보장은 없습니다. 다음 세 방식은 구분해야 합니다.
| 방식 | 학습 필요 | 성질 |
|---|---|---|
| 임의 prefix truncation | 없음 | 일반적으로 안전하지 않음 |
| PCA/projection | corpus fit | 새 좌표축·projection artifact |
| MRL prefix | multi-dim objective | 학습된 nested representation |
Model card가 지원하는 dimension과 normalization 순서를 따릅니다.
4. Dimension Sweep
dimensions = [128, 256, 512, 768, 1024]
for each dimension:
1. query/document vector truncate
2. model contract에 따라 normalize
3. fp32 exact retrieval
4. relevance metric + latency + bytes 측정
보고 표:
| Dim | Exact Recall@50 | nDCG@10 | bytes/vector(fp16) | query dot time |
|---|---|---|---|---|
| 128 | 256 | |||
| 256 | 512 | |||
| 512 | 1,024 | |||
| 1,024 | 2,048 |
전체 평균뿐 아니라 entity, 숫자, 부정, 긴 문서, cross-lingual slice를 확인합니다. 낮은 차원에서 드문 세부 정보가 먼저 사라질 수 있습니다.
5. 2D Matryoshka 관점
2D Matryoshka 계열은 network depth와 embedding dimension을 함께 elastic하게 쓰려는 방향입니다.
compute axis: transformer layers 6 / 12 / 24
vector axis: dimension 128 / 256 / 768
아이디어는 traffic에 따라 encoder compute와 vector cost를 동시에 조절하는 것입니다. 하지만 모든 조합이 같은 checkpoint에서 안전한 것은 아니며, 학습 recipe가 지원한 exit와 dimension만 평가해야 합니다.
6. Scalar Quantization
float16 / bfloat16
실수 범위를 유지하면서 byte를 절반으로 줄입니다. CPU index가 실제로 해당 dtype 계산을 효율적으로 지원하는지 확인합니다. 저장 dtype과 accumulation dtype도 구분합니다.
int8
각 값 또는 vector/block의 scale을 사용해 8-bit integer로 매핑합니다.
q_i = round(z_i / scale) + zero_point
z_i ≈ scale × (q_i - zero_point)
Symmetric normalized embedding에서는 대칭 scale이 자연스러울 수 있지만, 최적 policy는 vector distribution과 engine에 달려 있습니다.
Binary
부호 등을 1 bit로 바꿔 Hamming distance를 사용할 수 있습니다. memory와 coarse filtering은 크게 좋아지지만 score resolution 손실이 큽니다.
실용적인 방식은 binary로 후보를 넓게 찾고 원본 또는 int8 vector로 rescore하는 cascade입니다.
7. Product Quantization, PQ
PQ는 vector를 여러 subvector로 나누고 각 부분을 codebook centroid ID로 바꿉니다.
z = [z^(1), z^(2), ..., z^(m)]
each subvector → nearest centroid ID
stored code = [c1, c2, ..., cm]
Query와 centroid 사이의 distance table을 미리 계산해 compressed code를 빠르게 비교합니다.
주요 변수:
- subquantizer 수
m - subvector당 bit 수
- codebook training sample
- residual PQ 여부
- OPQ 같은 rotation 사용 여부
- original vector를 rerank용으로 보존할지
PQ codebook을 다른 model version의 vector에 재사용하면 distribution mismatch가 생길 수 있습니다.
8. 압축 손실을 Exact에서 먼저 잰다
Stage A fp32 full-dim exact
Stage B fp32 reduced-dim exact
Stage C quantized reduced-dim exact / exhaustive code scan
Stage D same compressed representation + ANN
측정값:
dimension loss = metric(A) - metric(B)
quantization loss = metric(B) - metric(C)
ANN loss = metric(C) - metric(D)
Code scan이 true exact floating search와 같다는 의미는 아닙니다. 여기서 exact는 해당 compressed representation의 모든 corpus item을 빠짐없이 비교했다는 뜻입니다.
9. HNSW
HNSW는 가까운 vector를 edge로 연결한 다층 proximity graph를 탐색합니다.
upper sparse layers → 멀리 이동
lower dense layer → 근방 정밀 탐색
대표 parameter:
| Parameter | 커지면 보통 | 비용 |
|---|---|---|
M | graph connectivity·recall 증가 | RAM·build 증가 |
efConstruction | graph quality 증가 | build time 증가 |
efSearch | search recall 증가 | query latency 증가 |
장점:
- 높은 recall–latency 성능
- search-time
efSearch조절 - 비교적 자연스러운 incremental insertion
주의:
- graph edge memory가 큼
- delete/update와 compaction 정책 필요
- filter가 graph traversal을 막을 수 있음
- replica마다 build order가 달라 미세한 결과 차이가 날 수 있음
10. IVF와 IVF-PQ
IVF는 corpus를 coarse centroid의 posting list로 나눕니다.
offline:
vectors → nearest coarse centroid → inverted list
online:
query → nearest nprobe centroids → scan their lists
| Parameter | 의미 | trade-off |
|---|---|---|
nlist | coarse partition 수 | 너무 작으면 scan 증가, 너무 크면 training·빈 list 문제 |
nprobe | query가 방문할 list 수 | recall 증가 ↔ latency 증가 |
| PQ code | list 안 vector 압축 | memory 감소 ↔ quantization loss |
대규모 batch·GPU 환경에서 매력적일 수 있지만, corpus size와 hardware에 맞춘 centroid training이 필요합니다.
11. DiskANN 계열
RAM에 전체 vector·graph를 올리기 어려울 때 SSD 접근을 고려한 graph index가 필요합니다. DiskANN 연구는 billion-scale nearest-neighbor search에서 memory가 제한된 machine과 SSD를 활용하는 설계를 제안했습니다.
운영에서 확인할 것:
- warm/cold cache latency
- random read pattern과 SSD IOPS
- compressed vector를 RAM에 둘지
- graph와 full vector의 배치
- index build·merge 시간
- node failure와 replica recovery
Disk 기반이라는 label만으로 저렴하다고 결론 내리지 않습니다. Tail latency와 SSD endurance가 비용의 일부입니다.
12. Filtered ANN
실제 검색은 tenant, ACL, language, date, category filter를 동반합니다.
vector top-k AND tenant_id = A AND access_level <= user
방법:
| 방식 | 문제 |
|---|---|
| ANN 후 post-filter | 살아남는 결과가 k보다 적을 수 있음 |
| filter 후 brute-force | 선택도가 낮으면 느림 |
| filter-aware traversal | engine 종속·index 복잡도 |
| partition별 index | 작은 shard·운영 수 증가 |
Filter selectivity별 recall·latency를 측정합니다. 전체 corpus benchmark만으로 multi-tenant traffic을 대표할 수 없습니다.
13. Pareto Frontier를 만든다
한 개 composite score보다 지배 관계가 분명합니다.
Configuration A dominates B if:
quality_A >= quality_B
latency_A <= latency_B
memory_A <= memory_B
and at least one is strictly better.
실험 grid 예:
dimensions: [256, 512, 1024]
representations: [fp16, int8, pq_64x8]
indexes:
flat: [{}]
hnsw:
- {M: 16, efConstruction: 128, efSearch: 64}
- {M: 32, efConstruction: 256, efSearch: 128}
ivfpq:
- {nlist: 4096, nprobe: 16, code: pq_64x8}
- {nlist: 4096, nprobe: 64, code: pq_64x8}
모든 조합을 무작정 실행하지 말고 Stage B/C에서 품질이 낮은 dimension·code를 먼저 제거합니다.
14. Target Recall에서 System을 비교한다
HNSW가 2ms, IVF가 1ms 같은 비교는 recall이 다르면 의미가 약합니다.
1. 각 index의 search parameter sweep
2. ANN recall@10 = 0.95가 되는 점을 interpolation
3. 같은 target recall에서 p50/p95/QPS/RAM 비교
4. qrel metric도 함께 확인
두 개의 recall을 계속 구분합니다.
neighbor preservation: ANN top-k vs exact top-k
task relevance: retrieved top-k vs qrel
15. End-to-end Latency Budget
T_total = T_queue
+ T_query_encode
+ T_network
+ T_ANN
+ T_metadata_fetch
+ T_rerank
+ T_context_pack
Vector search만 microbenchmark해 전체 SLA를 주장하지 않습니다. Query encoder가 7B이고 ANN이 2ms라면 병목은 model입니다.
측정 조건:
- batch 1과 concurrent load
- warm/cold cache
- corpus size와 filter selectivity
- hardware·thread·NUMA
- network hop
- top-k와 returned metadata size
- p50·p95·p99
16. Index Identity Contract
index_manifest:
index_id: policies-ko-v12
corpus_snapshot: docs-2026-07-01
chunker_revision: heading-v3
model_id: org/model
model_revision: abc123
query_prompt_revision: qprompt-v4
document_prompt_revision: dprompt-v3
pooling: mean
normalization: l2
dimension: 512
vector_dtype: int8
quantizer_revision: int8-calib-v2
similarity: inner_product
ann:
type: hnsw
M: 32
efConstruction: 256
build_code_commit: def456
document_count: 9843210
checksums:
id_map: "..."
vectors: "..."
Query encoder contract가 이 manifest와 다르면 request를 거절하거나 명시된 compatible route로 보냅니다.
17. 왜 Vector를 섞으면 안 되는가
Model A와 B가 모두 768차원이어도 좌표계가 다릅니다.
dot(embed_A(query), embed_B(document))
has no learned compatibility guarantee
같은 model이라도 다음 변경은 full re-embedding 후보입니다.
- model revision
- document instruction/prefix
- pooling
- normalization
- dimension
- quantizer/codebook
- tokenizer·truncation contract
일부 embedding converter 연구가 좌표계 변환을 학습하지만, 별도 학습·평가 없이 migration shortcut으로 가정하지 않습니다.
18. 안전한 Re-index
current index v11 ────────────── serves traffic
new corpus snapshot
→ encode with contract v12
→ build shadow index v12
→ integrity + exact/ANN eval
→ dual-read shadow comparison
→ 1% canary → 10% → 50% → 100%
→ keep v11 for rollback window
Gate:
- document count·ID coverage 일치
- duplicate/missing vector 0 또는 허용 budget 이하
- sample embedding deterministic check
- exact relevance regression 없음
- target ANN recall 달성
- p95·p99와 error rate budget 충족
- tenant ACL leakage test 통과
- rollback pointer 검증
19. Incremental Update
Append-only 문서와 수정·삭제는 다르게 다룹니다.
insert: new document vector + metadata
update: tombstone old ID + insert new version
delete: authorization 즉시 차단 + async physical compaction
보안상 삭제 요청은 graph compaction을 기다려서는 안 됩니다. Query path의 metadata/ACL 층에서 즉시 보이지 않게 한 뒤 물리 삭제를 확인합니다.
Contextual embedding은 한 chunk 수정이 주변 vector 재계산을 요구할 수 있으므로 긴 문서 편의 update scope를 manifest에 포함합니다.
20. 운영 Metric
Quality
- exact relevance Recall/nDCG
- ANN neighbor recall
- compressed score/rank correlation
- critical slice regression
Performance
- query encode p50/p95
- ANN p50/p95/p99
- QPS at target recall
- index build·load time
- re-embedding documents/s
Capacity
- bytes/vector
- index bytes/vector
- RAM·VRAM·disk
- replicas와 recovery time
Correctness
- missing/duplicate ID
- stale document rate
- ACL post-filter shortfall
- query/index contract mismatch
21. 선택 가이드
| 상황 | 첫 실험 |
|---|---|
| 수십만 vector, 충분한 RAM | fp16/fp32 flat exact baseline |
| 수백만~수천만, high recall | HNSW dimension·efSearch sweep |
| 대규모 GPU batch search | IVF/IVF-PQ sweep |
| 수억~수십억, RAM 제약 | PQ·disk-aware graph 검토 |
| mobile/offline | small encoder+MRL+int8/binary cascade |
| 강한 metadata filter | filter-aware engine/partition 실험 |
| multi-vector document | coarse single-vector → late-interaction cascade |
이 표는 출발점이며 corpus 분포와 update pattern이 최종 선택을 바꿉니다.
22. Checklist
- Raw vector·graph·metadata·replica 용량을 계산했다.
- MRL 지원 차원만 prefix truncation했다.
- Full-dim, reduced-dim, quantized, ANN을 단계별 비교했다.
- ANN recall과 relevance recall을 모두 냈다.
- 같은 target recall에서 latency·QPS를 비교했다.
- Filter selectivity와 concurrent load를 재현했다.
- Model·prompt·pooling·dimension·codebook을 index identity로 묶었다.
- 새 version은 shadow index와 dual-read로 검증했다.
- 삭제·ACL이 compaction 전에도 즉시 적용된다.
- Rollback 가능한 이전 index를 보존했다.
스스로 확인하기
- MRL이 아닌 model의 vector prefix를 임의로 자르면 안 되는 이유는 무엇인가?
fp32 exact → compressed exact → compressed ANN순서가 분리하는 세 손실은 무엇인가?- HNSW의
efSearch를 올렸을 때 기대되는 품질과 비용 변화는 무엇인가? - 서로 같은 dimension인 model A query vector와 model B document vector를 섞을 수 없는 이유는 무엇인가?
- Re-index 과정에서 dual-read와 rollback window가 필요한 이유는 무엇인가?
다음 글에서는 LLM backbone, data distillation, small model, contextual·reasoning·multimodal embedding과 평가·보안까지 2024–2026 연구 흐름을 연결합니다.