Gaze-LIPE / scripts /teacher_coordinate_audit.py
thanhhuyvan's picture
Publish KD reproducibility investigation
178f61f
Raw
History Blame Contribute Delete
2.3 kB
"""Audit cached teacher logits under plausible pitch/yaw coordinate conventions."""
from pathlib import Path
import sys
ROOT = Path(r"E:\Gaze_estimation")
sys.path.insert(0, str(ROOT / ".codex_deps"))
import h5py
import numpy as np
import pandas as pd
OUT = ROOT / "artifacts" / "kd-teacher-trap-diagnostic"
def expectation(logits):
x = logits - logits.max(axis=1, keepdims=True)
p = np.exp(x); p /= p.sum(axis=1, keepdims=True)
return (p * np.arange(90)).sum(axis=1) * 2.0 - 90.0
def vectors(pitch_deg, yaw_deg):
pitch = np.deg2rad(pitch_deg); yaw = np.deg2rad(yaw_deg)
return np.column_stack([-np.cos(pitch) * np.sin(yaw), -np.sin(pitch), -np.cos(pitch) * np.cos(yaw)])
rows = []
for subject in ("p01", "p08", "p11"):
path = ROOT / "data" / "processed" / f"{subject}_v16.h5"
with h5py.File(path, "r") as f:
a = expectation(f["teacher_pitch_logits"][:])
b = expectation(f["teacher_yaw_logits"][:])
gt = np.rad2deg(f["left_gaze"][:])
gt_vec = vectors(gt[:, 0], gt[:, 1])
for swap in (False, True):
base_p, base_y = (b, a) if swap else (a, b)
for pitch_sign in (-1, 1):
for yaw_sign in (-1, 1):
p = pitch_sign * base_p; y = yaw_sign * base_y
axis = np.abs(np.column_stack([p, y]) - gt).mean(axis=1)
pred_vec = vectors(p, y)
angular = np.rad2deg(np.arccos(np.clip((pred_vec * gt_vec).sum(axis=1), -1, 1)))
rows.append({
"subject": subject, "swap_pitch_yaw": swap,
"pitch_sign": pitch_sign, "yaw_sign": yaw_sign,
"samples": len(gt), "axis_mae_deg": axis.mean(),
"angular_3d_deg": angular.mean(),
})
df = pd.DataFrame(rows)
summary = df.groupby(["swap_pitch_yaw", "pitch_sign", "yaw_sign"], as_index=False)[["axis_mae_deg", "angular_3d_deg"]].mean()
summary["rank_axis"] = summary.axis_mae_deg.rank(method="min").astype(int)
summary["rank_3d"] = summary.angular_3d_deg.rank(method="min").astype(int)
df.to_csv(OUT / "teacher_coordinate_by_subject.csv", index=False)
summary.sort_values("axis_mae_deg").to_csv(OUT / "teacher_coordinate_summary.csv", index=False)
print(summary.sort_values("axis_mae_deg").to_string(index=False))