aifeifei798 commited on
Commit
448356a
·
verified ·
1 Parent(s): 8f8818c

Delete 演示程序

Browse files
演示程序/diagnose_layers.py DELETED
@@ -1,163 +0,0 @@
1
- # ====================================================================================
2
- # diagnose_layers.py
3
- # 目的:通过计算和可视化每一层激活的“AB面差异显著性”,
4
- # 来诊断模型中特定行为(如“安全拒绝”)主要发生在哪些层。
5
- # ====================================================================================
6
-
7
- print("--- Running Layer Diagnosis Script ---")
8
-
9
- import torch
10
- import gc
11
- import matplotlib.pyplot as plt
12
- import numpy as np
13
-
14
- from datasets import load_dataset
15
- from tqdm import tqdm
16
- from collections import defaultdict
17
- from transformers import AutoModelForCausalLM, AutoTokenizer
18
-
19
- # --- [配置参数] ---
20
- MODEL_ID = "./gemma-3-4b-it-qat-q4_0-unquantized"
21
- # 为了快速诊断,我们使用较少的样本
22
- NUM_SAMPLES_TO_DIAGNOSE = 64
23
- BATCH_SIZE = 4
24
- OUTPUT_CHART_FILENAME = "layer_significance_chart.png"
25
-
26
- # --- [STEP 1] 设置模型和分词器 ---
27
- print(f"\n[STEP 1] Loading model and tokenizer from: {MODEL_ID}")
28
- torch.set_grad_enabled(False)
29
-
30
- hf_model = AutoModelForCausalLM.from_pretrained(
31
- MODEL_ID,
32
- local_files_only=True,
33
- torch_dtype=torch.bfloat16,
34
- device_map="auto"
35
- )
36
- tokenizer = AutoTokenizer.from_pretrained(MODEL_ID, local_files_only=True)
37
- tokenizer.padding_side = 'left'
38
- if tokenizer.pad_token is None:
39
- tokenizer.pad_token = tokenizer.eos_token
40
-
41
- TOTAL_LAYERS = hf_model.config.text_config.num_hidden_layers
42
- print(f"[SUCCESS] Model with {TOTAL_LAYERS} layers and tokenizer loaded.")
43
-
44
-
45
- # --- [STEP 2] 准备数据 ---
46
- print(f"\n[STEP 2] Preparing datasets with {NUM_SAMPLES_TO_DIAGNOSE} samples each...")
47
-
48
- def reformat_texts(texts):
49
- return [[{"role": "user", "content": text}] for text in texts]
50
-
51
- # 加载有害指令 (A面)
52
- harmful_dataset = load_dataset('./harmful_behaviors')
53
- harmful_inst = reformat_texts(harmful_dataset['train']['text'])[:NUM_SAMPLES_TO_DIAGNOSE]
54
-
55
- # 加载无害指令 (B面)
56
- harmless_dataset = load_dataset('./harmless_alpaca')
57
- harmless_inst = reformat_texts(harmless_dataset['train']['text'])[:NUM_SAMPLES_TO_DIAGNOSE]
58
-
59
- print("[SUCCESS] Datasets prepared.")
60
-
61
-
62
- # --- [STEP 3] 定义激活收集的辅助函数 ---
63
-
64
- # 计算最大长度
65
- all_texts = [instr[0]['content'] for instr in harmful_inst + harmless_inst]
66
- max_len = max([tokenizer(text, return_tensors="pt").input_ids.shape[1] for text in all_texts])
67
- print(f"Max sequence length calculated: {max_len}")
68
-
69
- def tokenize_instructions(tokenizer, instructions, max_length):
70
- return tokenizer.apply_chat_template(
71
- instructions, padding="max_length", truncation=True, max_length=max_length,
72
- return_tensors="pt", return_dict=True, add_generation_prompt=True,
73
- )
74
-
75
- def get_activations(model, instructions, num_samples):
76
- """一个专门用于收集所有层激活的函数"""
77
- cache = defaultdict(list)
78
- def create_hook_fn(layer_name):
79
- def hook_fn(module, input, output):
80
- # 我们只关心最后一个 token 的激活,并且只收集残差流的输出
81
- # output[0] 是残差流的激活张量
82
- cache[layer_name].append(output[0][:, -1, :].cpu())
83
- return hook_fn
84
-
85
- hooks = []
86
- for i in range(TOTAL_LAYERS):
87
- layer_name = f"layer_{i}"
88
- module = model.get_submodule(f"model.language_model.layers.{i}")
89
- hook = module.register_forward_hook(create_hook_fn(layer_name))
90
- hooks.append(hook)
91
-
92
- num_batches = (num_samples + BATCH_SIZE - 1) // BATCH_SIZE
93
- for i in tqdm(range(num_batches), desc="Collecting activations"):
94
- start_idx, end_idx = i * BATCH_SIZE, min(num_samples, (i + 1) * BATCH_SIZE)
95
- batch_instructions = instructions[start_idx:end_idx]
96
- tokenized_input = tokenize_instructions(tokenizer, batch_instructions, max_length=max_len).to(model.device)
97
- model(**tokenized_input)
98
-
99
- for hook in hooks: hook.remove()
100
-
101
- # 拼接张量
102
- for layer_name, activations in cache.items():
103
- cache[layer_name] = torch.cat(activations, dim=0)
104
-
105
- return cache
106
-
107
- # --- [STEP 4] 收集两类数据的激活 ---
108
- print("\n[STEP 4] Collecting activations for both datasets...")
109
-
110
- print("Collecting for Harmful dataset (A-Side)...")
111
- harmful_activations = get_activations(hf_model, harmful_inst, NUM_SAMPLES_TO_DIAGNOSE)
112
-
113
- print("Collecting for Harmless dataset (B-Side)...")
114
- harmless_activations = get_activations(hf_model, harmless_inst, NUM_SAMPLES_TO_DIAGNOSE)
115
-
116
- print("[SUCCESS] All activations collected.")
117
-
118
-
119
- # --- [STEP 5] 计算并可视化每层的显著性 ---
120
- print("\n[STEP 5] Calculating and visualizing layer significance...")
121
-
122
- layer_significance = []
123
- layer_indices = range(TOTAL_LAYERS)
124
-
125
- for l in layer_indices:
126
- layer_name = f"layer_{l}"
127
-
128
- # 计算每个数据集在该层的均值激活
129
- harmful_mean_act = harmful_activations[layer_name].mean(dim=0)
130
- harmless_mean_act = harmless_activations[layer_name].mean(dim=0)
131
-
132
- # 计算差分向量
133
- diff_vector = harmful_mean_act - harmless_mean_act
134
-
135
- # 计算其L2范数(模长)作为显著性得分
136
- significance = torch.linalg.norm(diff_vector).item()
137
- layer_significance.append(significance)
138
- print(f"Layer {l:02d}: Significance (L2 Norm of diff) = {significance:.4f}")
139
-
140
- # 清理内存
141
- del harmful_activations, harmless_activations, hf_model
142
- gc.collect()
143
- torch.cuda.empty_cache()
144
-
145
- # 绘制图表
146
- print(f"\n[STEP 6] Generating chart and saving to {OUTPUT_CHART_FILENAME}...")
147
- plt.style.use('seaborn-v0_8-whitegrid') # 使用一个好看的样式
148
- fig, ax = plt.subplots(figsize=(15, 7))
149
-
150
- ax.plot(layer_indices, layer_significance, marker='o', linestyle='-', color='royalblue', label='Signal Significance')
151
- ax.set_title('Significance of "Refusal Signal" Across Model Layers', fontsize=16, fontweight='bold')
152
- ax.set_xlabel('Layer Index', fontsize=12)
153
- ax.set_ylabel('Significance Score (L2 Norm of Activation Difference)', fontsize=12)
154
- ax.grid(True, which='both', linestyle='--', linewidth=0.5)
155
- ax.set_xticks(np.arange(0, TOTAL_LAYERS, 2)) # 每隔2层显示一个刻度
156
- ax.legend()
157
- plt.tight_layout()
158
-
159
- # 保存图表
160
- plt.savefig(OUTPUT_CHART_FILENAME)
161
-
162
- print(f"\n[SUCCESS] Diagnosis complete. Chart saved to '{OUTPUT_CHART_FILENAME}'.")
163
- print("You can now analyze this chart to determine the optimal layers for your fine-tuning surgery.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
演示程序/finalize_save.py DELETED
@@ -1,59 +0,0 @@
1
- # ====================================================================================
2
- # finalize_save.py (v1.1 - Memory Optimized)
3
- # ====================================================================================
4
-
5
- import torch
6
- from transformers import AutoModelForCausalLM, AutoTokenizer
7
- import gc # 导入垃圾回收模块
8
-
9
- print("--- 运行最终模型保存脚本 (内存优化版) ---")
10
-
11
- # --- [STEP 1] 定义模型和路径 ---
12
- MODEL_ID = "./gemma-3-4b-it-qat-q4_0-unquantized"
13
- NEW_MODEL_ID = "./gemma-3-4b-it-qat-q4_0-unquantized-precise-abliterated"
14
- WEIGHTS_FILE = "./consolidated_precise_abliterated_weights.pth"
15
-
16
- print(f"原始模型 ID: {MODEL_ID}")
17
- print(f"权重文件路径: {WEIGHTS_FILE}")
18
- print(f"最终保存路径: {NEW_MODEL_ID}")
19
-
20
-
21
- # --- [STEP 2] 加载一个干净的原始模型到 CPU ---
22
- print("\n[STEP 2] 正在 CPU 上加载一个干净的原始模型架构...")
23
- clean_model = AutoModelForCausalLM.from_pretrained(
24
- MODEL_ID,
25
- local_files_only=True,
26
- torch_dtype=torch.bfloat16,
27
- device_map="cpu"
28
- )
29
- print("[SUCCESS] 干净的模型加载完成。")
30
-
31
-
32
- # --- [STEP 3] 加载之前保存的状态字典 ---
33
- print(f"\n[STEP 3] 正在从 {WEIGHTS_FILE} 加载手术后的权重...")
34
- consolidated_weights = torch.load(WEIGHTS_FILE, map_location="cpu")
35
- print("[SUCCESS] 权重文件加载完成。")
36
-
37
-
38
- # --- [STEP 4] 将权重应用到干净的模型上 ---
39
- print("\n[STEP 4] 正在将权重应用到模型...")
40
- clean_model.load_state_dict(consolidated_weights)
41
- print("[SUCCESS] 权重成功应用。")
42
-
43
-
44
- # --- [新增步骤] 释放内存 ---
45
- print("\n[内存优化] 正在释放已加载的权重字典以节省内存...")
46
- del consolidated_weights # 删除不再需要的权重字典
47
- gc.collect() # 强制执行垃圾回收
48
- print("[SUCCESS] 内存已释放。")
49
-
50
-
51
- # --- [STEP 5] 保存最终模型和分词器 ---
52
- print(f"\n[STEP 5] 正在将最终的、完整的模型保存到: {NEW_MODEL_ID}")
53
- clean_model.save_pretrained(NEW_MODEL_ID)
54
-
55
- # 同时,也需要保存分词器
56
- tokenizer = AutoTokenizer.from_pretrained(MODEL_ID, local_files_only=True)
57
- tokenizer.save_pretrained(NEW_MODEL_ID)
58
-
59
- print(f"\n[全部完成!] 您的手术后模型已成功保存到: {NEW_MODEL_ID}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
演示程序/precise_surgery.py DELETED
@@ -1,238 +0,0 @@
1
- # ====================================================================================
2
- # FINAL VERSION v7.0 (Precise Layer-Specific Surgery)
3
- # 核心改动:基于诊断图表的结论,只对模型高层进行手术,以达到最大效果和最小副作用。
4
- # ====================================================================================
5
- print("--- Running Abliteration Script v7.0 (Precise Surgery Edition) ---")
6
-
7
- import torch
8
- import functools
9
- import einops
10
- import gc
11
- import sys
12
-
13
- from datasets import load_dataset
14
- from tqdm import tqdm
15
- from torch import Tensor
16
- from typing import List, Dict
17
- from transformers import AutoModelForCausalLM, AutoTokenizer
18
- from jaxtyping import Float, Int
19
- from collections import defaultdict
20
-
21
- print("[INFO] All libraries imported successfully.")
22
-
23
- torch.set_grad_enabled(False)
24
-
25
- def reformat_texts(texts):
26
- return [[{"role": "user", "content": text}] for text in texts]
27
-
28
- def get_harmful_instructions():
29
- dataset = load_dataset('./harmful_behaviors')
30
- return reformat_texts(dataset['train']['text']), reformat_texts(dataset['test']['text'])
31
-
32
- def get_harmless_instructions():
33
- dataset = load_dataset('./harmless_alpaca')
34
- return reformat_texts(dataset['train']['text']), reformat_texts(dataset['test']['text'])
35
-
36
- # --- [STEP 1] 设置模型和路径 ---
37
- print("\n[STEP 1] Setting up model configuration...")
38
- MODEL_ID = "./gemma-3-4b-it-qat-q4_0-unquantized"
39
- # [修改] 新的模型名称,以体现“精准手术”
40
- NEW_MODEL_ID = "./gemma-3-4b-it-qat-q4_0-unquantized-precise-abliterated"
41
- print(f"Model ID: {MODEL_ID}")
42
-
43
- # --- [STEP 2] 加载模型和分词器 ---
44
- print("\n[STEP 2] Loading model and tokenizer...")
45
- hf_model = AutoModelForCausalLM.from_pretrained(
46
- MODEL_ID,
47
- local_files_only=True,
48
- torch_dtype=torch.bfloat16,
49
- device_map="auto"
50
- )
51
- tokenizer = AutoTokenizer.from_pretrained(MODEL_ID, local_files_only=True)
52
- tokenizer.padding_side = 'left'
53
- if tokenizer.pad_token is None:
54
- tokenizer.pad_token = tokenizer.eos_token
55
- print("[SUCCESS] Model and tokenizer loaded.")
56
-
57
- # --- [STEP 3] 准备数据和计算全局最大长度 ---
58
- print("\n[STEP 3] Preparing datasets and calculating max sequence length...")
59
- harmful_inst_train, harmful_inst_test = get_harmful_instructions()
60
- harmless_inst_train, harmless_inst_test = get_harmless_instructions()
61
-
62
- n_inst_train = min(256, len(harmful_inst_train), len(harmless_inst_train))
63
- batch_size = 4
64
- print(f"Using {n_inst_train} training samples per dataset with batch size {batch_size}.")
65
-
66
- all_instructions = harmful_inst_train[:n_inst_train] + harmless_inst_train[:n_inst_train]
67
- all_texts = [instr[0]['content'] for instr in all_instructions]
68
-
69
- print("Iterating through instructions to find the max token length...")
70
- tokenized_lengths = []
71
- for instruction in tqdm(reformat_texts(all_texts), desc="Tokenizing for max_len"):
72
- tokenized_output = tokenizer.apply_chat_template(instruction, add_generation_prompt=True, return_tensors="pt")
73
- tokenized_lengths.append(tokenized_output.shape[1])
74
- max_len = max(tokenized_lengths) if tokenized_lengths else 512
75
- print(f"[SUCCESS] Max sequence length set to: {max_len}")
76
-
77
- # --- [STEP 4] 定义分词函数 ---
78
- def tokenize_instructions(tokenizer, instructions, max_length):
79
- return tokenizer.apply_chat_template(
80
- instructions, padding="max_length", truncation=True, max_length=max_length,
81
- return_tensors="pt", return_dict=True, add_generation_prompt=True,
82
- )
83
- print("\n[STEP 4] Tokenization function defined.")
84
-
85
- # --- [STEP 5] 使用 PyTorch Hooks 采集激活值 ---
86
- # (此部分无需改动,我们仍然需要所有层的激活来进行潜在的分析)
87
- print("\n[STEP 5] Preparing for activation collection...")
88
- harmful, harmless = defaultdict(list), defaultdict(list)
89
- NUM_LAYERS = hf_model.config.text_config.num_hidden_layers
90
- print(f"Model has {NUM_LAYERS} layers.")
91
-
92
- def get_activations(model: AutoModelForCausalLM, instructions: List[Dict], cache_dict: Dict):
93
- temp_cache = defaultdict(list)
94
- def create_hook_fn(layer_name):
95
- def hook_fn(module, input, output):
96
- temp_cache[layer_name].append(output[0].cpu())
97
- return hook_fn
98
-
99
- hooks = []
100
- for i in range(NUM_LAYERS):
101
- layer_name = f"blocks.{i}.hook_resid_post"
102
- module = model.get_submodule(f"model.language_model.layers.{i}")
103
- hook = module.register_forward_hook(create_hook_fn(layer_name))
104
- hooks.append(hook)
105
-
106
- num_batches = (n_inst_train + batch_size - 1) // batch_size
107
- for i in tqdm(range(num_batches), desc="Collecting activations"):
108
- start_idx, end_idx = i * batch_size, min(n_inst_train, (i + 1) * batch_size)
109
- tokenized_input = tokenize_instructions(tokenizer, instructions[start_idx:end_idx], max_length=max_len).to(model.device)
110
- temp_cache.clear()
111
- model(**tokenized_input)
112
- for layer_name, activations in temp_cache.items():
113
- cache_dict[layer_name].extend(activations)
114
- for hook in hooks: hook.remove()
115
-
116
- print("Collecting harmful activations...")
117
- get_activations(hf_model, harmful_inst_train[:n_inst_train], harmful)
118
- print("Collecting harmless activations...")
119
- get_activations(hf_model, harmless_inst_train[:n_inst_train], harmless)
120
-
121
- harmful = {k: torch.cat(v) for k, v in harmful.items()}
122
- harmless = {k: torch.cat(v) for k, v in harmless.items()}
123
- print("[SUCCESS] All activations collected and concatenated.")
124
-
125
-
126
- # --- [STEP 6 - 精准手术版] 定义手术范围并计算目标向量 ---
127
- # [新增] 定义手术范围。基于诊断图,我们选择最后10层。
128
- START_LAYER = 24
129
- END_LAYER = NUM_LAYERS
130
- print(f"\n[PRECISE SURGERY] Defining surgery scope to layers [{START_LAYER}, {END_LAYER-1}].")
131
-
132
- def get_act_idx(cache_dict, act_name, layer): return cache_dict[f"blocks.{layer}.{act_name}"]
133
-
134
- # [修改] 只从目标层的激活中计算向量
135
- print(f"Computing refusal direction vector from layers {START_LAYER}-{END_LAYER-1}...")
136
- refusal_directions_in_scope = []
137
- for layer_num in range(START_LAYER, END_LAYER):
138
- harmful_mean_act = get_act_idx(harmful, "hook_resid_post", layer_num)[:, -1, :].mean(dim=0)
139
- harmless_mean_act = get_act_idx(harmless, "hook_resid_post", layer_num)[:, -1, :].mean(dim=0)
140
- refusal_dir = harmful_mean_act - harmless_mean_act
141
- refusal_directions_in_scope.append(refusal_dir)
142
-
143
- # [修改] 对目标范围内的向量求平均,得到最终的手术向量
144
- print("Averaging and normalizing the direction vector...")
145
- refusal_dir = torch.stack(refusal_directions_in_scope).mean(dim=0)
146
- refusal_dir /= refusal_dir.norm() # 归一化
147
- print("[SUCCESS] Precise refusal direction vector computed.")
148
-
149
-
150
- # --- [STEP 7 - 精准手术版] 只对目标层进行权重修改 ---
151
- print("\n[STEP 7] Applying orthogonalization surgery to specified layers...")
152
- def get_orthogonalized_matrix(matrix, vec):
153
- proj = (einops.einsum(matrix, vec.view(-1, 1), "d ..., d s -> ... s") * vec).T
154
- return matrix - proj
155
-
156
- # [修改] 我们仍然修改 Embedding 层,因为它影响全局,效果通常更好
157
- print("Orthogonalizing the Embedding layer...")
158
- target_device = hf_model.model.language_model.embed_tokens.weight.device
159
- hf_model.model.language_model.embed_tokens.weight.data = get_orthogonalized_matrix(hf_model.model.language_model.embed_tokens.weight.data.T, refusal_dir.to(target_device)).T
160
-
161
- # [修改] 循环只遍历我们定义的层范围
162
- for l in tqdm(range(START_LAYER, END_LAYER), desc=f"Orthogonalizing layers {START_LAYER}-{END_LAYER-1}"):
163
- layer = hf_model.get_submodule(f"model.language_model.layers.{l}")
164
-
165
- # 修改 o_proj
166
- target_device = layer.self_attn.o_proj.weight.device
167
- layer.self_attn.o_proj.weight.data = get_orthogonalized_matrix(layer.self_attn.o_proj.weight.data, refusal_dir.to(target_device))
168
-
169
- # 修改 down_proj
170
- target_device = layer.mlp.down_proj.weight.device
171
- layer.mlp.down_proj.weight.data = get_orthogonalized_matrix(layer.mlp.down_proj.weight.data, refusal_dir.to(target_device))
172
- print("[SUCCESS] Precise surgery on model weights has been completed.")
173
-
174
-
175
- # --- [STEP 8] & [STEP 9] 验证和对比 (无需改动) ---
176
- print("\n[STEP 8] Generating text for evaluation...")
177
- def generate_text(model, tokenizer, instructions, max_new_tokens=150, max_len_for_gen=512):
178
- generations = []
179
- gen_batch_size = 2
180
- for i in tqdm(range(0, len(instructions), gen_batch_size), desc="Generating text"):
181
- prompts = instructions[i : i + gen_batch_size]
182
- inputs = tokenize_instructions(tokenizer, prompts, max_length=max_len_for_gen).to(model.device)
183
- generated_ids = model.generate(**inputs, max_new_tokens=max_new_tokens, do_sample=False)
184
- input_len = inputs['input_ids'].shape[1]
185
- generations.extend(tokenizer.batch_decode(generated_ids[:, input_len:], skip_special_tokens=True))
186
- return generations
187
-
188
- N_INST_TEST = 4
189
- print("Generating baseline completions...")
190
- baseline_model = AutoModelForCausalLM.from_pretrained(MODEL_ID, local_files_only=True, torch_dtype=torch.bfloat16, device_map="auto")
191
- baseline_generations = generate_text(baseline_model, tokenizer, harmful_inst_test[:N_INST_TEST])
192
- del baseline_model
193
- gc.collect()
194
- torch.cuda.empty_cache()
195
- print("[SUCCESS] Baseline completions generated.")
196
-
197
- print("Generating orthogonalized completions...")
198
- orthogonalized_generations = generate_text(hf_model, tokenizer, harmful_inst_test[:N_INST_TEST])
199
- print("[SUCCESS] Orthogonalized completions generated.")
200
-
201
- print("\n--- FINAL RESULTS ---")
202
- for i in range(N_INST_TEST):
203
- print(f"\n--- INSTRUCTION {i+1} ---")
204
- print(f"PROMPT: {harmful_inst_test[i][0]['content']}")
205
- print(f"\033[92mBASELINE COMPLETION:\n{baseline_generations[i]}\033[0m")
206
- print(f"\033[95mORTHOGONALIZED (ABLITERATED) COMPLETION:\n{orthogonalized_generations[i]}\033[0m\n")
207
-
208
-
209
- # --- [STEP 10] 保存权重 (无需改动) ---
210
- print("\n[STEP 10] Extracting and saving weights (High-Compatibility Mode)...")
211
- from accelerate.hooks import remove_hook_from_module
212
- import warnings
213
- warnings.filterwarnings("ignore", message="You are removing the hook that was added by `Accelerate`")
214
-
215
- print("Step 1/3: Removing Accelerate hooks from the model...")
216
- hf_model.apply(remove_hook_from_module)
217
- print("...Hooks successfully removed.")
218
-
219
- print("Step 2/3: Moving the entire model to the CPU to consolidate weights...")
220
- try:
221
- hf_model = hf_model.to('cpu')
222
- print("...Model successfully consolidated on CPU.")
223
- except Exception as e:
224
- print(f"[FATAL ERROR] An error occurred while moving the model to CPU: {e}")
225
- sys.exit(1)
226
-
227
- gc.collect()
228
- torch.cuda.empty_cache()
229
-
230
- print("Step 3/3: Extracting the state dictionary and saving to file...")
231
- consolidated_state_dict = hf_model.state_dict()
232
- # [修改] 使用新的模型名称来命名权重文件
233
- weights_save_path = "./consolidated_precise_abliterated_weights.pth"
234
- print(f"Saving the consolidated weights to: {weights_save_path}")
235
- torch.save(consolidated_state_dict, weights_save_path)
236
-
237
- print(f"\n[SUCCESS!] Your model weights have been successfully saved to {weights_save_path}.")
238
- print("You can now run the 'finalize_save.py' script to create the final model folder.")