Download test_model.py from sage002/angstrom: direct link, hf CLI and curl.
- Browser
- Download file 5.48 kB
-
https://huggingface.co/sage002/angstrom/resolve/main/test_model.py
- Command line
-
hf download hf://sage002/angstrom/test_model.py
-
curl -L -o test_model.py https://huggingface.co/sage002/angstrom/resolve/main/test_model.py
5.48 kB
| """ | |
| Test Complete AngstromNano Model | |
| """ | |
| import sys | |
| sys.path.insert(0, '.') | |
| import torch | |
| from angstrom_nano import AngstromNanoConfig, AngstromNanoForCausalLM | |
| def test_model_initialization(): | |
| print("\n[Testing Model Initialization]") | |
| config = AngstromNanoConfig() | |
| model = AngstromNanoForCausalLM(config) | |
| total_params = sum(p.numel() for p in model.parameters()) | |
| trainable_params = sum(p.numel() for p in model.parameters() if p.requires_grad) | |
| print(f" Total parameters: {total_params:,} ({total_params/1e9:.2f}B)") | |
| print(f" Trainable parameters: {trainable_params:,}") | |
| print(f" Config estimate: {config.estimate_parameters()['total_billions']:.2f}B") | |
| print(" [PASS]") | |
| return model | |
| def test_forward_pass(): | |
| print("\n[Testing Forward Pass]") | |
| config = AngstromNanoConfig() | |
| model = AngstromNanoForCausalLM(config) | |
| batch_size, seq_len = 2, 128 | |
| input_ids = torch.randint(0, config.vocab_size, (batch_size, seq_len)) | |
| labels = torch.randint(0, config.vocab_size, (batch_size, seq_len)) | |
| outputs = model(input_ids, labels=labels) | |
| print(f" Input shape: {input_ids.shape}") | |
| print(f" Logits shape: {outputs['logits'].shape}") | |
| print(f" Loss: {outputs['loss'].item():.4f}") | |
| print(f" Aux loss: {outputs['aux_loss'].item():.6f}") | |
| assert outputs['logits'].shape == (batch_size, seq_len, config.vocab_size) | |
| assert outputs['loss'] is not None | |
| print(" [PASS]") | |
| def test_generation(): | |
| print("\n[Testing Text Generation]") | |
| config = AngstromNanoConfig() | |
| model = AngstromNanoForCausalLM(config) | |
| # Simple prompt | |
| prompt = torch.tensor([[1, 100, 200, 300]]) # BOS + 3 tokens | |
| generated = model.generate( | |
| prompt, | |
| max_new_tokens=20, | |
| temperature=1.0, | |
| ) | |
| print(f" Prompt length: {prompt.shape[1]}") | |
| print(f" Generated length: {generated.shape[1]}") | |
| print(f" Generated tokens: {generated[0].tolist()[:10]}...") | |
| assert generated.shape[1] > prompt.shape[1] | |
| print(" [PASS]") | |
| def test_kv_cache(): | |
| print("\n[Testing KV Cache]") | |
| config = AngstromNanoConfig() | |
| model = AngstromNanoForCausalLM(config) | |
| batch_size, seq_len = 1, 16 | |
| input_ids = torch.randint(0, config.vocab_size, (batch_size, seq_len)) | |
| # First forward pass with cache | |
| outputs1 = model(input_ids, use_cache=True) | |
| past_kv = outputs1['past_key_values'] | |
| print(f" Cached layers: {len(past_kv)}") | |
| print(f" Cached K shape: {past_kv[0][0].shape}") | |
| print(f" Cached V shape: {past_kv[0][1].shape}") | |
| # Second forward pass using cache | |
| next_token = torch.randint(0, config.vocab_size, (batch_size, 1)) | |
| outputs2 = model(next_token, past_key_values=past_kv, use_cache=True) | |
| print(f" New cached K shape: {outputs2['past_key_values'][0][0].shape}") | |
| assert len(past_kv) == config.num_hidden_layers | |
| assert outputs2['past_key_values'][0][0].shape[2] == seq_len + 1 | |
| print(" [PASS]") | |
| def test_gradient_flow(): | |
| print("\n[Testing Gradient Flow]") | |
| config = AngstromNanoConfig() | |
| model = AngstromNanoForCausalLM(config) | |
| batch_size, seq_len = 2, 32 | |
| input_ids = torch.randint(0, config.vocab_size, (batch_size, seq_len)) | |
| labels = torch.randint(0, config.vocab_size, (batch_size, seq_len)) | |
| outputs = model(input_ids, labels=labels) | |
| loss = outputs['loss'] | |
| loss.backward() | |
| # Check gradients in different parts | |
| embed_grad = model.model.embed_tokens.weight.grad | |
| first_layer_grad = model.model.layers[0].self_attn.q_proj.weight.grad | |
| last_layer_grad = model.model.layers[-1].self_attn.q_proj.weight.grad | |
| lm_head_grad = model.lm_head.weight.grad | |
| print(f" Loss: {loss.item():.4f}") | |
| print(f" Embedding grad norm: {embed_grad.norm().item():.6f}") | |
| print(f" First layer grad norm: {first_layer_grad.norm().item():.6f}") | |
| print(f" Last layer grad norm: {last_layer_grad.norm().item():.6f}") | |
| print(f" LM head grad norm: {lm_head_grad.norm().item():.6f}") | |
| assert all(g is not None for g in [embed_grad, first_layer_grad, last_layer_grad, lm_head_grad]) | |
| print(" [PASS]") | |
| def test_memory_usage(): | |
| print("\n[Testing Memory Usage]") | |
| config = AngstromNanoConfig() | |
| model = AngstromNanoForCausalLM(config) | |
| # Calculate model size | |
| param_size = sum(p.numel() * p.element_size() for p in model.parameters()) | |
| buffer_size = sum(b.numel() * b.element_size() for b in model.buffers()) | |
| total_size = param_size + buffer_size | |
| print(f" Parameter memory: {param_size / 1e9:.2f} GB") | |
| print(f" Buffer memory: {buffer_size / 1e6:.2f} MB") | |
| print(f" Total model size: {total_size / 1e9:.2f} GB") | |
| # Expected: ~8GB for FP32, ~4GB for FP16 | |
| expected_fp32 = config.estimate_parameters()['estimated_size_fp32_gb'] | |
| print(f" Expected FP32 size: {expected_fp32:.2f} GB") | |
| assert abs(total_size / 1e9 - expected_fp32) < 1.0 # Within 1GB tolerance | |
| print(" [PASS]") | |
| def main(): | |
| print("=" * 80) | |
| print("Testing Complete AngstromNano Model") | |
| print("=" * 80) | |
| torch.manual_seed(42) | |
| test_model_initialization() | |
| test_forward_pass() | |
| test_generation() | |
| test_kv_cache() | |
| test_gradient_flow() | |
| test_memory_usage() | |
| print("\n" + "=" * 80) | |
| print("All model tests passed!") | |
| print("=" * 80) | |
| if __name__ == "__main__": | |
| main() | |