Spaces:
Running
Running
| import pytest | |
| import torch | |
| from mini_transformer.modules.lm_head import LMHead | |
| # ----------------------- | |
| # Constructor checks | |
| # ----------------------- | |
| def test_ctor_type_and_value_checks(): | |
| with pytest.raises(TypeError): | |
| LMHead("64", 10) | |
| with pytest.raises(TypeError): | |
| LMHead(64, "10") | |
| with pytest.raises(ValueError): | |
| LMHead(0, 10) | |
| with pytest.raises(ValueError): | |
| LMHead(64, 0) | |
| def test_ctor_happy_path(): | |
| lm = LMHead(32, 1000) | |
| assert lm.d_model == 32 | |
| assert lm.vocab_size == 1000 | |
| assert lm.fc.weight.shape == (1000, 32) | |
| # ----------------------- | |
| # Forward checks (3D only) | |
| # ----------------------- | |
| def test_forward_type_and_shape_errors(): | |
| lm = LMHead(16, 50) | |
| with pytest.raises(TypeError): | |
| lm("not a tensor") | |
| with pytest.raises(ValueError): | |
| lm(torch.randn(2, 3, 4, 5)) # rank 4 not supported | |
| with pytest.raises(ValueError): | |
| lm(torch.randn(5, 16)) # rank 2 not supported | |
| with pytest.raises(ValueError): | |
| lm(torch.randn(2, 8, 15)) # last dim != d_model | |
| def test_forward_happy_path_and_zero_len(): | |
| device = ( | |
| torch.device(f"cuda:{torch.cuda.current_device()}") | |
| if torch.cuda.is_available() | |
| else torch.device("cpu") | |
| ) | |
| lm = LMHead(24, 101).to(device) | |
| # Non-empty | |
| x = torch.randn(3, 7, 24, device=device, dtype=torch.float32) | |
| y = lm(x) | |
| assert y.shape == (3, 7, 101) | |
| assert y.device == device and y.dtype == torch.float32 | |
| # Zero-length sequence allowed | |
| x0 = torch.randn(2, 0, 24, device=device, dtype=torch.float32) | |
| y0 = lm(x0) | |
| assert y0.shape == (2, 0, 101) | |
| def test_gradients_flow(): | |
| lm = LMHead(8, 40) | |
| x = torch.randn(3, 6, 8, requires_grad=True) | |
| y = lm(x) | |
| loss = y.pow(2).mean() | |
| loss.backward() | |
| assert x.grad is not None | |
| assert torch.isfinite(x.grad).all() | |