Download sweep_500m.py from Akahsizrr/spec100m: direct link, hf CLI and curl.
- Browser
- Download file 5.22 kB
-
https://huggingface.co/Akahsizrr/spec100m/resolve/4414b8a6dd96328b6626039dc164cee9dbe3eb6b/sweep_500m.py
- Command line
-
hf download hf://Akahsizrr/spec100m@4414b8a6dd96328b6626039dc164cee9dbe3eb6b/sweep_500m.py
-
curl -L -o sweep_500m.py https://huggingface.co/Akahsizrr/spec100m/resolve/4414b8a6dd96328b6626039dc164cee9dbe3eb6b/sweep_500m.py
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") | |