eyad-silx commited on
Commit
e653712
·
verified ·
1 Parent(s): e50bd42

push artifacts/scripts/qat_norms.py

Browse files
Files changed (1) hide show
  1. artifacts/scripts/qat_norms.py +119 -0
artifacts/scripts/qat_norms.py ADDED
@@ -0,0 +1,119 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """End-to-end norm tuning on the surrogate: every RMSNorm weight (F32, free in the GGUF) trained
2
+ against teacher trajectories with the eval's metric (KL + hidden-state distance), the same loss
3
+ the eval uses. Writes a new GGUF.
4
+
5
+ .venv/bin/python qat_norms.py --data /root/train_samples.json --out /root/models/chal-norms
6
+ """
7
+ import argparse
8
+ import json
9
+ import shutil
10
+ import sys
11
+ from pathlib import Path
12
+
13
+ sys.path.insert(0, "/root/ingot/src")
14
+ import numpy as np
15
+ import torch
16
+ from transformers import AutoModelForCausalLM
17
+
18
+ from common.gguf import read_header
19
+ from common.gguf.types import TYPES
20
+ from model_dedup.gguf_checkpoint import GgufCheckpoint
21
+
22
+ ap = argparse.ArgumentParser()
23
+ ap.add_argument("--teacher", default="/root/models/teacher")
24
+ ap.add_argument("--king", default="/root/models/king-ix")
25
+ ap.add_argument("--data", default="/root/train_samples.json")
26
+ ap.add_argument("--out", default="/root/models/chal-norms")
27
+ ap.add_argument("--steps", type=int, default=15)
28
+ ap.add_argument("--lr", type=float, default=3e-3)
29
+ ap.add_argument("--alpha", type=float, default=1.0)
30
+ ap.add_argument("--max-tokens", type=int, default=2200)
31
+ args = ap.parse_args()
32
+
33
+ ck = GgufCheckpoint(args.king, "cpu")
34
+ g = ck.g
35
+ records = json.loads(Path(args.data).read_text())
36
+ print("samples:", len(records))
37
+
38
+ model = AutoModelForCausalLM.from_pretrained(args.teacher, torch_dtype=torch.bfloat16, device_map="cuda")
39
+ model.eval()
40
+ model.gradient_checkpointing_enable()
41
+ sd_king = torch.load("/dev/shm/king_hf.pt", map_location="cpu", weights_only=True)
42
+ model.load_state_dict(sd_king, strict=True)
43
+
44
+ from eval_service import metrics # noqa: E402
45
+ from eval_service.config import LAYERS # noqa: E402
46
+
47
+ heads = metrics.heads({"teacher": Path(args.teacher), "king": Path(args.king)}, ["cuda:0"])["cuda:0"]
48
+ head_t, head_k = heads["teacher"], heads["king"]
49
+
50
+ params = []
51
+ for name, p in model.named_parameters():
52
+ p.requires_grad_(False)
53
+ if any(k in name for k in ("layernorm.weight", "norm.weight")):
54
+ p.requires_grad_(True)
55
+ params.append(p)
56
+ print("trainable norms:", len(params))
57
+
58
+ opt = torch.optim.Adam(params, lr=args.lr)
59
+ for step in range(args.steps):
60
+ torch.cuda.empty_cache()
61
+ total, n = 0.0, 0
62
+ for rec in records:
63
+ tokens = rec["prompt"] + rec["answer"]
64
+ if len(tokens) > args.max_tokens:
65
+ continue
66
+ first = len(rec["prompt"]) - 1
67
+ ids = torch.tensor([tokens], device="cuda")
68
+ out = model(input_ids=ids, output_hidden_states=True, use_cache=False)
69
+ h_k = torch.stack([out.hidden_states[l][0, first:].float() for l in LAYERS], 1)
70
+ st = metrics.load_states(rec["states"], tokens[:-1], first).float().to("cuda")
71
+ m = min(h_k.shape[0], st.shape[0])
72
+ h_k, st = h_k[:m], st[:m]
73
+ lp_t = head_t.logprobs(st[:, -1])
74
+ lp_k = head_k.logprobs(h_k[:, -1])
75
+ kl = (lp_t.exp() * (lp_t - lp_k)).sum(-1).mean()
76
+ a, b = st[1:], h_k[1:]
77
+ dist = ((b - a).norm(dim=-1) / a.norm(dim=-1)).mean()
78
+ loss = kl + args.alpha * dist
79
+ opt.zero_grad()
80
+ loss.backward()
81
+ torch.nn.utils.clip_grad_norm_(params, 1.0)
82
+ opt.step()
83
+ total += loss.item()
84
+ n += 1
85
+ del out, h_k, st, lp_t, lp_k, ids, loss
86
+ print(f"step {step}: loss {total / n:.5f} over {n} samples", flush=True)
87
+
88
+ # ---- write the norms back (attn/post/output norms stored as hf + 1; ssm_norm as-is)
89
+ out_dir = Path(args.out)
90
+ out_dir.mkdir(parents=True, exist_ok=True)
91
+ dst = out_dir / "chal-norms.gguf"
92
+ shutil.copy(Path(args.king) / "Ingot-IX-27B-Q2.gguf", dst)
93
+
94
+ def write_tensor(tname, values):
95
+ t = g.tensors[tname]
96
+ size = int(np.prod(t.shape)) * 4
97
+ raw = np.memmap(dst, np.uint8, "r+", g.data_start + t.offset, (size,))
98
+ raw.view("<f4")[:] = values.astype(np.float32).ravel()
99
+
100
+ n = int(g.kv["qwen35.block_count"].value)
101
+ with torch.no_grad():
102
+ for il in range(n):
103
+ for gguf_kind, hf_kind, plus1 in (
104
+ ("attn_norm", "input_layernorm", True),
105
+ ("post_attention_norm", "post_attention_layernorm", True),
106
+ ("ssm_norm", "linear_attn.norm", False),
107
+ ):
108
+ if f"blk.{il}.{gguf_kind}.weight" not in g.tensors:
109
+ continue
110
+ hf = f"model.layers.{il}.{hf_kind}.weight"
111
+ mod = model
112
+ for part in hf.split(".")[:-1]:
113
+ mod = getattr(mod, part)
114
+ w = mod.weight.detach().cpu().float()
115
+ write_tensor(f"blk.{il}.{gguf_kind}.weight", w.numpy() + (1.0 if plus1 else 0.0))
116
+ mod = model.model
117
+ w = mod.norm.weight.detach().cpu().float()
118
+ write_tensor("output_norm.weight", w.numpy() + 1.0)
119
+ print("saved", dst)