How does vocabulary size affect embedding table memory footprint at bfloat16 precision, and what are the tradeoffs of very small vs. very large vocabularies?
Same topic, related formats. Practice these next.
Same topic, related formats. Practice these next.
A model has d_model=4096 and you are considering three vocabulary sizes: 8k, 50k, and 200k tokens. Calculate the bfloat16 memory footprint of the combined embedding table + lm_head for each size. Then describe the practical tradeoffs (sequence length, softmax cost, multilingual coverage) of each vocabulary size choice.
Vocabulary memory is 2 × vocab × d_model × 2 bytes; at d_model=4096 that is 131 MB at 8k, 820 MB at 50k, 3.3 GB at 200k, trading sequence length against softmax and memory cost.
Picture each token getting its own labeled box in two warehouses, one where the model reads input and one where it writes output. More tokens means more boxes, so both warehouses get bigger and pricier to keep. But more boxes also let you pack a long word into a single box instead of spelling it out across five small ones. So a big warehouse stores text in fewer, fatter boxes, while a tiny warehouse forces long chains of little boxes for the same sentence. The choice is a balance: pay for warehouse space with a large vocabulary, or pay for longer chains of boxes with a small one.
Everything you need to truly understand this topic: intuition, mechanics, step by step explanation, code, formulas, and worked example. Click to expand.
Everything you need to truly understand this topic: intuition, mechanics, step by step explanation, code, formulas, and worked example.
Everything important, quickly.
4 min: bytes formula + 131 MB / 820 MB / 3.3 GB at d=4096 + small-vocab sequence tax + large-vocab softmax tax + weight tying + multilingual vs tiny-alphabet sweet spots.
def vocab_memory_gb(vocab_size: int, d_model: int,
weight_tied: bool = False,
bytes_per_param: int = 2) -> float:
"""Vocabulary-related memory in GB; bfloat16 is 2 bytes per value."""
n_matrices = 1 if weight_tied else 2 # embedding + lm_head unless tied
total_params = n_matrices * vocab_size * d_model
return total_params * bytes_per_param / (1024 ** 3)
d_model = 4096
for vocab_size in [8_000, 50_000, 200_000]:
untied = vocab_memory_gb(vocab_size, d_model)
tied = vocab_memory_gb(vocab_size, d_model, weight_tied=True)
print(f"{vocab_size:>7,}: {untied:5.2f} GB untied, {tied:5.2f} GB tied")
# 8,000: 0.12 GB untied, 0.06 GB tied
# 50,000: 0.76 GB untied, 0.38 GB tied
# 200,000: 3.05 GB untied, 1.53 GB tied| Concern | Small vocab (8k) | Large vocab (200k) |
|---|---|---|
| Interface memory at d=4096 | ~131 MB | ~3.3 GB |
| Sequence length / fertility | High (many tokens per word) | Low (compact tokens) |
| Attention cost | Worse (longer sequences, O(n squared)) | Better (shorter sequences) |
| Output softmax cost | Cheap per token | Expensive per token |
| Multilingual coverage | Poor outside English | Near-native across scripts |
| Best fit | Tiny-alphabet domains | Multilingual frontier models |
Real products, models, and research that use this idea.
What an interviewer would ask next. Try answering before peeking at the approach.
Red flags and common mistakes that signal junior thinking. Click to expand.
Counting only the embedding table and computing half the real memory, or using 4 bytes when modern LLMs serve at bfloat16's 2 bytes per value.
The night-before-the-interview bullets. Scan these on the way to the call.
Primary sources. Skim if you want the original framing.