mirror of
https://github.com/elder-plinius/OBLITERATUS.git
synced 2026-08-29 22:20:36 +02:00
Merge pull request #140 from elder-plinius/test/16-qwen25-projection-contract
test: lock Qwen2.5 projection contract
This commit is contained in:
@@ -8,7 +8,7 @@ from unittest.mock import MagicMock, Mock, patch
|
||||
|
||||
import pytest
|
||||
import torch
|
||||
from transformers import GPT2Config, GPT2LMHeadModel
|
||||
from transformers import GPT2Config, GPT2LMHeadModel, Qwen2Config, Qwen2ForCausalLM
|
||||
|
||||
from obliteratus.abliterate import (
|
||||
HARMFUL_PROMPTS,
|
||||
@@ -1900,6 +1900,73 @@ class TestDistillSVD:
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
class TestExcise:
|
||||
def test_qwen25_coder_advanced_excise_projects_all_dense_weights(self):
|
||||
"""Qwen2.5 must not silently resolve to zero projection targets."""
|
||||
config = Qwen2Config(
|
||||
vocab_size=128,
|
||||
hidden_size=32,
|
||||
intermediate_size=64,
|
||||
num_hidden_layers=2,
|
||||
num_attention_heads=4,
|
||||
num_key_value_heads=2,
|
||||
max_position_embeddings=64,
|
||||
)
|
||||
model = Qwen2ForCausalLM(config)
|
||||
handle = ModelHandle(
|
||||
model=model,
|
||||
tokenizer=MagicMock(),
|
||||
config=config,
|
||||
model_name="Qwen/Qwen2.5-Coder-7B-Instruct",
|
||||
task="causal_lm",
|
||||
)
|
||||
pipeline = AbliterationPipeline(
|
||||
model_name=handle.model_name,
|
||||
method="advanced",
|
||||
refinement_passes=1,
|
||||
norm_preserve=False,
|
||||
project_biases=False,
|
||||
layer_adaptive_strength=False,
|
||||
safety_neuron_masking=False,
|
||||
attention_head_surgery=False,
|
||||
use_sae_features=False,
|
||||
use_kl_optimization=False,
|
||||
projection_target="all",
|
||||
harmful_prompts=["harmful"],
|
||||
harmless_prompts=["harmless"],
|
||||
)
|
||||
pipeline.handle = handle
|
||||
pipeline._strong_layers = [0]
|
||||
direction = torch.arange(1, config.hidden_size + 1, dtype=torch.float32)
|
||||
direction /= direction.norm()
|
||||
pipeline.refusal_directions = {0: direction.clone()}
|
||||
pipeline.refusal_subspaces = {0: direction.unsqueeze(0)}
|
||||
|
||||
layer = model.model.layers[0]
|
||||
original_weights = {
|
||||
name: parameter.detach().clone()
|
||||
for name, parameter in layer.named_parameters()
|
||||
}
|
||||
|
||||
pipeline._excise()
|
||||
|
||||
expected = {
|
||||
"self_attn.q_proj.weight",
|
||||
"self_attn.k_proj.weight",
|
||||
"self_attn.v_proj.weight",
|
||||
"self_attn.o_proj.weight",
|
||||
"mlp.gate_proj.weight",
|
||||
"mlp.up_proj.weight",
|
||||
"mlp.down_proj.weight",
|
||||
}
|
||||
changed = {
|
||||
name
|
||||
for name, parameter in layer.named_parameters()
|
||||
if not torch.equal(original_weights[name], parameter)
|
||||
}
|
||||
assert handle.architecture == "qwen2"
|
||||
assert changed == expected
|
||||
assert pipeline._excise_modified_count == 8 # seven layer weights + lm_head
|
||||
|
||||
def test_excise_basic(self, handle):
|
||||
"""Basic method should modify weights."""
|
||||
from obliteratus.strategies.utils import get_layer_modules
|
||||
|
||||
Reference in New Issue
Block a user