physioex.explain.prototypes.posthoc#
- class physioex.explain.prototypes.posthoc.VQBottleneck(codebook_init, commitment_weight=0.25)[source]#
Bases:
ModuleDifferentiable vector quantization with straight-through estimator.
Forward:
z_q = codebook[argmin_k ||z - c_k||^2]. Backward: gradients pass through as ifz_q = z(STE), but the codebook receives gradients from||sg[z] - c_q||^2.- Parameters:
codebook_init (np.ndarray) – (M, d_model) initial codebook (e.g. from K-Means).
commitment_weight (float) – Weight β for commitment loss ||z - sg[c_q]||².
- physioex.explain.prototypes.posthoc.discover_prototypes_nmf(Z, Y, k_per_class=10, n_classes=5, random_state=42, max_iter=500)[source]#
Discover prototypes via per-class NMF decomposition.
For each class c, collects all embeddings F_c = Z[Y == c] and runs NMF: F_c ≈ E_c @ P_c, where P_c has k rows (the prototypes).
- Parameters:
- Returns:
prototypes: (k_per_class * n_classes, d_model) proto_labels: (k_per_class * n_classes,) class label per prototype
- Return type:
Tuple of
- physioex.explain.prototypes.posthoc.evaluate_metrics(y_true, y_pred, class_names=None, n_classes=5)[source]#
Compute standard sleep staging metrics.
- Parameters:
- Returns:
Dict with accuracy, f1_macro, kappa, per_class_f1, confusion_matrix.
- Return type:
- physioex.explain.prototypes.posthoc.learn_codebook_kmeans(Z, n_prototypes=50, random_state=42, batch_size=4096, max_iter=300)[source]#
Learn initial codebook via K-Means clustering.
This is Stage 1 (initialization). Use
train_codebook()for supervised refinement (Stage 2).- Parameters:
- Returns:
(n_prototypes, d_model) cluster centroids.
- Return type:
codebook
- physioex.explain.prototypes.posthoc.load_epoch_embeddings(emb_dir, split='train')[source]#
Load pre-extracted epoch embeddings and labels for a split.
Supports two layouts:
Per-subject (preferred):
emb_dir/{split}/{subject_id}_embeddings.npy emb_dir/{split}/{subject_id}_labels.npy
Flat (legacy):
emb_dir/{split}_embeddings.npy emb_dir/{split}_labels.npy
- physioex.explain.prototypes.posthoc.load_epoch_embeddings_per_subject(emb_dir, split='train')[source]#
Load per-subject epoch embeddings and labels for a split.
Returns a list of (Z_subj, Y_subj) tuples, one per subject, preserving the temporal order within each subject.
- physioex.explain.prototypes.posthoc.nearest_prototype_classify(Z, prototypes, proto_labels, metric='cosine')[source]#
Classify embeddings via nearest prototype.
For each embedding z_i, finds the prototype with highest similarity (cosine) or lowest distance (euclidean) and assigns its class label.
- physioex.explain.prototypes.posthoc.quantize_embeddings(Z, codebook)[source]#
Quantize each embedding to its nearest codebook entry (numpy).
- physioex.explain.prototypes.posthoc.train_codebook(train_subjects, downstream_fn, codebook_init, val_subjects=None, n_epochs=50, patience=5, batch_size=32, lr=0.0001, commitment_weight=0.25, device='cpu', sequence_length=21, save_path=None)[source]#
Supervised codebook refinement (Stage 2).
Optimizes the codebook so that quantized embeddings, when passed through the frozen downstream model, preserve classification accuracy.
Uses stride-1 sliding windows on real per-subject recordings so the sequence encoder sees coherent temporal context. Windows are fetched on-the-fly (no pre-materialization) to avoid OOM on large datasets.
- Parameters:
train_subjects (list[tuple[ndarray, ndarray]]) – List of (Z, Y) tuples per subject. Z: (n_epochs, d_model), Y: (n_epochs,).
downstream_fn (Callable[[Tensor], Tensor]) – Takes (B, L, d_model) -> (B, L, n_classes) logits.
codebook_init (ndarray) – (M, d_model) initial codebook from K-Means.
val_subjects (list[tuple[ndarray, ndarray]] | None) – Optional list of (Z, Y) per subject for validation.
n_epochs (int) – Maximum training epochs.
patience (int) – Early stopping patience.
batch_size (int) – Number of L-length windows per optimization step.
lr (float) – Learning rate for codebook.
commitment_weight (float) – beta for commitment loss.
device (str) – Torch device string.
sequence_length (int) – L, window length for sliding windows.
save_path (str | None) – Save best codebook here on every val improvement.
- Returns:
(M, d_model) best codebook as numpy array.
- Return type:
codebook