Buckets:

redmingwei's picture
download
raw
6.11 kB
#!/usr/bin/env python3
"""exp68p — 探查 train split 的确切形状与对应关系(不跑重计算)。
要回答四件事:
1. ViT-H-14_features_train.pt 里 img_features / text_features 各多少行?
2. 原始 train.pt 的 eeg / label / text / img 各是什么形状?
3. label 的取值个数 —— 是 16540(图像级)还是 1654(概念级)?
THINGS-EEG2 的 train split = 1654 概念 × 10 图 = 16540 图像。
4. ViT img_features 的行序是否与 EEG 的图像序一致?
检验:同一概念的 10 张图在 ViT 特征空间里应当比随机两张图更相似。
置换零 = 打乱概念分组后这个差距应消失。
"""
from __future__ import annotations
import json
import os
import time
from pathlib import Path
import numpy as np
for _v in ("OMP_NUM_THREADS", "OPENBLAS_NUM_THREADS", "MKL_NUM_THREADS"):
os.environ.setdefault(_v, "8")
FEAT_TRAIN_PT = "/training/eeg/eeg-image-decode/ViT-H-14_features_train.pt"
TRAIN_PT = "/training/eeg/things-eeg/Preprocessed_data_250Hz_whiten/sub-01/train.pt"
OUT = Path("/domains/runs/tier0-encoding")
def log(*a):
print(*a, flush=True)
def main():
import torch
t0 = time.time()
rep = {}
log("=" * 80)
log("exp68p — train split 形状与对应关系探查")
log("=" * 80)
# --- 1) ViT 特征 ---
f = torch.load(FEAT_TRAIN_PT, map_location="cpu", weights_only=False)
log(f"\n[ViT train 特征] {FEAT_TRAIN_PT}")
for k in f.keys():
v = f[k]
log(f" {k}: shape={tuple(v.shape)} dtype={v.dtype}")
rep[f"feat_{k}_shape"] = list(tuple(v.shape))
IMG = f["img_features"].numpy().astype(np.float32)
TXT = f["text_features"].numpy().astype(np.float32)
del f
# --- 2) 原始 train.pt ---
log(f"\n[原始 train.pt] {TRAIN_PT}")
d = torch.load(TRAIN_PT, map_location="cpu", weights_only=False)
for k in d.keys():
v = d[k]
if hasattr(v, "shape"):
log(f" {k}: shape={tuple(v.shape)} dtype={getattr(v,'dtype','')}")
rep[f"raw_{k}_shape"] = list(tuple(v.shape))
eeg = d["eeg"]
lab = np.asarray(d["label"])
txt = np.asarray(d["text"])
imgp = np.asarray(d["img"])
n_img_eeg = eeg.shape[0]
n_rep = eeg.shape[1]
log(f" eeg {tuple(eeg.shape)} | n_images={n_img_eeg} | n_reps={n_rep}")
# --- 3) label 语义 ---
lab0 = lab[:, 0]
uq = np.unique(lab0)
log(f"\n label 唯一值个数 = {len(uq)} (min {uq.min()}, max {uq.max()})")
log(f" label 是否沿 rep 恒定: {bool(np.all(lab == lab[:, :1]))}")
counts = np.bincount(lab0)
log(f" 每个 label 的图像数: min={counts[counts>0].min()} max={counts[counts>0].max()}")
rep["n_label_unique"] = int(len(uq))
rep["label_constant_over_rep"] = bool(np.all(lab == lab[:, :1]))
rep["images_per_label_min"] = int(counts[counts > 0].min())
rep["images_per_label_max"] = int(counts[counts > 0].max())
# label 是否按 10 张一组连续排布
order_ok = bool(np.all(np.diff(lab0) >= 0)) and bool(
len(set(lab0[:10].tolist())) == 1)
log(f" label 是否连续分组(每概念 10 张连排): {order_ok}")
log(f" label[:12] = {lab0[:12].tolist()}")
log(f" label[0:20] 每 10 个一折看: {[int(lab0[i]) for i in range(0, 20)]}")
rep["label_contiguous_groups"] = order_ok
# text 是否同一 label 内恒定
same_text = all(len(set(map(str, txt[lab0 == c]))) == 1
for c in uq[:50])
log(f" 同一 label 内 text 是否恒定(前 50 个 label): {same_text}")
rep["text_constant_within_label"] = bool(same_text)
log(f" text 样例: {str(txt[0,0])!r} | img 样例: {str(imgp[0,0])!r}")
log(f" img 样例(第 1234 行): {str(imgp[1234,0])!r}")
del eeg, d
# --- 4) ViT img_features 的行序 vs EEG 的图像序 ---
log("\n [对齐检验] 同一概念的 10 张图在 ViT 特征空间里应更相似")
if len(IMG) == n_img_eeg:
V = IMG / (np.linalg.norm(IMG, axis=1, keepdims=True) + 1e-12)
# 同一概念内的图像对(取前若干个概念的全部对)
pairs = []
for c in uq[:300]:
idx = np.where(lab0 == c)[0]
for i in range(len(idx)):
for j in range(i + 1, len(idx)):
pairs.append((idx[i], idx[j]))
pairs = np.array(pairs)
same = np.einsum("ij,ij->i", V[pairs[:, 0]], V[pairs[:, 1]]).mean()
rng = np.random.default_rng(0)
rnd = []
for _ in range(200):
p = rng.choice(n_img_eeg, size=len(pairs), replace=False)
rnd.append(np.einsum("ij,ij->i", V[p[:, 0]], V[p[:, 1]]).mean())
rnd = np.array(rnd)
log(f" 同一概念的平均余弦相似 = {same:+.4f}")
log(f" 随机配对的零分布 = {rnd.mean():+.4f} ± {rnd.std():.4f}"
f" [95%={np.percentile(rnd,95):+.4f}]")
gap = float(same - rnd.mean())
log(f" 差距 = {gap:+.4f} (置换零 p = "
f"{float((np.sum(rnd >= same) + 1) / (len(rnd) + 1)):.4f})")
rep["align_same_concept_cos"] = float(same)
rep["align_null_cos_mean"] = float(rnd.mean())
rep["align_null_cos_sd"] = float(rnd.std())
rep["align_gap"] = gap
rep["align_p"] = float((np.sum(rnd >= same) + 1) / (len(rnd) + 1))
log(f" → {'✅ ViT img_features 行序与 EEG 图像序一致' if gap > 3 * rnd.std() else '❌ 对齐存疑'}")
else:
log(f" ⚠️ ViT img_features 行数 {len(IMG)} != EEG 图像数 {n_img_eeg}"
" → 需要概念级聚合后再比对")
rep["align_note"] = "row count mismatch"
rep["elapsed_s"] = round(time.time() - t0, 1)
OUT.mkdir(parents=True, exist_ok=True)
(OUT / "exp68p_probe.json").write_text(
json.dumps(rep, indent=2, ensure_ascii=False), encoding="utf-8")
print("=== JSON BEGIN ===")
print(json.dumps(rep, indent=2, ensure_ascii=False))
print("=== JSON END ===")
log(f"\n耗时 {time.time()-t0:.0f}s")
if __name__ == "__main__":
main()

Xet Storage Details

Size:
6.11 kB
·
Xet hash:
a3f0313a3a5111a2fb6829e2884a778e6c676ea1c305514d1ab3a8e541d4ee8f

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.