experiment: validate beta selection on one paired full condition
This commit is contained in:
1 parent
ad9aa53ba7
commit
50f2da7216
8 files changed
+12434
-150
No files matched your search
@@ -252,6 +252,66 @@ def main(argv=None) -> int:
|
||||
"rare_class_recall": rare["rare_class_recall"],
|
||||
})
|
||||
|
||||
# ---- global validation evaluation (SELECTION ONLY) -------------------
|
||||
# This block never influences training and is never used to tune any
|
||||
# hyperparameter except the prototype-aggregation beta, which is selected
|
||||
# on validation metrics only. The test split is untouched here.
|
||||
val_embeddings = extract_embeddings(model, val_features)
|
||||
val_pred = nearest_prototype_predict(val_embeddings, global_prototypes)
|
||||
val_metrics = classification_metrics(val_labels, val_pred, bundle.num_classes)
|
||||
val_rare = rare_class_metrics(val_labels, val_pred, bundle.num_classes, union_rare)
|
||||
|
||||
val_eval_assignments, _ = partition_mod.partition_eval_split(
|
||||
val_labels, args.clients, args.alpha, args.dataset, args.seed, "validation"
|
||||
)
|
||||
val_per_client_rows = []
|
||||
for client_id in range(args.clients):
|
||||
idx = val_eval_assignments[client_id]
|
||||
if len(idx) == 0:
|
||||
val_per_client_rows.append({
|
||||
"client_id": client_id, "n_samples": 0, "accuracy": None,
|
||||
"macro_f1": None, "rare_class_macro_f1": None, "rare_class_recall": None,
|
||||
})
|
||||
continue
|
||||
emb = extract_embeddings(model, val_features[idx])
|
||||
pred = nearest_prototype_predict(emb, global_prototypes)
|
||||
metrics = classification_metrics(val_labels[idx], pred, bundle.num_classes)
|
||||
rare_ids = per_client_rare[client_id]
|
||||
if rare_ids:
|
||||
rare = rare_class_metrics(val_labels[idx], pred, bundle.num_classes, rare_ids)
|
||||
else:
|
||||
rare = {"rare_class_macro_f1": None, "rare_class_recall": None}
|
||||
val_per_client_rows.append({
|
||||
"client_id": client_id,
|
||||
"n_samples": int(len(idx)),
|
||||
"accuracy": metrics["accuracy"],
|
||||
"macro_f1": metrics["macro_f1"],
|
||||
"rare_class_macro_f1": rare["rare_class_macro_f1"],
|
||||
"rare_class_recall": rare["rare_class_recall"],
|
||||
})
|
||||
|
||||
def _mean_over_present(rows, key):
|
||||
values = [float(row[key]) for row in rows if row.get(key) is not None]
|
||||
return float(sum(values) / len(values)) if values else None
|
||||
|
||||
val_selection = {
|
||||
"val_rare_class_macro_f1_global": val_rare["rare_class_macro_f1"],
|
||||
"val_rare_class_recall_global": val_rare["rare_class_recall"],
|
||||
"val_macro_f1_global": val_metrics["macro_f1"],
|
||||
"val_weighted_f1_global": val_metrics["weighted_f1"],
|
||||
"val_accuracy_global": val_metrics["accuracy"],
|
||||
"val_rare_class_macro_f1_per_client_mean": _mean_over_present(
|
||||
val_per_client_rows, "rare_class_macro_f1"
|
||||
),
|
||||
"val_rare_class_recall_per_client_mean": _mean_over_present(
|
||||
val_per_client_rows, "rare_class_recall"
|
||||
),
|
||||
"val_n_eval_clients": sum(1 for row in val_per_client_rows if row["n_samples"] > 0),
|
||||
"selection_metric": "rare_class_macro_f1_per_client_mean",
|
||||
"selection_split": "validation",
|
||||
"test_used_for_selection": False,
|
||||
}
|
||||
|
||||
# ---- structured artifacts --------------------------------------------
|
||||
mode_tag = args.aggregation_mode
|
||||
if args.aggregation_mode == "support_weighted":
|
||||
@@ -301,6 +361,19 @@ def main(argv=None) -> int:
|
||||
for row in test_metrics["per_class"]
|
||||
])
|
||||
write_csv(run_dir / "per_client.csv", per_client_rows)
|
||||
write_json(run_dir / "val_global_metrics.json", {
|
||||
"accuracy": val_metrics["accuracy"],
|
||||
"macro_f1": val_metrics["macro_f1"],
|
||||
"weighted_f1": val_metrics["weighted_f1"],
|
||||
**val_rare,
|
||||
})
|
||||
write_json(run_dir / "val_confusion_matrix.json", val_metrics["confusion_matrix"])
|
||||
write_csv(run_dir / "val_per_class.csv", [
|
||||
{**row, "class_name": bundle.class_names[row["class_id"]]}
|
||||
for row in val_metrics["per_class"]
|
||||
])
|
||||
write_csv(run_dir / "val_per_client.csv", val_per_client_rows)
|
||||
write_json(run_dir / "val_selection.json", val_selection)
|
||||
write_csv(run_dir / "train_support_Nij.csv", [
|
||||
{"client_id": i, **{bundle.class_names[c]: int(support[i, c]) for c in range(bundle.num_classes)}}
|
||||
for i in range(args.clients)
|
||||
|
||||
Reference in new issue
Block a user