| """ |
| Quick smoke test: 3 steps of training to verify everything works. |
| """ |
| import sys; sys.path.insert(0, '.') |
| import torch |
| from pathlib import Path |
| from angstrom_nano import AngstromNanoConfig, AngstromNanoForCausalLM |
| from angstrom_nano.tokenizer import AngstromNanoTokenizer |
|
|
| text = Path("data/corpus.txt").read_text(encoding="utf-8") |
| tok = AngstromNanoTokenizer.train_bpe(["data/corpus.txt"], vocab_size=4096) |
| ids = torch.tensor(tok.encode(text, add_bos=True, add_eos=True), dtype=torch.long) |
| print(f"Vocab: {len(tok)}, Tokens: {len(ids):,}") |
|
|
| cfg = AngstromNanoConfig( |
| vocab_size=len(tok), hidden_size=192, intermediate_size=512, |
| num_hidden_layers=6, num_attention_heads=6, num_key_value_heads=3, |
| head_dim=32, num_local_experts=4, num_experts_per_tok=2, |
| max_position_embeddings=256, sliding_window=64, |
| scoring_func="sigmoid", use_qk_norm=True, use_routing_bias=True, |
| tie_word_embeddings=True, |
| ) |
| model = AngstromNanoForCausalLM(cfg) |
| p = sum(p.numel() for p in model.parameters()) |
| print(f"Model: {p:,} params") |
|
|
| opt = torch.optim.AdamW(model.parameters(), lr=3e-3) |
| for step in range(1, 4): |
| i = torch.randint(0, len(ids) - 64 - 1, (1,)).item() |
| x = ids[i:i+64].unsqueeze(0) |
| y = ids[i+1:i+65].unsqueeze(0) |
| out = model(x, labels=y, output_router_logits=True) |
| out["loss"].backward() |
| opt.step() |
| opt.zero_grad() |
| loss = out["loss"].item() |
| aux = out["aux_loss"].item() |
| print(f"step {step}: loss={loss:.4f} aux={aux:.6f}") |
|
|
| print("SMOKE TEST PASSED") |
|
|