angerami's picture
Claude Opus 4.7
Skip transform plotting cleanly when refined dataset is missing
e40b404
Raw History Blame Contribute Delete
3.8 kB
"""Summary plots logged as MLflow artifacts in the transform stage."""
import json
import logging
import os
import matplotlib.pyplot as plt
import mlflow
import numpy as np
from datasets import load_from_disk
from matplotlib.colors import LogNorm
def _load_refined(refined_path):
df = load_from_disk(refined_path).to_pandas()
with open(os.path.join(refined_path, "metadata.json")) as f:
metadata = json.load(f)
return df, metadata
def _plot_p_w_single(df, w_bins, model_name):
centers = 0.5 * (w_bins[:-1] + w_bins[1:])
width = w_bins[1] - w_bins[0]
row = df.query("layer == 0 and head == 0").iloc[0]
p_w = np.asarray(row["P_w"], dtype=float)
fig, ax = plt.subplots(figsize=(7, 4))
ax.bar(centers, p_w, width=width, align="center")
ax.set_xlabel("Weight")
ax.set_ylabel("Probability")
ax.set_title(f"{model_name} L0 H0 — P(W) [W_QK]")
fig.tight_layout()
return fig
def _plot_p_w_stacked(df_sorted, w_bins, n_layers, n_heads, model_name):
Z = np.array([np.asarray(row["P_w"], dtype=float)
for _, row in df_sorted.iterrows()]).T
floor = max(Z[Z > 0].min() * 0.5, 1e-12) if np.any(Z > 0) else 1e-12
Z_plot = np.maximum(Z, floor)
fig, ax = plt.subplots(figsize=(9, 5))
im = ax.imshow(
Z_plot,
aspect="auto",
origin="lower",
norm=LogNorm(vmin=floor, vmax=Z_plot.max()),
extent=[0, n_layers * n_heads, w_bins[0], w_bins[-1]],
cmap="viridis",
)
ax.set_xticks([i * n_heads for i in range(n_layers)])
ax.set_xticklabels([str(i) for i in range(n_layers)])
ax.set_xlabel("Layer")
ax.set_ylabel("Weight")
ax.set_title(f"{model_name} — P(W) stacked across heads [W_QK]")
cbar = fig.colorbar(im, ax=ax)
cbar.set_label("P(W) (log)")
fig.tight_layout()
return fig
def _plot_std_heatmap(df_sorted, n_layers, n_heads, model_name):
z = df_sorted.pivot(index="layer", columns="head", values="std").values.astype(float)
fig, ax = plt.subplots(figsize=(7, 5))
im = ax.imshow(z, aspect="auto", origin="lower", cmap="viridis")
ax.set_xticks(range(n_heads))
ax.set_yticks(range(n_layers))
ax.set_xlabel("Head")
ax.set_ylabel("Layer")
ax.set_title(f"{model_name} — std(W_QK) per head")
cbar = fig.colorbar(im, ax=ax)
cbar.set_label("std")
fig.tight_layout()
return fig
def log_transform_plots(refined_path, model_name=None):
"""Build and log summary plots for the refined dataset to the active MLflow run."""
if not os.path.isdir(refined_path):
logging.warning("Refined dataset not found at %s; skipping transform plots.", refined_path)
return
df, metadata = _load_refined(refined_path)
df = df.query("weight_type == 'W_QK'")
if df.empty:
logging.warning("No W_QK rows found in %s; skipping transform plots.", refined_path)
return
if model_name is None:
model_name = df["model"].iloc[0] if "model" in df.columns else ""
if "merged" in metadata and model_name in metadata["merged"]:
meta_for_model = metadata["merged"][model_name]
else:
meta_for_model = metadata
w_bins = np.array(meta_for_model["w_bins"])
df_sorted = df.sort_values(["layer", "head"]).reset_index(drop=True)
n_layers = int(df_sorted["layer"].max()) + 1
n_heads = int(df_sorted["head"].max()) + 1
figs = {
"plots/p_w_layer0_head0.png": _plot_p_w_single(df_sorted, w_bins, model_name),
"plots/p_w_stacked.png": _plot_p_w_stacked(df_sorted, w_bins, n_layers, n_heads, model_name),
"plots/std_heatmap.png": _plot_std_heatmap(df_sorted, n_layers, n_heads, model_name),
}
for path, fig in figs.items():
mlflow.log_figure(fig, path)
plt.close(fig)