| import numpy as np |
|
|
| from mla.backend import xp |
| from mla.tensor import Tensor |
| from mla.gradcheck import gradcheck |
| from mla.model import (Config, TiedEmbedding, RoPE, RMSNorm, repeat_kv, |
| Attention, SwiGLU, Block, Model) |
|
|
|
|
| def _tiny_cfg(): |
| return Config(vocab_size=7, d_model=4, n_layers=1, n_heads=2, |
| n_kv_heads=1, head_dim=2, swiglu_hidden=8, seq_len=3) |
|
|
|
|
| def test_embed_shape(): |
| xp.random.seed(0) |
| emb = TiedEmbedding(_tiny_cfg()) |
| ids = xp.asarray([[1, 3, 3], [0, 2, 5]]) |
| out = emb.embed(ids) |
| assert out.shape == (2, 3, 4) |
|
|
|
|
| def test_project_shape(): |
| xp.random.seed(0) |
| emb = TiedEmbedding(_tiny_cfg()) |
| h = Tensor(xp.random.randn(2, 3, 4)) |
| logits = emb.project(h) |
| assert logits.shape == (2, 3, 7) |
|
|
|
|
| def test_tied_weight_gradcheck(): |
| xp.random.seed(0) |
| ids = xp.asarray([[1, 3, 3], [0, 2, 5]]) |
|
|
| def f(w): |
| emb = w.gather(ids) |
| return emb.matmul(w.transpose()) |
|
|
| w = Tensor(xp.random.randn(7, 4)) |
| ok, rel = gradcheck(f, w) |
| assert ok, f"tied-embedding gradcheck failed, max_rel={rel}" |
|
|
|
|
| def test_tied_row_asymmetry(): |
| xp.random.seed(0) |
| ids = xp.asarray([[2]]) |
|
|
| def f(w): |
| emb = w.gather(ids) |
| return emb.matmul(w.transpose()) |
|
|
| w = Tensor(xp.random.randn(3, 2)) |
| f(w).backward() |
| g = np.asarray(w.grad) |
| assert np.abs(g[2]).sum() > np.abs(g[0]).sum() |
|
|
|
|
| def _rope_cfg(): |
| return Config(vocab_size=7, d_model=8, n_layers=1, n_heads=2, |
| n_kv_heads=1, head_dim=4, swiglu_hidden=8, seq_len=8) |
|
|
|
|
| def test_rope_shape(): |
| rope = RoPE(_rope_cfg()) |
| x = Tensor(xp.random.randn(2, 2, 3, 4)) |
| out = rope(x) |
| assert out.shape == (2, 2, 3, 4) |
|
|
|
|
| def test_rope_pos0_identity(): |
| rope = RoPE(_rope_cfg()) |
| x = Tensor(xp.random.randn(1, 1, 1, 4)) |
| out = rope(x, offset=0) |
| assert np.allclose(np.asarray(out.data), np.asarray(x.data)) |
|
|
|
|
| def test_rope_gradcheck(): |
| xp.random.seed(0) |
| rope = RoPE(_rope_cfg()) |
|
|
| def f(x): |
| return rope(x, offset=2) |
|
|
| x = Tensor(xp.random.randn(1, 2, 3, 4)) |
| ok, rel = gradcheck(f, x) |
| assert ok, f"rope gradcheck failed, max_rel={rel}" |
|
|
|
|
| def test_rope_relative_position(): |
| xp.random.seed(0) |
| rope = RoPE(_rope_cfg()) |
| q = xp.random.randn(1, 1, 1, 4) |
| k = xp.random.randn(1, 1, 1, 4) |
|
|
| def score(m, n): |
| qm = rope(Tensor(q), offset=m) |
| kn = rope(Tensor(k), offset=n) |
| return float((qm.data * kn.data).sum()) |
|
|
| assert abs(score(1, 4) - score(3, 6)) < 1e-9 |
| assert abs(score(1, 4) - score(1, 5)) > 1e-6 |
|
|
|
|
| def test_rmsnorm_shape(): |
| norm = RMSNorm(8) |
| x = Tensor(xp.random.randn(2, 3, 8)) |
| assert norm(x).shape == (2, 3, 8) |
|
|
|
|
| def test_rmsnorm_unit_rms(): |
| norm = RMSNorm(8, eps=1e-12) |
| x = Tensor(xp.random.randn(4, 8)) |
| y = np.asarray(norm(x).data) |
| rms = np.sqrt((y ** 2).mean(axis=-1)) |
| assert np.allclose(rms, 1.0, atol=1e-5) |
|
|
|
|
| def test_rmsnorm_gradcheck_x(): |
| xp.random.seed(0) |
| norm = RMSNorm(8) |
|
|
| def f(x): |
| return norm(x) |
|
|
| x = Tensor(xp.random.randn(2, 3, 8)) |
| ok, rel = gradcheck(f, x) |
| assert ok, f"rmsnorm dx gradcheck failed, max_rel={rel}" |
|
|
|
|
| def test_rmsnorm_gradcheck_gamma(): |
| xp.random.seed(0) |
| norm = RMSNorm(8) |
| x = Tensor(xp.random.randn(2, 3, 8)) |
|
|
| def f(w): |
| norm.weight = w |
| return norm(x) |
|
|
| g = Tensor(xp.random.randn(8)) |
| ok, rel = gradcheck(f, g) |
| assert ok, f"rmsnorm dgamma gradcheck failed, max_rel={rel}" |
|
|
|
|
| def _attn_cfg(): |
| return Config(vocab_size=7, d_model=8, n_layers=1, n_heads=2, |
| n_kv_heads=1, head_dim=4, swiglu_hidden=8, seq_len=8) |
|
|
|
|
| def test_repeat_kv(): |
| x = Tensor(xp.arange(2 * 1 * 2 * 3).reshape(2, 1, 2, 3).astype(float)) |
| y = repeat_kv(x, 3) |
| assert y.shape == (2, 3, 2, 3) |
| yd = np.asarray(y.data) |
| assert np.allclose(yd[:, 0], yd[:, 1]) |
| assert np.allclose(yd[:, 1], yd[:, 2]) |
|
|
|
|
| def test_repeat_kv_gradcheck(): |
| xp.random.seed(0) |
|
|
| def f(x): |
| return repeat_kv(x, 3) |
|
|
| x = Tensor(xp.random.randn(2, 1, 2, 3)) |
| ok, rel = gradcheck(f, x) |
| assert ok, f"repeat_kv gradcheck failed, max_rel={rel}" |
|
|
|
|
| def test_attention_shape(): |
| xp.random.seed(0) |
| cfg = _attn_cfg() |
| attn = Attention(cfg) |
| x = Tensor(xp.random.randn(2, 4, cfg.d_model)) |
| assert attn(x).shape == (2, 4, cfg.d_model) |
|
|
|
|
| def test_attention_causal(): |
| xp.random.seed(0) |
| cfg = _attn_cfg() |
| attn = Attention(cfg) |
| x = xp.random.randn(1, 4, cfg.d_model) |
| o1 = np.asarray(attn(Tensor(x)).data) |
| x2 = x.copy() |
| x2[0, 3] += 5.0 |
| o2 = np.asarray(attn(Tensor(x2)).data) |
| assert np.allclose(o1[0, :3], o2[0, :3]) |
| assert not np.allclose(o1[0, 3], o2[0, 3]) |
|
|
|
|
| def test_attention_gradcheck_x(): |
| xp.random.seed(0) |
| cfg = _attn_cfg() |
| attn = Attention(cfg) |
|
|
| def f(x): |
| return attn(x) |
|
|
| x = Tensor(xp.random.randn(1, 3, cfg.d_model)) |
| ok, rel = gradcheck(f, x) |
| assert ok, f"attention dx gradcheck failed, max_rel={rel}" |
|
|
|
|
| def test_attention_gradcheck_wq(): |
| xp.random.seed(0) |
| cfg = _attn_cfg() |
| attn = Attention(cfg) |
| x = Tensor(xp.random.randn(1, 3, cfg.d_model)) |
|
|
| def f(w): |
| attn.wq = w |
| return attn(x) |
|
|
| w = Tensor(xp.random.randn(cfg.d_model, cfg.n_heads * cfg.head_dim)) |
| ok, rel = gradcheck(f, w) |
| assert ok, f"attention dwq gradcheck failed, max_rel={rel}" |
|
|
|
|
| def test_swiglu_shape(): |
| xp.random.seed(0) |
| cfg = _attn_cfg() |
| mlp = SwiGLU(cfg) |
| x = Tensor(xp.random.randn(2, 3, cfg.d_model)) |
| assert mlp(x).shape == (2, 3, cfg.d_model) |
|
|
|
|
| def test_swiglu_gradcheck(): |
| xp.random.seed(0) |
| cfg = _attn_cfg() |
| mlp = SwiGLU(cfg) |
|
|
| def f(x): |
| return mlp(x) |
|
|
| x = Tensor(xp.random.randn(2, 3, cfg.d_model)) |
| ok, rel = gradcheck(f, x) |
| assert ok, f"swiglu gradcheck failed, max_rel={rel}" |
|
|
|
|
| def test_block_gradcheck(): |
| xp.random.seed(0) |
| cfg = _attn_cfg() |
| block = Block(cfg) |
|
|
| def f(x): |
| return block(x) |
|
|
| x = Tensor(xp.random.randn(1, 3, cfg.d_model)) |
| ok, rel = gradcheck(f, x) |
| assert ok, f"block gradcheck failed, max_rel={rel}" |
|
|
|
|
| def _tiny_model_cfg(): |
| return Config(vocab_size=7, d_model=8, n_layers=2, n_heads=2, |
| n_kv_heads=1, head_dim=4, swiglu_hidden=8, seq_len=8) |
|
|
|
|
| def test_model_forward_shape(): |
| xp.random.seed(0) |
| cfg = _tiny_model_cfg() |
| m = Model(cfg) |
| ids = xp.asarray([[1, 3, 5, 0], [2, 2, 4, 6]]) |
| out = m(ids) |
| assert out.shape == (2, 4, cfg.vocab_size) |
|
|
|
|
| def test_model_gradcheck(): |
| xp.random.seed(0) |
| cfg = _tiny_model_cfg() |
| m = Model(cfg) |
| ids = xp.asarray([[1, 3, 5], [2, 4, 6]]) |
|
|
| def f(w): |
| m.embed.weight = w |
| return m(ids) |
|
|
| w = Tensor(xp.random.randn(cfg.vocab_size, cfg.d_model) * 0.1) |
| ok, rel = gradcheck(f, w) |
| assert ok, f"full-model gradcheck failed, max_rel={rel}" |
|
|
|
|
| def test_param_count(): |
| m = Model(Config()) |
| assert m.n_params() == 3_869_184 |
|
|