angstrom / test_model.py
sage002's picture
Upload folder using huggingface_hub
2d1ceea verified
Raw
History Blame Contribute Delete
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()