chore: declare matplotlib and apply three behavior-preserving nits
- pyproject.toml: add a figures extra with matplotlib (used by the two figure scripts) so the environment is reproducible from pyproject alone. - partition.py: correct the partition_eval_split docstring (simulated per-client eval sets from the global split, not client-owned held-out data). - protean_cnn.py: extract_embeddings now moves batches to the model device. - posthoc_statistical_audit.py: refuse to write an empty table.
This commit is contained in:
1 parent
783127296a
commit
91b0e371f7
4 files changed
+16
-5
No files matched your search
@@ -20,6 +20,10 @@ research = [
|
||||
"pandas>=2.0",
|
||||
"torch>=2.0",
|
||||
]
|
||||
figures = [
|
||||
# Used by scripts/make_final_figures.py and scripts/make_comparison_figures.py.
|
||||
"matplotlib>=3.8",
|
||||
]
|
||||
dev = [
|
||||
"pytest>=7.0",
|
||||
]
|
||||
|
||||
@@ -55,6 +55,8 @@ def write_csv(name: str, rows: list[dict]) -> None:
|
||||
# never touch any pre-existing analysis artifact.
|
||||
if not name.startswith("posthoc__"):
|
||||
raise SystemExit(f"refusing to write non-posthoc artifact: {name}")
|
||||
if not rows:
|
||||
raise SystemExit(f"refusing to write empty table: {name}")
|
||||
path = ANALYSIS / name
|
||||
with path.open("w", newline="") as fh:
|
||||
w = csv.DictWriter(fh, fieldnames=list(rows[0].keys()))
|
||||
|
||||
@@ -103,11 +103,13 @@ def partition_eval_split(
|
||||
seed: int,
|
||||
split_name: str,
|
||||
):
|
||||
"""Partition a validation/test split into per-client local eval sets.
|
||||
"""Partition a validation/test split into per-client simulated eval sets.
|
||||
|
||||
The baseline evaluation is per client (each client scores its local held-out
|
||||
data). This uses the same frozen Dirichlet algorithm with a split-specific
|
||||
seed, so it is deterministic and paired across variants.
|
||||
Clients do not own held-out data in this design; instead the *global*
|
||||
validation/test split is divided into per-client eval sets with the same
|
||||
frozen Dirichlet algorithm, using a split-specific seed. The partition is
|
||||
therefore deterministic and identical across every aggregation variant of a
|
||||
condition, which keeps per-client comparisons paired.
|
||||
"""
|
||||
import numpy as np
|
||||
|
||||
|
||||
@@ -105,11 +105,14 @@ def extract_embeddings(model, features, batch_size: int = 1024):
|
||||
import numpy as np
|
||||
import torch
|
||||
|
||||
device = next(model.parameters()).device
|
||||
model.eval()
|
||||
outputs: list[np.ndarray] = []
|
||||
with torch.no_grad():
|
||||
for start in range(0, len(features), batch_size):
|
||||
batch = torch.as_tensor(features[start : start + batch_size], dtype=torch.float32)
|
||||
batch = torch.as_tensor(
|
||||
features[start : start + batch_size], dtype=torch.float32, device=device
|
||||
)
|
||||
outputs.append(model.embedding(batch).cpu().numpy())
|
||||
if not outputs:
|
||||
return np.empty((0, model.cfg.dense_units), dtype=np.float32)
|
||||
|
||||
Reference in new issue
Block a user