Spaces:
Running on Zero
Running on Zero
Commit ·
ba618db
1
Parent(s): 3a74c51
feat: add formla of Q, K matrix calculation
Browse files- app.py +42 -0
- src/plots.py +13 -10
app.py
CHANGED
|
@@ -77,6 +77,47 @@ Shaw relative attention (learned bias `b_{m-n}` on scores) is a **different**
|
|
| 77 |
mechanism and is not computed here.
|
| 78 |
"""
|
| 79 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 80 |
PLACEHOLDER = go.Figure().update_layout(
|
| 81 |
title="Run **Compute** on the Setup tab first",
|
| 82 |
template="plotly_white",
|
|
@@ -381,6 +422,7 @@ with gr.Blocks(title="RoPE Explorer") as demo:
|
|
| 381 |
head = gr.Slider(minimum=0, maximum=2, step=1, value=0, label="Head index (real models)")
|
| 382 |
|
| 383 |
with gr.Tab("Bulk changes"):
|
|
|
|
| 384 |
which = gr.Radio(["Q", "K"], value="Q", label="Tensor")
|
| 385 |
mod_2pi = gr.Checkbox(False, label="θ heatmap: wrap mod 2π")
|
| 386 |
bulk_main = gr.Plot(label="Before / after / delta")
|
|
|
|
| 77 |
mechanism and is not computed here.
|
| 78 |
"""
|
| 79 |
|
| 80 |
+
BULK_FORMULAS_MD = r"""
|
| 81 |
+
### What each Q/K matrix entry means
|
| 82 |
+
|
| 83 |
+
The selected heatmap entry is `X[h, k, j]`, where `X` is either **Q** or **K**, `h` is
|
| 84 |
+
the attention-head index, `k` is the token position, and `j` is the dimension within
|
| 85 |
+
that head.
|
| 86 |
+
|
| 87 |
+
For a real model, the first-layer projections calculate each entry as:
|
| 88 |
+
|
| 89 |
+
$$
|
| 90 |
+
Q^{before}_{k,h,j} = \left(H_k W_Q + b_Q\right)_{h d + j},\qquad
|
| 91 |
+
K^{before}_{k,h,j} = \left(H_k W_K + b_K\right)_{h d + j}
|
| 92 |
+
$$
|
| 93 |
+
|
| 94 |
+
Here `H_k` is the token's hidden vector, `d` is the dimension per head, and `W_Q`,
|
| 95 |
+
`W_K` are the model's query/key projection weights. In random-matrix mode, the initial
|
| 96 |
+
entries are sampled directly: `Q before ~ N(0, 1)` and `K before ~ N(0, 1)` using
|
| 97 |
+
independent seeds.
|
| 98 |
+
|
| 99 |
+
RoPE then transforms either matrix using
|
| 100 |
+
|
| 101 |
+
$$
|
| 102 |
+
\theta(k,i) = k\,base^{-2i/d}
|
| 103 |
+
$$
|
| 104 |
+
|
| 105 |
+
For the real-model Llama layout, the paired dimensions are `(i, i+d/2)`:
|
| 106 |
+
|
| 107 |
+
$$
|
| 108 |
+
X^{after}_{h,k,i} = X^{before}_{h,k,i}\cos\theta -
|
| 109 |
+
X^{before}_{h,k,i+d/2}\sin\theta
|
| 110 |
+
$$
|
| 111 |
+
$$
|
| 112 |
+
X^{after}_{h,k,i+d/2} = X^{before}_{h,k,i}\sin\theta +
|
| 113 |
+
X^{before}_{h,k,i+d/2}\cos\theta
|
| 114 |
+
$$
|
| 115 |
+
|
| 116 |
+
where `X` means either **Q** or **K**. Random-matrix mode uses adjacent pairs
|
| 117 |
+
`(2i, 2i+1)` instead. Therefore, **Before** contains projected or sampled values,
|
| 118 |
+
**After** contains rotated values, and **Delta = After − Before**.
|
| 119 |
+
"""
|
| 120 |
+
|
| 121 |
PLACEHOLDER = go.Figure().update_layout(
|
| 122 |
title="Run **Compute** on the Setup tab first",
|
| 123 |
template="plotly_white",
|
|
|
|
| 422 |
head = gr.Slider(minimum=0, maximum=2, step=1, value=0, label="Head index (real models)")
|
| 423 |
|
| 424 |
with gr.Tab("Bulk changes"):
|
| 425 |
+
gr.Markdown(BULK_FORMULAS_MD)
|
| 426 |
which = gr.Radio(["Q", "K"], value="Q", label="Tensor")
|
| 427 |
mod_2pi = gr.Checkbox(False, label="θ heatmap: wrap mod 2π")
|
| 428 |
bulk_main = gr.Plot(label="Before / after / delta")
|
src/plots.py
CHANGED
|
@@ -59,13 +59,16 @@ def bulk_before_after_delta(before: np.ndarray, after: np.ndarray, tokens=None)
|
|
| 59 |
go.Heatmap(
|
| 60 |
z=mat,
|
| 61 |
showscale=(i == 3),
|
| 62 |
-
|
|
|
|
| 63 |
),
|
| 64 |
row=1,
|
| 65 |
col=i,
|
| 66 |
)
|
|
|
|
|
|
|
| 67 |
fig.update_yaxes(autorange="reversed", row=1, col=i)
|
| 68 |
-
fig.update_layout(template="plotly_white", height=
|
| 69 |
return fig
|
| 70 |
|
| 71 |
|
|
@@ -78,10 +81,10 @@ def norms_and_cosine(before: np.ndarray, after: np.ndarray, tokens=None) -> go.F
|
|
| 78 |
fig.add_trace(go.Scatter(x=xs, y=nb, name="before", mode="lines+markers"), row=1, col=1)
|
| 79 |
fig.add_trace(go.Scatter(x=xs, y=na, name="after", mode="lines+markers"), row=1, col=1)
|
| 80 |
fig.add_trace(go.Bar(x=xs, y=cos, name="cosine", showlegend=False), row=1, col=2)
|
| 81 |
-
fig.update_xaxes(title_text="token", row=1, col=1)
|
| 82 |
-
fig.update_xaxes(title_text="token", row=1, col=2)
|
| 83 |
-
fig.update_yaxes(title_text="L2", row=1, col=1)
|
| 84 |
-
fig.update_yaxes(title_text="cosine", range=[min(0.0, float(np.min(cos)) - 0.05), 1.02], row=1, col=2)
|
| 85 |
fig.update_layout(template="plotly_white", height=380, barmode="group")
|
| 86 |
return fig
|
| 87 |
|
|
@@ -97,13 +100,13 @@ def theta_heatmap(seq_len: int, dim: int, base: float, mod_2pi: bool = False) ->
|
|
| 97 |
fig = go.Figure(
|
| 98 |
data=go.Heatmap(
|
| 99 |
z=z,
|
| 100 |
-
colorbar=dict(title="radians"),
|
| 101 |
hovertemplate="token k=%{y}<br>pair i=%{x}<br>θ=%{z:.4f}<extra></extra>",
|
| 102 |
)
|
| 103 |
)
|
| 104 |
fig.update_layout(
|
| 105 |
title=title,
|
| 106 |
-
xaxis_title="pair index i",
|
| 107 |
yaxis_title="token position k",
|
| 108 |
yaxis=dict(autorange="reversed"),
|
| 109 |
template="plotly_white",
|
|
@@ -117,8 +120,8 @@ def frequency_strip(dim: int, base: float) -> go.Figure:
|
|
| 117 |
fig = go.Figure(data=go.Bar(x=list(range(len(omega))), y=omega, name="ω_i"))
|
| 118 |
fig.update_layout(
|
| 119 |
title="Pair frequencies ω_i (pair 0 is fastest)",
|
| 120 |
-
xaxis_title="pair index i",
|
| 121 |
-
yaxis_title="ω",
|
| 122 |
yaxis_type="log",
|
| 123 |
template="plotly_white",
|
| 124 |
height=280,
|
|
|
|
| 59 |
go.Heatmap(
|
| 60 |
z=mat,
|
| 61 |
showscale=(i == 3),
|
| 62 |
+
colorbar=dict(title="matrix value") if i == 3 else None,
|
| 63 |
+
hovertemplate="token position k=%{y}<br>dimension index j=%{x}<br>value=%{z:.4f}<extra></extra>",
|
| 64 |
),
|
| 65 |
row=1,
|
| 66 |
col=i,
|
| 67 |
)
|
| 68 |
+
fig.update_xaxes(title_text="dimension index j (within selected head)", row=1, col=i)
|
| 69 |
+
fig.update_yaxes(title_text="token position k", row=1, col=i)
|
| 70 |
fig.update_yaxes(autorange="reversed", row=1, col=i)
|
| 71 |
+
fig.update_layout(template="plotly_white", height=430, margin=dict(t=60, b=65))
|
| 72 |
return fig
|
| 73 |
|
| 74 |
|
|
|
|
| 81 |
fig.add_trace(go.Scatter(x=xs, y=nb, name="before", mode="lines+markers"), row=1, col=1)
|
| 82 |
fig.add_trace(go.Scatter(x=xs, y=na, name="after", mode="lines+markers"), row=1, col=1)
|
| 83 |
fig.add_trace(go.Bar(x=xs, y=cos, name="cosine", showlegend=False), row=1, col=2)
|
| 84 |
+
fig.update_xaxes(title_text="token position k", row=1, col=1)
|
| 85 |
+
fig.update_xaxes(title_text="token position k", row=1, col=2)
|
| 86 |
+
fig.update_yaxes(title_text="L2 norm of Q/K vector", row=1, col=1)
|
| 87 |
+
fig.update_yaxes(title_text="cosine similarity (before, after)", range=[min(0.0, float(np.min(cos)) - 0.05), 1.02], row=1, col=2)
|
| 88 |
fig.update_layout(template="plotly_white", height=380, barmode="group")
|
| 89 |
return fig
|
| 90 |
|
|
|
|
| 100 |
fig = go.Figure(
|
| 101 |
data=go.Heatmap(
|
| 102 |
z=z,
|
| 103 |
+
colorbar=dict(title="rotation angle θ (radians)"),
|
| 104 |
hovertemplate="token k=%{y}<br>pair i=%{x}<br>θ=%{z:.4f}<extra></extra>",
|
| 105 |
)
|
| 106 |
)
|
| 107 |
fig.update_layout(
|
| 108 |
title=title,
|
| 109 |
+
xaxis_title="pair index i (dimension pair)",
|
| 110 |
yaxis_title="token position k",
|
| 111 |
yaxis=dict(autorange="reversed"),
|
| 112 |
template="plotly_white",
|
|
|
|
| 120 |
fig = go.Figure(data=go.Bar(x=list(range(len(omega))), y=omega, name="ω_i"))
|
| 121 |
fig.update_layout(
|
| 122 |
title="Pair frequencies ω_i (pair 0 is fastest)",
|
| 123 |
+
xaxis_title="pair index i (dimension pair)",
|
| 124 |
+
yaxis_title="frequency ω_i (radians per position)",
|
| 125 |
yaxis_type="log",
|
| 126 |
template="plotly_white",
|
| 127 |
height=280,
|