spec100m / sweep_500m.py
Akahsizrr's picture
squash to reclaim LFS quota
a8f07a3
Raw History Blame
5.22 kB
"""Find the 500M base config that keeps ~1M tok/s at 20M context.
Physics:
- Weight reads: (base + medusa) * 2 bytes / bandwidth
- Attention: 4 * top_k * L * (K+1) * block_size * d_model FLOPs
- tok/s = (K+1) / step_time
500M base needs large d and/or many L, but attention scales with d*L.
Sweet spot: K where weight_read_time ≈ attention_time.
"""
import time
import torch
from config import Config
from model import build_model
print(f"GPU: {torch.cuda.get_device_name(0)}")
vram_free = torch.cuda.mem_get_info()[0] / 1e9
print(f"VRAM: {vram_free:.1f} GB free")
CTX = 20_000_000
TOP_K = 3
# Candidate 500M base configs
# Key constraint: KV cache at 20M must fit: 20M * n_kv * hd * 4 * L < 40 GB
# => n_kv * hd * L < 500
configs = [
# (name, d, L, H, kv, ffn_mult, K, block_size, top_k)
# Current baseline (for comparison)
("baseline_228M", 384, 1, 12, 4, 2.667, 4096, 4097, 3),
# 500M base configs — varying d, L, K
# d=1024, L=8, kv=2: KV=20.5GB, base~481M
("500M_d1024_L8_K4096", 1024, 8, 16, 2, 16.0, 4096, 4097, 3),
("500M_d1024_L8_K2048", 1024, 8, 16, 2, 16.0, 2048, 2049, 3),
("500M_d1024_L8_K1024", 1024, 8, 16, 2, 16.0, 1024, 1025, 3),
("500M_d1024_L8_K512", 1024, 8, 16, 2, 16.0, 512, 513, 3),
# d=1024, L=8, kv=2, top_k=1 (faster attention, less context)
("500M_d1024_L8_K4096_t1", 1024, 8, 16, 2, 16.0, 4096, 4097, 1),
("500M_d1024_L8_K2048_t1", 1024, 8, 16, 2, 16.0, 2048, 2049, 1),
("500M_d1024_L8_K1024_t1", 1024, 8, 16, 2, 16.0, 1024, 1025, 1),
# d=768, L=12, kv=2: KV=18.4GB, base~277M (smaller base, more layers)
("277M_d768_L12_K4096", 768, 12, 12, 2, 10.0, 4096, 4097, 3),
("277M_d768_L12_K2048", 768, 12, 12, 2, 10.0, 2048, 2049, 3),
("277M_d768_L12_K1024", 768, 12, 12, 2, 10.0, 1024, 1025, 3),
# d=1536, L=4, kv=2: KV=15.7GB, base~498M (larger d, fewer layers)
("500M_d1536_L4_K4096", 1536, 4, 24, 2, 4.0, 4096, 4097, 3),
("500M_d1536_L4_K2048", 1536, 4, 24, 2, 4.0, 2048, 2049, 3),
("500M_d1536_L4_K1024", 1536, 4, 24, 2, 4.0, 1024, 1025, 3),
("500M_d1536_L4_K4096_t1", 1536, 4, 24, 2, 4.0, 4096, 4097, 1),
]
print(f"\n{'name':>28} {'d':>5} {'L':>3} {'K':>5} {'tk':>3} "
f"{'base(M)':>8} {'total(M)':>9} {'KV(GB)':>7} "
f"{'step(ms)':>9} {'tok/s':>10} {'us/tok':>8}")
print("-" * 95)
for name, d, L, H, kv, ffn, K, BS, tk in configs:
cfg = Config(
d_model=d, n_layers=L, n_heads=H, n_kv_heads=kv,
ffn_mult=ffn, medusa_heads=K, medusa_rank=1, medusa_hidden=0,
window_size=0, max_seq_len=CTX + K + 100, use_alibi=False,
moba_block_size=BS, moba_top_k=tk, dtype="bfloat16",
)
dt = getattr(torch, cfg.dtype)
dev = "cuda"
params = cfg.count_params()
base_m = params["base_total"] / 1e6
total_m = params["grand_total"] / 1e6
kv_gb = CTX * kv * (d // H) * 4 * L / 1e9
if kv_gb + total_m * 2 / 1e9 > vram_free * 0.9:
print(f"{name:>28} {d:5d} {L:3d} {K:5d} {tk:3d} "
f"{base_m:8.1f} {total_m:9.1f} {kv_gb:7.2f} --- VRAM too high ---")
continue
n_blocks = (CTX // BS) + 2
try:
m = build_model(cfg, dev)
m.precompute_medusa_tokens()
cache_k = [torch.zeros(1, n_blocks, BS, kv, d // H,
device=dev, dtype=dt) for _ in range(L)]
cache_v = [torch.zeros(1, n_blocks, BS, kv, d // H,
device=dev, dtype=dt) for _ in range(L)]
k_bar = [torch.zeros(1, n_blocks, kv, d // H,
device=dev, dtype=dt) for _ in range(L)]
# Fill cache
nf = CTX // BS
for lk, lv, lb in zip(cache_k, cache_v, k_bar):
lk[:, :nf].normal_(0, 0.1)
lv[:, :nf].normal_(0, 0.1)
lb[:, :nf] = lk[:, :nf].mean(dim=2)
input_ids = torch.randint(0, cfg.vocab_size, (1, K + 1), device=dev)
# Warmup
for _ in range(2):
with torch.no_grad():
h = m.forward_moba(input_ids, cache_k, cache_v, k_bar, nf, 0)
_ = m.medusa_argmax_fast(h[:, -1])
torch.cuda.synchronize()
# Measure
times = []
for _ in range(5):
torch.cuda.synchronize()
t0 = time.perf_counter()
with torch.no_grad():
h = m.forward_moba(input_ids, cache_k, cache_v, k_bar, nf, 0)
_ = m.medusa_argmax_fast(h[:, -1])
torch.cuda.synchronize()
times.append(time.perf_counter() - t0)
times.sort()
med = times[len(times) // 2]
ms = med * 1000
tps = (K + 1) / med
us = ms / (K + 1) * 1000
print(f"{name:>28} {d:5d} {L:3d} {K:5d} {tk:3d} "
f"{base_m:8.1f} {total_m:9.1f} {kv_gb:7.2f} "
f"{ms:9.1f} {tps:10,.0f} {us:8.2f}")
except Exception as e:
print(f"{name:>28} {d:5d} {L:3d} {K:5d} {tk:3d} "
f"{base_m:8.1f} {total_m:9.1f} {kv_gb:7.2f} --- ERROR: {e} ---")
torch.cuda.empty_cache()
try:
del m, cache_k, cache_v, k_bar
except:
pass
torch.cuda.empty_cache()
print(f"\n peak VRAM: {torch.cuda.max_memory_allocated()/1e9:.2f} GB")