File size: 4,734 Bytes
1836a26
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
import torch
import torch.nn.functional as F
from transformers import AutoModelForCausalLM, AutoTokenizer
from peft import PeftModel

# ==================== 1. 本地路径配置 ====================
base_model_path = "./Qwen3-4B-Thinking-2507"
lora_path = "./QiMing-Polaris-Qwen3-4B-Thinking-2507_burden_trained_lora"

# 测试 Prompt(使用你的 Alpaca 标准格式)
prompt = """Below is an instruction that describes a task, paired with an input that provides further context. Write a response that appropriately completes the request.



### Instruction:

What is the 'Burden-based Training' method?



### Input:





### Response:

"""

print("🚀 启动残差流向量干涉对比审计工具...")

# 2. 加载分词器和准备 Input
tokenizer = AutoTokenizer.from_pretrained(base_model_path, trust_remote_code=True)
inputs = tokenizer(prompt, return_tensors="pt").to("cuda")


# ==================== 审计核心 Hook 函数 ====================
def audit_model_interference(model):
    """通过注册 Hook 测量模型每一层的残差流变化量 Δh 以及夹角余弦 cos(h, Δh)"""
    residual_inputs = {}
    residual_outputs = {}
    hooks = []

    def make_hook(layer_idx):
        def hook(module, input_tensor, output_tensor):
            residual_inputs[layer_idx] = input_tensor[0].detach()
            # 如果输出是 tuple(如 Qwen 架构),取第 0 项向量
            out = output_tensor[0] if isinstance(output_tensor, tuple) else output_tensor
            residual_outputs[layer_idx] = out.detach()
        return hook

    # 兼容 PEFT 挂载前后的模型层获取
    if hasattr(model, "model") and hasattr(model.model, "layers"):
        layers = model.model.layers
    elif hasattr(model, "base_model"):
        layers = model.base_model.model.model.layers
    else:
        raise AttributeError("无法自动定位模型的 layers 结构")

    # 注册 Hook
    for i, layer in enumerate(layers):
        hooks.append(layer.register_forward_hook(make_hook(i)))

    # 前向传播捕获向量
    with torch.no_grad():
        _ = model(**inputs)

    # 及时清理 Hook 防止内存泄漏
    for h in hooks:
        h.remove()

    # 计算各层干涉数据
    metrics = []
    for i in range(len(layers)):
        h_l = residual_inputs[i][0, -1, :].float()      # 当前层最后一个 Token 的向量
        h_next = residual_outputs[i][0, -1, :].float()  # 下一层向量
        delta_h = h_next - h_l                    # 本层新增的向量变化量 Δh_l

        cos_sim = F.cosine_similarity(h_l, delta_h, dim=0).item()
        delta_norm = delta_h.norm().item()

        metrics.append({
            "layer": i,
            "norm": delta_norm,
            "cos_sim": cos_sim
        })

    return metrics


# ==================== 3. 测量 Base 模型 ====================
print(f"\n🔍 正在测量 1/2: 原始模型 [{base_model_path}]...")
base_model = AutoModelForCausalLM.from_pretrained(
    base_model_path,
    torch_dtype=torch.bfloat16,
    device_map="cuda",
    trust_remote_code=True
)
base_metrics = audit_model_interference(base_model)


# ==================== 4. 挂载 FT LoRA 并测量 ====================
print(f"🔍 正在测量 2/2: FT 负重训练模型 [Base + {lora_path}]...")
ft_model = PeftModel.from_pretrained(base_model, lora_path)
ft_metrics = audit_model_interference(ft_model)


# ==================== 5. 打印对比报告 ====================
print("\n" + "="*100)
print(f"{'层数':<6} | {'[原始 Base] cos(h,Δh)':<22} | {'[FT 负重] cos(h,Δh)':<22} | {'余弦变化(Diff)':<14} | {'干涉趋势变化'}")
print("="*100)

for i in range(len(base_metrics)):
    b_cos = base_metrics[i]["cos_sim"]
    ft_cos = ft_metrics[i]["cos_sim"]
    diff = ft_cos - b_cos

    b_type = "🔴减法" if b_cos < 0 else "🟢加法"
    ft_type = "🔴减法" if ft_cos < 0 else "🟢加法"

    # 判断趋势变化
    if ft_cos < b_cos:
        trend = "⬇️ 负向干涉增强 (做减法/抵消变强)"
    elif ft_cos > b_cos:
        trend = "⬆️ 正向叠加增强 (做加法)"
    else:
        trend = "➡️ 无变化"

    print(f"L-{i:<3} | {b_cos:<8.4f} ({b_type})   | {ft_cos:<8.4f} ({ft_type})   | {diff:<+10.4f}     | {trend}")

print("="*100)
print("💡 结果解读指南:")
print("1. [FT 负重] 的 cos(h,Δh) 数值越小或越负,说明 FT 训练在该层施加的‘相消干涉(减法/抵消)’越强。")
print("2. 如果变化趋势显示 '⬇️ 负向干涉增强',证明挂载 FT LoRA 后,该层正在主动计算反向向量去抵消杂音噪声!")
print("="*100)