Module neuralops.tests.test_qwen3_5_compressor_awareness
Comprehensive test suite verifying architecture-aware compression, dynamic rank selection, recovery parameter selection, and LoRA preservation on Qwen3.5 and across model families.
Functions
def test_compressors_skip_qwen3_5_sensitive_layers()-
Expand source code
def test_compressors_skip_qwen3_5_sensitive_layers(): """Verify that actual compressor instances skip sensitive layers on Qwen3.5.""" model = DummyQwen35Model(hidden_size=128, ffn_dim=256, num_layers=1) # 1. DirectSVD Compressor comp = DirectSVDCompressor(model, rank=32) comp.compress() assert isinstance(model.layers[0].delta_net.in_proj_qkv, nn.Linear) # Uncompressed assert isinstance(model.layers[0].attn.q_proj, nn.Linear) # Uncompressed assert isinstance(model.layers[0].expert_router, nn.Linear) # Uncompressed # FFN layers compressed into factorized layers assert not isinstance(model.layers[0].mlp.down_proj, nn.Linear) or hasattr(model.layers[0].mlp.down_proj, "U")Verify that actual compressor instances skip sensitive layers on Qwen3.5.
def test_dynamic_rank_selection()-
Expand source code
def test_dynamic_rank_selection(): """Verify dynamic rank computes min(256, max(128, min(in_f, out_f) // 4)) for Qwen3.5.""" # Qwen3.5 FFN layer: in_f=1024, out_f=3584 -> min=1024 -> 1024 // 4 = 256 rank_qwen = get_dynamic_compression_rank(1024, 3584, model_or_family="qwen3_5", default_rank=16) assert rank_qwen == 256 # Qwen3.5 smaller layer: in_f=400, out_f=400 -> min=400 -> 400 // 4 = 100 -> clamped to 128 rank_qwen_small = get_dynamic_compression_rank(400, 400, model_or_family="qwen3_5", default_rank=16) assert rank_qwen_small == 128 # Standard model (RoBERTa / BERT): retains default rank rank_bert = get_dynamic_compression_rank(768, 3072, model_or_family="bert", default_rank=32) assert rank_bert == 32 # Config override rank_override = get_dynamic_compression_rank(1024, 3584, model_or_family="qwen3_5", comp_config={"qwen3_5_rank": 64}) assert rank_override == 64Verify dynamic rank computes min(256, max(128, min(in_f, out_f) // 4)) for Qwen3.5.
def test_get_recovery_params()-
Expand source code
def test_get_recovery_params(): """Verify get_recovery_params unfreezes only LoRA adapters and classification heads, freezing all else.""" model = DummyQwen35Model(hidden_size=64, ffn_dim=128, num_layers=1) # Inject LoRA into model model, _ = apply_lora(model, r=8, alpha=16.0, target_modules={"down_proj"}) # Add dummy compressor factor parameters (.U, .V) model.layers[0].mlp.up_proj.U = nn.Parameter(torch.randn(128, 16)) model.layers[0].mlp.up_proj.V = nn.Parameter(torch.randn(16, 64)) trainable = get_recovery_params(model) trainable_names = [name for name, p in model.named_parameters() if p.requires_grad] # Only LoRA parameters and classification head ('score') must be trainable assert any("lora_" in n for n in trainable_names) assert any("score" in n for n in trainable_names) assert not any(n.endswith(".U") for n in trainable_names) assert not any(n.endswith(".V") for n in trainable_names) assert not any("mlp.up_proj.weight" in n for n in trainable_names)Verify get_recovery_params unfreezes only LoRA adapters and classification heads, freezing all else.
def test_lora_preservation_and_gradient_flow()-
Expand source code
def test_lora_preservation_and_gradient_flow(): """Verify that LoRA adapters on frozen backbones receive non-zero gradients after compressor injection.""" model = DummyQwen35Model(hidden_size=64, ffn_dim=128, num_layers=1) model, num_lora = apply_lora(model, r=8, alpha=16.0, target_modules={"down_proj"}) assert num_lora > 0 # Ensure LoRA adapters are not merged and trainable get_recovery_params(model) x = torch.randn(2, 64) out = model(x) loss = out.sum() loss.backward() # LoRA parameters must have non-zero gradients on active adapter matrices lora_grads = [p.grad for name, p in model.named_parameters() if "lora_" in name and p.grad is not None] assert len(lora_grads) > 0 assert any(g.abs().sum() > 0 for g in lora_grads) assert all(torch.isfinite(g).all() for g in lora_grads)Verify that LoRA adapters on frozen backbones receive non-zero gradients after compressor injection.
def test_qwen3_5_architecture_aware_layer_filtering()-
Expand source code
def test_qwen3_5_architecture_aware_layer_filtering(): """Verify should_compress_linear correctly protects sensitive layers on Qwen3.5 while allowing FFN.""" model = DummyQwen35Model() assert detect_family(model) == "qwen3_5" # Protected sensitive layers (including gate_proj per Task 1) assert not should_compress_linear(model, "layers.0.delta_net.in_proj_qkv") assert not should_compress_linear(model, "layers.0.delta_net.out_proj") assert not should_compress_linear(model, "layers.0.attn.q_proj") assert not should_compress_linear(model, "layers.0.attn.k_proj") assert not should_compress_linear(model, "layers.0.attn.v_proj") assert not should_compress_linear(model, "layers.0.attn.o_proj") assert not should_compress_linear(model, "layers.0.expert_router") assert not should_compress_linear(model, "layers.0.mlp.gate_proj") assert not should_compress_linear(model, "score") # Compressible FFN dense layers assert should_compress_linear(model, "layers.0.mlp.up_proj") assert should_compress_linear(model, "layers.0.mlp.down_proj")Verify should_compress_linear correctly protects sensitive layers on Qwen3.5 while allowing FFN.
def test_qwen3_5_capabilities_and_compatibility()-
Expand source code
def test_qwen3_5_capabilities_and_compatibility(): """Verify capability flags for Qwen3.5 hybrid architecture in registry.""" adapter = ModelAdapter(DummyQwen35Model()) assert adapter.causal is True assert adapter.supports_gqa is True assert adapter.supports_delta_net is True assert adapter.supports_moe is True # Causal modules are compatible compat, _ = is_module_declared_compatible("adaptive_svd", "qwen3_5") assert compat is TrueVerify capability flags for Qwen3.5 hybrid architecture in registry.
def test_standard_family_layer_filtering_preserved()-
Expand source code
def test_standard_family_layer_filtering_preserved(): """Verify standard models (BERT, RoBERTa, GPT) preserve their original compression filtering.""" bert = DummyStandardTransformer("bert", hidden_size=64) gpt = DummyStandardTransformer("gpt2", hidden_size=64) # BERT: all safe linear layers compressible, head protected assert should_compress_linear(bert, "attn.q_proj") assert should_compress_linear(bert, "mlp.fc1") assert not should_compress_linear(bert, "classifier") # GPT: attention projections and FFN compressible, head protected assert should_compress_linear(gpt, "attn.q_proj") assert should_compress_linear(gpt, "mlp.fc1") assert not should_compress_linear(gpt, "classifier")Verify standard models (BERT, RoBERTa, GPT) preserve their original compression filtering.
Classes
class DummyQwen35Block (hidden_size: int = 1024, ffn_dim: int = 3584)-
Expand source code
class DummyQwen35Block(nn.Module): """Synthetic Qwen3.5 hybrid block containing DeltaNet, GQA, MoE/FFN, and Norms.""" def __init__(self, hidden_size: int = 1024, ffn_dim: int = 3584): super().__init__() # 1. Sensitive linear attention / DeltaNet layer self.delta_net = nn.Module() self.delta_net.in_proj_qkv = nn.Linear(hidden_size, hidden_size * 3) self.delta_net.out_proj = nn.Linear(hidden_size, hidden_size) # 2. Sensitive GQA attention layer self.attn = nn.Module() self.attn.q_proj = nn.Linear(hidden_size, hidden_size) self.attn.k_proj = nn.Linear(hidden_size, 256) self.attn.v_proj = nn.Linear(hidden_size, 256) self.attn.o_proj = nn.Linear(hidden_size, hidden_size) # 3. Sensitive MoE router self.expert_router = nn.Linear(hidden_size, 4) # 4. Ordinary Dense FFN (compressible) self.mlp = nn.Module() self.mlp.gate_proj = nn.Linear(hidden_size, ffn_dim) self.mlp.up_proj = nn.Linear(hidden_size, ffn_dim) self.mlp.down_proj = nn.Linear(ffn_dim, hidden_size)Synthetic Qwen3.5 hybrid block containing DeltaNet, GQA, MoE/FFN, and Norms.
Initialize internal Module state, shared by both nn.Module and ScriptModule.
Ancestors
- torch.nn.modules.module.Module
class DummyQwen35Model (hidden_size: int = 1024, ffn_dim: int = 3584, num_layers: int = 2)-
Expand source code
class DummyQwen35Model(nn.Module): """Full dummy Qwen3.5 architecture.""" def __init__(self, hidden_size: int = 1024, ffn_dim: int = 3584, num_layers: int = 2): super().__init__() self.config = SimpleNamespace( model_type="qwen3_5", hidden_size=hidden_size, num_attention_heads=8, num_key_value_heads=2, head_dim=256, num_hidden_layers=num_layers, intermediate_size=ffn_dim, ) self.layers = nn.ModuleList([DummyQwen35Block(hidden_size, ffn_dim) for _ in range(num_layers)]) self.score = nn.Linear(hidden_size, 2) # Classification head def forward(self, x: torch.Tensor) -> torch.Tensor: for layer in self.layers: # FFN forward h = layer.mlp.down_proj(torch.relu(layer.mlp.up_proj(x))) x = x + h return self.score(x)Full dummy Qwen3.5 architecture.
Initialize internal Module state, shared by both nn.Module and ScriptModule.
Ancestors
- torch.nn.modules.module.Module
Methods
def forward(self, x: torch.Tensor) ‑> torch.Tensor-
Expand source code
def forward(self, x: torch.Tensor) -> torch.Tensor: for layer in self.layers: # FFN forward h = layer.mlp.down_proj(torch.relu(layer.mlp.up_proj(x))) x = x + h return self.score(x)Define the computation performed at every call.
Should be overridden by all subclasses.
Note
Although the recipe for forward pass needs to be defined within this function, one should call the :class:
Moduleinstance afterwards instead of this since the former takes care of running the registered hooks while the latter silently ignores them.
class DummyStandardTransformer (family: str = 'bert', hidden_size: int = 64)-
Expand source code
class DummyStandardTransformer(nn.Module): """Standard BERT / RoBERTa / GPT model.""" def __init__(self, family: str = "bert", hidden_size: int = 64): super().__init__() self.config = SimpleNamespace( model_type=family, hidden_size=hidden_size, num_attention_heads=4, num_hidden_layers=1, intermediate_size=hidden_size * 4, ) self.attn = nn.Module() self.attn.q_proj = nn.Linear(hidden_size, hidden_size) self.attn.k_proj = nn.Linear(hidden_size, hidden_size) self.attn.v_proj = nn.Linear(hidden_size, hidden_size) self.attn.out_proj = nn.Linear(hidden_size, hidden_size) self.mlp = nn.Module() self.mlp.fc1 = nn.Linear(hidden_size, hidden_size * 4) self.mlp.fc2 = nn.Linear(hidden_size * 4, hidden_size) self.classifier = nn.Linear(hidden_size, 2)Standard BERT / RoBERTa / GPT model.
Initialize internal Module state, shared by both nn.Module and ScriptModule.
Ancestors
- torch.nn.modules.module.Module