cross_model_convergence.py 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683
  1. #!/usr/bin/env python
  2. """
  3. 跨模型谱收敛实验流水线 - 方向 9 核心实验
  4. 功能:
  5. - 提取多个模型在同一文本集上的隐层表示
  6. - 计算跨模型谱稳定性指标 (RS_cross)
  7. - 计算谱 Platonic 距离矩阵 (SPD)
  8. - 逐层谱收敛轮廓分析 (LCP)
  9. 用法:
  10. # 运行完整 E1 实验
  11. python experiments/cross_model_convergence.py --experiment E1 --output-dir output/e1
  12. # 运行逐层分析
  13. python experiments/cross_model_convergence.py --experiment LCP --layers 10
  14. """
  15. import os
  16. import json
  17. import torch
  18. import numpy as np
  19. from pathlib import Path
  20. from typing import Dict, List, Tuple, Optional, Any
  21. from dataclasses import dataclass, asdict
  22. from datetime import datetime
  23. # 设置环境变量防止显存碎片化
  24. os.environ["PYTORCH_ALLOC_CONF"] = "expandable_segments:True"
  25. os.environ["HF_ENDPOINT"] = "https://hf-mirror.com"
  26. from transformers import AutoTokenizer, AutoModelForCausalLM
  27. from tqdm import tqdm
  28. # 导入谱计算模块
  29. import sys
  30. sys.path.insert(0, str(Path(__file__).parent.parent))
  31. from model.spectrum import compute_gram_spectrum, compute_spectrum_array, wasserstein1_distance
  32. from model.extractor import save_H, load_H, RepresentationLoader
  33. @dataclass
  34. class ExperimentConfig:
  35. """实验配置"""
  36. models: List[str]
  37. model_paths: Dict[str, str]
  38. datasets: List[str]
  39. output_dir: str
  40. batch_size: int = 16
  41. max_length: int = 512
  42. pooling: str = "mean"
  43. layer: int = -1 # -1 表示最后一层
  44. device: str = "cuda"
  45. @dataclass
  46. class ExperimentResult:
  47. """实验结果"""
  48. timestamp: str
  49. config: dict
  50. r_effs: Dict[str, Dict[str, float]] # {model: {dataset: r_eff}}
  51. rs_cross: Dict[str, float] # {dataset: RS_cross}
  52. spd_matrices: Dict[str, List[List[float]]] # {dataset: SPD_matrix}
  53. spectra: Dict[str, Dict[str, List[float]]] # {model: {dataset: spectrum}}
  54. class CrossModelConvergence:
  55. """跨模型谱收敛分析器"""
  56. def __init__(self, config: ExperimentConfig):
  57. self.config = config
  58. self.output_dir = Path(config.output_dir)
  59. self.output_dir.mkdir(parents=True, exist_ok=True)
  60. # 缓存加载的模型
  61. self.loaded_models: Dict[str, Tuple[AutoTokenizer, AutoModelForCausalLM]] = {}
  62. # 文本缓存
  63. self.texts_cache: Dict[str, List[str]] = {}
  64. def unload_all_models(self):
  65. """卸载所有模型并清理 GPU 缓存"""
  66. import gc
  67. self.loaded_models.clear()
  68. gc.collect()
  69. if torch.cuda.is_available():
  70. torch.cuda.empty_cache()
  71. def load_texts(self, dataset_name: str, limit: int = 500) -> List[str]:
  72. """加载数据集文本"""
  73. if dataset_name in self.texts_cache:
  74. return self.texts_cache[dataset_name][:limit]
  75. from database.corpus import CorpusLoader
  76. loader = CorpusLoader("database/corpus")
  77. try:
  78. texts = loader.load_texts(dataset_name, limit=limit)
  79. self.texts_cache[dataset_name] = texts
  80. print(f"加载 {dataset_name}: {len(texts)} 条文本")
  81. return texts
  82. except FileNotFoundError:
  83. print(f"警告:数据集 {dataset_name} 不存在")
  84. return []
  85. def load_model(self, model_name: str):
  86. """加载模型(带缓存)"""
  87. if model_name in self.loaded_models:
  88. return self.loaded_models[model_name]
  89. model_path = self.config.model_paths.get(
  90. model_name,
  91. f"model/weights/{model_name}"
  92. )
  93. print(f"加载模型:{model_name} (from {model_path})")
  94. tokenizer = AutoTokenizer.from_pretrained(
  95. model_path,
  96. trust_remote_code=True
  97. )
  98. # 设置 pad_token
  99. if tokenizer.pad_token is None:
  100. tokenizer.pad_token = tokenizer.eos_token
  101. if tokenizer.eos_token_id is None:
  102. tokenizer.eos_token_id = 50256 # 默认 EOS
  103. model = AutoModelForCausalLM.from_pretrained(
  104. model_path,
  105. torch_dtype=torch.float16,
  106. device_map="auto",
  107. output_hidden_states=True,
  108. trust_remote_code=True
  109. )
  110. model.eval()
  111. self.loaded_models[model_name] = (tokenizer, model)
  112. return tokenizer, model
  113. @torch.no_grad()
  114. def extract_hidden_states(
  115. self,
  116. model_name: str,
  117. texts: List[str],
  118. layer: int = -1
  119. ) -> torch.Tensor:
  120. """
  121. 提取隐层表示
  122. Returns:
  123. H: 表示矩阵 (d, N)
  124. """
  125. # 先清理缓存再加载新模型
  126. self.unload_all_models()
  127. tokenizer, model = self.load_model(model_name)
  128. all_features = []
  129. for i in range(0, len(texts), self.config.batch_size):
  130. batch = texts[i:i + self.config.batch_size]
  131. inputs = tokenizer(
  132. batch,
  133. return_tensors="pt",
  134. padding=True,
  135. truncation=True,
  136. max_length=self.config.max_length
  137. ).to(model.device)
  138. outputs = model(**inputs)
  139. hidden = outputs.hidden_states[layer] # (B, seq_len, d)
  140. attention_mask = inputs["attention_mask"]
  141. if self.config.pooling == "mean":
  142. # 对有效 token 取均值
  143. mask_expanded = attention_mask.unsqueeze(-1).float()
  144. feat = (hidden * mask_expanded).sum(1) / (mask_expanded.sum(1) + 1e-10)
  145. elif self.config.pooling == "last_token":
  146. # 取最后一个有效 token
  147. lengths = attention_mask.sum(1) - 1
  148. feat = hidden[torch.arange(len(batch)), lengths]
  149. else:
  150. # CLS token
  151. feat = hidden[:, 0, :]
  152. all_features.append(feat.cpu().float())
  153. # 转置为 (d, N)
  154. H = torch.cat(all_features, dim=0).T
  155. return H
  156. def compute_rs_cross(
  157. self,
  158. dataset_name: str,
  159. model_names: List[str],
  160. texts: Optional[List[str]] = None
  161. ) -> Dict[str, Any]:
  162. """
  163. 计算跨模型谱稳定性 RS_cross
  164. Returns:
  165. {
  166. "rs_cross": float,
  167. "r_effs": {model: r_eff},
  168. "std": float,
  169. "range": float
  170. }
  171. """
  172. if texts is None:
  173. texts = self.load_texts(dataset_name)
  174. if not texts:
  175. return {"rs_cross": 0, "r_effs": {}, "std": 0, "range": 0}
  176. r_effs = {}
  177. spectra = {}
  178. for model_name in tqdm(model_names, desc=f"RS_cross [{dataset_name}]"):
  179. # 提取或加载表示
  180. rep_path = f"representations/{model_name}_{dataset_name}.pt"
  181. rep_file = self.output_dir.parent / rep_path
  182. if rep_file.exists():
  183. H = load_H(model_name, dataset_name,
  184. representations_dir=str(rep_file.parent))
  185. else:
  186. H = self.extract_hidden_states(model_name, texts)
  187. save_H(H, model_name, dataset_name,
  188. representations_dir=str(rep_file.parent))
  189. # 计算有效秩
  190. H_tensor = torch.tensor(H.numpy() if hasattr(H, "cpu") else H) if not isinstance(H, torch.Tensor) else H
  191. r_eff = compute_gram_spectrum(H_tensor)
  192. r_effs[model_name] = r_eff
  193. # 计算谱(用于 SPD)
  194. _, prob = compute_spectrum_array(H)
  195. spectra[model_name] = prob
  196. # 计算 RS_cross = 方差
  197. values = list(r_effs.values())
  198. rs_cross = float(np.var(values))
  199. std = float(np.std(values))
  200. range_val = float(max(values) - min(values)) if values else 0
  201. return {
  202. "rs_cross": rs_cross,
  203. "r_effs": r_effs,
  204. "std": std,
  205. "range": range_val,
  206. "spectra": spectra
  207. }
  208. def compute_spd_matrix(
  209. self,
  210. spectra_dict: Dict[str, np.ndarray]
  211. ) -> np.ndarray:
  212. """
  213. 计算谱 Platonic 距离矩阵
  214. Returns:
  215. SPD 矩阵 (n, n)
  216. """
  217. model_names = list(spectra_dict.keys())
  218. n = len(model_names)
  219. spd_matrix = np.zeros((n, n))
  220. for i in range(n):
  221. for j in range(i + 1, n):
  222. p_i = spectra_dict[model_names[i]]
  223. p_j = spectra_dict[model_names[j]]
  224. # 对齐长度
  225. max_len = max(len(p_i), len(p_j))
  226. p_i_pad = np.pad(p_i, (0, max_len - len(p_i)))
  227. p_j_pad = np.pad(p_j, (0, max_len - len(p_j)))
  228. d = wasserstein1_distance(p_i_pad, p_j_pad)
  229. spd_matrix[i, j] = d
  230. spd_matrix[j, i] = d
  231. return spd_matrix, model_names
  232. def compute_layer_convergence_profile(
  233. self,
  234. dataset_name: str,
  235. model_names: List[str],
  236. n_layers: int,
  237. sample_layers: int = 10
  238. ) -> np.ndarray:
  239. """
  240. 逐层谱收敛轮廓 (LCP)
  241. Returns:
  242. RS_cross 值数组 (sample_layers,)
  243. """
  244. texts = self.load_texts(dataset_name)
  245. layer_indices = np.linspace(0, n_layers - 1, sample_layers, dtype=int)
  246. lcp = []
  247. for layer_idx in tqdm(layer_indices, desc="LCP"):
  248. result = self.compute_rs_cross(
  249. dataset_name, model_names, texts,
  250. layer=int(layer_idx)
  251. )
  252. lcp.append(result["rs_cross"])
  253. return np.array(lcp), layer_indices
  254. def run_experiment_e1(self) -> ExperimentResult:
  255. """运行 E1 基础谱收敛实验"""
  256. print("=" * 60)
  257. print("运行 E1: 基础谱收敛验证")
  258. print("=" * 60)
  259. def run_experiment_e2(self) -> Dict[str, Any]:
  260. """
  261. 运行 E2: 跨域谱分层验证
  262. 目的:验证不同领域的谱收敛程度不同
  263. 假设:形式化领域(代码/数学)收敛更好,开放领域(指令/创作)收敛更差
  264. """
  265. print("=" * 60)
  266. print("运行 E2: 跨域谱分层验证")
  267. print("=" * 60)
  268. # 领域分类(按形式化程度)
  269. domain_categories = {
  270. "highly_formal": ["humaneval", "code"], # 高度形式化:代码
  271. "formal": ["gsm8k", "math"], # 形式化:数学/推理
  272. "semi_formal": ["flores200", "translation"], # 半形式化:翻译
  273. "open": ["alpaca", "instruction"], # 开放:指令跟随
  274. }
  275. # 加载 E1 结果(如果已运行)
  276. e1_result_file = self.output_dir / "e1_result.json"
  277. if e1_result_file.exists():
  278. print(f"从 E1 结果加载数据:{e1_result_file}")
  279. with open(e1_result_file) as f:
  280. e1_result = json.load(f)
  281. rs_cross_all = e1_result.get("rs_cross", {})
  282. r_effs_all = e1_result.get("r_effs", {})
  283. else:
  284. print("未找到 E1 结果,重新计算...")
  285. # 需要先运行 E1
  286. self.run_experiment_e1()
  287. return self.run_experiment_e2()
  288. # 按类别聚合 RS_cross
  289. category_rs = {}
  290. category_domains = {}
  291. for category, domains in domain_categories.items():
  292. matching_domains = [d for d in domains if d in rs_cross_all]
  293. if matching_domains:
  294. rs_values = [rs_cross_all[d] for d in matching_domains]
  295. category_rs[category] = {
  296. "mean": float(np.mean(rs_values)),
  297. "std": float(np.std(rs_values)) if len(rs_values) > 1 else 0,
  298. "values": {d: rs_cross_all[d] for d in matching_domains},
  299. "domains": matching_domains
  300. }
  301. category_domains[category] = matching_domains
  302. # 排序:按 RS_cross 从小到大(收敛程度从高到低)
  303. sorted_categories = sorted(
  304. category_rs.items(),
  305. key=lambda x: x[1]["mean"]
  306. )
  307. # 计算领域间差异
  308. formal_domains = category_rs.get("highly_formal", {}).get("domains", []) + \
  309. category_rs.get("formal", {}).get("domains", [])
  310. open_domains = category_rs.get("open", {}).get("domains", [])
  311. formal_rs = [rs_cross_all[d] for d in formal_domains if d in rs_cross_all]
  312. open_rs = [rs_cross_all[d] for d in open_domains if d in rs_cross_all]
  313. comparison = {
  314. "formal_mean": float(np.mean(formal_rs)) if formal_rs else None,
  315. "open_mean": float(np.mean(open_rs)) if open_rs else None,
  316. "difference": None,
  317. "ratio": None
  318. }
  319. if comparison["formal_mean"] and comparison["open_mean"]:
  320. comparison["difference"] = comparison["open_mean"] - comparison["formal_mean"]
  321. comparison["ratio"] = comparison["open_mean"] / comparison["formal_mean"]
  322. result = {
  323. "timestamp": datetime.now().isoformat(),
  324. "category_rs_cross": category_rs,
  325. "sorted_by_convergence": [
  326. {"category": cat, "mean_rs_cross": data["mean"], "domains": data["domains"]}
  327. for cat, data in sorted_categories
  328. ],
  329. "formal_vs_open_comparison": comparison,
  330. "hypothesis_support": self._evaluate_hypothesis(comparison),
  331. "raw_rs_cross": rs_cross_all
  332. }
  333. # 保存结果
  334. self._save_e2_result(result)
  335. return result
  336. def _evaluate_hypothesis(self, comparison: Dict) -> Dict[str, Any]:
  337. """评估假设是否得到支持"""
  338. if not comparison["formal_mean"] or not comparison["open_mean"]:
  339. return {"supported": False, "reason": "数据不足"}
  340. # 假设:形式化领域 RS_cross < 开放领域 RS_cross
  341. supported = comparison["formal_mean"] < comparison["open_mean"]
  342. effect_size = comparison["ratio"]
  343. # 效应量判断
  344. if effect_size is None:
  345. strength = "unknown"
  346. elif effect_size > 10:
  347. strength = "very_strong"
  348. elif effect_size > 5:
  349. strength = "strong"
  350. elif effect_size > 2:
  351. strength = "moderate"
  352. else:
  353. strength = "weak"
  354. return {
  355. "supported": supported,
  356. "formal_mean": comparison["formal_mean"],
  357. "open_mean": comparison["open_mean"],
  358. "ratio_open_to_formal": effect_size,
  359. "effect_strength": strength,
  360. "interpretation": "形式化领域谱收敛显著优于开放领域" if supported else "假设未获支持"
  361. }
  362. def _save_e2_result(self, result: Dict):
  363. """保存 E2 结果"""
  364. result_file = self.output_dir / "e2_result.json"
  365. with open(result_file, "w") as f:
  366. json.dump(result, f, indent=2)
  367. print(f"\nE2 结果已保存到:{result_file}")
  368. # 生成摘要报告
  369. self._generate_e2_summary(result)
  370. def _generate_e2_summary(self, result: Dict):
  371. """生成 E2 摘要报告"""
  372. summary = [
  373. "# E2 实验摘要:跨域谱分层验证",
  374. "",
  375. f"实验时间:{result['timestamp']}",
  376. "",
  377. "## 假设",
  378. "形式化领域(代码/数学)的谱收敛程度优于开放领域(指令/创作)",
  379. "",
  380. "## 按类别 RS_cross(越小越收敛)",
  381. ""
  382. ]
  383. summary.append("| 类别 | 平均 RS_cross | 包含领域 |")
  384. summary.append("|------|--------------|----------|")
  385. for cat, data in result["category_rs_cross"].items():
  386. domains = ", ".join(data["domains"])
  387. summary.append(f"| {cat} | {data['mean']:.4f} | {domains} |")
  388. summary.append("")
  389. summary.append("## 形式化 vs 开放领域对比")
  390. comp = result["formal_vs_open_comparison"]
  391. if comp["formal_mean"]:
  392. summary.append(f"- 形式化领域平均 RS_cross: {comp['formal_mean']:.4f}")
  393. summary.append(f"- 开放领域平均 RS_cross: {comp['open_mean']:.4f}")
  394. summary.append(f"- 差异:{comp['difference']:.4f}")
  395. summary.append(f"- 比率(开放/形式化):{comp['ratio']:.2f}x")
  396. summary.append("")
  397. summary.append("## 假设验证")
  398. hyp = result["hypothesis_support"]
  399. status = "✅ 支持" if hyp["supported"] else "❌ 不支持"
  400. summary.append(f"状态:{status}")
  401. summary.append(f"效应强度:{hyp.get('effect_strength', 'unknown')}")
  402. summary.append(f"解释:{hyp['interpretation']}")
  403. summary.append("")
  404. summary.append("## 原始数据")
  405. summary.append("| 领域 | RS_cross |")
  406. summary.append("|------|----------|")
  407. for domain, rs in sorted(result["raw_rs_cross"].items(), key=lambda x: x[1]):
  408. summary.append(f"| {domain} | {rs:.4f} |")
  409. summary_file = self.output_dir / "e2_summary.md"
  410. with open(summary_file, "w") as f:
  411. f.write("\n".join(summary))
  412. print(f"摘要报告已保存到:{summary_file}")
  413. config_dict = asdict(self.config)
  414. result = ExperimentResult(
  415. timestamp=datetime.now().isoformat(),
  416. config=config_dict,
  417. r_effs={},
  418. rs_cross={},
  419. spd_matrices={},
  420. spectra={}
  421. )
  422. # 对每个数据集计算 RS_cross
  423. for dataset_name in self.config.datasets:
  424. print(f"\n[数据集] {dataset_name}")
  425. rs_result = self.compute_rs_cross(
  426. dataset_name,
  427. self.config.models
  428. )
  429. result.r_effs[dataset_name] = rs_result["r_effs"]
  430. result.rs_cross[dataset_name] = rs_result["rs_cross"]
  431. # 计算 SPD 矩阵
  432. spd_matrix, model_names = self.compute_spd_matrix(
  433. rs_result["spectra"]
  434. )
  435. result.spd_matrices[dataset_name] = spd_matrix.tolist()
  436. result.spectra[dataset_name] = {
  437. m: s.tolist() for m, s in
  438. zip(model_names, rs_result["spectra"].values())
  439. }
  440. print(f" RS_cross = {rs_result['rs_cross']:.4f}")
  441. print(f" 模型 r_eff 范围:[{min(rs_result['r_effs'].values()):.2f}, "
  442. f"{max(rs_result['r_effs'].values()):.2f}]")
  443. # 保存结果
  444. self._save_result(result)
  445. return result
  446. def run_experiment_lcp(
  447. self,
  448. dataset_name: str,
  449. n_layers: int,
  450. sample_layers: int = 10
  451. ) -> Dict[str, Any]:
  452. """运行逐层谱收敛轮廓实验"""
  453. print("=" * 60)
  454. print(f"运行 LCP: 逐层谱收敛分析 [{dataset_name}]")
  455. print("=" * 60)
  456. lcp, layer_indices = self.compute_layer_convergence_profile(
  457. dataset_name,
  458. self.config.models,
  459. n_layers,
  460. sample_layers
  461. )
  462. result = {
  463. "timestamp": datetime.now().isoformat(),
  464. "dataset": dataset_name,
  465. "models": self.config.models,
  466. "layer_indices": layer_indices.tolist(),
  467. "lcp_values": lcp.tolist(),
  468. "n_layers": n_layers
  469. }
  470. # 保存结果
  471. result_file = self.output_dir / f"lcp_{dataset_name}.json"
  472. with open(result_file, "w") as f:
  473. json.dump(result, f, indent=2)
  474. print(f"\nLCP 结果已保存到:{result_file}")
  475. print(f"RS_cross 从 {lcp[0]:.4f} (浅层) 到 {lcp[-1]:.4f} (深层)")
  476. return result
  477. def _save_result(self, result: ExperimentResult):
  478. """保存实验结果"""
  479. result_dict = {
  480. "timestamp": result.timestamp,
  481. "config": result.config,
  482. "r_effs": result.r_effs,
  483. "rs_cross": result.rs_cross,
  484. "spd_matrices": result.spd_matrices,
  485. }
  486. result_file = self.output_dir / "e1_result.json"
  487. with open(result_file, "w") as f:
  488. json.dump(result_dict, f, indent=2)
  489. print(f"\nE1 结果已保存到:{result_file}")
  490. # 生成摘要报告
  491. self._generate_summary(result_dict)
  492. def _generate_summary(self, result: Dict):
  493. """生成摘要报告"""
  494. summary = ["# E1 实验摘要", ""]
  495. summary.append("## 实验配置")
  496. summary.append(f"- 时间:{result['timestamp']}")
  497. summary.append(f"- 模型数:{len(result['config']['models'])}")
  498. summary.append(f"- 数据集数:{len(result['config']['datasets'])}")
  499. summary.append("")
  500. summary.append("## RS_cross 结果")
  501. summary.append("| 数据集 | RS_cross |")
  502. summary.append("|--------|----------|")
  503. for ds, rs in result["rs_cross"].items():
  504. summary.append(f"| {ds} | {rs:.4f} |")
  505. summary.append("")
  506. summary.append("## 各模型 r_eff")
  507. for ds, r_effs in result["r_effs"].items():
  508. summary.append(f"### {ds}")
  509. for model, r_eff in r_effs.items():
  510. summary.append(f"- {model}: {r_eff:.2f}")
  511. summary.append("")
  512. summary_file = self.output_dir / "e1_summary.md"
  513. with open(summary_file, "w") as f:
  514. f.write("\n".join(summary))
  515. print(f"摘要报告已保存到:{summary_file}")
  516. def main():
  517. import argparse
  518. parser = argparse.ArgumentParser(description="跨模型谱收敛实验")
  519. parser.add_argument("--experiment", type=str,
  520. choices=["E1", "E2", "LCP"], default="E1",
  521. help="实验类型")
  522. parser.add_argument("--output-dir", type=str,
  523. default="experiments/output/cross_model",
  524. help="输出目录")
  525. parser.add_argument("--dataset", type=str,
  526. default="gsm8k",
  527. help="数据集名称 (LCP 实验用)")
  528. parser.add_argument("--layers", type=int, default=32,
  529. help="模型层数 (LCP 实验用)")
  530. parser.add_argument("--sample-layers", type=int, default=10,
  531. help="采样层数 (LCP 实验用)")
  532. args = parser.parse_args()
  533. # 实验配置
  534. config = ExperimentConfig(
  535. models=[
  536. "llama3.2-3b-instruct",
  537. "Mistral-7B-v0.3",
  538. "llama3-8b",
  539. "Qwen2.5-7B-Instruct",
  540. "gemma-2-9b-it"
  541. ],
  542. model_paths={
  543. "llama3.2-3b-instruct": "model/weights/llama3.2-3b-instruct",
  544. "Mistral-7B-v0.3": "model/weights/Mistral-7B-v0.3",
  545. "llama3-8b": "model/weights/llama3-8b",
  546. "Qwen2.5-7B-Instruct": "model/weights/Qwen2.5-7B-Instruct",
  547. "gemma-2-9b-it": "model/weights/gemma-2-9b-it"
  548. },
  549. datasets=["gsm8k", "math", "humaneval", "alpaca"],
  550. output_dir=args.output_dir,
  551. batch_size=8,
  552. max_length=512,
  553. pooling="mean"
  554. )
  555. analyzer = CrossModelConvergence(config)
  556. if args.experiment == "E1":
  557. analyzer.run_experiment_e1()
  558. elif args.experiment == "E2":
  559. analyzer.run_experiment_e2()
  560. elif args.experiment == "LCP":
  561. analyzer.run_experiment_lcp(
  562. args.dataset,
  563. args.layers,
  564. args.sample_layers
  565. )
  566. if __name__ == "__main__":
  567. main()