tchbcb commited on
Commit
a519dbe
·
verified ·
1 Parent(s): f706c1b

backup s27_calibrate.py

Browse files
Files changed (1) hide show
  1. sft-adapter/s27_calibrate.py +209 -0
sft-adapter/s27_calibrate.py ADDED
@@ -0,0 +1,209 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ s27_calibrate.py — samai-27b SFT 后校准 (Kaggle 2xT4, nf4 + adapter)
5
+
6
+ 产物 /tmp/k27/s27_calibration.json:
7
+ expert_freq: {"35": [f0..f7], ...} 8 个 ponder 层各专家被激活的 token 频率 (GGUF 合并权重)
8
+ halting_w: [w_1..w_K] 停机质量分布 (记录用; flat GGUF 不使用)
9
+ steps_mean / steps_hist / n_prompts
10
+
11
+ 用法:
12
+ python3 s27_calibrate.py
13
+ """
14
+ import argparse, json, os, time
15
+ import numpy as np
16
+ import torch
17
+
18
+ os.environ.setdefault("HF_HOME", "/tmp/k27/hf_home")
19
+ os.environ.setdefault("PYTORCH_CUDA_ALLOC_CONF", "expandable_segments:True")
20
+ os.environ.setdefault("TOKENIZERS_PARALLELISM", "false")
21
+
22
+ T0 = time.time()
23
+
24
+
25
+ def log(m):
26
+ print(f"[{time.time()-T0:6.1f}s] {m}", flush=True)
27
+
28
+
29
+ PROMPTS = [
30
+ ("chat", "你好,请用一句话介绍你自己。"),
31
+ ("chat", "帮我想一个周末去公园野餐的计划,两三句就行。"),
32
+ ("chat", "用一句话解释什么是复利。"),
33
+ ("chat", "给我讲一个冷笑话。"),
34
+ ("arith", "37 + 58 = ?"),
35
+ ("arith", "12 × 17 = ?"),
36
+ ("arith", "小明有 45 个苹果,分给 5 个朋友每人相同数量,每人几个?"),
37
+ ("rent", "一个出租院落面积 20 亩,去年每亩租金 1600 元,今年每亩租金比去年上涨 50%。"
38
+ "今年该院落全部出租,租金总额是多少?注意:不需要考虑押金和卫生费。"),
39
+ ("trap", "一个出租院落面积 20 亩,去年每亩租金 1600 元,今年每亩租金比去年上涨 50%。"
40
+ "若同时考虑押金 2000 元和每亩卫生费 10 元,今年该院落全部出租的租金总额是多少?"
41
+ "(押金可退,不计入租金)"),
42
+ ("long", "人工智能的发展经历了多次浪潮。从符号主义到连接主义,从专家系统到深度学习,"
43
+ "每一次范式转移都带来了能力的跃升。近年来,大语言模型通过海量文本预训练与指令微调,"
44
+ "展现出前所未有的通用性。请把这段话压缩成一句话。"),
45
+ ("en", "Translate to Chinese: The quick brown fox jumps over the lazy dog."),
46
+ ("code", "用 Python 写一个判断质数的函数,只要函数体。"),
47
+ ]
48
+
49
+
50
+ def main():
51
+ ap = argparse.ArgumentParser()
52
+ ap.add_argument("--base",
53
+ default="/tmp/k27/hf_home/models--tchbcb--samai-27b/snapshots/883452faeb47f1394acd180a778dc5d53f049f1b")
54
+ ap.add_argument("--adapter", default="/tmp/k27/s27_sft_adapter")
55
+ ap.add_argument("--out", default="/tmp/k27/s27_calibration.json")
56
+ a = ap.parse_args()
57
+
58
+ from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig
59
+ from peft import PeftModel
60
+
61
+ log("loading tokenizer ...")
62
+ tok = AutoTokenizer.from_pretrained(a.base, trust_remote_code=True)
63
+
64
+ log("loading base (nf4, manual balanced map) ...")
65
+ from accelerate import init_empty_weights
66
+ from transformers import AutoConfig
67
+
68
+ def build_map(base):
69
+ """与 s27_train.py 同款: visual→cpu, lm_head→GPU1(纯前向 logits 尾部), 层贪心均衡"""
70
+ cfgm = AutoConfig.from_pretrained(base, trust_remote_code=True)
71
+ with init_empty_weights():
72
+ mm = AutoModelForCausalLM.from_config(cfgm, trust_remote_code=True)
73
+ LM = "model.language_model"
74
+ SKIP = ("lm_head", "router", "halter", "mtp", "norm", "visual", "embed_tokens")
75
+ lay, oth = {}, {}
76
+ for name, p in mm.named_parameters():
77
+ if name.startswith(LM + ".layers."):
78
+ li = int(name.split(".layers.")[1].split(".")[0])
79
+ b = p.numel() * (2 if ("router" in name or "halter" in name or "norm" in name) else 0.6)
80
+ lay[li] = lay.get(li, 0) + b
81
+ else:
82
+ b = p.numel() * (2 if any(k in name for k in SKIP) else 0.6)
83
+ top = ".".join(name.split(".")[:3]) if name.startswith(LM) else ".".join(name.split(".")[:2])
84
+ oth[top] = oth.get(top, 0) + b
85
+ dmap = {LM + ".embed_tokens": 0}
86
+ fill = oth.pop(LM + ".embed_tokens", 0)
87
+ oth.pop(LM + ".norm", None)
88
+ oth.pop("lm_head", None)
89
+ hi = 0
90
+ for li in sorted(lay):
91
+ if fill + lay[li] <= 10.0 * 2**30:
92
+ dmap[f"{LM}.layers.{li}"] = 0
93
+ fill += lay[li]
94
+ hi = li
95
+ for li in sorted(lay):
96
+ if li > hi:
97
+ dmap[f"{LM}.layers.{li}"] = 1
98
+ dmap[LM + ".norm"] = 1
99
+ dmap["mtp"] = 1
100
+ dmap["lm_head"] = 1
101
+ dmap["model.visual"] = "cpu"
102
+ for extra, _b in oth.items():
103
+ if extra.startswith(LM) and extra not in dmap:
104
+ dmap[extra] = 1
105
+ for name, _ in mm.named_modules():
106
+ if not name or name in dmap:
107
+ continue
108
+ if any(name.startswith(k + ".") for k in dmap):
109
+ continue
110
+ if any(k.startswith(name + ".") for k in dmap):
111
+ continue
112
+ parts = name.split(".")
113
+ dev = 0
114
+ for i in range(len(parts) - 1, 0, -1):
115
+ anc = ".".join(parts[:i])
116
+ if anc in dmap:
117
+ dev = dmap[anc]
118
+ break
119
+ dmap[name] = dev
120
+ del mm
121
+ return dmap
122
+
123
+ bnb = BitsAndBytesConfig(
124
+ load_in_4bit=True, bnb_4bit_quant_type="nf4",
125
+ bnb_4bit_compute_dtype=torch.float16, bnb_4bit_use_double_quant=True,
126
+ llm_int8_skip_modules=["lm_head", "router", "halter", "mtp", "norm", "visual"],
127
+ llm_int8_enable_fp32_cpu_offload=True)
128
+ model = AutoModelForCausalLM.from_pretrained(
129
+ a.base, trust_remote_code=True, quantization_config=bnb,
130
+ dtype=torch.float16, attn_implementation="eager",
131
+ device_map=build_map(a.base))
132
+ log(f"gpu0={torch.cuda.memory_allocated(0)/2**30:.2f}G "
133
+ f"gpu1={torch.cuda.memory_allocated(1)/2**30:.2f}G")
134
+
135
+ log("attaching adapter ...")
136
+ model = PeftModel.from_pretrained(model, a.adapter)
137
+ model.eval()
138
+
139
+ cfg = model.config
140
+ cfg.ponder_all_positions = True # prefill 全位置思考 → 统计充分
141
+ cfg.ponder_forced_steps = 0
142
+ cfg.use_cache = False
143
+
144
+ pl_ids = list(cfg.ponder_layers)
145
+ pl_layers = list(model.ponder_layers)
146
+ log(f"ponder layers: {pl_ids}")
147
+ K = int(getattr(cfg, "max_ponder_steps", 8) or 8)
148
+ eps = float(getattr(cfg, "ponder_epsilon", 0.01) or 0.01)
149
+
150
+ freq_acc = {li: np.zeros(8) for li in pl_ids}
151
+ freq_n = 0
152
+ W_sum = np.zeros(K) # 各步质量累加 (跨层/位置/样本)
153
+ W_pos = 0 # 位置·层 计数
154
+ steps_hist = np.zeros(K + 1)
155
+
156
+ for i, (tag, text) in enumerate(PROMPTS):
157
+ enc = tok.apply_chat_template(
158
+ [{"role": "user", "content": text}], add_generation_prompt=True,
159
+ tokenize=True, return_tensors="pt", enable_thinking=False)
160
+ if not torch.is_tensor(enc):
161
+ enc = enc["input_ids"]
162
+ with torch.no_grad():
163
+ model(input_ids=enc.cuda(), use_cache=False)
164
+ # ---- expert freq (fresh 路由的 _last_mask: (B,T,N)) ----
165
+ for li, layer in zip(pl_ids, pl_layers):
166
+ m = getattr(layer.mlp, "_last_mask", None)
167
+ if m is not None:
168
+ freq_acc[li] += m.float().mean(dim=(0, 1)).cpu().numpy()
169
+ # ---- halting w (last_w_stack: (B, W, K_exec), 已含 p_N 截断) ----
170
+ for layer in pl_layers:
171
+ w = getattr(layer, "last_w_stack", None)
172
+ if w is None:
173
+ continue
174
+ wf = w.float().cpu().numpy()
175
+ k_exec = wf.shape[-1]
176
+ W_sum[:k_exec] += wf.reshape(-1, k_exec).sum(0)
177
+ W_pos += wf.shape[0] * wf.shape[1]
178
+ s = getattr(layer, "last_steps", None)
179
+ if s is not None:
180
+ for st in s.float().flatten().cpu().numpy().clip(0, K).astype(int):
181
+ steps_hist[st] += 1
182
+ freq_n += 1
183
+ log(f"{i+1}/{len(PROMPTS)} {tag}: ok")
184
+ torch.cuda.empty_cache()
185
+
186
+ expert_freq = {str(li): (freq_acc[li] / max(freq_n, 1)).round(6).tolist()
187
+ for li in pl_ids}
188
+ halting_w = (W_sum / max(W_pos, 1))
189
+ halting_w = [w for w in halting_w if w > 1e-6]
190
+ ssum = sum(halting_w) or 1.0
191
+ halting_w = [round(w / ssum, 6) for w in halting_w]
192
+ steps_mean = float((np.arange(1, K + 1) * steps_hist[1:]).sum()
193
+ / max(steps_hist.sum(), 1.0))
194
+ out = {
195
+ "expert_freq": expert_freq,
196
+ "halting_w": halting_w,
197
+ "steps_hist": steps_hist.astype(int).tolist(),
198
+ "steps_mean": round(steps_mean, 4),
199
+ "n_prompts": len(PROMPTS),
200
+ "adapter": a.adapter,
201
+ "note": "expert_freq = 激活频率 f_i (静态合并 concat_i(f_i*E_i)); SFT 后 router",
202
+ }
203
+ json.dump(out, open(a.out, "w"), indent=1, ensure_ascii=False)
204
+ log("saved " + a.out)
205
+ print(json.dumps(out, indent=1))
206
+
207
+
208
+ if __name__ == "__main__":
209
+ main()