Naphula commited on
Commit
ae1ef82
·
verified ·
1 Parent(s): 439bda2

Upload merge_composition_audit.py

Browse files
Files changed (1) hide show
  1. merge_composition_audit.py +94 -0
merge_composition_audit.py ADDED
@@ -0,0 +1,94 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import torch
3
+ from safetensors.torch import safe_open
4
+ import yaml
5
+
6
+ # --- CONFIGURATION ---
7
+ YAML_PATH = "B:/24B/karcher_stock_24b/mergekit_config.yml"
8
+ FINAL_MERGE_DIR = "B:/24B/karcher_stock_24b"
9
+ LAYERS_TO_SCAN =[
10
+ "model.layers.10.mlp.down_proj.weight" # "model.language_model.layers.10.mlp.gate_proj.weight"
11
+ ]
12
+ # ---------------------
13
+
14
+ def load_tensor(model_dir, tensor_name):
15
+ """Finds and loads a tensor from a directory of safetensors."""
16
+ for file in os.listdir(model_dir):
17
+ if file.endswith(".safetensors"):
18
+ filepath = os.path.join(model_dir, file)
19
+ with safe_open(filepath, framework="pt", device="cpu") as f:
20
+ if tensor_name in f.keys():
21
+ return f.get_tensor(tensor_name).float()
22
+ raise ValueError(f"Tensor {tensor_name} not found in {model_dir}")
23
+
24
+ def main():
25
+ print("Loading YAML config...")
26
+ with open(YAML_PATH, 'r') as f:
27
+ config = yaml.safe_load(f)
28
+
29
+ base_path = config['base_model']
30
+ donor_paths = [m['model'] for m in config['models']]
31
+
32
+ print(f"\nScanning {len(LAYERS_TO_SCAN)} MLP layers for structural influence...\n")
33
+
34
+ for layer in LAYERS_TO_SCAN:
35
+ print(f"--- Layer: {layer} ---")
36
+ try:
37
+ base_w = load_tensor(base_path, layer)
38
+ final_w = load_tensor(FINAL_MERGE_DIR, layer)
39
+
40
+ # Use float64 for norm calculations to prevent precision loss in energy ratios
41
+ final_norm = torch.norm(final_w.double()).item()
42
+ final_tv = final_w - base_w
43
+ final_tv_norm = torch.norm(final_tv.double()).item()
44
+
45
+ results = []
46
+
47
+ # 1. Collect raw magnitudes of the components
48
+ base_norm = torch.norm(base_w.double()).item()
49
+ donor_tvs = []
50
+ for donor in donor_paths:
51
+ dw = load_tensor(donor, layer)
52
+ donor_tvs.append(dw - base_w)
53
+
54
+ donor_tv_norms = [torch.norm(dtv.double()).item() for dtv in donor_tvs]
55
+
56
+ # 2. Calculate Total Component Energy (Base + all Donor Deltas)
57
+ total_component_energy = base_norm + sum(donor_tv_norms)
58
+
59
+ results = []
60
+ # 3. Assign Share to Base Model
61
+ base_share = (base_norm / total_component_energy) * 100
62
+ results.append(("(Base Model)", -1.0, 0.0, base_share))
63
+
64
+ # 4. Assign Share to Donors
65
+ for i, donor in enumerate(donor_paths):
66
+ donor_tv = donor_tvs[i]
67
+
68
+ cos_sim = torch.nn.functional.cosine_similarity(
69
+ final_tv.flatten(), donor_tv.flatten(), dim=0
70
+ ).item()
71
+
72
+ rel_mag = (torch.norm(donor_tv.double()).item() / final_tv_norm)
73
+
74
+ # Compositional Share: How much of the total energy sum belongs to this donor's delta
75
+ comp_share = (donor_tv_norms[i] / total_component_energy) * 100
76
+
77
+ name = donor.split("/")[-1][:50]
78
+ results.append((name, cos_sim, rel_mag, comp_share))
79
+
80
+ # Sort by highest similarity (Donors first, Base at the very bottom)
81
+ results.sort(key=lambda x: x[1], reverse=True)
82
+
83
+ print(f"{'Model Name':<55} | {'Alignment {Cos}':<12} | {'Rel Mag (TV)':<12} | {'Merge Composition'}")
84
+ print("-" * 105)
85
+ for name, sim, mag, energy in results:
86
+ sim_str = f"{sim:12.4f}" if sim >= 0 else " N/A "
87
+ mag_str = f"{mag:11.2f}x" if mag > 0 else " N/A "
88
+ print(f"{name:<55} | {sim_str} | {mag_str} | {energy:>13.2f}%")
89
+
90
+ except Exception as e:
91
+ print(f"Skipping layer due to error: {e}")
92
+
93
+ if __name__ == "__main__":
94
+ main()