Spaces:
Running
Running
Upload arcee_fusion_salience_scanner.py
Browse files
arcee_fusion_salience_scanner.py
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import torch
|
| 2 |
+
from safetensors import safe_open
|
| 3 |
+
import os
|
| 4 |
+
import re
|
| 5 |
+
from collections import defaultdict
|
| 6 |
+
|
| 7 |
+
# --- CONFIGURATION ---
|
| 8 |
+
base_model_path = r'B:\12B\models--mistralai--Mistral-Nemo-Instruct-2407'
|
| 9 |
+
merged_model_path = r'C:\Quanter\model_cache\EldritchLabs__DeepWater-Pleroma-12B-v1'
|
| 10 |
+
# ---------------------
|
| 11 |
+
|
| 12 |
+
def get_tensor_map(path):
|
| 13 |
+
tensor_map = {}
|
| 14 |
+
files = [f for f in os.listdir(path) if f.endswith('.safetensors')]
|
| 15 |
+
for f in files:
|
| 16 |
+
full_path = os.path.join(path, f)
|
| 17 |
+
with safe_open(full_path, framework="pt") as st:
|
| 18 |
+
for k in st.keys():
|
| 19 |
+
tensor_map[k] = full_path
|
| 20 |
+
return tensor_map
|
| 21 |
+
|
| 22 |
+
print("π Indexing model shards...")
|
| 23 |
+
base_map = get_tensor_map(base_model_path)
|
| 24 |
+
merged_map = get_tensor_map(merged_model_path)
|
| 25 |
+
|
| 26 |
+
# Group results by layer
|
| 27 |
+
layer_stats = defaultdict(lambda: {"changed": 0, "total": 0})
|
| 28 |
+
|
| 29 |
+
print("π Scanning tensors and calculating saliency density...")
|
| 30 |
+
common_tensors = set(base_map.keys()) & set(merged_map.keys())
|
| 31 |
+
|
| 32 |
+
for k in sorted(common_tensors):
|
| 33 |
+
# Extract layer number from name (e.g., 'model.layers.5.self_attn...')
|
| 34 |
+
layer_match = re.search(r'\.layers\.(\0?(\d+))\.', k)
|
| 35 |
+
layer_id = int(layer_match.group(1)) if layer_match else "Non-Layer"
|
| 36 |
+
|
| 37 |
+
with safe_open(base_map[k], framework="pt") as b_st:
|
| 38 |
+
base_t = b_st.get_tensor(k)
|
| 39 |
+
with safe_open(merged_map[k], framework="pt") as m_st:
|
| 40 |
+
merged_t = m_st.get_tensor(k)
|
| 41 |
+
|
| 42 |
+
# Arcee Fusion logic: if weights are identical, they came from Base.
|
| 43 |
+
# If they are different, they are "New Info" from the fusion.
|
| 44 |
+
# We use a tiny atol to account for potential bf16/f16 casting jitters
|
| 45 |
+
changed_mask = ~torch.isclose(base_t, merged_t, rtol=1e-05, atol=1e-08)
|
| 46 |
+
|
| 47 |
+
layer_stats[layer_id]["changed"] += torch.count_nonzero(changed_mask).item()
|
| 48 |
+
layer_stats[layer_id]["total"] += merged_t.numel()
|
| 49 |
+
|
| 50 |
+
print("\n" + "="*60)
|
| 51 |
+
print(f"{'LAYER':<12} | {'NEW INFO %':<12} | {'VISUAL DENSITY (β = New, β = Base)'}")
|
| 52 |
+
print("="*60)
|
| 53 |
+
|
| 54 |
+
# Sort layers: Non-Layer first, then 0, 1, 2...
|
| 55 |
+
sorted_keys = sorted([k for k in layer_stats.keys() if isinstance(k, int)])
|
| 56 |
+
if "Non-Layer" in layer_stats:
|
| 57 |
+
sorted_keys = ["Non-Layer"] + sorted_keys
|
| 58 |
+
|
| 59 |
+
for lid in sorted_keys:
|
| 60 |
+
stats = layer_stats[lid]
|
| 61 |
+
percentage = (stats["changed"] / stats["total"]) * 100
|
| 62 |
+
|
| 63 |
+
# Create ASCII bar
|
| 64 |
+
bar_width = 30
|
| 65 |
+
filled = int((percentage / 100) * bar_width)
|
| 66 |
+
bar = "β" * filled + "β" * (bar_width - filled)
|
| 67 |
+
|
| 68 |
+
label = f"Layer {lid}" if isinstance(lid, int) else lid
|
| 69 |
+
print(f"{label:<12} | {percentage:>10.2f}% | {bar}")
|
| 70 |
+
|
| 71 |
+
print("="*60)
|
| 72 |
+
print("Analysis Complete.")
|