File size: 2,603 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
import torch
import os
from transformers import AutoModelForCausalLM, AutoTokenizer
from peft import PeftModel

# 1. 路径定义
BASE_MODEL_PATH = "./Qwen3-4B-Thinking-2507"
LORA_PATH = "./Qwen3-4B-Thinking-2507_FTtrained_lora"
OUTPUT_PRUNED_PATH = "./QiMing-Polaris-Qwen3-4B-HardPruned"

# 2. 定义需要剪掉的层(根据你的 Audit 数据,L-29 到 L-32 发生了剧烈塌缩)
LAYERS_TO_REMOVE = [29, 30, 31, 32]

print("🚀 阶段 1/4: 正在加载基础模型与分词器...")
tokenizer = AutoTokenizer.from_pretrained(BASE_MODEL_PATH, trust_remote_code=True)
base_model = AutoModelForCausalLM.from_pretrained(
    BASE_MODEL_PATH,
    dtype=torch.bfloat16,  # 避免 deprecated 警告
    device_map="cpu",  # 融合与剪枝在 CPU 内存上进行,防止显存溢出
    trust_remote_code=True,
)

print("🔗 阶段 2/4: 加载并融合 LoRA 适配器...")
lora_model = PeftModel.from_pretrained(base_model, LORA_PATH)
merged_model = lora_model.merge_and_unload()
print("✅ LoRA 权重融合成功!")

print("✂️ 阶段 3/4: 正在执行硬剪枝 (Hard Pruning)...")
original_layers_count = len(merged_model.model.layers)
print(f"原模型总层数: {original_layers_count} 层")

# 计算需要保留的层索引
keep_indices = [i for i in range(original_layers_count) if i not in LAYERS_TO_REMOVE]
print(f"准备移除的层: {LAYERS_TO_REMOVE}")
print(f"保留的层索引数量: {len(keep_indices)} 层")

# 1. 物理切割:重构 layers 的 ModuleList
pruned_layers = torch.nn.ModuleList(
    [merged_model.model.layers[i] for i in keep_indices]
)
merged_model.model.layers = pruned_layers

# 2. 【核心修复】同步更新 config 中的所有层数及 layer_types 列表
configs_to_update = [merged_model.config]
if (
    hasattr(merged_model.config, "text_config")
    and merged_model.config.text_config is not None
):
    configs_to_update.append(merged_model.config.text_config)

for cfg in configs_to_update:
    cfg.num_hidden_layers = len(keep_indices)

    # 切割 layer_types 列表以匹配新的层数
    if hasattr(cfg, "layer_types") and cfg.layer_types is not None:
        cfg.layer_types = [cfg.layer_types[i] for i in keep_indices]

print(f"剪枝完成!新模型总层数: {len(merged_model.model.layers)} 层")

print(f"💾 阶段 4/4: 正在保存硬剪枝后的全新模型至 {OUTPUT_PRUNED_PATH}...")
os.makedirs(OUTPUT_PRUNED_PATH, exist_ok=True)
merged_model.save_pretrained(OUTPUT_PRUNED_PATH, safe_serialization=True)
tokenizer.save_pretrained(OUTPUT_PRUNED_PATH)

print("🎉 恭喜!硬剪枝独立模型已成功保存导出!")