Module neuralops.tests.test_zeros_attention_comprehensive

Functions

def make_config(hidden_size=64, num_heads=4, is_decoder=False, model_type='bert')
Expand source code
def make_config(hidden_size=64, num_heads=4, is_decoder=False, model_type="bert"):
    return types.SimpleNamespace(
        hidden_size=hidden_size,
        num_attention_heads=num_heads,
        num_key_value_heads=num_heads,
        head_dim=hidden_size // num_heads,
        is_decoder=is_decoder,
        model_type=model_type,
        dropout=0.0,
        lora_rank=16,
    )
def test_bidirectional_shape_and_centering()
Expand source code
def test_bidirectional_shape_and_centering():
    cfg = make_config(hidden_size=64, num_heads=4, is_decoder=False, model_type="bert")
    attn = ZeroSAttention(cfg, pretrained_attn=DummyAttn(64))
    attn.eval()

    B, L, D = 2, 8, 64
    x = torch.randn(B, L, D)
    mask = torch.ones(B, L)
    mask[:, -2:] = 0  # Mask out last two tokens

    out, _ = attn(x, attention_mask=mask)
    assert out.shape == (B, L, D), f"Expected {(B, L, D)}, got {out.shape}"
    assert not torch.isnan(out).any(), "Bidirectional output contains NaNs"
def test_causal_shape_and_causality()
Expand source code
def test_causal_shape_and_causality():
    cfg = make_config(hidden_size=64, num_heads=4, is_decoder=True, model_type="gpt2")
    attn = ZeroSAttention(cfg, pretrained_attn=DummyAttn(64))
    attn.eval()

    B, L, D = 2, 8, 64
    x = torch.randn(B, L, D)

    # 1. Shape check
    out, _ = attn(x)
    assert out.shape == (B, L, D), f"Expected shape {(B, L, D)}, got {out.shape}"
    assert not torch.isnan(out).any(), "Output contains NaNs"

    # 2. Strict Causality check:
    # Modifying future tokens (e.g. at index > l) must not affect output at position l
    l_probe = 3
    x_mod = x.clone()
    # Change all tokens strictly after l_probe
    x_mod[:, l_probe + 1 :, :] = torch.randn_like(x_mod[:, l_probe + 1 :, :]) * 5.0 + 10.0

    out_orig, _ = attn(x)
    out_mod, _ = attn(x_mod)

    # Positions 0 to l_probe must be identical within numerical precision
    diff = torch.max(torch.abs(out_orig[:, : l_probe + 1, :] - out_mod[:, : l_probe + 1, :]))
    assert diff.item() < 1e-5, f"Causality violated! Max diff at probe pos: {diff.item()}"
def test_four_architectures_forward()
Expand source code
def test_four_architectures_forward():
    try:
        from test_four_architectures import get_all_four_models
        models = get_all_four_models(d=64, h=4)
    except ImportError:
        pytest.skip("test_four_architectures fixture not available in environment")
        return
    x = torch.randn(2, 8, 64)

    for arch_name, model in models.items():
        # Inject ZeroSAttention into the model self-attention
        old_attn = (
            getattr(model, "attention", None)
            or getattr(model, "attn", None)
            or getattr(model, "self_attn", None)
        )
        assert old_attn is not None, f"Could not find attention module in {arch_name}"

        injected = inject_zeros_attention(
            layer=model,
            model_config=model.config,
            old_attn=old_attn,
        )
        assert injected is not None, f"Injection failed for {arch_name}"

        # Forward check
        out = model(x)
        assert out.shape == (2, 8, 2), f"{arch_name} output shape mismatch: {out.shape}"
        assert not torch.isnan(out).any(), f"{arch_name} output contains NaNs"
        assert not torch.isinf(out).any(), f"{arch_name} output contains Infs"

        # Backward check
        loss = out.sum()
        loss.backward()
        grad_params = sum(1 for p in model.parameters() if p.grad is not None)
        assert grad_params > 0, f"{arch_name} computed zero gradients"
def test_head_mask_broadcasting()
Expand source code
def test_head_mask_broadcasting():
    cfg = make_config(hidden_size=64, num_heads=4, is_decoder=False)
    attn = ZeroSAttention(cfg, pretrained_attn=DummyAttn(64))
    attn.eval()

    B, L, D, H = 2, 8, 64, 4
    x = torch.randn(B, L, D)

    # 1D mask [H]
    m1 = torch.ones(H)
    out1, _ = attn(x, head_mask=m1)
    assert out1.shape == (B, L, D)

    # 2D mask [B, H]
    m2 = torch.ones(B, H)
    out2, _ = attn(x, head_mask=m2)
    assert out2.shape == (B, L, D)

    # 3D mask [B, H, L]
    m3 = torch.ones(B, H, L)
    out3, _ = attn(x, head_mask=m3)
    assert out3.shape == (B, L, D)

    # 4D mask [B, H, L, L]
    m4 = torch.ones(B, H, L, L)
    out4, _ = attn(x, head_mask=m4)
    assert out4.shape == (B, L, D)
def test_inject_with_none_old_attn_returns_none()
Expand source code
def test_inject_with_none_old_attn_returns_none():
    layer = nn.Module()
    layer.attention = DummyAttn(64)
    res = inject_zeros_attention(layer=layer, old_attn=None)
    assert res is None, "inject_zeros_attention must return None when old_attn is None"
def test_lora_adapter_preservation()
Expand source code
def test_lora_adapter_preservation():
    # Construct source module with LoRA adapters
    src = DummyAttn(64)
    # Wrap q_proj with mock LoRA
    src.q_proj.lora_A = nn.Parameter(torch.randn(16, 64) * 0.5)
    src.q_proj.lora_B = nn.Parameter(torch.randn(64, 16) * 0.5)

    cfg = make_config(hidden_size=64, num_heads=4)
    zeros = ZeroSAttention(cfg, pretrained_attn=src)

    # Check that lora weights were copied and remain trainable
    assert zeros.W_q.lora_A is not None
    assert zeros.W_q.lora_B is not None
    assert torch.allclose(zeros.W_q.lora_A, src.q_proj.lora_A)
    assert torch.allclose(zeros.W_q.lora_B, src.q_proj.lora_B)
    assert zeros.W_q.lora_A.requires_grad is True
    assert zeros.W_q.lora_B.requires_grad is True
    assert zeros.W_q.weight.requires_grad is False
def test_rope_and_even_odd_dim_safety()
Expand source code
def test_rope_and_even_odd_dim_safety():
    # Test _rotate_half on both even and odd dimensions
    for d in [16, 17, 63, 64]:
        t = torch.randn(2, 4, 8, d)
        rotated = _rotate_half(t)
        assert rotated.shape == t.shape, f"Odd dim {d} failed shape preservation in _rotate_half"

    # Test apply_rotary_pos_emb with odd dimension
    head_dim_odd = 15
    q = torch.randn(2, 8, 4, head_dim_odd)
    k = torch.randn(2, 8, 4, head_dim_odd)
    cos = torch.randn(8, head_dim_odd)
    sin = torch.randn(8, head_dim_odd)

    q_rot, k_rot = apply_rotary_pos_emb(q, k, cos, sin)
    assert q_rot.shape == q.shape
    assert k_rot.shape == k.shape
    assert not torch.isnan(q_rot).any()

Classes

class DummyAttn (d=64)
Expand source code
class DummyAttn(nn.Module):
    def __init__(self, d=64):
        super().__init__()
        self.q_proj = nn.Linear(d, d)
        self.k_proj = nn.Linear(d, d)
        self.v_proj = nn.Linear(d, d)
        self.o_proj = nn.Linear(d, d)
        self.hidden_size = d
        self.num_heads = 4

Base class for all neural network modules.

Your models should also subclass this class.

Modules can also contain other Modules, allowing them to be nested in a tree structure. You can assign the submodules as regular attributes::

import torch.nn as nn
import torch.nn.functional as F


class Model(nn.Module):
    def __init__(self) -> None:
        super().__init__()
        self.conv1 = nn.Conv2d(1, 20, 5)
        self.conv2 = nn.Conv2d(20, 20, 5)

    def forward(self, x):
        x = F.relu(self.conv1(x))
        return F.relu(self.conv2(x))

Submodules assigned in this way will be registered, and will also have their parameters converted when you call :meth:to, etc.

Note

As per the example above, an __init__() call to the parent class must be made before assignment on the child.

:ivar training: Boolean represents whether this module is in training or evaluation mode. :vartype training: bool

Initialize internal Module state, shared by both nn.Module and ScriptModule.

Ancestors

  • torch.nn.modules.module.Module