35 return project_residual_to_logits(model, resid)
39 if hasattr(model.tokenizer,
"chat_template")
and model.tokenizer.chat_template:
40 messages = [{
"role":
"user",
"content": prompt}]
41 return model.tokenizer.apply_chat_template(
69 noise_scale: float = 3.0,
70 n_noise_runs: int = 10,
72 m = load_model(model_id)
73 tokens = m.to_tokens(prompt)
74 target_id = m.to_tokens(target_token, prepend_bos=
False)[0, 0].item()
77 clean_logits, clean_cache = m.run_with_cache(tokens)
78 baseline_prob = torch.softmax(clean_logits[0, -1], dim=-1)[target_id].item()
81 for _
in range(n_noise_runs):
84 cl = m.run_with_hooks(tokens, fwd_hooks=[(
"hook_embed",
lambda v, hook=
None: ne.to(v.device))])
85 corrupted_prob += torch.softmax(cl[0, -1], dim=-1)[target_id].item()
86 corrupted_prob /= n_noise_runs
87 corruption_effect = baseline_prob - corrupted_prob
90 for layer
in range(m.cfg.n_layers):
92 for _
in range(n_noise_runs):
94 def make_hooks(ne_, li):
96 (
"hook_embed",
lambda v, hook=
None, n=ne_: n.to(v.device)),
97 (f
"blocks.{li}.hook_resid_post",
lambda v, hook=
None, li=li: (
99 (slice(
None), -1, slice(
None)),
100 clean_cache[f
"blocks.{li}.hook_resid_post"][:, -1, :].to(v.device)
104 with torch.no_grad():
105 pl = m.run_with_hooks(tokens, fwd_hooks=make_hooks(ne, layer))
106 patch_probs.append(torch.softmax(pl[0, -1], dim=-1)[target_id].item())
108 restored = sum(patch_probs) / len(patch_probs)
109 drop = round(max(restored - corrupted_prob, 0.0) / max(corruption_effect, 1e-6), 4)
112 "baseline_prob": round(baseline_prob, 4),
113 "corrupted_prob": round(corrupted_prob, 4),
114 "corruption_effect": round(corruption_effect, 4),
118 "patched_prob": round(restored, 4),
119 "attn_patched_prob": 0.0,
120 "mlp_patched_prob": 0.0,
124 return sorted(results, key=
lambda x: x[
"drop"], reverse=
True)
128 prompt, response, prompt_tokens, response_tokens,
129 sig_prompt_tis, sig_response_tis,
130 model_id: str =
"llama-3.2-1b",
131 noise_scale: float = 3.0,
132 n_noise_runs: int = 5,
134 m = load_model(model_id)
135 full_ctx = f
"{prompt}\n{response}"
136 tokens = m.to_tokens(full_ctx)
137 n_tokens = tokens.shape[1]
139 with torch.no_grad():
140 clean_logits = m(tokens)
142 target_ids, baseline_probs = {}, {}
143 for rti
in sig_response_tis:
144 tok_str = f
" {response_tokens[rti].strip()}"
146 tid = m.to_tokens(tok_str, prepend_bos=
False)[0, 0].item()
149 target_ids[rti] = tid
150 baseline_probs[rti] = torch.softmax(clean_logits[0, -1], dim=-1)[tid].item()
153 return {
"attributions": []}
155 prefix_len = m.to_tokens(prompt +
"\n", prepend_bos=
True).shape[1]
157 def get_token_pos(word_idx):
158 words = prompt.split()
159 if word_idx >= len(words):
161 char_pos = sum(len(w) + 1
for w
in words[:word_idx])
163 return m.to_tokens(prompt[:char_pos], prepend_bos=
True).shape[1] - 1
167 scores = {rti: {}
for rti
in target_ids}
168 for pti
in sig_prompt_tis:
169 tok_pos = get_token_pos(pti)
170 if tok_pos
is None or tok_pos >= n_tokens:
173 corrupted_probs = {rti: 0.0
for rti
in target_ids}
174 for _
in range(n_noise_runs):
176 with torch.no_grad():
177 logits = m.run_with_hooks(
179 fwd_hooks=[(
"hook_embed",
lambda v, hook=
None, n=ne: n.to(v.device))]
181 probs = torch.softmax(logits[0, -1], dim=-1)
182 for rti, tid
in target_ids.items():
183 corrupted_probs[rti] += probs[tid].item()
185 for rti
in target_ids:
186 corrupted_probs[rti] /= n_noise_runs
187 scores[rti][pti] = max(round(baseline_probs[rti] - corrupted_probs[rti], 4), 0.0)
190 for rti, tid
in target_ids.items():
192 mx = max(raw.values(), default=1e-6)
or 1e-6
193 prompt_scores = sorted([
196 "prompt_token": prompt_tokens[pti],
197 "score": round(raw.get(pti, 0.0) / mx, 4),
198 "raw_score": raw.get(pti, 0.0),
200 for pti
in sig_prompt_tis
201 ], key=
lambda x: x[
"score"], reverse=
True)
202 attributions.append({
204 "response_token": response_tokens[rti],
205 "baseline_prob": round(baseline_probs[rti], 4),
206 "prompt_scores": prompt_scores,
210 return {
"attributions": attributions}
215 model_id: str =
"llama-3.2-1b",
218 m = load_model(model_id)
219 tokens = m.to_tokens(prompt)
220 with torch.no_grad():
221 _, cache = m.run_with_cache(tokens)
224 for layer
in range(m.cfg.n_layers):
225 resid = cache[f
"blocks.{layer}.hook_resid_post"][0, -1, :]
226 resid_normed = m.ln_final(resid.unsqueeze(0).unsqueeze(0))[0, 0, :]
228 probs = torch.softmax(logits, dim=-1)
229 topk = probs.topk(top_k)
233 {
"token": m.to_string([tid.item()]),
"prob": round(p.item(), 4)}
234 for tid, p
in zip(topk.indices, topk.values)
245 mid = resolve_model_id(model_id)
256 return embed.weight.device
257 dev = getattr(model,
"device",
None)
259 return dev
if isinstance(dev, torch.device)
else torch.device(str(dev))
260 return torch.device(DEVICE)
264 prompt_len = int(input_ids.shape[-1])
265 new_tokens = output_ids[0, prompt_len:]
266 return model.tokenizer.decode(new_tokens.tolist(), skip_special_tokens=
True).strip()
273 temperature: float = 0.7,
274 model: Any |
None =
None,
279 input_ids = m.tokenizer(formatted, return_tensors=
"pt").input_ids.to(device)
281 if hasattr(m,
"hf_model"):
283 if tok.pad_token_id
is None and tok.eos_token_id
is not None:
284 tok.pad_token_id = tok.eos_token_id
285 pad_id = tok.pad_token_id
if tok.pad_token_id
is not None else tok.eos_token_id
286 gen_kwargs: dict[str, Any] = {
287 "max_new_tokens": max_new_tokens,
288 "do_sample": temperature > 0,
290 if pad_id
is not None:
291 gen_kwargs[
"pad_token_id"] = pad_id
293 gen_kwargs[
"temperature"] = temperature
294 with torch.no_grad():
295 output_ids = m.hf_model.generate(input_ids, **gen_kwargs)
298 eos_id = getattr(m.tokenizer,
"eos_token_id",
None)
299 generated: list[int] = []
301 with torch.no_grad():
303 for _
in range(max_new_tokens):
307 next_id = int(row.argmax().item())
309 probs = torch.softmax(row / temperature, dim=-1)
310 next_id = int(torch.multinomial(probs, 1).item())
311 if eos_id
is not None and next_id == eos_id:
313 generated.append(next_id)
315 [cur, torch.tensor([[next_id]], device=device, dtype=cur.dtype)],
319 return m.tokenizer.decode(generated, skip_special_tokens=
True).strip()
324 model_id: str =
"llama-3.2-1b",
325 max_new_tokens: int = 200,
326 temperature: float = 0.7,
328 m = load_model(model_id)
330 input_ids = m.tokenizer(formatted, return_tensors=
"pt").input_ids.to(DEVICE)
332 with torch.no_grad():
334 for _
in range(max_new_tokens):
336 next_logits = logits[0, -1] / max(temperature, 1e-6)
337 probs = torch.softmax(next_logits, dim=-1)
338 next_id = int(torch.multinomial(probs, 1).item())
339 if next_id == m.tokenizer.eos_token_id:
341 tok_str = m.tokenizer.decode([next_id], skip_special_tokens=
True)
343 cur = torch.cat([cur, torch.tensor([[next_id]], device=DEVICE)], dim=1)
run_prompt_attribution(prompt, response, prompt_tokens, response_tokens, sig_prompt_tis, sig_response_tis, str model_id="llama-3.2-1b", float noise_scale=3.0, int n_noise_runs=5)