AQIT 0.1.0
Loading...
Searching...
No Matches
attention_check.py
Go to the documentation of this file.
1# Copyright (c) 2025-present Aquin Labs Private Limited. All Rights Reserved.
2"""`aquin check attention --check` — save JSON + diagram to the current working directory."""
3
4from __future__ import annotations
5
6import json
7from datetime import datetime, timezone
8from pathlib import Path
9from typing import Any
10
11_JSON_NAME = "attention-check.json"
12_PNG_NAME = "attention-check.png"
13
14
16 result: dict[str, Any],
17 *,
18 tool_name: str | None,
19 cwd: str | Path,
20) -> tuple[Path, Path]:
21 cwd = Path(cwd)
22 json_path = cwd / _JSON_NAME
23 png_path = cwd / _PNG_NAME
24
25 payload = {
26 "saved_at": datetime.now(timezone.utc).isoformat(),
27 "tool": tool_name,
28 **result,
29 }
30 json_path.write_text(json.dumps(payload, indent=2, default=str), encoding="utf-8")
31 _plot_attention_check(result, tool_name, png_path)
32 return json_path, png_path
33
34
35
37 result: dict[str, Any],
38 tool_name: str | None,
39 png_path: Path,
40) -> None:
41 import matplotlib
42
43 matplotlib.use("Agg")
44 import matplotlib.pyplot as plt
45 import numpy as np
46
47 if result.get("error"):
48 fig, ax = plt.subplots(figsize=(6, 2))
49 ax.axis("off")
50 ax.text(0.5, 0.5, f"Error: {result['error']}", ha="center", va="center", wrap=True)
51 fig.savefig(png_path, dpi=140, bbox_inches="tight", facecolor="#0f1117")
52 plt.close(fig)
53 return
54
55 _ = tool_name
56 _plot_llm_attention(result, png_path, plt, np)
57
58
59def _plot_llm_attention(result: dict[str, Any], png_path: Path, plt: Any, np: Any) -> None:
60 n_layers = int(result.get("n_layers") or 0)
61 n_heads = int(result.get("n_heads") or 0)
62 heads = result.get("heads") or []
64 sink = np.zeros((max(n_layers, 1), max(n_heads, 1)))
65 induction = np.zeros_like(sink)
66 for row in heads:
67 layer = int(row.get("layer", 0))
68 head = int(row.get("head", 0))
69 if layer < sink.shape[0] and head < sink.shape[1]:
70 sink[layer, head] = float(row.get("sink_score") or 0)
71 induction[layer, head] = float(row.get("induction_score") or 0)
72
73 prompt = str(result.get("prompt") or "")[:72]
74 fig, axes = plt.subplots(1, 2, figsize=(11, 4.5), facecolor="#0f1117")
75 fig.suptitle(f"Attention routing — {prompt}", color="#e5e7eb", fontsize=11, y=1.02)
76
77 for ax, data, title in (
78 (axes[0], sink, "Sink score"),
79 (axes[1], induction, "Induction score"),
80 ):
81 im = ax.imshow(data, aspect="auto", cmap="viridis", origin="lower")
82 ax.set_xlabel("Head", color="#9ca3af", fontsize=9)
83 ax.set_ylabel("Layer", color="#9ca3af", fontsize=9)
84 ax.set_title(title, color="#e5e7eb", fontsize=10)
85 ax.tick_params(colors="#6b7280", labelsize=8)
86 fig.colorbar(im, ax=ax, fraction=0.046, pad=0.04)
87
88 fig.tight_layout()
89 fig.savefig(png_path, dpi=140, bbox_inches="tight", facecolor="#0f1117")
90 plt.close(fig)
91
92
93
94def _short_token(tok: str, limit: int = 10) -> str:
95 t = tok.replace("Ġ", " ").replace("##", "")
96 if len(t) <= limit:
97 return t
98 return t[: limit - 1] + "…"
None _plot_attention_check(dict[str, Any] result, str|None tool_name, Path png_path)
None _plot_llm_attention(dict[str, Any] result, Path png_path, Any plt, Any np)
str _short_token(str tok, int limit=10)
tuple[Path, Path] write_attention_check(dict[str, Any] result, *, str|None tool_name, str|Path cwd)