Navigation
⚡ Inference Systems· 8 min read

Embedding Models

Bulk embedding for search/RAG indexes, throughput optimization, variable-length packing, and serving billions of embeddings.

embeddingsearchragthroughputpackingvectorbatch

Embedding models convert text (or images) into dense vectors for search, retrieval, RAG, and clustering. Unlike generative models, embedding inference is a single forward pass per input — the challenge is pure throughput at massive scale.


1. Embedding vs Generation

DimensionGeneration (LLM)Embedding
OutputVariable-length text (autoregressive)Fixed-size vector (one forward pass)
Steps per inputHundreds (decode steps)1 (single forward)
KV cacheYes (grows with context)No
BottleneckMemory bandwidth (decode)Compute (encode)
Batch efficiencyLimited by KV cache memoryUnlimited (no per-request state)

Embedding is the simplest inference workload — high batch sizes, no KV cache, no autoregressive loop. But the scale can be enormous: indexing billions of documents requires billions of forward passes.


2. Throughput Optimization

Large Batch Sizes

Without KV cache, all GPU memory is available for batch data:

# Embedding with large batch
from sentence_transformers import SentenceTransformer

model = SentenceTransformer("BAAI/bge-large-en-v1.5", device="cuda")
embeddings = model.encode(
    texts,
    batch_size=512,        # much larger than LLM serving
    show_progress_bar=True,
    normalize_embeddings=True,
)
ModelBatch sizeThroughput (H100)
BGE-large (335M)51215,000+ texts/sec
E5-mistral (7B)32500+ texts/sec
CLIP ViT-L (400M)2568,000+ images/sec

Variable-Length Packing

Texts have different lengths. Naive padding wastes compute:

Without packing:
  "Hello" (2 tokens)     → [Hello, PAD, PAD, ..., PAD]  (512 tokens, 99% waste)
  "Long document..." (500 tokens) → [Long, document, ..., end] (512 tokens, 2% waste)

With packing:
  Pack multiple short texts into one sequence:
  [Hello | SEP | How are you | SEP | Hi there | SEP | PAD]
  → 3 texts in 1 sequence, much less waste

Sorted batching: Sort texts by length, batch similar lengths together — reduces padding waste from ~60% to ~10%.


3. Serving Architecture for RAG

Document ingestion:
  Documents → Chunker (512 tokens each) → Embedding model → Vector DB (Pinecone, Weaviate, etc.)

Query time:
  User query → Embedding model → query vector → Vector DB search → top-K chunks → LLM

Serving pattern:
  - Ingestion: OFFLINE, batch millions of documents (throughput-critical)
  - Query: ONLINE, single query at a time (latency-critical, <10ms)

Dual Optimization

PhasePriorityBatch sizeOptimization
IngestionThroughput256-1024FP16, torch.compile, multi-GPU data parallel
QueryLatency1-8CUDA graphs, pre-warmed model, cached computation

4. Scaling to Billions

For indexing billions of documents:

ApproachThroughputCost
Single H10015K texts/sec1×
8× H100 (data parallel)120K texts/sec8×
Spot instances (elastic)Variable0.3× per GPU
CPU inference (quantized)1K texts/sec per node0.05× per unit

At 15K texts/sec: 1 billion documents takes ~18.5 hours on a single H100. With 8 GPUs: ~2.3 hours.


Self-Check

  • Compare embedding inference to LLM generation (no KV cache, no autoregression)
  • Calculate throughput for a given model and batch size
  • Implement sorted batching to reduce padding waste
  • Design a dual-optimization serving architecture for RAG (ingestion + query)
  • Estimate time to embed 1B documents on a given hardware setup

References